Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Xing Lin
qemu
Commits
fb0eaffc
Commit
fb0eaffc
authored
Jan 04, 2004
by
bellard
Browse files
PowerPC fixes (Jocelyn Mayer)
git-svn-id:
svn://svn.savannah.nongnu.org/qemu/trunk@483
c046a42c-6fe2-441c-8c8c-71466251a162
parent
07ad1b93
Changes
6
Hide whitespace changes
Inline
Side-by-side
target-ppc/cpu.h
View file @
fb0eaffc
...
...
@@ -152,7 +152,7 @@ typedef struct CPUPPCState {
/* general purpose registers */
uint32_t
gpr
[
32
];
/* floating point registers */
uint64_t
fpr
[
32
];
double
fpr
[
32
];
/* segment registers */
ppc_sr_t
sr
[
16
];
/* special purpose registers */
...
...
@@ -172,7 +172,10 @@ typedef struct CPUPPCState {
uint32_t
exception
;
/* qemu dedicated */
uint64_t
ft0
;
/* temporary float register */
/* temporary float registers */
double
ft0
;
double
ft1
;
double
ft2
;
int
interrupt_request
;
jmp_buf
jmp_env
;
int
exception_index
;
...
...
@@ -374,35 +377,4 @@ enum {
EXCP_BRANCH
=
0x104
,
/* branch instruction */
};
/*
* We need to put in some extra aux table entries to tell glibc what
* the cache block size is, so it can use the dcbz instruction safely.
*/
#define AT_DCACHEBSIZE 19
#define AT_ICACHEBSIZE 20
#define AT_UCACHEBSIZE 21
/* A special ignored type value for PPC, for glibc compatibility. */
#define AT_IGNOREPPC 22
/*
* The requirements here are:
* - keep the final alignment of sp (sp & 0xf)
* - make sure the 32-bit value at the first 16 byte aligned position of
* AUXV is greater than 16 for glibc compatibility.
* AT_IGNOREPPC is used for that.
* - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
* even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
*/
#define DLINFO_ARCH_ITEMS 3
#define ARCH_DLINFO \
do { \
/* \
* Now handle glibc compatibility. \
*/
\
NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \
NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \
\
NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20); \
NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20); \
NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \
} while (0)
#endif
/* !defined (__CPU_PPC_H__) */
target-ppc/exec.h
View file @
fb0eaffc
...
...
@@ -29,6 +29,12 @@ register uint32_t T2 asm(AREG3);
#define PARAM(n) ((uint32_t)PARAM##n)
#define SPARAM(n) ((int32_t)PARAM##n)
#define FT0 (env->ft0)
#define FT1 (env->ft1)
#define FT2 (env->ft2)
#define FTS0 ((float)env->ft0)
#define FTS1 ((float)env->ft1)
#define FTS2 ((float)env->ft2)
#define RETURN() __asm__ __volatile__("");
...
...
@@ -145,8 +151,8 @@ uint32_t do_load_xer (void);
void
do_store_xer
(
uint32_t
value
);
uint32_t
do_load_msr
(
void
);
void
do_store_msr
(
uint32_t
msr_value
);
uint32_t
do_load_fpscr
(
void
);
void
do_store_fpscr
(
uint
8
_t
mask
,
uint32_t
fp
);
void
do_load_fpscr
(
void
);
void
do_store_fpscr
(
uint
32
_t
mask
);
int32_t
do_sraw
(
int32_t
Ta
,
uint32_t
Tb
);
void
do_lmw
(
int
reg
,
uint32_t
src
);
...
...
@@ -154,4 +160,7 @@ void do_stmw (int reg, uint32_t dest);
void
do_lsw
(
uint32_t
reg
,
int
count
,
uint32_t
src
);
void
do_stsw
(
uint32_t
reg
,
int
count
,
uint32_t
dest
);
void
do_dcbz
(
void
);
void
do_icbi
(
void
);
#endif
/* !defined (__PPC_H__) */
target-ppc/helper.c
View file @
fb0eaffc
...
...
@@ -121,67 +121,67 @@ void do_store_msr (uint32_t msr_value)
}
/* The 32 MSB of the target fpr are undefined. They'll be zero... */
uint32_t
do_load_fpscr
(
void
)
/* Floating point operations helpers */
void
do_load_fpscr
(
void
)
{
return
(
fpscr_fx
<<
FPSCR_FX
)
|
(
fpscr_fex
<<
FPSCR_FEX
)
|
(
fpscr_vx
<<
FPSCR_VX
)
|
(
fpscr_ox
<<
FPSCR_OX
)
|
(
fpscr_ux
<<
FPSCR_UX
)
|
(
fpscr_zx
<<
FPSCR_ZX
)
|
(
fpscr_xx
<<
FPSCR_XX
)
|
(
fpscr_vsxnan
<<
FPSCR_VXSNAN
)
|
(
fpscr_vxisi
<<
FPSCR_VXISI
)
|
(
fpscr_vxidi
<<
FPSCR_VXIDI
)
|
(
fpscr_vxzdz
<<
FPSCR_VXZDZ
)
|
(
fpscr_vximz
<<
FPSCR_VXIMZ
)
|
(
fpscr_fr
<<
FPSCR_FR
)
|
(
fpscr_fi
<<
FPSCR_FI
)
|
(
fpscr_fprf
<<
FPSCR_FPRF
)
|
(
fpscr_vxsoft
<<
FPSCR_VXSOFT
)
|
(
fpscr_vxsqrt
<<
FPSCR_VXSQRT
)
|
(
fpscr_oe
<<
FPSCR_OE
)
|
(
fpscr_ue
<<
FPSCR_UE
)
|
(
fpscr_ze
<<
FPSCR_ZE
)
|
(
fpscr_xe
<<
FPSCR_XE
)
|
(
fpscr_ni
<<
FPSCR_NI
)
|
(
fpscr_rn
<<
FPSCR_RN
);
/* The 32 MSB of the target fpr are undefined.
* They'll be zero...
*/
union
{
double
d
;
struct
{
uint32_t
u
[
2
];
}
s
;
}
u
;
int
i
;
u
.
s
.
u
[
0
]
=
0
;
u
.
s
.
u
[
1
]
=
0
;
for
(
i
=
0
;
i
<
8
;
i
++
)
u
.
s
.
u
[
1
]
|=
env
->
fpscr
[
i
]
<<
(
4
*
i
);
FT0
=
u
.
d
;
}
/* We keep only 32 bits of input... */
/* For now, this is COMPLETELY BUGGY ! */
void
do_store_fpscr
(
uint8_t
mask
,
uint32_t
fp
)
void
do_store_fpscr
(
uint32_t
mask
)
{
/*
* We use only the 32 LSB of the incoming fpr
*/
union
{
double
d
;
struct
{
uint32_t
u
[
2
];
}
s
;
}
u
;
int
i
;
for
(
i
=
0
;
i
<
7
;
i
++
)
{
if
((
mask
&
(
1
<<
i
))
==
0
)
fp
&=
~
(
0xf
<<
(
4
*
i
));
u
.
d
=
FT0
;
if
(
mask
&
0x80
)
env
->
fpscr
[
0
]
=
(
env
->
fpscr
[
0
]
&
0x9
)
|
((
u
.
s
.
u
[
1
]
>>
28
)
&
~
0x9
);
for
(
i
=
1
;
i
<
7
;
i
++
)
{
if
(
mask
&
(
1
<<
(
7
-
i
)))
env
->
fpscr
[
i
]
=
(
u
.
s
.
u
[
1
]
>>
(
4
*
(
7
-
i
)))
&
0xF
;
}
/* TODO: update FEX & VX */
/* Set rounding mode */
switch
(
env
->
fpscr
[
0
]
&
0x3
)
{
case
0
:
/* Best approximation (round to nearest) */
fesetround
(
FE_TONEAREST
);
break
;
case
1
:
/* Smaller magnitude (round toward zero) */
fesetround
(
FE_TOWARDZERO
);
break
;
case
2
:
/* Round toward +infinite */
fesetround
(
FE_UPWARD
);
break
;
case
3
:
/* Round toward -infinite */
fesetround
(
FE_DOWNWARD
);
break
;
}
if
((
mask
&
80
)
!=
0
)
fpscr_fx
=
(
fp
>>
FPSCR_FX
)
&
0x01
;
fpscr_fex
=
(
fp
>>
FPSCR_FEX
)
&
0x01
;
fpscr_vx
=
(
fp
>>
FPSCR_VX
)
&
0x01
;
fpscr_ox
=
(
fp
>>
FPSCR_OX
)
&
0x01
;
fpscr_ux
=
(
fp
>>
FPSCR_UX
)
&
0x01
;
fpscr_zx
=
(
fp
>>
FPSCR_ZX
)
&
0x01
;
fpscr_xx
=
(
fp
>>
FPSCR_XX
)
&
0x01
;
fpscr_vsxnan
=
(
fp
>>
FPSCR_VXSNAN
)
&
0x01
;
fpscr_vxisi
=
(
fp
>>
FPSCR_VXISI
)
&
0x01
;
fpscr_vxidi
=
(
fp
>>
FPSCR_VXIDI
)
&
0x01
;
fpscr_vxzdz
=
(
fp
>>
FPSCR_VXZDZ
)
&
0x01
;
fpscr_vximz
=
(
fp
>>
FPSCR_VXIMZ
)
&
0x01
;
fpscr_fr
=
(
fp
>>
FPSCR_FR
)
&
0x01
;
fpscr_fi
=
(
fp
>>
FPSCR_FI
)
&
0x01
;
fpscr_fprf
=
(
fp
>>
FPSCR_FPRF
)
&
0x1F
;
fpscr_vxsoft
=
(
fp
>>
FPSCR_VXSOFT
)
&
0x01
;
fpscr_vxsqrt
=
(
fp
>>
FPSCR_VXSQRT
)
&
0x01
;
fpscr_oe
=
(
fp
>>
FPSCR_OE
)
&
0x01
;
fpscr_ue
=
(
fp
>>
FPSCR_UE
)
&
0x01
;
fpscr_ze
=
(
fp
>>
FPSCR_ZE
)
&
0x01
;
fpscr_xe
=
(
fp
>>
FPSCR_XE
)
&
0x01
;
fpscr_ni
=
(
fp
>>
FPSCR_NI
)
&
0x01
;
fpscr_rn
=
(
fp
>>
FPSCR_RN
)
&
0x03
;
}
int32_t
do_sraw
(
int32_t
value
,
uint32_t
shift
)
...
...
@@ -220,20 +220,14 @@ void do_lsw (uint32_t reg, int count, uint32_t src)
int
sh
;
for
(;
count
>
3
;
count
-=
4
,
src
+=
4
)
{
if
(
reg
==
32
)
reg
=
0
;
ugpr
(
reg
++
)
=
ld32
(
src
);
if
(
T2
==
32
)
T2
=
0
;
}
if
(
count
>
0
)
{
for
(
sh
=
24
,
tmp
=
0
;
count
>
0
;
count
--
,
src
++
,
sh
-=
8
)
{
if
(
reg
==
32
)
reg
=
0
;
tmp
|=
ld8
(
src
)
<<
sh
;
if
(
sh
==
0
)
{
sh
=
32
;
ugpr
(
reg
++
)
=
tmp
;
tmp
=
0
;
}
for
(
sh
=
24
;
count
>
0
;
count
--
,
src
++
,
sh
-=
8
)
{
tmp
|=
ld8
(
src
)
<<
sh
;
}
ugpr
(
reg
)
=
tmp
;
}
...
...
@@ -244,19 +238,30 @@ void do_stsw (uint32_t reg, int count, uint32_t dest)
int
sh
;
for
(;
count
>
3
;
count
-=
4
,
dest
+=
4
)
{
st32
(
dest
,
ugpr
(
reg
++
));
if
(
reg
==
32
)
reg
=
0
;
st32
(
dest
,
ugpr
(
reg
++
));
}
if
(
count
>
0
)
{
for
(
sh
=
24
;
count
>
0
;
count
--
,
dest
++
,
sh
-=
8
)
{
if
(
reg
==
32
)
reg
=
0
;
st8
(
dest
,
(
ugpr
(
reg
)
>>
sh
)
&
0xFF
);
if
(
sh
==
0
)
{
sh
=
32
;
reg
++
;
}
}
}
void
do_dcbz
(
void
)
{
int
i
;
/* Assume cache line size is 32 */
for
(
i
=
0
;
i
<
8
;
i
++
)
{
st32
(
T0
,
0
);
T0
+=
4
;
}
}
/* Instruction cache invalidation helper */
void
do_icbi
(
void
)
{
tb_invalidate_page
(
T0
);
}
target-ppc/op.c
View file @
fb0eaffc
...
...
@@ -27,6 +27,12 @@
#define Ts2 (int32_t)T2
#define FT0 (env->ft0)
#define FT1 (env->ft1)
#define FT2 (env->ft2)
#define FTS0 ((float)env->ft0)
#define FTS1 ((float)env->ft1)
#define FTS2 ((float)env->ft2)
#define PPC_OP(name) void op_##name(void)
...
...
@@ -173,6 +179,13 @@ PPC_OP(set_Rc0_1)
RETURN
();
}
/* Set Rc1 (for floating point arithmetic) */
PPC_OP
(
set_Rc1
)
{
env
->
crf
[
1
]
=
regs
->
fpscr
[
7
];
RETURN
();
}
PPC_OP
(
set_T0
)
{
T0
=
PARAM
(
1
);
...
...
@@ -278,6 +291,25 @@ PPC_OP(load_lr)
RETURN
();
}
/* FPSCR */
PPC_OP
(
load_fpscr
)
{
do_load_fpscr
();
RETURN
();
}
PPC_OP
(
store_fpscr
)
{
do_store_fpscr
(
PARAM
(
1
));
RETURN
();
}
PPC_OP
(
reset_scrfx
)
{
regs
->
fpscr
[
7
]
&=
~
0x8
;
RETURN
();
}
/* Set reservation */
PPC_OP
(
set_reservation
)
{
...
...
@@ -988,7 +1020,7 @@ PPC_OP(xori)
/* rotate left word immediate then mask insert */
PPC_OP
(
rlwimi
)
{
T0
=
rotl
(
T0
,
PARAM
(
1
)
&
PARAM
(
2
))
|
(
T
0
&
PARAM
(
3
));
T0
=
(
rotl
(
T0
,
PARAM
(
1
)
)
&
PARAM
(
2
))
|
(
T
1
&
PARAM
(
3
));
RETURN
();
}
...
...
@@ -1216,123 +1248,171 @@ PPC_OP(store_spr)
regs
->
spr
[
PARAM
(
1
)]
=
T0
;
}
/* FPSCR */
PPC_OP
(
load_fpscr
)
{
T0
=
do_load_fpscr
();
}
PPC_OP
(
store_fpscr
)
{
do_store_fpscr
(
PARAM
(
1
),
T0
);
}
/*** Floating-point store ***/
static
inline
uint32_t
dtos
(
uint64_t
f
)
{
unsigned
int
e
,
m
,
s
;
e
=
(((
f
>>
52
)
&
0x7ff
)
-
1022
)
+
126
;
s
=
(
f
>>
63
);
m
=
(
f
>>
29
);
return
(
s
<<
31
)
|
(
e
<<
23
)
|
m
;
}
static
inline
uint64_t
stod
(
uint32_t
f
)
{
unsigned
int
e
,
m
,
s
;
e
=
((
f
>>
23
)
&
0xff
)
-
126
+
1022
;
s
=
f
>>
31
;
m
=
f
&
((
1
<<
23
)
-
1
);
return
((
uint64_t
)
s
<<
63
)
|
((
uint64_t
)
e
<<
52
)
|
((
uint64_t
)
m
<<
29
);
}
PPC_OP
(
stfd_z_FT0
)
{
st
64
(
SPARAM
(
1
),
FT0
);
st
fq
((
void
*
)
SPARAM
(
1
),
FT0
);
}
PPC_OP
(
stfd_FT0
)
{
T0
+=
SPARAM
(
1
);
st
64
(
T0
,
FT0
);
st
fq
((
void
*
)
T0
,
FT0
);
}
PPC_OP
(
stfdx_z_FT0
)
{
st
64
(
T0
,
FT0
);
st
fq
((
void
*
)
T0
,
FT0
);
}
PPC_OP
(
stfdx_FT0
)
{
T0
+=
T1
;
st
64
(
T0
,
FT0
);
st
fq
((
void
*
)
T0
,
FT0
);
}
PPC_OP
(
stfs_z_FT0
)
{
st32
(
SPARAM
(
1
),
dtos
(
FT0
));
float
tmp
=
FT0
;
stfl
((
void
*
)
SPARAM
(
1
),
tmp
);
}
PPC_OP
(
stfs_FT0
)
{
float
tmp
=
FT0
;
T0
+=
SPARAM
(
1
);
st
32
(
T0
,
dtos
(
FT0
)
);
st
fl
((
void
*
)
T0
,
tmp
);
}
PPC_OP
(
stfsx_z_FT0
)
{
st32
(
T0
,
dtos
(
FT0
));
float
tmp
=
FT0
;
stfl
((
void
*
)
T0
,
tmp
);
}
PPC_OP
(
stfsx_FT0
)
{
float
tmp
=
FT0
;
T0
+=
T1
;
st
32
(
T0
,
dtos
(
FT0
)
);
st
fl
((
void
*
)
T0
,
tmp
);
}
/*** Floating-point load ***/
PPC_OP
(
lfd_z_FT0
)
{
FT0
=
ld
64
(
SPARAM
(
1
));
FT0
=
ld
fq
((
void
*
)
SPARAM
(
1
));
}
PPC_OP
(
lfd_FT0
)
{
T0
+=
SPARAM
(
1
);
FT0
=
ld
64
(
T0
);
FT0
=
ld
fq
((
void
*
)
T0
);
}
PPC_OP
(
lfdx_z_FT0
)
{
FT0
=
ld
64
(
T0
);
FT0
=
ld
fq
((
void
*
)
T0
);
}
PPC_OP
(
lfdx_FT0
)
{
T0
+=
T1
;
FT0
=
ld
64
(
T0
);
FT0
=
ld
fq
((
void
*
)
T0
);
}
PPC_OP
(
lfs_z_FT0
)
{
FT0
=
stod
(
ld32
(
SPARAM
(
1
)));
float
tmp
=
ldfl
((
void
*
)
SPARAM
(
1
));
FT0
=
tmp
;
}
PPC_OP
(
lfs_FT0
)
{
float
tmp
;
T0
+=
SPARAM
(
1
);
FT0
=
stod
(
ld32
(
T0
));
tmp
=
ldfl
((
void
*
)
T0
);
FT0
=
tmp
;
}
PPC_OP
(
lfsx_z_FT0
)
{
FT0
=
stod
(
ld32
(
T0
));
float
tmp
;
tmp
=
ldfl
((
void
*
)
T0
);
FT0
=
tmp
;
}
PPC_OP
(
lfsx_FT0
)
{
float
tmp
;
T0
+=
T1
;
tmp
=
ldfl
((
void
*
)
T0
);
FT0
=
tmp
;
}
PPC_OP
(
lwarx_z
)
{
T1
=
ld32
(
T0
);
regs
->
reserve
=
T0
;
RETURN
();
}
PPC_OP
(
lwarx
)
{
T0
+=
T1
;
T1
=
ld32
(
T0
);
regs
->
reserve
=
T0
;
RETURN
();
}
PPC_OP
(
stwcx_z
)
{
if
(
regs
->
reserve
!=
T0
)
{
env
->
crf
[
0
]
=
xer_ov
;
}
else
{
st32
(
T0
,
T1
);
env
->
crf
[
0
]
=
xer_ov
|
0x02
;
}
regs
->
reserve
=
0
;
RETURN
();
}
PPC_OP
(
stwcx
)
{
T0
+=
T1
;
FT0
=
stod
(
ld32
(
T0
));
if
(
regs
->
reserve
!=
(
T0
&
~
0x03
))
{
env
->
crf
[
0
]
=
xer_ov
;
}
else
{
st32
(
T0
,
T2
);
env
->
crf
[
0
]
=
xer_ov
|
0x02
;
}
regs
->
reserve
=
0
;
RETURN
();
}
PPC_OP
(
dcbz_z
)
{
do_dcbz
();
RETURN
();
}
PPC_OP
(
dcbz
)
{
T0
+=
T1
;
do_dcbz
();
RETURN
();
}
/* Instruction cache block invalidate */
PPC_OP
(
icbi_z
)
{
do_icbi
();
RETURN
();
}
PPC_OP
(
icbi
)
{
T0
+=
T1
;
do_icbi
();
RETURN
();
}
target-ppc/op_template.h
View file @
fb0eaffc
...
...
@@ -70,18 +70,90 @@ void OPPROTO glue(op_store_T1_crf_crf, REG)(void)
regs
->
crf
[
REG
]
=
T1
;
}
/* Floating point condition and status register moves */
void
OPPROTO
glue
(
op_load_fpscr_T0_fpscr
,
REG
)(
void
)
{
T0
=
regs
->
fpscr
[
REG
];
RETURN
();
}
#if REG == 0
void
OPPROTO
glue
(
op_store_T0_fpscr_fpscr
,
REG
)(
void
)
{
regs
->
fpscr
[
REG
]
=
(
regs
->
fpscr
[
REG
]
&
0x9
)
|
(
T0
&
~
0x9
);
RETURN
();
}
void
OPPROTO
glue
(
op_store_T0_fpscri_fpscr
,
REG
)(
void
)
{
regs
->
fpscr
[
REG
]
=
(
regs
->
fpscr
[
REG
]
&
~
0x9
)
|
(
PARAM
(
1
)
&
0x9
);
RETURN
();
}
void
OPPROTO
glue
(
op_clear_fpscr_fpscr
,
REG
)(
void
)
{
regs
->
fpscr
[
REG
]
=
(
regs
->
fpscr
[
REG
]
&
0x9
);
RETURN
();
}
#else
void
OPPROTO
glue
(
op_store_T0_fpscr_fpscr
,
REG
)(
void
)
{
regs
->
fpscr
[
REG
]
=
T0
;
RETURN
();
}
void
OPPROTO
glue
(
op_store_T0_fpscri_fpscr
,
REG
)(
void
)
{
regs
->
fpscr
[
REG
]
=
PARAM
(
1
);
RETURN
();
}
void
OPPROTO
glue
(
op_clear_fpscr_fpscr
,
REG
)(
void
)
{
regs
->
fpscr
[
REG
]
=
0x0
;
RETURN
();
}
#endif
#endif
/* REG <= 7 */
/* float moves */
void
OPPROTO
glue
(
op_load_FT0_fpr
,
REG
)(
void
)
/* floating point registers moves */
void
OPPROTO
glue
(
op_load_fpr_FT0_fpr
,
REG
)(
void
)
{
FT0
=
env
->
fpr
[
REG
];
RETURN
();
}
void
OPPROTO
glue
(
op_store_FT0_fpr
,
REG
)(
void
)
void
OPPROTO
glue
(
op_store_FT0_fpr
_fpr
,
REG
)(
void
)
{
env
->
fpr
[
REG
]
=
FT0
;
RETURN
();
}
void
OPPROTO
glue
(
op_load_fpr_FT1_fpr
,
REG
)(
void
)
{
FT1
=
env
->
fpr
[
REG
];
RETURN
();
}
void
OPPROTO
glue
(
op_store_FT1_fpr_fpr
,
REG
)(
void
)
{
env
->
fpr
[
REG
]
=
FT1
;