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:
ths 2007-05-07 13:55:33 +00:00
parent 8b4af70527
commit 5a5012ecbd
11 changed files with 1740 additions and 557 deletions

View File

@ -4,6 +4,7 @@
- ds1225y nvram support (Herve Poussineau) - ds1225y nvram support (Herve Poussineau)
- CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau) - CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau)
- Several Sparc fixes (Aurelien Jarno, Blue Swirl) - Several Sparc fixes (Aurelien Jarno, Blue Swirl)
- MIPS 64-bit FPU support (Thiemo Seufer)
version 0.9.0: version 0.9.0:

View File

@ -575,7 +575,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
{ {
for (i = 0; i < 32; i++) 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; 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++) 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; ptr += 4;
} }

View File

@ -10,11 +10,12 @@ General
when the Qemu FPU emulation is disabled. Also gdb inside the emulated when the Qemu FPU emulation is disabled. Also gdb inside the emulated
system does not work. Both problems are caused by insufficient system does not work. Both problems are caused by insufficient
handling of self-modifying code. handling of self-modifying code.
- Floating point exception emulation is incomplete.
MIPS64 MIPS64
------ ------
- No 64bit TLB support - No 64bit TLB support
- no 64bit wide registers for FPU - 64bit FPU not fully implemented
- 64bit mul/div handling broken - 64bit mul/div handling broken
"Generic" 4Kc system emulation "Generic" 4Kc system emulation

View File

