mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
MIPS FPU support (Marius Goeger)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1964 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
@@ -819,6 +819,8 @@ elif test "$target_cpu" = "mips" -o "$target_cpu" = "mipsel" ; then
|
||||
echo "TARGET_ARCH=mips" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"mips\"" >> $config_h
|
||||
echo "#define TARGET_MIPS 1" >> $config_h
|
||||
echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
|
||||
echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
|
||||
elif test "$target_cpu" = "sh4" ; then
|
||||
echo "TARGET_ARCH=sh4" >> $config_mak
|
||||
echo "#define TARGET_ARCH \"sh4\"" >> $config_h
|
||||
|
||||
+44
-11
@@ -10,10 +10,19 @@
|
||||
|
||||
typedef union fpr_t fpr_t;
|
||||
union fpr_t {
|
||||
double d;
|
||||
float f;
|
||||
uint32_t u[2];
|
||||
float64 fd; /* ieee double precision */
|
||||
float32 fs[2];/* ieee single precision */
|
||||
uint64_t d; /* binary single fixed-point */
|
||||
uint32_t w[2]; /* binary single fixed-point */
|
||||
};
|
||||
/* define FP_ENDIAN_IDX to access the same location
|
||||
* in the fpr_t union regardless of the host endianess
|
||||
*/
|
||||
#if defined(WORDS_BIGENDIAN)
|
||||
# define FP_ENDIAN_IDX 1
|
||||
#else
|
||||
# define FP_ENDIAN_IDX 0
|
||||
#endif
|
||||
|
||||
#if defined(MIPS_USES_R4K_TLB)
|
||||
typedef struct tlb_t tlb_t;
|
||||
@@ -44,12 +53,38 @@ struct CPUMIPSState {
|
||||
#if defined(MIPS_USES_FPU)
|
||||
/* Floating point registers */
|
||||
fpr_t fpr[16];
|
||||
/* Floating point special purpose registers */
|
||||
#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 */
|
||||
uint32_t fcr0;
|
||||
uint32_t fcr25;
|
||||
uint32_t fcr26;
|
||||
uint32_t fcr28;
|
||||
uint32_t fcsr;
|
||||
/* 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 FP_INEXACT 1
|
||||
#define FP_UNDERFLOW 2
|
||||
#define FP_OVERFLOW 4
|
||||
#define FP_DIV0 8
|
||||
#define FP_INVALID 16
|
||||
#define FP_UNIMPLEMENTED 32
|
||||
|
||||
#endif
|
||||
#if defined(MIPS_USES_R4K_TLB)
|
||||
tlb_t tlb[16];
|
||||
@@ -71,6 +106,7 @@ struct CPUMIPSState {
|
||||
#define CP0St_CU1 29
|
||||
#define CP0St_CU0 28
|
||||
#define CP0St_RP 27
|
||||
#define CP0St_FR 26
|
||||
#define CP0St_RE 25
|
||||
#define CP0St_BEV 22
|
||||
#define CP0St_TS 21
|
||||
@@ -138,9 +174,6 @@ struct CPUMIPSState {
|
||||
uint32_t CP0_ErrorEPC;
|
||||
uint32_t CP0_DESAVE;
|
||||
/* Qemu */
|
||||
#if defined (USE_HOST_FLOAT_REGS) && defined(MIPS_USES_FPU)
|
||||
double ft0, ft1, ft2;
|
||||
#endif
|
||||
struct QEMUTimer *timer; /* Internal timer */
|
||||
int interrupt_request;
|
||||
jmp_buf jmp_env;
|
||||
|
||||
+20
-6
@@ -21,13 +21,20 @@ register host_uint_t T1 asm(AREG2);
|
||||
register host_uint_t T2 asm(AREG3);
|
||||
|
||||
#if defined (USE_HOST_FLOAT_REGS)
|
||||
register double FT0 asm(FREG0);
|
||||
register double FT1 asm(FREG1);
|
||||
register double FT2 asm(FREG2);
|
||||
#error "implement me."
|
||||
#else
|
||||
#define FT0 (env->ft0.d)
|
||||
#define FT1 (env->ft1.d)
|
||||
#define FT2 (env->ft2.d)
|
||||
#define FDT0 (env->ft0.fd)
|
||||
#define FDT1 (env->ft1.fd)
|
||||
#define FDT2 (env->ft2.fd)
|
||||
#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 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])
|
||||
#endif
|
||||
|
||||
#if defined (DEBUG_OP)
|
||||
@@ -65,6 +72,13 @@ void do_tlbwi (void);
|
||||
void do_tlbwr (void);
|
||||
void do_tlbp (void);
|
||||
void do_tlbr (void);
|
||||
#ifdef MIPS_USES_FPU
|
||||
void dump_fpu(CPUState *env);
|
||||
void fpu_dump_state(CPUState *env, FILE *f,
|
||||
int (*fpu_fprintf)(FILE *f, const char *fmt, ...),
|
||||
int flags);
|
||||
#endif
|
||||
void dump_sc (void);
|
||||
void do_lwl_raw (uint32_t);
|
||||
void do_lwr_raw (uint32_t);
|
||||
uint32_t do_swl_raw (uint32_t);
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* MIPS emulation micro-operations templates for floating point reg
|
||||
* load & store for qemu.
|
||||
*
|
||||
* Copyright (c) 2006 Marius Groeger
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#if defined(SFREG)
|
||||
|
||||
#define OP_WLOAD_FREG(treg, tregname, SFREG) \
|
||||
void glue(glue(op_load_fpr_,tregname), SFREG) (void) \
|
||||
{ \
|
||||
treg = FPR_W(env, SFREG); \
|
||||
RETURN(); \
|
||||
}
|
||||
|
||||
#define OP_WSTORE_FREG(treg, tregname, SFREG) \
|
||||
void glue(glue(op_store_fpr_,tregname), SFREG) (void)\
|
||||
{ \
|
||||
FPR_W(env, SFREG) = 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)
|
||||
|
||||
OP_WLOAD_FREG(WT1, WT1_fpr, SFREG)
|
||||
OP_WSTORE_FREG(WT1, WT1_fpr, SFREG)
|
||||
|
||||
OP_WLOAD_FREG(WT2, WT2_fpr, SFREG)
|
||||
OP_WSTORE_FREG(WT2, WT2_fpr, SFREG)
|
||||
|
||||
#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_DSTORE_FREG(treg, tregname, DFREG) \
|
||||
void glue(glue(op_store_fpr_,tregname), DFREG) (void)\
|
||||
{ \
|
||||
FPR_D(env, DFREG) = treg; \
|
||||
RETURN(); \
|
||||
}
|
||||
|
||||
OP_DLOAD_FREG(DT0, DT0_fpr, DFREG)
|
||||
OP_DSTORE_FREG(DT0, DT0_fpr, DFREG)
|
||||
|
||||
OP_DLOAD_FREG(DT1, DT1_fpr, DFREG)
|
||||
OP_DSTORE_FREG(DT1, DT1_fpr, DFREG)
|
||||
|
||||
OP_DLOAD_FREG(DT2, DT2_fpr, DFREG)
|
||||
OP_DSTORE_FREG(DT2, DT2_fpr, DFREG)
|
||||
|
||||
#endif
|
||||
|
||||
#if defined (FTN)
|
||||
|
||||
#define SET_RESET(treg, tregname) \
|
||||
void glue(op_set, tregname)(void) \
|
||||
{ \
|
||||
treg = PARAM1; \
|
||||
RETURN(); \
|
||||
} \
|
||||
void glue(op_reset, tregname)(void) \
|
||||
{ \
|
||||
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)
|
||||
|
||||
#endif
|
||||
@@ -24,6 +24,12 @@ enum {
|
||||
/* Uses MIPS R4Kc TLB model */
|
||||
#define MIPS_USES_R4K_TLB
|
||||
#define MIPS_TLB_NB 16
|
||||
/* basic FPU register support */
|
||||
#define MIPS_USES_FPU 1
|
||||
/* Define a implementation number of 1.
|
||||
* Define a major version 1, minor version 0.
|
||||
*/
|
||||
#define MIPS_FCR0 ((0 << 16) | (1 << 8) | (1 << 4) | 0)
|
||||
/* Have config1, runs in big-endian mode, uses TLB */
|
||||
#define MIPS_CONFIG0 \
|
||||
((1 << CP0C0_M) | (0x000 << CP0C0_K23) | (0x000 << CP0C0_KU) | \
|
||||
@@ -31,14 +37,14 @@ enum {
|
||||
/* 16 TLBs, 64 sets Icache, 16 bytes Icache line, 2-way Icache,
|
||||
* 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache,
|
||||
* no performance counters, watch registers present, no code compression,
|
||||
* EJTAG present, no FPU
|
||||
* EJTAG present, FPU enable bit depending on MIPS_USES_FPU
|
||||
*/
|
||||
#define MIPS_CONFIG1 \
|
||||
((15 << CP0C1_MMU) | \
|
||||
(0x000 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x01 << CP0C1_IA) | \
|
||||
(0x000 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x01 << CP0C1_DA) | \
|
||||
(0 << CP0C1_PC) | (1 << CP0C1_WR) | (0 << CP0C1_CA) | \
|
||||
(1 << CP0C1_EP) | (0 << CP0C1_FP))
|
||||
(1 << CP0C1_EP) | (MIPS_USES_FPU << CP0C1_FP))
|
||||
#elif defined (MIPS_CPU == MIPS_R4Kp)
|
||||
/* 32 bits target */
|
||||
#define TARGET_LONG_BITS 32
|
||||
@@ -52,7 +58,7 @@ enum {
|
||||
#error "MIPS CPU not defined"
|
||||
/* Remainder for other flags */
|
||||
//#define TARGET_MIPS64
|
||||
//define MIPS_USES_FPU
|
||||
//#define MIPS_USES_FPU
|
||||
#endif
|
||||
|
||||
#endif /* !defined (__QEMU_MIPS_DEFS_H__) */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -529,6 +529,47 @@ void do_mtc0 (int reg, int sel)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MIPS_USES_FPU
|
||||
#include "softfloat.h"
|
||||
|
||||
void fpu_handle_exception(void)
|
||||
{
|
||||
#ifdef CONFIG_SOFTFLOAT
|
||||
int flags = get_float_exception_flags(&env->fp_status);
|
||||
unsigned int cpuflags = 0, enable, cause = 0;
|
||||
|
||||
enable = GET_FP_ENABLE(env->fcr31);
|
||||
|
||||
/* determine current flags */
|
||||
if (flags & float_flag_invalid) {
|
||||
cpuflags |= FP_INVALID;
|
||||
cause |= FP_INVALID & enable;
|
||||
}
|
||||
if (flags & float_flag_divbyzero) {
|
||||
cpuflags |= FP_DIV0;
|
||||
cause |= FP_DIV0 & enable;
|
||||
}
|
||||
if (flags & float_flag_overflow) {
|
||||
cpuflags |= FP_OVERFLOW;
|
||||
cause |= FP_OVERFLOW & enable;
|
||||
}
|
||||
if (flags & float_flag_underflow) {
|
||||
cpuflags |= FP_UNDERFLOW;
|
||||
cause |= FP_UNDERFLOW & enable;
|
||||
}
|
||||
if (flags & float_flag_inexact) {
|
||||
cpuflags |= FP_INEXACT;
|
||||
cause |= FP_INEXACT & enable;
|
||||
}
|
||||
SET_FP_FLAGS(env->fcr31, cpuflags);
|
||||
SET_FP_CAUSE(env->fcr31, cause);
|
||||
#else
|
||||
SET_FP_FLAGS(env->fcr31, 0);
|
||||
SET_FP_CAUSE(env->fcr31, 0);
|
||||
#endif
|
||||
}
|
||||
#endif /* MIPS_USES_FPU */
|
||||
|
||||
/* TLB management */
|
||||
#if defined(MIPS_USES_R4K_TLB)
|
||||
static void invalidate_tlb (int idx)
|
||||
|
||||
@@ -118,3 +118,26 @@ void glue(op_sc, MEMSUFFIX) (void)
|
||||
}
|
||||
RETURN();
|
||||
}
|
||||
|
||||
#ifdef MIPS_USES_FPU
|
||||
void glue(op_lwc1, MEMSUFFIX) (void)
|
||||
{
|
||||
WT0 = glue(ldl, MEMSUFFIX)(T0);
|
||||
RETURN();
|
||||
}
|
||||
void glue(op_swc1, MEMSUFFIX) (void)
|
||||
{
|
||||
glue(stl, MEMSUFFIX)(T0, WT0);
|
||||
RETURN();
|
||||
}
|
||||
void glue(op_ldc1, MEMSUFFIX) (void)
|
||||
{
|
||||
DT0 = glue(ldq, MEMSUFFIX)(T0);
|
||||
RETURN();
|
||||
}
|
||||
void glue(op_sdc1, MEMSUFFIX) (void)
|
||||
{
|
||||
glue(stq, MEMSUFFIX)(T0, DT0);
|
||||
RETURN();
|
||||
}
|
||||
#endif
|
||||
|
||||
+641
-3
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user