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)
- 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:

View File

@ -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;
}

View File

@ -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

View File

@ -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,

View File

@ -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)

View File

@ -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

View File

@ -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;

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);
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 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);