MIPS 64-bit FPU support, plus some collateral bugfixes in the
conditional branch handling. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2779 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
8b4af70527
commit
5a5012ecbd
@ -4,6 +4,7 @@
|
||||
- ds1225y nvram support (Herve Poussineau)
|
||||
- CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau)
|
||||
- Several Sparc fixes (Aurelien Jarno, Blue Swirl)
|
||||
- MIPS 64-bit FPU support (Thiemo Seufer)
|
||||
|
||||
version 0.9.0:
|
||||
|
||||
|
@ -575,7 +575,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
|
||||
{
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
*(uint32_t *)ptr = tswapl(FPR_W (env, i));
|
||||
*(uint32_t *)ptr = tswapl(env->fpr[i].fs[FP_ENDIAN_IDX]);
|
||||
ptr += 4;
|
||||
}
|
||||
|
||||
@ -637,7 +637,7 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
|
||||
{
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
FPR_W (env, i) = tswapl(*(uint32_t *)ptr);
|
||||
env->fpr[i].fs[FP_ENDIAN_IDX] = tswapl(*(uint32_t *)ptr);
|
||||
ptr += 4;
|
||||
}
|
||||
|
||||
|
@ -10,11 +10,12 @@ General
|
||||
when the Qemu FPU emulation is disabled. Also gdb inside the emulated
|
||||
system does not work. Both problems are caused by insufficient
|
||||
handling of self-modifying code.
|
||||
- Floating point exception emulation is incomplete.
|
||||
|
||||
MIPS64
|
||||
------
|
||||
- No 64bit TLB support
|
||||
- no 64bit wide registers for FPU
|
||||
- 64bit FPU not fully implemented
|
||||
- 64bit mul/div handling broken
|
||||
|
||||
"Generic" 4Kc system emulation
|
||||
|
@ -21,7 +21,7 @@ typedef union fpr_t fpr_t;
|
||||
union fpr_t {
|
||||
float64 fd; /* ieee double precision */
|
||||
float32 fs[2];/* ieee single precision */
|
||||
uint64_t d; /* binary single fixed-point */
|
||||
uint64_t d; /* binary double fixed-point */
|
||||
uint32_t w[2]; /* binary single fixed-point */
|
||||
};
|
||||
/* define FP_ENDIAN_IDX to access the same location
|
||||
@ -64,31 +64,35 @@ struct CPUMIPSState {
|
||||
target_ulong HI, LO;
|
||||
/* Floating point registers */
|
||||
fpr_t fpr[32];
|
||||
#define FPR(cpu, n) ((fpr_t*)&(cpu)->fpr[(n) / 2])
|
||||
#define FPR_FD(cpu, n) (FPR(cpu, n)->fd)
|
||||
#define FPR_FS(cpu, n) (FPR(cpu, n)->fs[((n) & 1) ^ FP_ENDIAN_IDX])
|
||||
#define FPR_D(cpu, n) (FPR(cpu, n)->d)
|
||||
#define FPR_W(cpu, n) (FPR(cpu, n)->w[((n) & 1) ^ FP_ENDIAN_IDX])
|
||||
|
||||
#ifndef USE_HOST_FLOAT_REGS
|
||||
fpr_t ft0;
|
||||
fpr_t ft1;
|
||||
fpr_t ft2;
|
||||
#endif
|
||||
float_status fp_status;
|
||||
/* fpu implementation/revision register */
|
||||
/* fpu implementation/revision register (fir) */
|
||||
uint32_t fcr0;
|
||||
#define FCR0_F64 22
|
||||
#define FCR0_L 21
|
||||
#define FCR0_W 20
|
||||
#define FCR0_3D 19
|
||||
#define FCR0_PS 18
|
||||
#define FCR0_D 17
|
||||
#define FCR0_S 16
|
||||
#define FCR0_PRID 8
|
||||
#define FCR0_REV 0
|
||||
/* fcsr */
|
||||
uint32_t fcr31;
|
||||
#define SET_FP_COND(reg) do { (reg) |= (1<<23); } while(0)
|
||||
#define CLEAR_FP_COND(reg) do { (reg) &= ~(1<<23); } while(0)
|
||||
#define IS_FP_COND_SET(reg) (((reg) & (1<<23)) != 0)
|
||||
#define GET_FP_CAUSE(reg) (((reg) >> 12) & 0x3f)
|
||||
#define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f)
|
||||
#define GET_FP_FLAGS(reg) (((reg) >> 2) & 0x1f)
|
||||
#define SET_FP_CAUSE(reg,v) do { (reg) = ((reg) & ~(0x3f << 12)) | ((v) << 12); } while(0)
|
||||
#define SET_FP_ENABLE(reg,v) do { (reg) = ((reg) & ~(0x1f << 7)) | ((v) << 7); } while(0)
|
||||
#define SET_FP_FLAGS(reg,v) do { (reg) = ((reg) & ~(0x1f << 2)) | ((v) << 2); } while(0)
|
||||
#define SET_FP_COND(num,env) do { (env->fcr31) |= ((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23))); } while(0)
|
||||
#define CLEAR_FP_COND(num,env) do { (env->fcr31) &= ~((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23))); } while(0)
|
||||
#define IS_FP_COND_SET(num,env) (((env->fcr31) & ((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23)))) != 0)
|
||||
#define GET_FP_CAUSE(reg) (((reg) >> 12) & 0x3f)
|
||||
#define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f)
|
||||
#define GET_FP_FLAGS(reg) (((reg) >> 2) & 0x1f)
|
||||
#define SET_FP_CAUSE(reg,v) do { (reg) = ((reg) & ~(0x3f << 12)) | ((v & 0x3f) << 12); } while(0)
|
||||
#define SET_FP_ENABLE(reg,v) do { (reg) = ((reg) & ~(0x1f << 7)) | ((v & 0x1f) << 7); } while(0)
|
||||
#define SET_FP_FLAGS(reg,v) do { (reg) = ((reg) & ~(0x1f << 2)) | ((v & 0x1f) << 2); } while(0)
|
||||
#define UPDATE_FP_FLAGS(reg,v) do { (reg) |= ((v & 0x1f) << 2); } while(0)
|
||||
#define FP_INEXACT 1
|
||||
#define FP_UNDERFLOW 2
|
||||
#define FP_OVERFLOW 4
|
||||
@ -267,6 +271,7 @@ struct CPUMIPSState {
|
||||
|
||||
int SYNCI_Step; /* Address step size for SYNCI */
|
||||
int CCRes; /* Cycle count resolution/divisor */
|
||||
int Status_rw_bitmask; /* Read/write bits in CP0_Status */
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
target_ulong tls_value;
|
||||
@ -330,10 +335,11 @@ enum {
|
||||
EXCP_RI,
|
||||
EXCP_OVERFLOW,
|
||||
EXCP_TRAP,
|
||||
EXCP_FPE,
|
||||
EXCP_DDBS,
|
||||
EXCP_DWATCH,
|
||||
EXCP_LAE,
|
||||
EXCP_SAE, /* 24 */
|
||||
EXCP_LAE, /* 24 */
|
||||
EXCP_SAE,
|
||||
EXCP_LTLBL,
|
||||
EXCP_TLBL,
|
||||
EXCP_TLBS,
|
||||
|
@ -29,12 +29,18 @@ register target_ulong T2 asm(AREG3);
|
||||
#define FST0 (env->ft0.fs[FP_ENDIAN_IDX])
|
||||
#define FST1 (env->ft1.fs[FP_ENDIAN_IDX])
|
||||
#define FST2 (env->ft2.fs[FP_ENDIAN_IDX])
|
||||
#define FSTH0 (env->ft0.fs[!FP_ENDIAN_IDX])
|
||||
#define FSTH1 (env->ft1.fs[!FP_ENDIAN_IDX])
|
||||
#define FSTH2 (env->ft2.fs[!FP_ENDIAN_IDX])
|
||||
#define DT0 (env->ft0.d)
|
||||
#define DT1 (env->ft1.d)
|
||||
#define DT2 (env->ft2.d)
|
||||
#define WT0 (env->ft0.w[FP_ENDIAN_IDX])
|
||||
#define WT1 (env->ft1.w[FP_ENDIAN_IDX])
|
||||
#define WT2 (env->ft2.w[FP_ENDIAN_IDX])
|
||||
#define WTH0 (env->ft0.w[!FP_ENDIAN_IDX])
|
||||
#define WTH1 (env->ft1.w[!FP_ENDIAN_IDX])
|
||||
#define WTH2 (env->ft2.w[!FP_ENDIAN_IDX])
|
||||
#endif
|
||||
|
||||
#if defined (DEBUG_OP)
|
||||
|
@ -19,75 +19,103 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#if defined(SFREG)
|
||||
#if defined(FREG)
|
||||
|
||||
#define OP_WLOAD_FREG(treg, tregname, SFREG) \
|
||||
void glue(glue(op_load_fpr_,tregname), SFREG) (void) \
|
||||
{ \
|
||||
treg = FPR_W(env, SFREG); \
|
||||
RETURN(); \
|
||||
#define OP_WLOAD_FREG(treg, tregname, FREG) \
|
||||
void glue(glue(op_load_fpr_,tregname), FREG) (void) \
|
||||
{ \
|
||||
treg = env->fpr[FREG].fs[FP_ENDIAN_IDX]; \
|
||||
RETURN(); \
|
||||
}
|
||||
|
||||
#define OP_WSTORE_FREG(treg, tregname, SFREG) \
|
||||
void glue(glue(op_store_fpr_,tregname), SFREG) (void)\
|
||||
{ \
|
||||
FPR_W(env, SFREG) = treg; \
|
||||
RETURN(); \
|
||||
#define OP_WSTORE_FREG(treg, tregname, FREG) \
|
||||
void glue(glue(op_store_fpr_,tregname), FREG) (void) \
|
||||
{ \
|
||||
env->fpr[FREG].fs[FP_ENDIAN_IDX] = treg; \
|
||||
RETURN(); \
|
||||
}
|
||||
|
||||
/* WT0 = SFREG.w: op_load_fpr_WT0_fprSFREG */
|
||||
OP_WLOAD_FREG(WT0, WT0_fpr, SFREG)
|
||||
/* SFREG.w = WT0: op_store_fpr_WT0_fprSFREG */
|
||||
OP_WSTORE_FREG(WT0, WT0_fpr, SFREG)
|
||||
/* WT0 = FREG.w: op_load_fpr_WT0_fprFREG */
|
||||
OP_WLOAD_FREG(WT0, WT0_fpr, FREG)
|
||||
/* FREG.w = WT0: op_store_fpr_WT0_fprFREG */
|
||||
OP_WSTORE_FREG(WT0, WT0_fpr, FREG)
|
||||
|
||||
OP_WLOAD_FREG(WT1, WT1_fpr, SFREG)
|
||||
OP_WSTORE_FREG(WT1, WT1_fpr, SFREG)
|
||||
OP_WLOAD_FREG(WT1, WT1_fpr, FREG)
|
||||
OP_WSTORE_FREG(WT1, WT1_fpr, FREG)
|
||||
|
||||
OP_WLOAD_FREG(WT2, WT2_fpr, SFREG)
|
||||
OP_WSTORE_FREG(WT2, WT2_fpr, SFREG)
|
||||
OP_WLOAD_FREG(WT2, WT2_fpr, FREG)
|
||||
OP_WSTORE_FREG(WT2, WT2_fpr, FREG)
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(DFREG)
|
||||
|
||||
#define OP_DLOAD_FREG(treg, tregname, DFREG) \
|
||||
void glue(glue(op_load_fpr_,tregname), DFREG) (void) \
|
||||
{ \
|
||||
treg = FPR_D(env, DFREG); \
|
||||
RETURN(); \
|
||||
#define OP_DLOAD_FREG(treg, tregname, FREG) \
|
||||
void glue(glue(op_load_fpr_,tregname), FREG) (void) \
|
||||
{ \
|
||||
if (env->CP0_Status & (1 << CP0St_FR)) \
|
||||
treg = env->fpr[FREG].fd; \
|
||||
else \
|
||||
treg = (uint64_t)(env->fpr[FREG | 1].fs[FP_ENDIAN_IDX]) << 32 | \
|
||||
env->fpr[FREG & ~1].fs[FP_ENDIAN_IDX]; \
|
||||
RETURN(); \
|
||||
}
|
||||
|
||||
#define OP_DSTORE_FREG(treg, tregname, DFREG) \
|
||||
void glue(glue(op_store_fpr_,tregname), DFREG) (void)\
|
||||
{ \
|
||||
FPR_D(env, DFREG) = treg; \
|
||||
RETURN(); \
|
||||
#define OP_DSTORE_FREG(treg, tregname, FREG) \
|
||||
void glue(glue(op_store_fpr_,tregname), FREG) (void) \
|
||||
{ \
|
||||
if (env->CP0_Status & (1 << CP0St_FR)) \
|
||||
env->fpr[FREG].fd = treg; \
|
||||
else { \
|
||||
env->fpr[FREG | 1].fs[FP_ENDIAN_IDX] = treg >> 32; \
|
||||
env->fpr[FREG & ~1].fs[FP_ENDIAN_IDX] = treg; \
|
||||
} \
|
||||
RETURN(); \
|
||||
}
|
||||
|
||||
OP_DLOAD_FREG(DT0, DT0_fpr, DFREG)
|
||||
OP_DSTORE_FREG(DT0, DT0_fpr, DFREG)
|
||||
OP_DLOAD_FREG(DT0, DT0_fpr, FREG)
|
||||
OP_DSTORE_FREG(DT0, DT0_fpr, FREG)
|
||||
|
||||
OP_DLOAD_FREG(DT1, DT1_fpr, DFREG)
|
||||
OP_DSTORE_FREG(DT1, DT1_fpr, DFREG)
|
||||
OP_DLOAD_FREG(DT1, DT1_fpr, FREG)
|
||||
OP_DSTORE_FREG(DT1, DT1_fpr, FREG)
|
||||
|
||||
OP_DLOAD_FREG(DT2, DT2_fpr, DFREG)
|
||||
OP_DSTORE_FREG(DT2, DT2_fpr, DFREG)
|
||||
OP_DLOAD_FREG(DT2, DT2_fpr, FREG)
|
||||
OP_DSTORE_FREG(DT2, DT2_fpr, FREG)
|
||||
|
||||
#define OP_PSLOAD_FREG(treg, tregname, FREG) \
|
||||
void glue(glue(op_load_fpr_,tregname), FREG) (void) \
|
||||
{ \
|
||||
treg = env->fpr[FREG].fs[!FP_ENDIAN_IDX]; \
|
||||
RETURN(); \
|
||||
}
|
||||
|
||||
#define OP_PSSTORE_FREG(treg, tregname, FREG) \
|
||||
void glue(glue(op_store_fpr_,tregname), FREG) (void) \
|
||||
{ \
|
||||
env->fpr[FREG].fs[!FP_ENDIAN_IDX] = treg; \
|
||||
RETURN(); \
|
||||
}
|
||||
|
||||
OP_PSLOAD_FREG(WTH0, WTH0_fpr, FREG)
|
||||
OP_PSSTORE_FREG(WTH0, WTH0_fpr, FREG)
|
||||
|
||||
OP_PSLOAD_FREG(WTH1, WTH1_fpr, FREG)
|
||||
OP_PSSTORE_FREG(WTH1, WTH1_fpr, FREG)
|
||||
|
||||
OP_PSLOAD_FREG(WTH2, WTH2_fpr, FREG)
|
||||
OP_PSSTORE_FREG(WTH2, WTH2_fpr, FREG)
|
||||
|
||||
#endif
|
||||
|
||||
#if defined (FTN)
|
||||
|
||||
#define SET_RESET(treg, tregname) \
|
||||
#define SET_RESET(treg, tregname) \
|
||||
void glue(op_set, tregname)(void) \
|
||||
{ \
|
||||
treg = PARAM1; \
|
||||
RETURN(); \
|
||||
} \
|
||||
{ \
|
||||
treg = PARAM1; \
|
||||
RETURN(); \
|
||||
} \
|
||||
void glue(op_reset, tregname)(void) \
|
||||
{ \
|
||||
treg = 0; \
|
||||
RETURN(); \
|
||||
} \
|
||||
{ \
|
||||
treg = 0; \
|
||||
RETURN(); \
|
||||
}
|
||||
|
||||
SET_RESET(WT0, _WT0)
|
||||
SET_RESET(WT1, _WT1)
|
||||
@ -95,6 +123,9 @@ SET_RESET(WT2, _WT2)
|
||||
SET_RESET(DT0, _DT0)
|
||||
SET_RESET(DT1, _DT1)
|
||||
SET_RESET(DT2, _DT2)
|
||||
SET_RESET(WTH0, _WTH0)
|
||||
SET_RESET(WTH1, _WTH1)
|
||||
SET_RESET(WTH2, _WTH2)
|
||||
|
||||
#undef SET_RESET
|
||||
#endif
|
||||
|
@ -379,6 +379,9 @@ void do_interrupt (CPUState *env)
|
||||
case EXCP_TRAP:
|
||||
cause = 13;
|
||||
goto set_EPC;
|
||||
case EXCP_FPE:
|
||||
cause = 15;
|
||||
goto set_EPC;
|
||||
case EXCP_LTLBL:
|
||||
cause = 1;
|
||||
goto set_EPC;
|
||||
|
934
target-mips/op.c
934
target-mips/op.c
File diff suppressed because it is too large
Load Diff
@ -220,3 +220,35 @@ void glue(op_sdc1, MEMSUFFIX) (void)
|
||||
glue(stq, MEMSUFFIX)(T0, DT0);
|
||||
RETURN();
|
||||
}
|
||||
void glue(op_lwxc1, MEMSUFFIX) (void)
|
||||
{
|
||||
WT0 = glue(ldl, MEMSUFFIX)(T0 + T1);
|
||||
RETURN();
|
||||
}
|
||||
void glue(op_swxc1, MEMSUFFIX) (void)
|
||||
{
|
||||
glue(stl, MEMSUFFIX)(T0 + T1, WT0);
|
||||
RETURN();
|
||||
}
|
||||
void glue(op_ldxc1, MEMSUFFIX) (void)
|
||||
{
|
||||
DT0 = glue(ldq, MEMSUFFIX)(T0 + T1);
|
||||
RETURN();
|
||||
}
|
||||
void glue(op_sdxc1, MEMSUFFIX) (void)
|
||||
{
|
||||
glue(stq, MEMSUFFIX)(T0 + T1, DT0);
|
||||
RETURN();
|
||||
}
|
||||
void glue(op_luxc1, MEMSUFFIX) (void)
|
||||
{
|
||||
/* XXX: is defined as unaligned */
|
||||
DT0 = glue(ldq, MEMSUFFIX)(T0 + T1);
|
||||
RETURN();
|
||||
}
|
||||
void glue(op_suxc1, MEMSUFFIX) (void)
|
||||
{
|
||||
/* XXX: is defined as unaligned */
|
||||
glue(stq, MEMSUFFIX)(T0 + T1, DT0);
|
||||
RETURN();
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -55,7 +55,7 @@
|
||||
|
||||
/* Define a implementation number of 1.
|
||||
Define a major version 1, minor version 0. */
|
||||
#define MIPS_FCR0 ((0 << 16) | (1 << 8) | (1 << 4) | 0)
|
||||
#define MIPS_FCR0 ((0 << FCR0_S) | (0x1 << FCR0_PRID) | (0x10 << FCR0_REV))
|
||||
|
||||
|
||||
struct mips_def_t {
|
||||
@ -69,6 +69,7 @@ struct mips_def_t {
|
||||
int32_t CP0_Config7;
|
||||
int32_t SYNCI_Step;
|
||||
int32_t CCRes;
|
||||
int32_t Status_rw_bitmask;
|
||||
int32_t CP1_fcr0;
|
||||
};
|
||||
|
||||
@ -86,7 +87,7 @@ static mips_def_t mips_defs[] =
|
||||
.CP0_Config3 = MIPS_CONFIG3,
|
||||
.SYNCI_Step = 32,
|
||||
.CCRes = 2,
|
||||
.CP1_fcr0 = MIPS_FCR0,
|
||||
.Status_rw_bitmask = 0x3278FF17,
|
||||
},
|
||||
{
|
||||
.name = "4KEcR1",
|
||||
@ -97,7 +98,6 @@ static mips_def_t mips_defs[] =
|
||||
.CP0_Config3 = MIPS_CONFIG3,
|
||||
.SYNCI_Step = 32,
|
||||
.CCRes = 2,
|
||||
.CP1_fcr0 = MIPS_FCR0,
|
||||
},
|
||||
{
|
||||
.name = "4KEc",
|
||||
@ -108,7 +108,7 @@ static mips_def_t mips_defs[] =
|
||||
.CP0_Config3 = MIPS_CONFIG3,
|
||||
.SYNCI_Step = 32,
|
||||
.CCRes = 2,
|
||||
.CP1_fcr0 = MIPS_FCR0,
|
||||
.Status_rw_bitmask = 0x3278FF17,
|
||||
},
|
||||
{
|
||||
.name = "24Kc",
|
||||
@ -119,7 +119,7 @@ static mips_def_t mips_defs[] =
|
||||
.CP0_Config3 = MIPS_CONFIG3,
|
||||
.SYNCI_Step = 32,
|
||||
.CCRes = 2,
|
||||
.CP1_fcr0 = MIPS_FCR0,
|
||||
.Status_rw_bitmask = 0x3278FF17,
|
||||
},
|
||||
{
|
||||
.name = "24Kf",
|
||||
@ -130,7 +130,9 @@ static mips_def_t mips_defs[] =
|
||||
.CP0_Config3 = MIPS_CONFIG3,
|
||||
.SYNCI_Step = 32,
|
||||
.CCRes = 2,
|
||||
.CP1_fcr0 = MIPS_FCR0,
|
||||
.Status_rw_bitmask = 0x3678FF17,
|
||||
.CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
|
||||
(1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID),
|
||||
},
|
||||
#else
|
||||
{
|
||||
@ -142,7 +144,10 @@ static mips_def_t mips_defs[] =
|
||||
.CP0_Config3 = MIPS_CONFIG3,
|
||||
.SYNCI_Step = 16,
|
||||
.CCRes = 2,
|
||||
.CP1_fcr0 = MIPS_FCR0,
|
||||
.Status_rw_bitmask = 0x3678FFFF,
|
||||
.CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
|
||||
(1 << FCR0_D) | (1 << FCR0_S) |
|
||||
(0x4 << FCR0_PRID) | (0x0 << FCR0_REV),
|
||||
},
|
||||
#endif
|
||||
};
|
||||
@ -191,6 +196,7 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def)
|
||||
env->CP0_Config7 = def->CP0_Config7;
|
||||
env->SYNCI_Step = def->SYNCI_Step;
|
||||
env->CCRes = def->CCRes;
|
||||
env->Status_rw_bitmask = def->Status_rw_bitmask;
|
||||
env->fcr0 = def->CP1_fcr0;
|
||||
#if defined (MIPS_USES_R4K_TLB)
|
||||
env->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63);
|
||||
|
Loading…
Reference in New Issue
Block a user