Skip to content

Commit

Permalink
MIPS 64-bit FPU support, plus some collateral bugfixes in the
Browse files Browse the repository at this point in the history
conditional branch handling.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2779 c046a42c-6fe2-441c-8c8c-71466251a162
  • Loading branch information
ths committed May 7, 2007
1 parent 8b4af70 commit 5a5012e
Show file tree
Hide file tree
Showing 11 changed files with 1,703 additions and 520 deletions.
1 change: 1 addition & 0 deletions Changelog
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
4 changes: 2 additions & 2 deletions gdbstub.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down
3 changes: 2 additions & 1 deletion target-mips/TODO
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
44 changes: 25 additions & 19 deletions target-mips/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions target-mips/exec.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
123 changes: 77 additions & 46 deletions target-mips/fop_template.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,82 +19,113 @@
* 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, FREG)
OP_WSTORE_FREG(WT1, WT1_fpr, FREG)

OP_WLOAD_FREG(WT2, WT2_fpr, FREG)
OP_WSTORE_FREG(WT2, WT2_fpr, FREG)

#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(); \
}

OP_WLOAD_FREG(WT1, WT1_fpr, SFREG)
OP_WSTORE_FREG(WT1, WT1_fpr, SFREG)
#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_WLOAD_FREG(WT2, WT2_fpr, SFREG)
OP_WSTORE_FREG(WT2, WT2_fpr, SFREG)
OP_DLOAD_FREG(DT0, DT0_fpr, FREG)
OP_DSTORE_FREG(DT0, DT0_fpr, FREG)

#endif
OP_DLOAD_FREG(DT1, DT1_fpr, FREG)
OP_DSTORE_FREG(DT1, DT1_fpr, FREG)

#if defined(DFREG)
OP_DLOAD_FREG(DT2, DT2_fpr, FREG)
OP_DSTORE_FREG(DT2, DT2_fpr, FREG)

#define OP_DLOAD_FREG(treg, tregname, DFREG) \
void glue(glue(op_load_fpr_,tregname), DFREG) (void) \
{ \
treg = FPR_D(env, DFREG); \
RETURN(); \
#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_DSTORE_FREG(treg, tregname, DFREG) \
void glue(glue(op_store_fpr_,tregname), DFREG) (void)\
{ \
FPR_D(env, DFREG) = treg; \
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_DLOAD_FREG(DT0, DT0_fpr, DFREG)
OP_DSTORE_FREG(DT0, DT0_fpr, DFREG)
OP_PSLOAD_FREG(WTH0, WTH0_fpr, FREG)
OP_PSSTORE_FREG(WTH0, WTH0_fpr, FREG)

OP_DLOAD_FREG(DT1, DT1_fpr, DFREG)
OP_DSTORE_FREG(DT1, DT1_fpr, DFREG)
OP_PSLOAD_FREG(WTH1, WTH1_fpr, FREG)
OP_PSSTORE_FREG(WTH1, WTH1_fpr, FREG)

OP_DLOAD_FREG(DT2, DT2_fpr, DFREG)
OP_DSTORE_FREG(DT2, DT2_fpr, DFREG)
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)
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
3 changes: 3 additions & 0 deletions target-mips/helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 5a5012e

Please sign in to comment.