@ -21,7 +21,7 @@ typedef union fpr_t fpr_t;
union fpr_t { union fpr_t {
float64 fd; /* ieee double precision */ float64 fd; /* ieee double precision */
float32 fs[2];/* ieee single 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 */ uint32_t w[2]; /* binary single fixed-point */
}; };
/* define FP_ENDIAN_IDX to access the same location /* define FP_ENDIAN_IDX to access the same location
@ -64,31 +64,35 @@ struct CPUMIPSState {
target_ulong HI, LO; target_ulong HI, LO;
/* Floating point registers */ /* Floating point registers */
fpr_t fpr[32]; 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 #ifndef USE_HOST_FLOAT_REGS
fpr_t ft0; fpr_t ft0;
fpr_t ft1; fpr_t ft1;
fpr_t ft2; fpr_t ft2;
#endif #endif
float_status fp_status; float_status fp_status;
/* fpu implementation/revision register */ /* fpu implementation/revision register (fir) */
uint32_t fcr0; 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 */ /* fcsr */
uint32_t fcr31; uint32_t fcr31;
#define SET_FP_COND(reg) do { (reg) |= (1<<23); } while(0) #define SET_FP_COND(num,env) do { (env->fcr31) |= ((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23))); } while(0)
#define CLEAR_FP_COND(reg) do { (reg) &= ~(1<<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(reg) (((reg) & (1<<23)) != 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_CAUSE(reg) (((reg) >> 12) & 0x3f)
#define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f) #define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f)
#define GET_FP_FLAGS(reg) (((reg) >> 2) & 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_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) << 7); } 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) << 2); } 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_INEXACT 1
#define FP_UNDERFLOW 2 #define FP_UNDERFLOW 2
#define FP_OVERFLOW 4 #define FP_OVERFLOW 4
@ -267,6 +271,7 @@ struct CPUMIPSState {
int SYNCI_Step; /* Address step size for SYNCI */ int SYNCI_Step; /* Address step size for SYNCI */
int CCRes; /* Cycle count resolution/divisor */ int CCRes; /* Cycle count resolution/divisor */
int Status_rw_bitmask; /* Read/write bits in CP0_Status */
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
target_ulong tls_value; target_ulong tls_value;
@ -330,10 +335,11 @@ enum {
EXCP_RI, EXCP_RI,
EXCP_OVERFLOW, EXCP_OVERFLOW,
EXCP_TRAP, EXCP_TRAP,
EXCP_FPE,
EXCP_DDBS, EXCP_DDBS,
EXCP_DWATCH, EXCP_DWATCH,
EXCP_LAE, EXCP_LAE, /* 24 */
EXCP_SAE, /* 24 */ EXCP_SAE,
EXCP_LTLBL, EXCP_LTLBL,
EXCP_TLBL, EXCP_TLBL,
EXCP_TLBS, EXCP_TLBS,

View File

@ -29,12 +29,18 @@ register target_ulong T2 asm(AREG3);
#define FST0 (env->ft0.fs[FP_ENDIAN_IDX]) #define FST0 (env->ft0.fs[FP_ENDIAN_IDX])
#define FST1 (env->ft1.fs[FP_ENDIAN_IDX]) #define FST1 (env->ft1.fs[FP_ENDIAN_IDX])
#define FST2 (env->ft2.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 DT0 (env->ft0.d)
#define DT1 (env->ft1.d) #define DT1 (env->ft1.d)
#define DT2 (env->ft2.d) #define DT2 (env->ft2.d)
#define WT0 (env->ft0.w[FP_ENDIAN_IDX]) #define WT0 (env->ft0.w[FP_ENDIAN_IDX])
#define WT1 (env->ft1.w[FP_ENDIAN_IDX]) #define WT1 (env->ft1.w[FP_ENDIAN_IDX])
#define WT2 (env->ft2.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 #endif
#if defined (DEBUG_OP) #if defined (DEBUG_OP)

View File

@ -19,75 +19,103 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * 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) \ #define OP_WLOAD_FREG(treg, tregname, FREG) \
void glue(glue(op_load_fpr_,tregname), SFREG) (void) \ void glue(glue(op_load_fpr_,tregname), FREG) (void) \
{ \ { \
treg = FPR_W(env, SFREG); \ treg = env->fpr[FREG].fs[FP_ENDIAN_IDX]; \
RETURN(); \ RETURN(); \
} }
#define OP_WSTORE_FREG(treg, tregname, SFREG) \ #define OP_WSTORE_FREG(treg, tregname, FREG) \
void glue(glue(op_store_fpr_,tregname), SFREG) (void)\ void glue(glue(op_store_fpr_,tregname), FREG) (void) \
{ \ { \
FPR_W(env, SFREG) = treg; \ env->fpr[FREG].fs[FP_ENDIAN_IDX] = treg; \
RETURN(); \ RETURN(); \
} }
/* WT0 = SFREG.w: op_load_fpr_WT0_fprSFREG */ /* WT0 = FREG.w: op_load_fpr_WT0_fprFREG */
OP_WLOAD_FREG(WT0, WT0_fpr, SFREG) OP_WLOAD_FREG(WT0, WT0_fpr, FREG)
/* SFREG.w = WT0: op_store_fpr_WT0_fprSFREG */ /* FREG.w = WT0: op_store_fpr_WT0_fprFREG */
OP_WSTORE_FREG(WT0, WT0_fpr, SFREG) OP_WSTORE_FREG(WT0, WT0_fpr, FREG)
OP_WLOAD_FREG(WT1, WT1_fpr, SFREG) OP_WLOAD_FREG(WT1, WT1_fpr, FREG)
OP_WSTORE_FREG(WT1, WT1_fpr, SFREG) OP_WSTORE_FREG(WT1, WT1_fpr, FREG)
OP_WLOAD_FREG(WT2, WT2_fpr, SFREG) OP_WLOAD_FREG(WT2, WT2_fpr, FREG)
OP_WSTORE_FREG(WT2, WT2_fpr, SFREG) OP_WSTORE_FREG(WT2, WT2_fpr, FREG)
#endif #define OP_DLOAD_FREG(treg, tregname, FREG) \
void glue(glue(op_load_fpr_,tregname), FREG) (void) \
#if defined(DFREG) { \
if (env->CP0_Status & (1 << CP0St_FR)) \
#define OP_DLOAD_FREG(treg, tregname, DFREG) \ treg = env->fpr[FREG].fd; \
void glue(glue(op_load_fpr_,tregname), DFREG) (void) \ else \
{ \ treg = (uint64_t)(env->fpr[FREG | 1].fs[FP_ENDIAN_IDX]) << 32 | \
treg = FPR_D(env, DFREG); \ env->fpr[FREG & ~1].fs[FP_ENDIAN_IDX]; \
RETURN(); \ RETURN(); \
} }
#define OP_DSTORE_FREG(treg, tregname, DFREG) \ #define OP_DSTORE_FREG(treg, tregname, FREG) \
void glue(glue(op_store_fpr_,tregname), DFREG) (void)\ void glue(glue(op_store_fpr_,tregname), FREG) (void) \
{ \ { \
FPR_D(env, DFREG) = treg; \ if (env->CP0_Status & (1 << CP0St_FR)) \
RETURN(); \ 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_DLOAD_FREG(DT0, DT0_fpr, FREG)
OP_DSTORE_FREG(DT0, DT0_fpr, DFREG) OP_DSTORE_FREG(DT0, DT0_fpr, FREG)
OP_DLOAD_FREG(DT1, DT1_fpr, DFREG) OP_DLOAD_FREG(DT1, DT1_fpr, FREG)
OP_DSTORE_FREG(DT1, DT1_fpr, DFREG) OP_DSTORE_FREG(DT1, DT1_fpr, FREG)
OP_DLOAD_FREG(DT2, DT2_fpr, DFREG) OP_DLOAD_FREG(DT2, DT2_fpr, FREG)
OP_DSTORE_FREG(DT2, DT2_fpr, DFREG) 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 #endif
#if defined (FTN) #if defined (FTN)
#define SET_RESET(treg, tregname) \ #define SET_RESET(treg, tregname) \
void glue(op_set, tregname)(void) \ void glue(op_set, tregname)(void) \
{ \ { \
treg = PARAM1; \ treg = PARAM1; \
RETURN(); \ RETURN(); \
} \ } \
void glue(op_reset, tregname)(void) \ void glue(op_reset, tregname)(void) \
{ \ { \
treg = 0; \ treg = 0; \
RETURN(); \ RETURN(); \
} \ }
SET_RESET(WT0, _WT0) SET_RESET(WT0, _WT0)
SET_RESET(WT1, _WT1) SET_RESET(WT1, _WT1)
@ -95,6 +123,9 @@ SET_RESET(WT2, _WT2)
SET_RESET(DT0, _DT0) SET_RESET(DT0, _DT0)
SET_RESET(DT1, _DT1) SET_RESET(DT1, _DT1)
SET_RESET(DT2, _DT2) SET_RESET(DT2, _DT2)
SET_RESET(WTH0, _WTH0)
SET_RESET(WTH1, _WTH1)
SET_RESET(WTH2, _WTH2)
#undef SET_RESET #undef SET_RESET
#endif #endif

View File

@ -379,6 +379,9 @@ void do_interrupt (CPUState *env)
case EXCP_TRAP: case EXCP_TRAP:
cause = 13; cause = 13;
goto set_EPC; goto set_EPC;
case EXCP_FPE:
cause = 15;
goto set_EPC;
case EXCP_LTLBL: case EXCP_LTLBL:
cause = 1; cause = 1;
goto set_EPC; goto set_EPC;

File diff suppressed because it is too large Load Diff

View File

@ -220,3 +220,35 @@ void glue(op_sdc1, MEMSUFFIX) (void)
glue(stq, MEMSUFFIX)(T0, DT0); glue(stq, MEMSUFFIX)(T0, DT0);
RETURN(); 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

View File

@ -55,7 +55,7 @@
/* Define a implementation number of 1. /* Define a implementation number of 1.
Define a major version 1, minor version 0. */ 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 { struct mips_def_t {
@ -69,6 +69,7 @@ struct mips_def_t {
int32_t CP0_Config7; int32_t CP0_Config7;
int32_t SYNCI_Step; int32_t SYNCI_Step;
int32_t CCRes; int32_t CCRes;
int32_t Status_rw_bitmask;
int32_t CP1_fcr0; int32_t CP1_fcr0;
}; };
@ -86,7 +87,7 @@ static mips_def_t mips_defs[] =
.CP0_Config3 = MIPS_CONFIG3, .CP0_Config3 = MIPS_CONFIG3,
.SYNCI_Step = 32, .SYNCI_Step = 32,
.CCRes = 2, .CCRes = 2,
.CP1_fcr0 = MIPS_FCR0, .Status_rw_bitmask = 0x3278FF17,
}, },
{ {
.name = "4KEcR1", .name = "4KEcR1",
@ -97,7 +98,6 @@ static mips_def_t mips_defs[] =
.CP0_Config3 = MIPS_CONFIG3, .CP0_Config3 = MIPS_CONFIG3,
.SYNCI_Step = 32, .SYNCI_Step = 32,
.CCRes = 2, .CCRes = 2,
.CP1_fcr0 = MIPS_FCR0,
}, },
{ {
.name = "4KEc", .name = "4KEc",
@ -108,7 +108,7 @@ static mips_def_t mips_defs[] =
.CP0_Config3 = MIPS_CONFIG3, .CP0_Config3 = MIPS_CONFIG3,
.SYNCI_Step = 32, .SYNCI_Step = 32,
.CCRes = 2, .CCRes = 2,
.CP1_fcr0 = MIPS_FCR0, .Status_rw_bitmask = 0x3278FF17,
}, },
{ {
.name = "24Kc", .name = "24Kc",
@ -119,7 +119,7 @@ static mips_def_t mips_defs[] =
.CP0_Config3 = MIPS_CONFIG3, .CP0_Config3 = MIPS_CONFIG3,
.SYNCI_Step = 32, .SYNCI_Step = 32,
.CCRes = 2, .CCRes = 2,
.CP1_fcr0 = MIPS_FCR0, .Status_rw_bitmask = 0x3278FF17,
}, },
{ {
.name = "24Kf", .name = "24Kf",
@ -130,7 +130,9 @@ static mips_def_t mips_defs[] =
.CP0_Config3 = MIPS_CONFIG3, .CP0_Config3 = MIPS_CONFIG3,
.SYNCI_Step = 32, .SYNCI_Step = 32,
.CCRes = 2, .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 #else
{ {
@ -142,7 +144,10 @@ static mips_def_t mips_defs[] =
.CP0_Config3 = MIPS_CONFIG3, .CP0_Config3 = MIPS_CONFIG3,
.SYNCI_Step = 16, .SYNCI_Step = 16,
.CCRes = 2, .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 #endif
}; };
@ -191,6 +196,7 @@ int cpu_mips_register (CPUMIPSState *env, mips_def_t *def)
env->CP0_Config7 = def->CP0_Config7; env->CP0_Config7 = def->CP0_Config7;
env->SYNCI_Step = def->SYNCI_Step; env->SYNCI_Step = def->SYNCI_Step;
env->CCRes = def->CCRes; env->CCRes = def->CCRes;
env->Status_rw_bitmask = def->Status_rw_bitmask;
env->fcr0 = def->CP1_fcr0; env->fcr0 = def->CP1_fcr0;
#if defined (MIPS_USES_R4K_TLB) #if defined (MIPS_USES_R4K_TLB)
env->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63); env->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63);