* [Qemu-devel] [PATCH 6/6] A cumulative MIPS patchset
@ 2006-11-21 15:22 Thiemo Seufer
0 siblings, 0 replies; only message in thread
From: Thiemo Seufer @ 2006-11-21 15:22 UTC (permalink / raw)
To: qemu-devel
Hello All,
this patch adds support for all mandatory MIPS32R2 instructions,
rationalizes the instruction decoding to check always 32-bit words,
reduces the number of magic constants in the code, adds a few bits
which make eventually implementation of MIPS64 support and optional
MIPS32 features easier.
The emulated CPU still identifies itself as a MIPS32(R1) 4Kc.
Currently it doesn't throw a RI exception for R2 instructions, this
is useful for Linux userland emulation, and also follows the current
policy which doesn't distinguish between MIPS32R1 instructions and
those of earlier ISAs.
Thiemo
Index: qemu-work/target-mips/cpu.h
===================================================================
--- qemu-work.orig/target-mips/cpu.h 2006-11-21 13:42:28.000000000 +0000
+++ qemu-work/target-mips/cpu.h 2006-11-21 13:42:52.000000000 +0000
@@ -99,14 +99,16 @@
#endif
uint32_t CP0_index;
uint32_t CP0_random;
- uint32_t CP0_EntryLo0;
- uint32_t CP0_EntryLo1;
- uint32_t CP0_Context;
+ uint64_t CP0_EntryLo0;
+ uint64_t CP0_EntryLo1;
+ uint64_t CP0_Context;
uint32_t CP0_PageMask;
+ uint32_t CP0_PageGrain;
uint32_t CP0_Wired;
+ uint32_t CP0_HWREna;
uint32_t CP0_BadVAddr;
uint32_t CP0_Count;
- uint32_t CP0_EntryHi;
+ uint64_t CP0_EntryHi;
uint32_t CP0_Compare;
uint32_t CP0_Status;
#define CP0St_CU3 31
@@ -116,19 +118,36 @@
#define CP0St_RP 27
#define CP0St_FR 26
#define CP0St_RE 25
+#define CP0St_MX 24
+#define CP0St_PX 23
#define CP0St_BEV 22
#define CP0St_TS 21
#define CP0St_SR 20
#define CP0St_NMI 19
#define CP0St_IM 8
+#define CP0St_KX 7
+#define CP0St_SX 6
+#define CP0St_UX 5
#define CP0St_UM 4
+#define CP0St_R0 3
#define CP0St_ERL 2
#define CP0St_EXL 1
#define CP0St_IE 0
+ uint32_t CP0_IntCtl;
+ uint32_t CP0_SRSCtl;
uint32_t CP0_Cause;
+#define CP0Ca_BD 31
+#define CP0Ca_TI 30
+#define CP0Ca_CE 28
+#define CP0Ca_DC 27
+#define CP0Ca_PCI 26
#define CP0Ca_IV 23
+#define CP0Ca_WP 22
+#define CP0Ca_IP 8
+#define CP0Ca_EC 2
uint32_t CP0_EPC;
uint32_t CP0_PRid;
+ uint32_t CP0_EBase;
uint32_t CP0_Config0;
#define CP0C0_M 31
#define CP0C0_K23 28
@@ -140,8 +159,10 @@
#define CP0C0_AT 13
#define CP0C0_AR 10
#define CP0C0_MT 7
+#define CP0C0_VI 3
#define CP0C0_K0 0
uint32_t CP0_Config1;
+#define CP0C1_M 31
#define CP0C1_MMU 25
#define CP0C1_IS 22
#define CP0C1_IL 19
@@ -149,14 +170,38 @@
#define CP0C1_DS 13
#define CP0C1_DL 10
#define CP0C1_DA 7
+#define CP0C1_C2 6
+#define CP0C1_MD 5
#define CP0C1_PC 4
#define CP0C1_WR 3
#define CP0C1_CA 2
#define CP0C1_EP 1
#define CP0C1_FP 0
+ uint32_t CP0_Config2;
+#define CP0C2_M 31
+#define CP0C2_TU 28
+#define CP0C2_TS 24
+#define CP0C2_TL 20
+#define CP0C2_TA 16
+#define CP0C2_SU 12
+#define CP0C2_SS 8
+#define CP0C2_SL 4
+#define CP0C2_SA 0
+ uint32_t CP0_Config3;
+#define CP0C3_M 31
+#define CP0C3_DSPP 10
+#define CP0C3_LPA 7
+#define CP0C3_VEIC 6
+#define CP0C3_VInt 5
+#define CP0C3_SP 4
+#define CP0C3_MT 2
+#define CP0C3_SM 1
+#define CP0C3_TL 0
uint32_t CP0_LLAddr;
uint32_t CP0_WatchLo;
uint32_t CP0_WatchHi;
+ uint32_t CP0_XContext;
+ uint32_t CP0_Framemask;
uint32_t CP0_Debug;
#define CPDB_DBD 31
#define CP0DB_DM 30
@@ -177,8 +222,11 @@
#define CP0DB_DBp 1
#define CP0DB_DSS 0
uint32_t CP0_DEPC;
+ uint32_t CP0_Performance0;
uint32_t CP0_TagLo;
uint32_t CP0_DataLo;
+ uint32_t CP0_TagHi;
+ uint32_t CP0_DataHi;
uint32_t CP0_ErrorEPC;
uint32_t CP0_DESAVE;
/* Qemu */
@@ -211,6 +259,9 @@
int halted; /* TRUE if the CPU is in suspend state */
+ int SYNCI_Step; /* Address step size for SYNCI */
+ int CCRes; /* Cycle count resolution/divisor */
+
CPU_COMMON
int ram_size;
Index: qemu-work/target-mips/exec.h
===================================================================
--- qemu-work.orig/target-mips/exec.h 2006-11-21 13:42:28.000000000 +0000
+++ qemu-work/target-mips/exec.h 2006-11-21 14:01:25.000000000 +0000
@@ -68,6 +68,7 @@
#endif
void do_mfc0_random(void);
void do_mfc0_count(void);
+void do_mtc0_entryhi(uint32_t in);
void do_mtc0_status_debug(uint32_t old, uint32_t val);
void do_mtc0_status_irqraise_debug(void);
void do_tlbwi (void);
Index: qemu-work/target-mips/helper.c
===================================================================
--- qemu-work.orig/target-mips/helper.c 2006-11-21 13:42:28.000000000 +0000
+++ qemu-work/target-mips/helper.c 2006-11-21 13:42:52.000000000 +0000
@@ -302,15 +302,9 @@
#endif
env->CP0_Wired = 0;
env->CP0_Config0 = MIPS_CONFIG0;
-#if defined (MIPS_CONFIG1)
env->CP0_Config1 = MIPS_CONFIG1;
-#endif
-#if defined (MIPS_CONFIG2)
env->CP0_Config2 = MIPS_CONFIG2;
-#endif
-#if defined (MIPS_CONFIG3)
env->CP0_Config3 = MIPS_CONFIG3;
-#endif
env->CP0_WatchLo = 0;
env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
goto set_error_EPC;
Index: qemu-work/target-mips/mips-defs.h
===================================================================
--- qemu-work.orig/target-mips/mips-defs.h 2006-11-21 13:42:28.000000000 +0000
+++ qemu-work/target-mips/mips-defs.h 2006-11-21 13:42:52.000000000 +0000
@@ -29,26 +29,44 @@
* Define a major version 1, minor version 0.
*/
#define MIPS_FCR0 ((0 << 16) | (1 << 8) | (1 << 4) | 0)
-/* Have config1, uses TLB */
-#define MIPS_CONFIG0_1 \
-((1 << CP0C0_M) | (0 << CP0C0_K23) | (0 << CP0C0_KU) | \
- (1 << CP0C0_MT) | (2 << CP0C0_K0))
+ /* Have config1, is MIPS32R1, uses TLB, no virtual icache,
+ uncached coherency */
+#define MIPS_CONFIG0_1 \
+ ((1 << CP0C0_M) | (0x0 << CP0C0_K23) | (0x0 << CP0C0_KU) | \
+ (0x0 << CP0C0_AT) | (0x0 << CP0C0_AR) | (0x1 << CP0C0_MT) | \
+ (0x2 << CP0C0_K0))
#ifdef TARGET_WORDS_BIGENDIAN
#define MIPS_CONFIG0 (MIPS_CONFIG0_1 | (1 << CP0C0_BE))
#else
#define MIPS_CONFIG0 MIPS_CONFIG0_1
#endif
-/* 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, 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) | (MIPS_USES_FPU << CP0C1_FP))
+/* Have config2, 16 TLB entries, 64 sets Icache, 16 bytes Icache line,
+ 2-way Icache, 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache,
+ no coprocessor2 attached, no MDMX support attached,
+ no performance counters, watch registers present,
+ no code compression, EJTAG present, FPU enable bit depending on
+ MIPS_USES_FPU */
+#define MIPS_CONFIG1_1 \
+((1 << CP0C1_M) | ((MIPS_TLB_NB - 1) << CP0C1_MMU) | \
+ (0x0 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x1 << CP0C1_IA) | \
+ (0x0 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x1 << CP0C1_DA) | \
+ (0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) | \
+ (1 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP))
+#ifdef MIPS_USES_FPU
+#define MIPS_CONFIG1 (MIPS_CONFIG1_1 | (1 << CP0C1_FP))
+#else
+#define MIPS_CONFIG1 (MIPS_CONFIG1_1 | (0 << CP0C1_FP))
+#endif
+/* Have config3, no tertiary/secondary caches implemented */
+#define MIPS_CONFIG2 \
+((1 << CP0C2_M))
+/* No config4, no DSP ASE, no large physaddr,
+ no external interrupt controller, no vectored interupts,
+ no 1kb pages, no MT ASE, no SmartMIPS ASE, no trace logic */
+#define MIPS_CONFIG3 \
+((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) | \
+ (0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) | \
+ (0 << CP0C3_MT) | (0 << CP0C3_SM) | (0 << CP0C3_TL))
#elif (MIPS_CPU == MIPS_R4Kp)
/* 32 bits target */
#define TARGET_LONG_BITS 32
@@ -60,7 +78,7 @@
#define MIPS_USES_R4K_FPM
#else
#error "MIPS CPU not defined"
-/* Remainder for other flags */
+/* Reminder for other flags */
//#define TARGET_MIPS64
//#define MIPS_USES_FPU
#endif
Index: qemu-work/target-mips/op.c
===================================================================
--- qemu-work.orig/target-mips/op.c 2006-11-21 13:42:28.000000000 +0000
+++ qemu-work/target-mips/op.c 2006-11-21 13:58:05.000000000 +0000
@@ -437,6 +437,18 @@
RETURN();
}
+void op_rotr (void)
+{
+ target_ulong tmp;
+
+ if (T1) {
+ tmp = T0 << (0x20 - T1);
+ T0 = (T0 >> T1) | tmp;
+ } else
+ T0 = T1;
+ RETURN();
+}
+
void op_sllv (void)
{
T0 = T1 << (T0 & 0x1F);
@@ -455,6 +467,19 @@
RETURN();
}
+void op_rotrv (void)
+{
+ target_ulong tmp;
+
+ T0 &= 0x1F;
+ if (T0) {
+ tmp = T1 << (0x20 - T0);
+ T0 = (T1 >> T0) | tmp;
+ } else
+ T0 = T1;
+ RETURN();
+}
+
void op_clo (void)
{
int n;
@@ -602,6 +627,20 @@
RETURN();
}
+void op_movf (void)
+{
+ if (!(env->fcr31 & PARAM1))
+ env->gpr[PARAM2] = env->gpr[PARAM3];
+ RETURN();
+}
+
+void op_movt (void)
+{
+ if (env->fcr31 & PARAM1)
+ env->gpr[PARAM2] = env->gpr[PARAM3];
+ RETURN();
+}
+
/* Tests */
#define OP_COND(name, cond) \
void glue(op_, name) (void) \
@@ -625,28 +664,32 @@
OP_COND(lez, (int32_t)T0 <= 0);
OP_COND(ltz, (int32_t)T0 < 0);
-/* Branchs */
+/* Branches */
//#undef USE_DIRECT_JUMP
void OPPROTO op_goto_tb0(void)
{
GOTO_TB(op_goto_tb0, PARAM1, 0);
+ RETURN();
}
void OPPROTO op_goto_tb1(void)
{
GOTO_TB(op_goto_tb1, PARAM1, 1);
+ RETURN();
}
/* Branch to register */
void op_save_breg_target (void)
{
env->btarget = T2;
+ RETURN();
}
void op_restore_breg_target (void)
{
T2 = env->btarget;
+ RETURN();
}
void op_breg (void)
@@ -724,12 +767,24 @@
RETURN();
}
+void op_mfc0_pagegrain (void)
+{
+ T0 = env->CP0_PageGrain;
+ RETURN();
+}
+
void op_mfc0_wired (void)
{
T0 = env->CP0_Wired;
RETURN();
}
+void op_mfc0_hwrena (void)
+{
+ T0 = env->CP0_HWREna;
+ RETURN();
+}
+
void op_mfc0_badvaddr (void)
{
T0 = env->CP0_BadVAddr;
@@ -766,6 +821,18 @@
RETURN();
}
+void op_mfc0_intctl (void)
+{
+ T0 = env->CP0_IntCtl;
+ RETURN();
+}
+
+void op_mfc0_srsctl (void)
+{
+ T0 = env->CP0_SRSCtl;
+ RETURN();
+}
+
void op_mfc0_cause (void)
{
T0 = env->CP0_Cause;
@@ -784,6 +851,12 @@
RETURN();
}
+void op_mfc0_ebase (void)
+{
+ T0 = env->CP0_EBase;
+ RETURN();
+}
+
void op_mfc0_config0 (void)
{
T0 = env->CP0_Config0;
@@ -796,24 +869,48 @@
RETURN();
}
+void op_mfc0_config2 (void)
+{
+ T0 = env->CP0_Config2;
+ RETURN();
+}
+
+void op_mfc0_config3 (void)
+{
+ T0 = env->CP0_Config3;
+ RETURN();
+}
+
void op_mfc0_lladdr (void)
{
T0 = env->CP0_LLAddr >> 4;
RETURN();
}
-void op_mfc0_watchlo (void)
+void op_mfc0_watchlo0 (void)
{
T0 = env->CP0_WatchLo;
RETURN();
}
-void op_mfc0_watchhi (void)
+void op_mfc0_watchhi0 (void)
{
T0 = env->CP0_WatchHi;
RETURN();
}
+void op_mfc0_xcontext (void)
+{
+ T0 = env->CP0_XContext;
+ RETURN();
+}
+
+void op_mfc0_framemask (void)
+{
+ T0 = env->CP0_Framemask;
+ RETURN();
+}
+
void op_mfc0_debug (void)
{
T0 = env->CP0_Debug;
@@ -828,6 +925,12 @@
RETURN();
}
+void op_mfc0_performance0 (void)
+{
+ T0 = env->CP0_Performance0;
+ RETURN();
+}
+
void op_mfc0_taglo (void)
{
T0 = env->CP0_TagLo;
@@ -840,6 +943,18 @@
RETURN();
}
+void op_mfc0_taghi (void)
+{
+ T0 = env->CP0_TagHi;
+ RETURN();
+}
+
+void op_mfc0_datahi (void)
+{
+ T0 = env->CP0_DataHi;
+ RETURN();
+}
+
void op_mfc0_errorepc (void)
{
T0 = env->CP0_ErrorEPC;
@@ -854,37 +969,57 @@
void op_mtc0_index (void)
{
- env->CP0_index = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F);
+ env->CP0_index = (env->CP0_index & 0x80000000) | (T0 & (MIPS_TLB_NB - 1));
RETURN();
}
void op_mtc0_entrylo0 (void)
{
- env->CP0_EntryLo0 = T0 & 0x3FFFFFFF;
+ /* Large physaddr not implemented */
+ /* 1k pages not implemented */
+ env->CP0_EntryLo0 = T0 & 0x3FFFFFFFUL;
RETURN();
}
void op_mtc0_entrylo1 (void)
{
- env->CP0_EntryLo1 = T0 & 0x3FFFFFFF;
+ /* Large physaddr not implemented */
+ /* 1k pages not implemented */
+ env->CP0_EntryLo1 = T0 & 0x3FFFFFFFUL;
RETURN();
}
void op_mtc0_context (void)
{
- env->CP0_Context = (env->CP0_Context & 0xFF800000) | (T0 & 0x007FFFF0);
+ env->CP0_Context = (env->CP0_Context & ~0x007FFFFF) | (T0 & 0x007FFFF0);
RETURN();
}
void op_mtc0_pagemask (void)
{
- env->CP0_PageMask = T0 & 0x01FFE000;
+ /* 1k pages not implemented */
+ env->CP0_PageMask = T0 & 0x1FFFE000;
+ RETURN();
+}
+
+void op_mtc0_pagegrain (void)
+{
+ /* SmartMIPS not implemented */
+ /* Large physaddr not implemented */
+ /* 1k pages not implemented */
+ env->CP0_PageGrain = 0;
RETURN();
}
void op_mtc0_wired (void)
{
- env->CP0_Wired = T0 & 0x0000000F;
+ env->CP0_Wired = T0 & (MIPS_TLB_NB - 1);
+ RETURN();
+}
+
+void op_mtc0_hwrena (void)
+{
+ env->CP0_HWREna = T0 & 0x0000000F;
RETURN();
}
@@ -950,6 +1085,20 @@
RETURN();
}
+void op_mtc0_intctl (void)
+{
+ /* vectored interrupts not implemented */
+ env->CP0_IntCtl = 0;
+ RETURN();
+}
+
+void op_mtc0_srsctl (void)
+{
+ /* shadow registers not implemented */
+ env->CP0_SRSCtl = 0;
+ RETURN();
+}
+
void op_mtc0_cause (void)
{
uint32_t val, old;
@@ -960,7 +1109,6 @@
#if 0
{
int i, mask;
-
/* Check if we ever asserted a software IRQ */
for (i = 0; i < 2; i++) {
mask = 0x100 << i;
@@ -978,28 +1126,56 @@
RETURN();
}
+void op_mtc0_ebase (void)
+{
+ /* vectored interrupts not implemented */
+ /* Multi-CPU not implemented */
+ env->CP0_EBase = 0x80000000 | (T0 & 0x3FFFF000);
+ RETURN();
+}
+
void op_mtc0_config0 (void)
{
#if defined(MIPS_USES_R4K_TLB)
- env->CP0_Config0 = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001);
+ /* Fixed mapping MMU not implemented */
+ env->CP0_Config0 = (env->CP0_Config0 & 0x8017FF88) | (T0 & 0x00000001);
#else
- env->CP0_Config0 = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001);
+ env->CP0_Config0 = (env->CP0_Config0 & 0xFE17FF88) | (T0 & 0x00000001);
#endif
RETURN();
}
-void op_mtc0_watchlo (void)
+void op_mtc0_config2 (void)
+{
+ /* tertiary/secondary caches not implemented */
+ env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
+ RETURN();
+}
+
+void op_mtc0_watchlo0 (void)
{
env->CP0_WatchLo = T0;
RETURN();
}
-void op_mtc0_watchhi (void)
+void op_mtc0_watchhi0 (void)
{
env->CP0_WatchHi = T0 & 0x40FF0FF8;
RETURN();
}
+void op_mtc0_xcontext (void)
+{
+ env->CP0_XContext = T0; /* XXX */
+ RETURN();
+}
+
+void op_mtc0_framemask (void)
+{
+ env->CP0_Framemask = T0; /* XXX */
+ RETURN();
+}
+
void op_mtc0_debug (void)
{
env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120);
@@ -1016,12 +1192,36 @@
RETURN();
}
+void op_mtc0_performance0 (void)
+{
+ env->CP0_Performance0 = T0; /* XXX */
+ RETURN();
+}
+
void op_mtc0_taglo (void)
{
env->CP0_TagLo = T0 & 0xFFFFFCF6;
RETURN();
}
+void op_mtc0_datalo (void)
+{
+ env->CP0_DataLo = T0; /* XXX */
+ RETURN();
+}
+
+void op_mtc0_taghi (void)
+{
+ env->CP0_TagHi = T0; /* XXX */
+ RETURN();
+}
+
+void op_mtc0_datahi (void)
+{
+ env->CP0_DataHi = T0; /* XXX */
+ RETURN();
+}
+
void op_mtc0_errorepc (void)
{
env->CP0_ErrorEPC = T0;
@@ -1422,6 +1622,42 @@
void op_pmon (void)
{
CALL_FROM_TB1(do_pmon, PARAM1);
+ RETURN();
+}
+
+void op_di (void)
+{
+ uint32_t val;
+
+ T0 = env->CP0_Status;
+ val = T0 & ~(1 << CP0St_IE);
+ if (val != T0) {
+ env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+ env->CP0_Status = val;
+ }
+ RETURN();
+}
+
+void op_ei (void)
+{
+ uint32_t val;
+
+ T0 = env->CP0_Status;
+ val = T0 | (1 << CP0St_IE);
+ if (val != T0) {
+ const uint32_t mask = 0x0000FF00;
+
+ env->CP0_Status = val;
+ if (!(env->hflags & MIPS_HFLAG_EXL) &&
+ !(env->hflags & MIPS_HFLAG_ERL) &&
+ !(env->hflags & MIPS_HFLAG_DM) &&
+ (env->CP0_Status & env->CP0_Cause & mask)) {
+ env->interrupt_request |= CPU_INTERRUPT_HARD;
+ if (logfile)
+ CALL_FROM_TB0(do_mtc0_status_irqraise_debug);
+ }
+ }
+ RETURN();
}
void op_trap (void)
@@ -1434,12 +1670,14 @@
void op_debug (void)
{
- CALL_FROM_TB1(do_raise_exception, EXCP_DEBUG);
+ CALL_FROM_TB1(do_raise_exception, EXCP_DEBUG);
+ RETURN();
}
void op_set_lladdr (void)
{
env->CP0_LLAddr = T2;
+ RETURN();
}
void debug_eret (void);
@@ -1456,12 +1694,50 @@
env->CP0_Status &= ~(1 << CP0St_EXL);
}
env->CP0_LLAddr = 1;
+ RETURN();
}
void op_deret (void)
{
CALL_FROM_TB0(debug_eret);
env->PC = env->CP0_DEPC;
+ RETURN();
+}
+
+void op_rdhwr_cpunum(void)
+{
+ if (env->CP0_HWREna & (1 << 0))
+ T0 = env->CP0_EBase & 0x2ff;
+ else
+ CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI);
+ RETURN();
+}
+
+void op_rdhwr_synci_step(void)
+{
+ if (env->CP0_HWREna & (1 << 1))
+ T0 = env->SYNCI_Step;
+ else
+ CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI);
+ RETURN();
+}
+
+void op_rdhwr_cc(void)
+{
+ if (env->CP0_HWREna & (1 << 2))
+ T0 = env->CP0_Count;
+ else
+ CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI);
+ RETURN();
+}
+
+void op_rdhwr_ccres(void)
+{
+ if (env->CP0_HWREna & (1 << 3))
+ T0 = env->CCRes;
+ else
+ CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI);
+ RETURN();
}
void op_save_state (void)
@@ -1491,10 +1767,119 @@
void op_exit_tb (void)
{
EXIT_TB();
+ RETURN();
}
void op_wait (void)
{
env->halted = 1;
CALL_FROM_TB1(do_raise_exception, EXCP_HLT);
+ RETURN();
+}
+
+/* Bitfield operations. */
+void op_ext(void)
+{
+ unsigned int pos = PARAM1;
+ unsigned int size = PARAM2 % (0x20 - pos);
+
+ T0 = (T1 >> pos) & ((1 << size) - 1);
+ RETURN();
+}
+
+void op_dextm(void)
+{
+ unsigned int pos = PARAM1;
+ unsigned int size = PARAM2 % (0x40 - pos);
+
+ T0 = (T1 >> pos) & ((1 << size) - 1);
+ RETURN();
+}
+
+void op_dextu(void)
+{
+ unsigned int pos = PARAM1 + 0x20;
+ unsigned int size = PARAM2 % (0x40 - pos);
+
+ T0 = (T1 >> pos) & ((1 << size) - 1);
+ RETURN();
+}
+
+void op_dext(void)
+{
+ unsigned int pos = PARAM1;
+ unsigned int size = PARAM2 % 0x20;
+
+ T0 = (T1 >> pos) & ((1 << size) - 1);
+ RETURN();
+}
+
+void op_ins(void)
+{
+ unsigned int pos = PARAM1;
+ unsigned int size = PARAM2 % (0x20 - pos);
+ uint32_t mask = ((1 << size) - 1) << pos;
+
+ T0 = (T2 & ~mask) | ((T1 << pos) & mask);
+ RETURN();
+}
+
+void op_dinsm(void)
+{
+ unsigned int pos = PARAM1;
+ unsigned int size = PARAM2 % (0x40 - pos);
+ target_ulong mask = ((1 << size) - 1) << pos;
+
+ T0 = (T2 & ~mask) | ((T1 << pos) & mask);
+ RETURN();
+}
+
+void op_dinsu(void)
+{
+ unsigned int pos = PARAM1 + 0x20;
+ unsigned int size = PARAM2 % (0x40 - pos);
+ target_ulong mask = ((1 << size) - 1) << pos;
+
+ T0 = (T2 & ~mask) | ((T1 << pos) & mask);
+ RETURN();
+}
+
+void op_dins(void)
+{
+ unsigned int pos = PARAM1;
+ unsigned int size = PARAM2;
+ target_ulong mask = ((1 << size) - 1) << pos;
+
+ T0 = (T2 & ~mask) | ((T1 << pos) & mask);
+ RETURN();
+}
+
+void op_wsbh(void)
+{
+ T0 = ((T1 << 8) & ~0x00FF00FF) | ((T1 >> 8) & 0x00FF00FF);
+ RETURN();
+}
+
+void op_dsbh(void)
+{
+ T0 = ((T1 << 8) & ~0x00FF00FF00FF00FFULL) | ((T1 >> 8) & 0x00FF00FF00FF00FFULL);
+ RETURN();
+}
+
+void op_dshd(void)
+{
+ T0 = ((T1 << 16) & ~0x0000FFFF0000FFFFULL) | ((T1 >> 16) & 0x0000FFFF0000FFFFULL);
+ RETURN();
+}
+
+void op_seb(void)
+{
+ T0 = ((T1 & 0xFF) ^ 0x80) - 0x80;
+ RETURN();
+}
+
+void op_seh(void)
+{
+ T0 = ((T1 & 0xFFFF) ^ 0x8000) - 0x8000;
+ RETURN();
}
Index: qemu-work/target-mips/op_helper.c
===================================================================
--- qemu-work.orig/target-mips/op_helper.c 2006-11-21 13:42:28.000000000 +0000
+++ qemu-work/target-mips/op_helper.c 2006-11-21 13:42:52.000000000 +0000
@@ -152,14 +152,19 @@
cpu_abort(env, "mtc0 compare\n");
}
+void do_mtc0_entryhi (uint32_t val)
+{
+ cpu_abort(env, "mtc0 entryhi\n");
+}
+
void do_mtc0_status_debug(uint32_t old, uint32_t val)
{
- cpu_abort(env, "mtc0 status\n");
+ cpu_abort(env, "mtc0 status debug\n");
}
-void do_mtc0_status_irqraise_debug(void)
+void do_mtc0_status_irqraise_debug (void)
{
- cpu_abort(env, "mtc0 status\n");
+ cpu_abort(env, "mtc0 status irqraise debug\n");
}
void do_tlbwi (void)
@@ -200,6 +205,19 @@
T0 = cpu_mips_get_count(env);
}
+void do_mtc0_entryhi (uint32_t in)
+{
+ uint32_t old;
+
+ /* 1k pages not implemented */
+ /* Ignore MIPS64 TLB for now */
+ old = env->CP0_EntryHi;
+ env->CP0_EntryHi = in & 0xFFFFE0FF;
+ /* If the ASID changes, flush qemu's TLB. */
+ if ((old & 0xFF) != (in & 0xFF))
+ cpu_mips_tlb_flush(env, 1);
+}
+
void do_mtc0_status_debug(uint32_t old, uint32_t val)
{
const uint32_t mask = 0x0000FF00;
Index: qemu-work/target-mips/translate.c
===================================================================
--- qemu-work.orig/target-mips/translate.c 2006-11-21 13:42:28.000000000 +0000
+++ qemu-work/target-mips/translate.c 2006-11-21 14:01:43.000000000 +0000
@@ -50,184 +50,313 @@
#include "gen-op.h"
-/* MIPS opcodes */
-#define EXT_SPECIAL 0x100
-#define EXT_SPECIAL2 0x200
-#define EXT_REGIMM 0x300
-#define EXT_CP0 0x400
-#define EXT_CP1 0x500
-#define EXT_CP2 0x600
-#define EXT_CP3 0x700
+/* MIPS major opcodes */
+#define MASK_OP_MAJOR(op) (op & (0x3F << 26))
enum {
/* indirect opcode tables */
- OPC_SPECIAL = 0x00,
- OPC_BREGIMM = 0x01,
- OPC_CP0 = 0x10,
- OPC_CP1 = 0x11,
- OPC_CP2 = 0x12,
- OPC_CP3 = 0x13,
- OPC_SPECIAL2 = 0x1C,
+ OPC_SPECIAL = (0x00 << 26),
+ OPC_REGIMM = (0x01 << 26),
+ OPC_CP0 = (0x10 << 26),
+ OPC_CP1 = (0x11 << 26),
+ OPC_CP2 = (0x12 << 26),
+ OPC_CP3 = (0x13 << 26),
+ OPC_SPECIAL2 = (0x1C << 26),
+ OPC_SPECIAL3 = (0x1F << 26),
/* arithmetic with immediate */
- OPC_ADDI = 0x08,
- OPC_ADDIU = 0x09,
- OPC_SLTI = 0x0A,
- OPC_SLTIU = 0x0B,
- OPC_ANDI = 0x0C,
- OPC_ORI = 0x0D,
- OPC_XORI = 0x0E,
- OPC_LUI = 0x0F,
+ OPC_ADDI = (0x08 << 26),
+ OPC_ADDIU = (0x09 << 26),
+ OPC_SLTI = (0x0A << 26),
+ OPC_SLTIU = (0x0B << 26),
+ OPC_ANDI = (0x0C << 26),
+ OPC_ORI = (0x0D << 26),
+ OPC_XORI = (0x0E << 26),
+ OPC_LUI = (0x0F << 26),
+ OPC_DADDI = (0x18 << 26),
+ OPC_DADDIU = (0x19 << 26),
/* Jump and branches */
- OPC_J = 0x02,
- OPC_JAL = 0x03,
- OPC_BEQ = 0x04, /* Unconditional if rs = rt = 0 (B) */
- OPC_BEQL = 0x14,
- OPC_BNE = 0x05,
- OPC_BNEL = 0x15,
- OPC_BLEZ = 0x06,
- OPC_BLEZL = 0x16,
- OPC_BGTZ = 0x07,
- OPC_BGTZL = 0x17,
- OPC_JALX = 0x1D, /* MIPS 16 only */
+ OPC_J = (0x02 << 26),
+ OPC_JAL = (0x03 << 26),
+ OPC_BEQ = (0x04 << 26), /* Unconditional if rs = rt = 0 (B) */
+ OPC_BEQL = (0x14 << 26),
+ OPC_BNE = (0x05 << 26),
+ OPC_BNEL = (0x15 << 26),
+ OPC_BLEZ = (0x06 << 26),
+ OPC_BLEZL = (0x16 << 26),
+ OPC_BGTZ = (0x07 << 26),
+ OPC_BGTZL = (0x17 << 26),
+ OPC_JALX = (0x1D << 26), /* MIPS 16 only */
/* Load and stores */
- OPC_LB = 0x20,
- OPC_LH = 0x21,
- OPC_LWL = 0x22,
- OPC_LW = 0x23,
- OPC_LBU = 0x24,
- OPC_LHU = 0x25,
- OPC_LWR = 0x26,
- OPC_LWU = 0x27,
- OPC_SB = 0x28,
- OPC_SH = 0x29,
- OPC_SWL = 0x2A,
- OPC_SW = 0x2B,
- OPC_SWR = 0x2E,
- OPC_LL = 0x30,
- OPC_SC = 0x38,
+ OPC_LDL = (0x1A << 26),
+ OPC_LDR = (0x1B << 26),
+ OPC_LB = (0x20 << 26),
+ OPC_LH = (0x21 << 26),
+ OPC_LWL = (0x22 << 26),
+ OPC_LW = (0x23 << 26),
+ OPC_LBU = (0x24 << 26),
+ OPC_LHU = (0x25 << 26),
+ OPC_LWR = (0x26 << 26),
+ OPC_LWU = (0x27 << 26),
+ OPC_SB = (0x28 << 26),
+ OPC_SH = (0x29 << 26),
+ OPC_SWL = (0x2A << 26),
+ OPC_SW = (0x2B << 26),
+ OPC_SDL = (0x2C << 26),
+ OPC_SDR = (0x2D << 26),
+ OPC_SWR = (0x2E << 26),
+ OPC_LL = (0x30 << 26),
+ OPC_LLD = (0x34 << 26),
+ OPC_LD = (0x37 << 26),
+ OPC_SC = (0x38 << 26),
+ OPC_SCD = (0x3C << 26),
+ OPC_SD = (0x3F << 26),
/* Floating point load/store */
- OPC_LWC1 = 0x31,
- OPC_LWC2 = 0x32,
- OPC_LDC1 = 0x35,
- OPC_LDC2 = 0x36,
- OPC_SWC1 = 0x39,
- OPC_SWC2 = 0x3A,
- OPC_SDC1 = 0x3D,
- OPC_SDC2 = 0x3E,
+ OPC_LWC1 = (0x31 << 26),
+ OPC_LWC2 = (0x32 << 26),
+ OPC_LDC1 = (0x35 << 26),
+ OPC_LDC2 = (0x36 << 26),
+ OPC_SWC1 = (0x39 << 26),
+ OPC_SWC2 = (0x3A << 26),
+ OPC_SDC1 = (0x3D << 26),
+ OPC_SDC2 = (0x3E << 26),
+ /* MDMX ASE specific */
+ OPC_MDMX = (0x1E << 26),
/* Cache and prefetch */
- OPC_CACHE = 0x2F,
- OPC_PREF = 0x33,
+ OPC_CACHE = (0x2F << 26),
+ OPC_PREF = (0x33 << 26),
+ /* Reserved major opcode */
+ OPC_MAJOR3B_RESERVED = (0x3B << 26),
};
/* MIPS special opcodes */
+#define MASK_SPECIAL(op) MASK_OP_MAJOR(op) | (op & 0x3F)
+
enum {
/* Shifts */
- OPC_SLL = 0x00 | EXT_SPECIAL,
+ OPC_SLL = 0x00 | OPC_SPECIAL,
/* NOP is SLL r0, r0, 0 */
/* SSNOP is SLL r0, r0, 1 */
- OPC_SRL = 0x02 | EXT_SPECIAL,
- OPC_SRA = 0x03 | EXT_SPECIAL,
- OPC_SLLV = 0x04 | EXT_SPECIAL,
- OPC_SRLV = 0x06 | EXT_SPECIAL,
- OPC_SRAV = 0x07 | EXT_SPECIAL,
+ /* EHB is SLL r0, r0, 3 */
+ OPC_SRL = 0x02 | OPC_SPECIAL, /* also ROTR */
+ OPC_SRA = 0x03 | OPC_SPECIAL,
+ OPC_SLLV = 0x04 | OPC_SPECIAL,
+ OPC_SRLV = 0x06 | OPC_SPECIAL,
+ OPC_SRAV = 0x07 | OPC_SPECIAL,
+ OPC_DSLLV = 0x14 | OPC_SPECIAL,
+ OPC_DSRLV = 0x16 | OPC_SPECIAL, /* also DROTRV */
+ OPC_DSRAV = 0x17 | OPC_SPECIAL,
+ OPC_DSLL = 0x38 | OPC_SPECIAL,
+ OPC_DSRL = 0x3A | OPC_SPECIAL, /* also DROTR */
+ OPC_DSRA = 0x3B | OPC_SPECIAL,
+ OPC_DSLL32 = 0x3C | OPC_SPECIAL,
+ OPC_DSRL32 = 0x3E | OPC_SPECIAL, /* also DROTR32 */
+ OPC_DSRA32 = 0x3F | OPC_SPECIAL,
/* Multiplication / division */
- OPC_MULT = 0x18 | EXT_SPECIAL,
- OPC_MULTU = 0x19 | EXT_SPECIAL,
- OPC_DIV = 0x1A | EXT_SPECIAL,
- OPC_DIVU = 0x1B | EXT_SPECIAL,
+ OPC_MULT = 0x18 | OPC_SPECIAL,
+ OPC_MULTU = 0x19 | OPC_SPECIAL,
+ OPC_DIV = 0x1A | OPC_SPECIAL,
+ OPC_DIVU = 0x1B | OPC_SPECIAL,
+ OPC_DMULT = 0x1C | OPC_SPECIAL,
+ OPC_DMULTU = 0x1D | OPC_SPECIAL,
+ OPC_DDIV = 0x1E | OPC_SPECIAL,
+ OPC_DDIVU = 0x1F | OPC_SPECIAL,
/* 2 registers arithmetic / logic */
- OPC_ADD = 0x20 | EXT_SPECIAL,
- OPC_ADDU = 0x21 | EXT_SPECIAL,
- OPC_SUB = 0x22 | EXT_SPECIAL,
- OPC_SUBU = 0x23 | EXT_SPECIAL,
- OPC_AND = 0x24 | EXT_SPECIAL,
- OPC_OR = 0x25 | EXT_SPECIAL,
- OPC_XOR = 0x26 | EXT_SPECIAL,
- OPC_NOR = 0x27 | EXT_SPECIAL,
- OPC_SLT = 0x2A | EXT_SPECIAL,
- OPC_SLTU = 0x2B | EXT_SPECIAL,
+ OPC_ADD = 0x20 | OPC_SPECIAL,
+ OPC_ADDU = 0x21 | OPC_SPECIAL,
+ OPC_SUB = 0x22 | OPC_SPECIAL,
+ OPC_SUBU = 0x23 | OPC_SPECIAL,
+ OPC_AND = 0x24 | OPC_SPECIAL,
+ OPC_OR = 0x25 | OPC_SPECIAL,
+ OPC_XOR = 0x26 | OPC_SPECIAL,
+ OPC_NOR = 0x27 | OPC_SPECIAL,
+ OPC_SLT = 0x2A | OPC_SPECIAL,
+ OPC_SLTU = 0x2B | OPC_SPECIAL,
+ OPC_DADD = 0x2C | OPC_SPECIAL,
+ OPC_DADDU = 0x2D | OPC_SPECIAL,
+ OPC_DSUB = 0x2E | OPC_SPECIAL,
+ OPC_DSUBU = 0x2F | OPC_SPECIAL,
/* Jumps */
- OPC_JR = 0x08 | EXT_SPECIAL,
- OPC_JALR = 0x09 | EXT_SPECIAL,
+ OPC_JR = 0x08 | OPC_SPECIAL, /* Also JR.HB */
+ OPC_JALR = 0x09 | OPC_SPECIAL, /* Also JALR.HB */
/* Traps */
- OPC_TGE = 0x30 | EXT_SPECIAL,
- OPC_TGEU = 0x31 | EXT_SPECIAL,
- OPC_TLT = 0x32 | EXT_SPECIAL,
- OPC_TLTU = 0x33 | EXT_SPECIAL,
- OPC_TEQ = 0x34 | EXT_SPECIAL,
- OPC_TNE = 0x36 | EXT_SPECIAL,
+ OPC_TGE = 0x30 | OPC_SPECIAL,
+ OPC_TGEU = 0x31 | OPC_SPECIAL,
+ OPC_TLT = 0x32 | OPC_SPECIAL,
+ OPC_TLTU = 0x33 | OPC_SPECIAL,
+ OPC_TEQ = 0x34 | OPC_SPECIAL,
+ OPC_TNE = 0x36 | OPC_SPECIAL,
/* HI / LO registers load & stores */
- OPC_MFHI = 0x10 | EXT_SPECIAL,
- OPC_MTHI = 0x11 | EXT_SPECIAL,
- OPC_MFLO = 0x12 | EXT_SPECIAL,
- OPC_MTLO = 0x13 | EXT_SPECIAL,
+ OPC_MFHI = 0x10 | OPC_SPECIAL,
+ OPC_MTHI = 0x11 | OPC_SPECIAL,
+ OPC_MFLO = 0x12 | OPC_SPECIAL,
+ OPC_MTLO = 0x13 | OPC_SPECIAL,
/* Conditional moves */
- OPC_MOVZ = 0x0A | EXT_SPECIAL,
- OPC_MOVN = 0x0B | EXT_SPECIAL,
+ OPC_MOVZ = 0x0A | OPC_SPECIAL,
+ OPC_MOVN = 0x0B | OPC_SPECIAL,
- OPC_MOVCI = 0x01 | EXT_SPECIAL,
+ OPC_MOVCI = 0x01 | OPC_SPECIAL,
/* Special */
- OPC_PMON = 0x05 | EXT_SPECIAL,
- OPC_SYSCALL = 0x0C | EXT_SPECIAL,
- OPC_BREAK = 0x0D | EXT_SPECIAL,
- OPC_SYNC = 0x0F | EXT_SPECIAL,
+ OPC_PMON = 0x05 | OPC_SPECIAL, /* inofficial */
+ OPC_SYSCALL = 0x0C | OPC_SPECIAL,
+ OPC_BREAK = 0x0D | OPC_SPECIAL,
+ OPC_SPIM = 0x0E | OPC_SPECIAL, /* inofficial */
+ OPC_SYNC = 0x0F | OPC_SPECIAL,
+
+ OPC_SPECIAL15_RESERVED = 0x15 | OPC_SPECIAL,
+ OPC_SPECIAL28_RESERVED = 0x28 | OPC_SPECIAL,
+ OPC_SPECIAL29_RESERVED = 0x29 | OPC_SPECIAL,
+ OPC_SPECIAL35_RESERVED = 0x35 | OPC_SPECIAL,
+ OPC_SPECIAL37_RESERVED = 0x37 | OPC_SPECIAL,
+ OPC_SPECIAL39_RESERVED = 0x39 | OPC_SPECIAL,
+ OPC_SPECIAL3D_RESERVED = 0x3D | OPC_SPECIAL,
+};
+
+/* REGIMM (rt field) opcodes */
+#define MASK_REGIMM(op) MASK_OP_MAJOR(op) | (op & (0x1F << 16))
+
+enum {
+ OPC_BLTZ = (0x00 << 16) | OPC_REGIMM,
+ OPC_BLTZL = (0x02 << 16) | OPC_REGIMM,
+ OPC_BGEZ = (0x01 << 16) | OPC_REGIMM,
+ OPC_BGEZL = (0x03 << 16) | OPC_REGIMM,
+ OPC_BLTZAL = (0x10 << 16) | OPC_REGIMM,
+ OPC_BLTZALL = (0x12 << 16) | OPC_REGIMM,
+ OPC_BGEZAL = (0x11 << 16) | OPC_REGIMM,
+ OPC_BGEZALL = (0x13 << 16) | OPC_REGIMM,
+ OPC_TGEI = (0x08 << 16) | OPC_REGIMM,
+ OPC_TGEIU = (0x09 << 16) | OPC_REGIMM,
+ OPC_TLTI = (0x0A << 16) | OPC_REGIMM,
+ OPC_TLTIU = (0x0B << 16) | OPC_REGIMM,
+ OPC_TEQI = (0x0C << 16) | OPC_REGIMM,
+ OPC_TNEI = (0x0E << 16) | OPC_REGIMM,
+ OPC_SYNCI = (0x1F << 16) | OPC_REGIMM,
};
+/* Special2 opcodes */
+#define MASK_SPECIAL2(op) MASK_OP_MAJOR(op) | (op & 0x3F)
+
enum {
- /* Mutiply & xxx operations */
- OPC_MADD = 0x00 | EXT_SPECIAL2,
- OPC_MADDU = 0x01 | EXT_SPECIAL2,
- OPC_MUL = 0x02 | EXT_SPECIAL2,
- OPC_MSUB = 0x04 | EXT_SPECIAL2,
- OPC_MSUBU = 0x05 | EXT_SPECIAL2,
+ /* Multiply & xxx operations */
+ OPC_MADD = 0x00 | OPC_SPECIAL2,
+ OPC_MADDU = 0x01 | OPC_SPECIAL2,
+ OPC_MUL = 0x02 | OPC_SPECIAL2,
+ OPC_MSUB = 0x04 | OPC_SPECIAL2,
+ OPC_MSUBU = 0x05 | OPC_SPECIAL2,
/* Misc */
- OPC_CLZ = 0x20 | EXT_SPECIAL2,
- OPC_CLO = 0x21 | EXT_SPECIAL2,
+ OPC_CLZ = 0x20 | OPC_SPECIAL2,
+ OPC_CLO = 0x21 | OPC_SPECIAL2,
+ OPC_DCLZ = 0x24 | OPC_SPECIAL2,
+ OPC_DCLO = 0x25 | OPC_SPECIAL2,
/* Special */
- OPC_SDBBP = 0x3F | EXT_SPECIAL2,
+ OPC_SDBBP = 0x3F | OPC_SPECIAL2,
};
-/* Branch REGIMM */
+/* Special3 opcodes */
+#define MASK_SPECIAL3(op) MASK_OP_MAJOR(op) | (op & 0x3F)
+
enum {
- OPC_BLTZ = 0x00 | EXT_REGIMM,
- OPC_BLTZL = 0x02 | EXT_REGIMM,
- OPC_BGEZ = 0x01 | EXT_REGIMM,
- OPC_BGEZL = 0x03 | EXT_REGIMM,
- OPC_BLTZAL = 0x10 | EXT_REGIMM,
- OPC_BLTZALL = 0x12 | EXT_REGIMM,
- OPC_BGEZAL = 0x11 | EXT_REGIMM,
- OPC_BGEZALL = 0x13 | EXT_REGIMM,
- OPC_TGEI = 0x08 | EXT_REGIMM,
- OPC_TGEIU = 0x09 | EXT_REGIMM,
- OPC_TLTI = 0x0A | EXT_REGIMM,
- OPC_TLTIU = 0x0B | EXT_REGIMM,
- OPC_TEQI = 0x0C | EXT_REGIMM,
- OPC_TNEI = 0x0E | EXT_REGIMM,
+ OPC_EXT = 0x00 | OPC_SPECIAL3,
+ OPC_DEXTM = 0x01 | OPC_SPECIAL3,
+ OPC_DEXTU = 0x02 | OPC_SPECIAL3,
+ OPC_DEXT = 0x03 | OPC_SPECIAL3,
+ OPC_INS = 0x04 | OPC_SPECIAL3,
+ OPC_DINSM = 0x05 | OPC_SPECIAL3,
+ OPC_DINSU = 0x06 | OPC_SPECIAL3,
+ OPC_DINS = 0x07 | OPC_SPECIAL3,
+ OPC_BSHFL = 0x20 | OPC_SPECIAL3,
+ OPC_DBSHFL = 0x24 | OPC_SPECIAL3,
+ OPC_RDHWR = 0x3B | OPC_SPECIAL3,
};
+/* BSHFL opcodes */
+#define MASK_BSHFL(op) MASK_SPECIAL3(op) | (op & (0x1F << 6))
+
enum {
- /* Coprocessor 0 (MMU) */
- OPC_MFC0 = 0x00 | EXT_CP0,
- OPC_MTC0 = 0x04 | EXT_CP0,
- OPC_TLBR = 0x01 | EXT_CP0,
- OPC_TLBWI = 0x02 | EXT_CP0,
- OPC_TLBWR = 0x06 | EXT_CP0,
- OPC_TLBP = 0x08 | EXT_CP0,
- OPC_ERET = 0x18 | EXT_CP0,
- OPC_DERET = 0x1F | EXT_CP0,
- OPC_WAIT = 0x20 | EXT_CP0,
+ OPC_WSBH = (0x02 << 6) | OPC_BSHFL,
+ OPC_SEB = (0x10 << 6) | OPC_BSHFL,
+ OPC_SEH = (0x18 << 6) | OPC_BSHFL,
};
-#ifdef MIPS_USES_FPU
+/* DBSHFL opcodes */
+#define MASK_DBSHFL(op) MASK_SPECIAL3(op) | (op & (0x1F << 6))
+
enum {
- /* Coprocessor 1 (FPU) */
- OPC_MFC1 = 0x00 | EXT_CP1,
- OPC_MTC1 = 0x04 | EXT_CP1,
- OPC_CFC1 = 0x02 | EXT_CP1,
- OPC_CTC1 = 0x06 | EXT_CP1,
+ OPC_DSBH = (0x02 << 6) | OPC_DBSHFL,
+ OPC_DSHD = (0x05 << 6) | OPC_DBSHFL,
+};
+
+/* Coprocessor 0 (rs field) */
+#define MASK_CP0(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21))
+
+enum {
+ OPC_MFC0 = (0x00 << 21) | OPC_CP0,
+ OPC_DMFC0 = (0x01 << 21) | OPC_CP0,
+ OPC_MTC0 = (0x04 << 21) | OPC_CP0,
+ OPC_DMTC0 = (0x05 << 21) | OPC_CP0,
+ OPC_RDPGPR = (0x0A << 21) | OPC_CP0,
+ OPC_MFMC0 = (0x0B << 21) | OPC_CP0,
+ OPC_WRPGPR = (0x0E << 21) | OPC_CP0,
+ OPC_C0 = (0x10 << 21) | OPC_CP0,
+ OPC_C0_FIRST = (0x10 << 21) | OPC_CP0,
+ OPC_C0_LAST = (0x1F << 21) | OPC_CP0,
+};
+
+/* MFMC0 opcodes */
+#define MASK_MFMC0(op) MASK_CP0(op) | (op & ((0x0C << 11) | (1 << 5)))
+
+enum {
+ OPC_DI = (0 << 5) | (0x0C << 11) | OPC_MFMC0,
+ OPC_EI = (1 << 5) | (0x0C << 11) | OPC_MFMC0,
+};
+
+/* Coprocessor 0 (with rs == C0) */
+#define MASK_C0(op) MASK_CP0(op) | (op & 0x3F)
+
+enum {
+ OPC_TLBR = 0x01 | OPC_C0,
+ OPC_TLBWI = 0x02 | OPC_C0,
+ OPC_TLBWR = 0x06 | OPC_C0,
+ OPC_TLBP = 0x08 | OPC_C0,
+ OPC_RFE = 0x10 | OPC_C0,
+ OPC_ERET = 0x18 | OPC_C0,
+ OPC_DERET = 0x1F | OPC_C0,
+ OPC_WAIT = 0x20 | OPC_C0,
+};
+
+/* Coprocessor 1 (rs field) */
+#define MASK_CP1(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21))
+
+enum {
+ OPC_MFC1 = (0x00 << 21) | OPC_CP1,
+ OPC_DMFC1 = (0x01 << 21) | OPC_CP1,
+ OPC_CFC1 = (0x02 << 21) | OPC_CP1,
+ OPC_MFHCI = (0x03 << 21) | OPC_CP1,
+ OPC_MTC1 = (0x04 << 21) | OPC_CP1,
+ OPC_DMTC1 = (0x05 << 21) | OPC_CP1,
+ OPC_CTC1 = (0x06 << 21) | OPC_CP1,
+ OPC_MTHCI = (0x07 << 21) | OPC_CP1,
+ OPC_BC1 = (0x08 << 21) | OPC_CP1, /* bc */
+ OPC_S_FMT = (0x10 << 21) | OPC_CP1, /* 16: fmt=single fp */
+ OPC_D_FMT = (0x11 << 21) | OPC_CP1, /* 17: fmt=double fp */
+ OPC_E_FMT = (0x12 << 21) | OPC_CP1, /* 18: fmt=extended fp */
+ OPC_Q_FMT = (0x13 << 21) | OPC_CP1, /* 19: fmt=quad fp */
+ OPC_W_FMT = (0x14 << 21) | OPC_CP1, /* 20: fmt=32bit fixed */
+ OPC_L_FMT = (0x15 << 21) | OPC_CP1, /* 21: fmt=64bit fixed */
+};
+
+enum {
+ OPC_BC1F = (0x00 << 16) | OPC_BC1,
+ OPC_BC1T = (0x01 << 16) | OPC_BC1,
+ OPC_BC1FL = (0x02 << 16) | OPC_BC1,
+ OPC_BC1TL = (0x03 << 16) | OPC_BC1,
};
-#endif
+
+#define MASK_CP1_BCOND(op) MASK_CP1(op) | (op & ((0x1F << 21) | (0x3 << 16)))
+#define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & ((0x1F << 21) | 0x3F))
+
+#define MASK_CP2(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21))
+#define MASK_CP3(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21))
const unsigned char *regnames[] =
{ "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
@@ -260,8 +389,7 @@
GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
-#ifdef MIPS_USES_FPU
-const unsigned char *fregnames[] =
+static const char *fregnames[] =
{ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
@@ -344,8 +472,6 @@
FOP_CONDS(d)
FOP_CONDS(s)
-#endif
-
typedef struct DisasContext {
struct TranslationBlock *tb;
target_ulong pc, saved_pc;
@@ -410,9 +536,7 @@
} \
} while (0)
-#ifdef MIPS_USES_FPU
-
-# define GEN_LOAD_FREG_FTN(FTn, Fn) \
+#define GEN_LOAD_FREG_FTN(FTn, Fn) \
do { \
glue(gen_op_load_fpr_, FTn)(Fn); \
} while (0)
@@ -422,8 +546,6 @@
glue(gen_op_store_fpr_, FTn)(Fn); \
} while (0)
-#endif
-
static inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
{
#if defined MIPS_DEBUG_DISAS
@@ -487,7 +609,7 @@
}
#endif
-#ifdef TARGET_MIPS64
+#ifdef MIPS_HAS_MIPS64
OP_LD_TABLE(d);
OP_LD_TABLE(dl);
OP_LD_TABLE(dr);
@@ -510,18 +632,16 @@
OP_ST_TABLE(b);
OP_LD_TABLE(l);
OP_ST_TABLE(c);
-#ifdef MIPS_USES_FPU
OP_LD_TABLE(wc1);
OP_ST_TABLE(wc1);
OP_LD_TABLE(dc1);
OP_ST_TABLE(dc1);
-#endif
/* Load and store */
-static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt,
+static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
int base, int16_t offset)
{
- const unsigned char *opn = "unk";
+ const char *opn = "unk";
if (base == 0) {
GEN_LOAD_IMM_TN(T0, offset);
@@ -536,23 +656,27 @@
* memory access
*/
switch (opc) {
-#if defined(TARGET_MIPS64)
+#ifdef MIPS_HAS_MIPS64
case OPC_LD:
-#if defined (MIPS_HAS_UNALIGNED_LS)
- case OPC_ULD:
-#endif
op_ldst(ld);
GEN_STORE_TN_REG(rt, T0);
opn = "ld";
break;
+ case OPC_LLD:
+ op_ldst(lld);
+ GEN_STORE_TN_REG(rt, T0);
+ opn = "lld";
+ break;
case OPC_SD:
-#if defined (MIPS_HAS_UNALIGNED_LS)
- case OPC_USD:
-#endif
GEN_LOAD_REG_TN(T1, rt);
op_ldst(sd);
opn = "sd";
break;
+ case OPC_SCD:
+ GEN_LOAD_REG_TN(T1, rt);
+ op_ldst(scd);
+ opn = "scd";
+ break;
case OPC_LDL:
op_ldst(ldl);
GEN_STORE_TN_REG(rt, T0);
@@ -575,9 +699,6 @@
break;
#endif
case OPC_LW:
-#if defined (MIPS_HAS_UNALIGNED_LS)
- case OPC_ULW:
-#endif
op_ldst(lw);
GEN_STORE_TN_REG(rt, T0);
opn = "lw";
@@ -588,33 +709,21 @@
opn = "lwu";
break;
case OPC_SW:
-#if defined (MIPS_HAS_UNALIGNED_LS)
- case OPC_USW:
-#endif
GEN_LOAD_REG_TN(T1, rt);
op_ldst(sw);
opn = "sw";
break;
case OPC_LH:
-#if defined (MIPS_HAS_UNALIGNED_LS)
- case OPC_ULH:
-#endif
op_ldst(lh);
GEN_STORE_TN_REG(rt, T0);
opn = "lh";
break;
case OPC_SH:
-#if defined (MIPS_HAS_UNALIGNED_LS)
- case OPC_USH:
-#endif
GEN_LOAD_REG_TN(T1, rt);
op_ldst(sh);
opn = "sh";
break;
case OPC_LHU:
-#if defined (MIPS_HAS_UNALIGNED_LS)
- case OPC_ULHU:
-#endif
op_ldst(lhu);
GEN_STORE_TN_REG(rt, T0);
opn = "lhu";
@@ -675,13 +784,11 @@
MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
}
-#ifdef MIPS_USES_FPU
-
/* Load and store */
-static void gen_flt_ldst (DisasContext *ctx, uint16_t opc, int ft,
+static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft,
int base, int16_t offset)
{
- const unsigned char *opn = "unk";
+ const char *opn = "unk";
if (base == 0) {
GEN_LOAD_IMM_TN(T0, offset);
@@ -718,21 +825,20 @@
break;
default:
MIPS_INVAL("float load/store");
- generate_exception(ctx, EXCP_CpU);
+ generate_exception_err(ctx, EXCP_CpU, 1);
return;
}
MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]);
}
-#endif
/* Arithmetic with immediate operand */
-static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt,
+static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt,
int rs, int16_t imm)
{
uint32_t uimm;
- const unsigned char *opn = "unk";
+ const char *opn = "unk";
- if (rt == 0 && opc != OPC_ADDI) {
+ if (rt == 0 && opc != OPC_ADDI && opc != OPC_DADDI) {
/* if no destination, treat it as a NOP
* For addi, we must generate the overflow exception when needed.
*/
@@ -740,8 +846,9 @@
return;
}
if (opc == OPC_ADDI || opc == OPC_ADDIU ||
+ opc == OPC_DADDI || opc == OPC_DADDIU ||
opc == OPC_SLTI || opc == OPC_SLTIU)
- uimm = (int32_t)imm; /* Sign extent to 32 bits */
+ uimm = (int32_t)imm; /* Sign extend to 32 bits */
else
uimm = (uint16_t)imm;
if (opc != OPC_LUI) {
@@ -761,6 +868,17 @@
gen_op_add();
opn = "addiu";
break;
+#ifdef MIPS_HAS_MIPS64
+ case OPC_DADDI:
+ save_cpu_state(ctx, 1);
+ gen_op_daddo();
+ opn = "daddi";
+ break;
+ case OPC_DADDIU:
+ gen_op_dadd();
+ opn = "daddiu";
+ break;
+#endif
case OPC_SLTI:
gen_op_lt();
opn = "slti";
@@ -793,9 +911,50 @@
opn = "sra";
break;
case OPC_SRL:
- gen_op_srl();
- opn = "srl";
+ if ((ctx->opcode >> 21) & 1) {
+ gen_op_rotr();
+ opn = "rotr";
+ } else {
+ gen_op_srl();
+ opn = "srl";
+ }
+ break;
+#ifdef MIPS_HAS_MIPS64
+ case OPC_DSLL:
+ gen_op_dsll();
+ opn = "dsll";
+ break;
+ case OPC_DSRA:
+ gen_op_dsra();
+ opn = "dsra";
+ break;
+ case OPC_DSRL:
+ if ((ctx->opcode >> 21) & 1) {
+ gen_op_drotr();
+ opn = "drotr";
+ } else {
+ gen_op_dsrl();
+ opn = "dsrl";
+ }
+ break;
+ case OPC_DSLL32:
+ gen_op_dsll32();
+ opn = "dsll32";
+ break;
+ case OPC_DSRA32:
+ gen_op_dsra32();
+ opn = "dsra32";
+ break;
+ case OPC_DSRL32:
+ if ((ctx->opcode >> 21) & 1) {
+ gen_op_drotr32();
+ opn = "drotr32";
+ } else {
+ gen_op_dsrl32();
+ opn = "dsrl32";
+ }
break;
+#endif
default:
MIPS_INVAL("imm arith");
generate_exception(ctx, EXCP_RI);
@@ -806,12 +965,13 @@
}
/* Arithmetic */
-static void gen_arith (DisasContext *ctx, uint16_t opc,
+static void gen_arith (DisasContext *ctx, uint32_t opc,
int rd, int rs, int rt)
{
- const unsigned char *opn = "unk";
+ const char *opn = "unk";
- if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB) {
+ if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB
+ && opc != OPC_DADD && opc != OPC_DSUB) {
/* if no destination, treat it as a NOP
* For add & sub, we must generate the overflow exception when needed.
*/
@@ -839,6 +999,26 @@
gen_op_sub();
opn = "subu";
break;
+#ifdef MIPS_HAS_MIPS64
+ case OPC_DADD:
+ save_cpu_state(ctx, 1);
+ gen_op_daddo();
+ opn = "dadd";
+ break;
+ case OPC_DADDU:
+ gen_op_dadd();
+ opn = "daddu";
+ break;
+ case OPC_DSUB:
+ save_cpu_state(ctx, 1);
+ gen_op_dsubo();
+ opn = "dsub";
+ break;
+ case OPC_DSUBU:
+ gen_op_dsub();
+ opn = "dsubu";
+ break;
+#endif
case OPC_SLT:
gen_op_lt();
opn = "slt";
@@ -884,9 +1064,33 @@
opn = "srav";
break;
case OPC_SRLV:
- gen_op_srlv();
- opn = "srlv";
+ if ((ctx->opcode >> 6) & 1) {
+ gen_op_rotrv();
+ opn = "rotrv";
+ } else {
+ gen_op_srlv();
+ opn = "srlv";
+ }
+ break;
+#ifdef MIPS_HAS_MIPS64
+ case OPC_DSLLV:
+ gen_op_dsllv();
+ opn = "dsllv";
+ break;
+ case OPC_DSRAV:
+ gen_op_dsrav();
+ opn = "dsrav";
+ break;
+ case OPC_DSRLV:
+ if ((ctx->opcode >> 6) & 1) {
+ gen_op_drotrv();
+ opn = "drotrv";
+ } else {
+ gen_op_dsrlv();
+ opn = "dsrlv";
+ }
break;
+#endif
default:
MIPS_INVAL("arith");
generate_exception(ctx, EXCP_RI);
@@ -898,9 +1102,9 @@
}
/* Arithmetic on HI/LO registers */
-static void gen_HILO (DisasContext *ctx, uint16_t opc, int reg)
+static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg)
{
- const unsigned char *opn = "unk";
+ const char *opn = "unk";
if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) {
/* Treat as a NOP */
@@ -936,10 +1140,10 @@
MIPS_DEBUG("%s %s", opn, regnames[reg]);
}
-static void gen_muldiv (DisasContext *ctx, uint16_t opc,
+static void gen_muldiv (DisasContext *ctx, uint32_t opc,
int rs, int rt)
{
- const unsigned char *opn = "unk";
+ const char *opn = "unk";
GEN_LOAD_REG_TN(T0, rs);
GEN_LOAD_REG_TN(T1, rt);
@@ -960,6 +1164,24 @@
gen_op_multu();
opn = "multu";
break;
+#ifdef MIPS_HAS_MIPS64
+ case OPC_DDIV:
+ gen_op_ddiv();
+ opn = "ddiv";
+ break;
+ case OPC_DDIVU:
+ gen_op_ddivu();
+ opn = "ddivu";
+ break;
+ case OPC_DMULT:
+ gen_op_dmult();
+ opn = "dmult";
+ break;
+ case OPC_DMULTU:
+ gen_op_dmultu();
+ opn = "dmultu";
+ break;
+#endif
case OPC_MADD:
gen_op_madd();
opn = "madd";
@@ -984,10 +1206,10 @@
MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
}
-static void gen_cl (DisasContext *ctx, uint16_t opc,
+static void gen_cl (DisasContext *ctx, uint32_t opc,
int rd, int rs)
{
- const unsigned char *opn = "unk";
+ const char *opn = "unk";
if (rd == 0) {
/* Treat as a NOP */
MIPS_DEBUG("NOP");
@@ -996,15 +1218,23 @@
GEN_LOAD_REG_TN(T0, rs);
switch (opc) {
case OPC_CLO:
- /* CLO */
gen_op_clo();
opn = "clo";
break;
case OPC_CLZ:
- /* CLZ */
gen_op_clz();
opn = "clz";
break;
+#ifdef MIPS_HAS_MIPS64
+ case OPC_DCLO:
+ gen_op_dclo();
+ opn = "dclo";
+ break;
+ case OPC_DCLZ:
+ gen_op_dclz();
+ opn = "dclz";
+ break;
+#endif
default:
MIPS_INVAL("CLx");
generate_exception(ctx, EXCP_RI);
@@ -1015,7 +1245,7 @@
}
/* Traps */
-static void gen_trap (DisasContext *ctx, uint16_t opc,
+static void gen_trap (DisasContext *ctx, uint32_t opc,
int rs, int rt, int16_t imm)
{
int cond;
@@ -1130,7 +1360,7 @@
}
/* Branches (before delay slot) */
-static void gen_compute_branch (DisasContext *ctx, uint16_t opc,
+static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
int rs, int rt, int32_t offset)
{
target_ulong btarget;
@@ -1180,8 +1410,9 @@
case OPC_JR:
case OPC_JALR:
/* Jump to register */
- if (offset != 0) {
- /* Only hint = 0 is valid */
+ if (offset != 0 && offset != 16) {
+ /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
+ others are reserved. */
generate_exception(ctx, EXCP_RI);
return;
}
@@ -1348,81 +1579,330 @@
return;
}
+/* special3 bitfield operations */
+static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
+ int rs, int pos, int size)
+{
+ int p = pos & 0x1F;
+ int sz = (size & 0x1F) + 1;
+
+ GEN_LOAD_REG_TN(T1, rs);
+ switch (opc) {
+ case OPC_EXT:
+ gen_op_ext(p, sz);
+ break;
+ case OPC_DEXTM:
+ gen_op_dextm(p, sz);
+ break;
+ case OPC_DEXTU:
+ gen_op_dextu(p, sz);
+ break;
+ case OPC_DEXT:
+ gen_op_dext(p, sz);
+ break;
+ case OPC_INS:
+ GEN_LOAD_REG_TN(T2, rt);
+ gen_op_ins(p, sz);
+ break;
+ case OPC_DINSM:
+ GEN_LOAD_REG_TN(T2, rt);
+ gen_op_dinsm(p, sz);
+ break;
+ case OPC_DINSU:
+ GEN_LOAD_REG_TN(T2, rt);
+ gen_op_dinsu(p, sz);
+ break;
+ case OPC_DINS:
+ GEN_LOAD_REG_TN(T2, rt);
+ gen_op_dins(p, sz);
+ break;
+ default:
+ MIPS_INVAL("bitops");
+ generate_exception(ctx, EXCP_RI);
+ return;
+ }
+ GEN_STORE_TN_REG(rt, T0);
+}
+
/* CP0 (MMU and control) */
static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
{
- const unsigned char *rn;
+ const char *rn = "invalid";
- if (sel != 0 && reg != 16 && reg != 28) {
- rn = "invalid";
- goto die;
- }
switch (reg) {
case 0:
- gen_op_mfc0_index();
- rn = "Index";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_index();
+ rn = "Index";
+ break;
+ case 1:
+// gen_op_mfc0_mvpcontrol(); /* MT ASE */
+ rn = "MVPControl";
+// break;
+ case 2:
+// gen_op_mfc0_mvpconf0(); /* MT ASE */
+ rn = "MVPConf0";
+// break;
+ case 3:
+// gen_op_mfc0_mvpconf1(); /* MT ASE */
+ rn = "MVPConf1";
+// break;
+ default:
+ goto die;
+ }
break;
case 1:
- gen_op_mfc0_random();
- rn = "Random";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_random();
+ rn = "Random";
+ break;
+ case 1:
+// gen_op_mfc0_vpecontrol(); /* MT ASE */
+ rn = "VPEControl";
+// break;
+ case 2:
+// gen_op_mfc0_vpeconf0(); /* MT ASE */
+ rn = "VPEConf0";
+// break;
+ case 3:
+// gen_op_mfc0_vpeconf1(); /* MT ASE */
+ rn = "VPEConf1";
+// break;
+ case 4:
+// gen_op_mfc0_YQMask(); /* MT ASE */
+ rn = "YQMask";
+// break;
+ case 5:
+// gen_op_mfc0_vpeschedule(); /* MT ASE */
+ rn = "VPESchedule";
+// break;
+ case 6:
+// gen_op_mfc0_vpeschefback(); /* MT ASE */
+ rn = "VPEScheFBack";
+// break;
+ case 7:
+// gen_op_mfc0_vpeopt(); /* MT ASE */
+ rn = "VPEOpt";
+// break;
+ default:
+ goto die;
+ }
break;
case 2:
- gen_op_mfc0_entrylo0();
- rn = "EntryLo0";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_entrylo0();
+ rn = "EntryLo0";
+ break;
+ case 1:
+// gen_op_mfc0_tcstatus(); /* MT ASE */
+ rn = "TCStatus";
+// break;
+ case 2:
+// gen_op_mfc0_tcbind(); /* MT ASE */
+ rn = "TCBind";
+// break;
+ case 3:
+// gen_op_mfc0_tcrestart(); /* MT ASE */
+ rn = "TCRestart";
+// break;
+ case 4:
+// gen_op_mfc0_tchalt(); /* MT ASE */
+ rn = "TCHalt";
+// break;
+ case 5:
+// gen_op_mfc0_tccontext(); /* MT ASE */
+ rn = "TCContext";
+// break;
+ case 6:
+// gen_op_mfc0_tcschedule(); /* MT ASE */
+ rn = "TCSchedule";
+// break;
+ case 7:
+// gen_op_mfc0_tcschefback(); /* MT ASE */
+ rn = "TCScheFBack";
+// break;
+ default:
+ goto die;
+ }
break;
case 3:
-//
- /* also CONF */
- gen_op_mfc0_entrylo1();
- rn = "EntryLo1";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_entrylo1();
+ rn = "EntryLo1";
+ break;
+ default:
+ goto die;
+ }
break;
case 4:
- gen_op_mfc0_context();
- rn = "Context";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_context();
+ rn = "Context";
+ break;
+ case 1:
+// gen_op_mfc0_contextconfig(); /* SmartMIPS ASE */
+ rn = "ContextConfig";
+// break;
+ default:
+ goto die;
+ }
break;
case 5:
- gen_op_mfc0_pagemask();
- rn = "PageMask";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_pagemask();
+ rn = "PageMask";
+ break;
+ case 1:
+ gen_op_mfc0_pagegrain();
+ rn = "PageGrain";
+ break;
+ default:
+ goto die;
+ }
break;
case 6:
- gen_op_mfc0_wired();
- rn = "Wired";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_wired();
+ rn = "Wired";
+ break;
+ case 1:
+// gen_op_mfc0_srsconf0(); /* shadow registers */
+ rn = "SRSConf0";
+// break;
+ case 2:
+// gen_op_mfc0_srsconf1(); /* shadow registers */
+ rn = "SRSConf1";
+// break;
+ case 3:
+// gen_op_mfc0_srsconf2(); /* shadow registers */
+ rn = "SRSConf2";
+// break;
+ case 4:
+// gen_op_mfc0_srsconf3(); /* shadow registers */
+ rn = "SRSConf3";
+// break;
+ case 5:
+// gen_op_mfc0_srsconf4(); /* shadow registers */
+ rn = "SRSConf4";
+// break;
+ default:
+ goto die;
+ }
break;
case 7:
-// gen_op_mfc0_info();
- rn = "Info";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_hwrena();
+ rn = "HWREna";
+ break;
+ default:
+ goto die;
+ }
break;
case 8:
- gen_op_mfc0_badvaddr();
- rn = "BadVaddr";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_badvaddr();
+ rn = "BadVaddr";
+ break;
+ default:
+ goto die;
+ }
break;
case 9:
- gen_op_mfc0_count();
- rn = "Count";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_count();
+ rn = "Count";
+ break;
+ /* 6,7 are implementation dependent */
+ default:
+ goto die;
+ }
break;
case 10:
- gen_op_mfc0_entryhi();
- rn = "EntryHi";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_entryhi();
+ rn = "EntryHi";
+ break;
+ default:
+ goto die;
+ }
break;
case 11:
- gen_op_mfc0_compare();
- rn = "Compare";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_compare();
+ rn = "Compare";
+ break;
+ /* 6,7 are implementation dependent */
+ default:
+ goto die;
+ }
break;
case 12:
- gen_op_mfc0_status();
- rn = "Status";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_status();
+ rn = "Status";
+ break;
+ case 1:
+ gen_op_mfc0_intctl();
+ rn = "IntCtl";
+ break;
+ case 2:
+ gen_op_mfc0_srsctl();
+ rn = "SRSCtl";
+ break;
+ case 3:
+// gen_op_mfc0_srsmap(); /* shadow registers */
+ rn = "SRSMap";
+// break;
+ default:
+ goto die;
+ }
break;
case 13:
- gen_op_mfc0_cause();
- rn = "Cause";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_cause();
+ rn = "Cause";
+ break;
+ default:
+ goto die;
+ }
break;
case 14:
- gen_op_mfc0_epc();
- rn = "EPC";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_epc();
+ rn = "EPC";
+ break;
+ default:
+ goto die;
+ }
break;
case 15:
- gen_op_mfc0_prid();
- rn = "PRid";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_prid();
+ rn = "PRid";
+ break;
+ case 1:
+ gen_op_mfc0_ebase();
+ rn = "EBase";
+ break;
+ default:
+ goto die;
+ }
break;
case 16:
switch (sel) {
@@ -1434,91 +1914,285 @@
gen_op_mfc0_config1();
rn = "Config1";
break;
+ case 2:
+ gen_op_mfc0_config2();
+ rn = "Config2";
+ break;
+ case 3:
+ gen_op_mfc0_config3();
+ rn = "Config3";
+ break;
+ /* 6,7 are implementation dependent */
default:
- rn = "Unknown config register";
goto die;
}
break;
case 17:
- gen_op_mfc0_lladdr();
- rn = "LLAddr";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_lladdr();
+ rn = "LLAddr";
+ break;
+ default:
+ goto die;
+ }
break;
case 18:
- gen_op_mfc0_watchlo();
- rn = "WatchLo";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_watchlo0();
+ rn = "WatchLo";
+ break;
+ case 1:
+// gen_op_mfc0_watchlo1();
+ rn = "WatchLo1";
+// break;
+ case 2:
+// gen_op_mfc0_watchlo2();
+ rn = "WatchLo2";
+// break;
+ case 3:
+// gen_op_mfc0_watchlo3();
+ rn = "WatchLo3";
+// break;
+ case 4:
+// gen_op_mfc0_watchlo4();
+ rn = "WatchLo4";
+// break;
+ case 5:
+// gen_op_mfc0_watchlo5();
+ rn = "WatchLo5";
+// break;
+ case 6:
+// gen_op_mfc0_watchlo6();
+ rn = "WatchLo6";
+// break;
+ case 7:
+// gen_op_mfc0_watchlo7();
+ rn = "WatchLo7";
+// break;
+ default:
+ goto die;
+ }
break;
case 19:
- gen_op_mfc0_watchhi();
- rn = "WatchHi";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_watchhi0();
+ rn = "WatchHi";
+ break;
+ case 1:
+// gen_op_mfc0_watchhi1();
+ rn = "WatchHi1";
+// break;
+ case 2:
+// gen_op_mfc0_watchhi2();
+ rn = "WatchHi2";
+// break;
+ case 3:
+// gen_op_mfc0_watchhi3();
+ rn = "WatchHi3";
+// break;
+ case 4:
+// gen_op_mfc0_watchhi4();
+ rn = "WatchHi4";
+// break;
+ case 5:
+// gen_op_mfc0_watchhi5();
+ rn = "WatchHi5";
+// break;
+ case 6:
+// gen_op_mfc0_watchhi6();
+ rn = "WatchHi6";
+// break;
+ case 7:
+// gen_op_mfc0_watchhi7();
+ rn = "WatchHi7";
+// break;
+ default:
+ goto die;
+ }
break;
case 20:
- /* 64 bit only */
-// gen_op_mfc0_xcontext();
- rn = "XContext";
+ switch (sel) {
+ case 0:
+ /* 64 bit MMU only */
+ gen_op_mfc0_xcontext();
+ rn = "XContext";
+ break;
+ default:
+ goto die;
+ }
break;
case 21:
-// gen_op_mfc0_framemask();
- rn = "Framemask";
+ /* Officially reserved, but sel 0 is used for R1x000 framemask */
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_framemask();
+ rn = "Framemask";
+ break;
+ default:
+ goto die;
+ }
break;
case 22:
-// gen_op_mfc0_diagnostic();
- rn = "'Diagnostic";
- break;
+ /* ignored */
+ rn = "'Diagnostic"; /* implementation dependent */
+ break;
case 23:
- gen_op_mfc0_debug();
- rn = "Debug";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_debug(); /* EJTAG support */
+ rn = "Debug";
+ break;
+ case 1:
+// gen_op_mfc0_tracecontrol(); /* PDtrace support */
+ rn = "TraceControl";
+// break;
+ case 2:
+// gen_op_mfc0_tracecontrol2(); /* PDtrace support */
+ rn = "TraceControl2";
+// break;
+ case 3:
+// gen_op_mfc0_usertracedata(); /* PDtrace support */
+ rn = "UserTraceData";
+// break;
+ case 4:
+// gen_op_mfc0_debug(); /* PDtrace support */
+ rn = "TraceBPC";
+// break;
+ default:
+ goto die;
+ }
break;
case 24:
- gen_op_mfc0_depc();
- rn = "DEPC";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_depc(); /* EJTAG support */
+ rn = "DEPC";
+ break;
+ default:
+ goto die;
+ }
break;
case 25:
-// gen_op_mfc0_performance();
- rn = "Performance";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_performance0();
+ rn = "Performance0";
+ break;
+ case 1:
+// gen_op_mfc0_performance1();
+ rn = "Performance1";
+// break;
+ case 2:
+// gen_op_mfc0_performance2();
+ rn = "Performance2";
+// break;
+ case 3:
+// gen_op_mfc0_performance3();
+ rn = "Performance3";
+// break;
+ case 4:
+// gen_op_mfc0_performance4();
+ rn = "Performance4";
+// break;
+ case 5:
+// gen_op_mfc0_performance5();
+ rn = "Performance5";
+// break;
+ case 6:
+// gen_op_mfc0_performance6();
+ rn = "Performance6";
+// break;
+ case 7:
+// gen_op_mfc0_performance7();
+ rn = "Performance7";
+// break;
+ default:
+ goto die;
+ }
break;
case 26:
-// gen_op_mfc0_ecc();
- rn = "ECC";
- break;
+ rn = "ECC";
+ break;
case 27:
-// gen_op_mfc0_cacheerr();
- rn = "CacheErr";
+ switch (sel) {
+ /* ignored */
+ case 0 ... 3:
+ rn = "CacheErr";
+ break;
+ default:
+ goto die;
+ }
break;
case 28:
switch (sel) {
case 0:
+ case 2:
+ case 4:
+ case 6:
gen_op_mfc0_taglo();
rn = "TagLo";
break;
case 1:
+ case 3:
+ case 5:
+ case 7:
gen_op_mfc0_datalo();
rn = "DataLo";
break;
default:
- rn = "unknown sel";
goto die;
}
break;
case 29:
-// gen_op_mfc0_taghi();
- rn = "TagHi";
+ switch (sel) {
+ case 0:
+ case 2:
+ case 4:
+ case 6:
+ gen_op_mfc0_taghi();
+ rn = "TagHi";
+ break;
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ gen_op_mfc0_datahi();
+ rn = "DataHi";
+ break;
+ default:
+ goto die;
+ }
break;
case 30:
- gen_op_mfc0_errorepc();
- rn = "ErrorEPC";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_errorepc();
+ rn = "ErrorEPC";
+ break;
+ default:
+ goto die;
+ }
break;
case 31:
- gen_op_mfc0_desave();
- rn = "DESAVE";
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_desave(); /* EJTAG support */
+ rn = "DESAVE";
+ break;
+ default:
+ goto die;
+ }
break;
default:
- rn = "unknown";
goto die;
}
#if defined MIPS_DEBUG_DISAS
if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
- env->PC, rn, T0, reg, sel);
+ fprintf(logfile, "mfc0 %s (reg %d sel %d)\n",
+ rn, reg, sel);
}
#endif
return;
@@ -1526,8 +2200,8 @@
die:
#if defined MIPS_DEBUG_DISAS
if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
- env->PC, rn, T0, reg, sel);
+ fprintf(logfile, "mfc0 %s (reg %d sel %d)\n",
+ rn, reg, sel);
}
#endif
generate_exception(ctx, EXCP_RI);
@@ -1535,167 +2209,583 @@
static void gen_mtc0 (DisasContext *ctx, int reg, int sel)
{
- const unsigned char *rn;
- uint32_t val, old;
+ const char *rn = "invalid";
- if (sel != 0 && reg != 16 && reg != 28) {
- val = -1;
- old = -1;
- rn = "invalid";
- goto die;
- }
switch (reg) {
case 0:
- gen_op_mtc0_index();
- rn = "Index";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_index();
+ rn = "Index";
+ break;
+ case 1:
+// gen_op_mtc0_mvpcontrol(); /* MT ASE */
+ rn = "MVPControl";
+// break;
+ case 2:
+// gen_op_mtc0_mvpconf0(); /* MT ASE */
+ rn = "MVPConf0";
+// break;
+ case 3:
+// gen_op_mtc0_mvpconf1(); /* MT ASE */
+ rn = "MVPConf1";
+// break;
+ default:
+ goto die;
+ }
break;
case 1:
-// ignore or except?
- rn = "Random";
+ switch (sel) {
+ case 0:
+ /* ignored */
+ rn = "Random";
+ break;
+ case 1:
+// gen_op_mtc0_vpecontrol(); /* MT ASE */
+ rn = "VPEControl";
+// break;
+ case 2:
+// gen_op_mtc0_vpeconf0(); /* MT ASE */
+ rn = "VPEConf0";
+// break;
+ case 3:
+// gen_op_mtc0_vpeconf1(); /* MT ASE */
+ rn = "VPEConf1";
+// break;
+ case 4:
+// gen_op_mtc0_YQMask(); /* MT ASE */
+ rn = "YQMask";
+// break;
+ case 5:
+// gen_op_mtc0_vpeschedule(); /* MT ASE */
+ rn = "VPESchedule";
+// break;
+ case 6:
+// gen_op_mtc0_vpeschefback(); /* MT ASE */
+ rn = "VPEScheFBack";
+// break;
+ case 7:
+// gen_op_mtc0_vpeopt(); /* MT ASE */
+ rn = "VPEOpt";
+// break;
+ default:
+ goto die;
+ }
break;
case 2:
- gen_op_mtc0_entrylo0();
- rn = "EntryLo0";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_entrylo0();
+ rn = "EntryLo0";
+ break;
+ case 1:
+// gen_op_mtc0_tcstatus(); /* MT ASE */
+ rn = "TCStatus";
+// break;
+ case 2:
+// gen_op_mtc0_tcbind(); /* MT ASE */
+ rn = "TCBind";
+// break;
+ case 3:
+// gen_op_mtc0_tcrestart(); /* MT ASE */
+ rn = "TCRestart";
+// break;
+ case 4:
+// gen_op_mtc0_tchalt(); /* MT ASE */
+ rn = "TCHalt";
+// break;
+ case 5:
+// gen_op_mtc0_tccontext(); /* MT ASE */
+ rn = "TCContext";
+// break;
+ case 6:
+// gen_op_mtc0_tcschedule(); /* MT ASE */
+ rn = "TCSchedule";
+// break;
+ case 7:
+// gen_op_mtc0_tcschefback(); /* MT ASE */
+ rn = "TCScheFBack";
+// break;
+ default:
+ goto die;
+ }
break;
case 3:
- gen_op_mtc0_entrylo1();
- rn = "EntryLo1";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_entrylo1();
+ rn = "EntryLo1";
+ break;
+ default:
+ goto die;
+ }
break;
case 4:
- gen_op_mtc0_context();
- rn = "Context";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_context();
+ rn = "Context";
+ break;
+ case 1:
+// gen_op_mtc0_contextconfig(); /* SmartMIPS ASE */
+ rn = "ContextConfig";
+// break;
+ default:
+ goto die;
+ }
break;
case 5:
- gen_op_mtc0_pagemask();
- rn = "PageMask";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_pagemask();
+ rn = "PageMask";
+ break;
+ case 1:
+ gen_op_mtc0_pagegrain();
+ rn = "PageGrain";
+ break;
+ default:
+ goto die;
+ }
break;
case 6:
- gen_op_mtc0_wired();
- rn = "Wired";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_wired();
+ rn = "Wired";
+ break;
+ case 1:
+// gen_op_mtc0_srsconf0(); /* shadow registers */
+ rn = "SRSConf0";
+// break;
+ case 2:
+// gen_op_mtc0_srsconf1(); /* shadow registers */
+ rn = "SRSConf1";
+// break;
+ case 3:
+// gen_op_mtc0_srsconf2(); /* shadow registers */
+ rn = "SRSConf2";
+// break;
+ case 4:
+// gen_op_mtc0_srsconf3(); /* shadow registers */
+ rn = "SRSConf3";
+// break;
+ case 5:
+// gen_op_mtc0_srsconf4(); /* shadow registers */
+ rn = "SRSConf4";
+// break;
+ default:
+ goto die;
+ }
break;
case 7:
-// ignore or except?
- rn = "Info";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_hwrena();
+ rn = "HWREna";
+ break;
+ default:
+ goto die;
+ }
break;
case 8:
-// ignore or except?
+ /* ignored */
rn = "BadVaddr";
break;
case 9:
- gen_op_mtc0_count();
- rn = "Count";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_count();
+ rn = "Count";
+ break;
+ /* 6,7 are implementation dependent */
+ default:
+ goto die;
+ }
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
break;
case 10:
- gen_op_mtc0_entryhi();
- rn = "EntryHi";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_entryhi();
+ rn = "EntryHi";
+ break;
+ default:
+ goto die;
+ }
break;
case 11:
- gen_op_mtc0_compare();
- rn = "Compare";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_compare();
+ rn = "Compare";
+ break;
+ /* 6,7 are implementation dependent */
+ default:
+ goto die;
+ }
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
break;
case 12:
- gen_op_mtc0_status();
- rn = "Status";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_status();
+ rn = "Status";
+ break;
+ case 1:
+ gen_op_mtc0_intctl();
+ rn = "IntCtl";
+ break;
+ case 2:
+ gen_op_mtc0_srsctl();
+ rn = "SRSCtl";
+ break;
+ case 3:
+// gen_op_mtc0_srsmap(); /* shadow registers */
+ rn = "SRSMap";
+// break;
+ default:
+ goto die;
+ }
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
break;
case 13:
- gen_op_mtc0_cause();
- rn = "Cause";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_cause();
+ rn = "Cause";
+ break;
+ default:
+ goto die;
+ }
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
break;
case 14:
- gen_op_mtc0_epc();
- rn = "EPC";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_epc();
+ rn = "EPC";
+ break;
+ default:
+ goto die;
+ }
break;
case 15:
-// ignore or except?
- rn = "PRid";
+ switch (sel) {
+ case 0:
+ /* ignored */
+ rn = "PRid";
+ break;
+ case 1:
+ gen_op_mtc0_ebase();
+ rn = "EBase";
+ break;
+ default:
+ goto die;
+ }
break;
case 16:
switch (sel) {
case 0:
gen_op_mtc0_config0();
- rn = "Config0";
+ rn = "Config";
+ break;
+ case 1:
+ /* ignored */
+ rn = "Config1";
+ break;
+ case 2:
+ gen_op_mtc0_config2();
+ rn = "Config2";
+ break;
+ case 3:
+ /* ignored */
+ rn = "Config3";
break;
+ /* 6,7 are implementation dependent */
default:
rn = "Invalid config selector";
goto die;
}
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
break;
case 17:
-// ignore or except?
- rn = "LLaddr";
+ switch (sel) {
+ case 0:
+ /* ignored */
+ rn = "LLAddr";
+ break;
+ default:
+ goto die;
+ }
break;
case 18:
- gen_op_mtc0_watchlo();
- rn = "WatchLo";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_watchlo0();
+ rn = "WatchLo";
+ break;
+ case 1:
+// gen_op_mtc0_watchlo1();
+ rn = "WatchLo1";
+// break;
+ case 2:
+// gen_op_mtc0_watchlo2();
+ rn = "WatchLo2";
+// break;
+ case 3:
+// gen_op_mtc0_watchlo3();
+ rn = "WatchLo3";
+// break;
+ case 4:
+// gen_op_mtc0_watchlo4();
+ rn = "WatchLo4";
+// break;
+ case 5:
+// gen_op_mtc0_watchlo5();
+ rn = "WatchLo5";
+// break;
+ case 6:
+// gen_op_mtc0_watchlo6();
+ rn = "WatchLo6";
+// break;
+ case 7:
+// gen_op_mtc0_watchlo7();
+ rn = "WatchLo7";
+// break;
+ default:
+ goto die;
+ }
break;
case 19:
- gen_op_mtc0_watchhi();
- rn = "WatchHi";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_watchhi0();
+ rn = "WatchHi";
+ break;
+ case 1:
+// gen_op_mtc0_watchhi1();
+ rn = "WatchHi1";
+// break;
+ case 2:
+// gen_op_mtc0_watchhi2();
+ rn = "WatchHi2";
+// break;
+ case 3:
+// gen_op_mtc0_watchhi3();
+ rn = "WatchHi3";
+// break;
+ case 4:
+// gen_op_mtc0_watchhi4();
+ rn = "WatchHi4";
+// break;
+ case 5:
+// gen_op_mtc0_watchhi5();
+ rn = "WatchHi5";
+// break;
+ case 6:
+// gen_op_mtc0_watchhi6();
+ rn = "WatchHi6";
+// break;
+ case 7:
+// gen_op_mtc0_watchhi7();
+ rn = "WatchHi7";
+// break;
+ default:
+ goto die;
+ }
break;
case 20:
- /* 64 bit only */
-// gen_op_mtc0_xcontext();
- rn = "XContext";
+ switch (sel) {
+ case 0:
+ /* 64 bit MMU only */
+ gen_op_mtc0_xcontext();
+ rn = "XContext";
+ break;
+ default:
+ goto die;
+ }
break;
case 21:
-// gen_op_mtc0_framemask();
- rn = "Framemask";
- break;
+ /* Officially reserved, but sel 0 is used for R1x000 framemask */
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_framemask();
+ rn = "Framemask";
+ break;
+ default:
+ goto die;
+ }
+ break;
case 22:
-// ignore or except?
- rn = "Diagnostic";
+ /* ignored */
+ rn = "Diagnostic"; /* implementation dependent */
break;
case 23:
- gen_op_mtc0_debug();
- rn = "Debug";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_debug(); /* EJTAG support */
+ rn = "Debug";
+ break;
+ case 1:
+// gen_op_mtc0_tracecontrol(); /* PDtrace support */
+ rn = "TraceControl";
+// break;
+ case 2:
+// gen_op_mtc0_tracecontrol2(); /* PDtrace support */
+ rn = "TraceControl2";
+// break;
+ case 3:
+// gen_op_mtc0_usertracedata(); /* PDtrace support */
+ rn = "UserTraceData";
+// break;
+ case 4:
+// gen_op_mtc0_debug(); /* PDtrace support */
+ rn = "TraceBPC";
+// break;
+ default:
+ goto die;
+ }
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
break;
case 24:
- gen_op_mtc0_depc();
- rn = "DEPC";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_depc(); /* EJTAG support */
+ rn = "DEPC";
+ break;
+ default:
+ goto die;
+ }
break;
case 25:
-// ignore or except?
- rn = "Performance";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_performance0();
+ rn = "Performance0";
+ break;
+ case 1:
+// gen_op_mtc0_performance1();
+ rn = "Performance1";
+// break;
+ case 2:
+// gen_op_mtc0_performance2();
+ rn = "Performance2";
+// break;
+ case 3:
+// gen_op_mtc0_performance3();
+ rn = "Performance3";
+// break;
+ case 4:
+// gen_op_mtc0_performance4();
+ rn = "Performance4";
+// break;
+ case 5:
+// gen_op_mtc0_performance5();
+ rn = "Performance5";
+// break;
+ case 6:
+// gen_op_mtc0_performance6();
+ rn = "Performance6";
+// break;
+ case 7:
+// gen_op_mtc0_performance7();
+ rn = "Performance7";
+// break;
+ default:
+ goto die;
+ }
break;
case 26:
-// ignore or except?
+ /* ignored */
rn = "ECC";
break;
case 27:
-// ignore or except?
- rn = "CacheErr";
+ switch (sel) {
+ case 0 ... 3:
+ /* ignored */
+ rn = "CacheErr";
+ break;
+ default:
+ goto die;
+ }
break;
case 28:
switch (sel) {
case 0:
+ case 2:
+ case 4:
+ case 6:
gen_op_mtc0_taglo();
rn = "TagLo";
break;
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ gen_op_mtc0_datalo();
+ rn = "DataLo";
+ break;
default:
- rn = "invalid sel";
goto die;
}
break;
case 29:
-// gen_op_mtc0_taghi();
- rn = "TagHi";
+ switch (sel) {
+ case 0:
+ case 2:
+ case 4:
+ case 6:
+ gen_op_mtc0_taghi();
+ rn = "TagHi";
+ break;
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ gen_op_mtc0_datahi();
+ rn = "DataHi";
+ break;
+ default:
+ rn = "invalid sel";
+ goto die;
+ }
break;
case 30:
- gen_op_mtc0_errorepc();
- rn = "ErrorEPC";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_errorepc();
+ rn = "ErrorEPC";
+ break;
+ default:
+ goto die;
+ }
break;
case 31:
- gen_op_mtc0_desave();
- rn = "DESAVE";
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_desave(); /* EJTAG support */
+ rn = "DESAVE";
+ break;
+ default:
+ goto die;
+ }
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
break;
default:
- rn = "unknown";
goto die;
}
#if defined MIPS_DEBUG_DISAS
if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "%08x mtc0 %s => %08x (%d %d)\n",
- env->PC, rn, T0, reg, sel);
+ fprintf(logfile, "mtc0 %s (reg %d sel %d)\n",
+ rn, reg, sel);
}
#endif
return;
@@ -1703,16 +2793,16 @@
die:
#if defined MIPS_DEBUG_DISAS
if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "%08x mtc0 %s => %08x (%d %d)\n",
- env->PC, rn, T0, reg, sel);
+ fprintf(logfile, "mtc0 %s (reg %d sel %d)\n",
+ rn, reg, sel);
}
#endif
generate_exception(ctx, EXCP_RI);
}
-static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
+static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd)
{
- const unsigned char *opn = "unk";
+ const char *opn = "unk";
if (!(ctx->CP0_Status & (1 << CP0St_CU0)) &&
(ctx->hflags & MIPS_HFLAG_UM) &&
@@ -1721,7 +2811,7 @@
if (loglevel & CPU_LOG_TB_IN_ASM) {
fprintf(logfile, "CP0 is not usable\n");
}
- generate_exception_err (ctx, EXCP_CpU, 0);
+ generate_exception (ctx, EXCP_CpU);
return;
}
@@ -1737,13 +2827,12 @@
break;
case OPC_MTC0:
/* If we get an exception, we want to restart at next instruction */
+ /* XXX: breaks for mtc in delay slot */
ctx->pc += 4;
save_cpu_state(ctx, 1);
ctx->pc -= 4;
GEN_LOAD_REG_TN(T0, rt);
gen_mtc0(ctx, rd, ctx->opcode & 0x7);
- /* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
opn = "mtc0";
break;
#if defined(MIPS_USES_R4K_TLB)
@@ -1801,31 +2890,30 @@
MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
}
-#ifdef MIPS_USES_FPU
/* CP1 Branches (before delay slot) */
-static void gen_compute_branch1 (DisasContext *ctx, uint16_t cond,
+static void gen_compute_branch1 (DisasContext *ctx, uint32_t op,
int32_t offset)
{
target_ulong btarget;
btarget = ctx->pc + 4 + offset;
- switch (cond) {
- case 0x0000: /* bc1f */
+ switch (op) {
+ case OPC_BC1F:
gen_op_bc1f();
MIPS_DEBUG("bc1f %08x", btarget);
goto not_likely;
- case 0x0002: /* bc1fl */
+ case OPC_BC1FL:
gen_op_bc1f();
MIPS_DEBUG("bc1fl %08x", btarget);
goto likely;
- case 0x0001: /* bc1t */
+ case OPC_BC1T:
gen_op_bc1t();
MIPS_DEBUG("bc1t %08x", btarget);
not_likely:
ctx->hflags |= MIPS_HFLAG_BC;
break;
- case 0x0003: /* bc1tl */
+ case OPC_BC1TL:
gen_op_bc1t();
MIPS_DEBUG("bc1tl %08x", btarget);
likely:
@@ -1833,7 +2921,7 @@
break;
default:
MIPS_INVAL("cp1 branch/jump");
- generate_exception(ctx, EXCP_RI);
+ generate_exception_err (ctx, EXCP_RI, 1);
return;
}
gen_op_set_bcond();
@@ -1846,9 +2934,9 @@
}
/* Coprocessor 1 (FPU) */
-static void gen_cp1 (DisasContext *ctx, uint16_t opc, int rt, int fs)
+static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
{
- const unsigned char *opn = "unk";
+ const char *opn = "unk";
switch (opc) {
case OPC_MFC1:
@@ -1866,7 +2954,7 @@
case OPC_CFC1:
if (fs != 0 && fs != 31) {
MIPS_INVAL("cfc1 freg");
- generate_exception(ctx, EXCP_RI);
+ generate_exception_err (ctx, EXCP_RI, 1);
return;
}
GEN_LOAD_IMM_TN(T1, fs);
@@ -1875,9 +2963,9 @@
opn = "cfc1";
break;
case OPC_CTC1:
- if (fs != 0 && fs != 31) {
+ if (fs != 0 && fs != 31) {
MIPS_INVAL("ctc1 freg");
- generate_exception(ctx, EXCP_RI);
+ generate_exception_err (ctx, EXCP_RI, 1);
return;
}
GEN_LOAD_IMM_TN(T1, fs);
@@ -1891,7 +2979,7 @@
ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
((ctx->opcode >> 16) & 0x1F));
}
- generate_exception(ctx, EXCP_RI);
+ generate_exception_err (ctx, EXCP_RI, 1);
return;
}
MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]);
@@ -1909,16 +2997,16 @@
*/
#define CHECK_FR(ctx, freg) do { \
if (!((ctx)->CP0_Status & (1<<CP0St_FR)) && ((freg) & 1)) { \
- generate_exception(ctx, EXCP_RI); \
+ generate_exception_err (ctx, EXCP_RI, 1); \
return; \
} \
} while(0)
#define FOP(func, fmt) (((fmt) << 21) | (func))
-static void gen_farith (DisasContext *ctx, int fmt, int ft, int fs, int fd, int func)
+static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd)
{
- const unsigned char *opn = "unk";
+ const char *opn = "unk";
const char *condnames[] = {
"c.f",
"c.un",
@@ -1938,7 +3026,8 @@
"c.ngt",
};
int binary = 0;
-
+ uint32_t func = ctx->opcode & 0x3f;
+
switch (ctx->opcode & FOP(0x3f, 0x1f)) {
case FOP(0, 17):
CHECK_FR(ctx, fs | ft | fd);
@@ -2034,7 +3123,7 @@
GEN_LOAD_FREG_FTN(DT0, fs);
gen_op_float_floorw_d();
GEN_STORE_FTN_FREG(fd, WT2);
- opn = "ceil.w.d";
+ opn = "floor.w.d";
break;
case FOP(33, 16): /* cvt.d.s */
CHECK_FR(ctx, fs | fd);
@@ -2202,11 +3291,11 @@
break;
default:
if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "Invalid arith function: %08x %03x %03x %03x\n",
+ fprintf(logfile, "Invalid FP arith function: %08x %03x %03x %03x\n",
ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
((ctx->opcode >> 16) & 0x1F));
}
- generate_exception(ctx, EXCP_RI);
+ generate_exception_err (ctx, EXCP_RI, 1);
return;
}
if (binary)
@@ -2214,14 +3303,27 @@
else
MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]);
}
-#endif
-/* ISA extensions */
+static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf)
+{
+ uint32_t ccbit;
+
+ if (cc)
+ ccbit = 1 << (24 + cc);
+ else
+ ccbit = 1 << 23;
+ if (!tf)
+ gen_op_movf(ccbit, rd, rs);
+ else
+ gen_op_movt(ccbit, rd, rs);
+}
+
+/* ISA extensions (ASEs) */
/* MIPS16 extension to MIPS32 */
/* SmartMIPS extension to MIPS32 */
-#ifdef TARGET_MIPS64
-static void gen_arith64 (DisasContext *ctx, uint16_t opc)
+#ifdef MIPS_HAS_MIPS64
+static void gen_arith64 (DisasContext *ctx, uint32_t opc)
{
if (func == 0x02 && rd == 0) {
/* NOP */
@@ -2266,7 +3368,7 @@
{
int32_t offset;
int rs, rt, rd, sa;
- uint16_t op, op1;
+ uint32_t op, op1, op2;
int16_t imm;
/* make sure instructions are on a word boundary */
@@ -2280,76 +3382,86 @@
MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4);
gen_blikely(ctx);
}
- op = ctx->opcode >> 26;
- rs = ((ctx->opcode >> 21) & 0x1F);
- rt = ((ctx->opcode >> 16) & 0x1F);
- rd = ((ctx->opcode >> 11) & 0x1F);
- sa = ((ctx->opcode >> 6) & 0x1F);
+ op = MASK_OP_MAJOR(ctx->opcode);
+ rs = (ctx->opcode >> 21) & 0x1f;
+ rt = (ctx->opcode >> 16) & 0x1f;
+ rd = (ctx->opcode >> 11) & 0x1f;
+ sa = (ctx->opcode >> 6) & 0x1f;
imm = (int16_t)ctx->opcode;
switch (op) {
- case 0x00: /* Special opcode */
- op1 = ctx->opcode & 0x3F;
+ case OPC_SPECIAL:
+ op1 = MASK_SPECIAL(ctx->opcode);
switch (op1) {
- case 0x00: /* Arithmetic with immediate */
- case 0x02 ... 0x03:
- gen_arith_imm(ctx, op1 | EXT_SPECIAL, rd, rt, sa);
- break;
- case 0x04: /* Arithmetic */
- case 0x06 ... 0x07:
- case 0x0A ... 0x0B:
- case 0x20 ... 0x27:
- case 0x2A ... 0x2B:
- gen_arith(ctx, op1 | EXT_SPECIAL, rd, rs, rt);
+ case OPC_SLL: /* Arithmetic with immediate */
+ case OPC_SRL ... OPC_SRA:
+ gen_arith_imm(ctx, op1, rd, rt, sa);
+ break;
+ case OPC_SLLV: /* Arithmetic */
+ case OPC_SRLV ... OPC_SRAV:
+ case OPC_MOVZ ... OPC_MOVN:
+ case OPC_ADD ... OPC_NOR:
+ case OPC_SLT ... OPC_SLTU:
+ gen_arith(ctx, op1, rd, rs, rt);
break;
- case 0x18 ... 0x1B: /* MULT / DIV */
- gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt);
+ case OPC_MULT ... OPC_DIVU:
+ gen_muldiv(ctx, op1, rs, rt);
break;
- case 0x08 ... 0x09: /* Jumps */
- gen_compute_branch(ctx, op1 | EXT_SPECIAL, rs, rd, sa);
+ case OPC_JR ... OPC_JALR:
+ gen_compute_branch(ctx, op1, rs, rd, sa);
return;
- case 0x30 ... 0x34: /* Traps */
- case 0x36:
- gen_trap(ctx, op1 | EXT_SPECIAL, rs, rt, -1);
- break;
- case 0x10: /* Move from HI/LO */
- case 0x12:
- gen_HILO(ctx, op1 | EXT_SPECIAL, rd);
- break;
- case 0x11:
- case 0x13: /* Move to HI/LO */
- gen_HILO(ctx, op1 | EXT_SPECIAL, rs);
+ case OPC_TGE ... OPC_TEQ: /* Traps */
+ case OPC_TNE:
+ gen_trap(ctx, op1, rs, rt, -1);
+ break;
+ case OPC_MFHI: /* Move from HI/LO */
+ case OPC_MFLO:
+ gen_HILO(ctx, op1, rd);
+ break;
+ case OPC_MTHI:
+ case OPC_MTLO: /* Move to HI/LO */
+ gen_HILO(ctx, op1, rs);
+ break;
+ case OPC_PMON: /* Pmon entry point */
+ gen_op_pmon(sa);
break;
- case 0x0C: /* SYSCALL */
+ case OPC_SYSCALL:
generate_exception(ctx, EXCP_SYSCALL);
+ ctx->bstate = BS_EXCP;
break;
- case 0x0D: /* BREAK */
+ case OPC_BREAK:
generate_exception(ctx, EXCP_BREAK);
break;
- case 0x0F: /* SYNC */
- /* Treat as a noop */
+ case OPC_SPIM: /* SPIM ? */
+ /* Implemented as RI exception for now. */
+ MIPS_INVAL("spim (unofficial)");
+ generate_exception(ctx, EXCP_RI);
break;
- case 0x05: /* Pmon entry point */
- gen_op_pmon((ctx->opcode >> 6) & 0x1F);
+ case OPC_SYNC:
+ /* Treat as a noop. */
break;
- case 0x01: /* MOVCI */
-#if defined (MIPS_HAS_MOVCI)
- /* XXX */
-#else
- /* Not implemented */
- generate_exception_err (ctx, EXCP_CpU, 1);
-#endif
+ case OPC_MOVCI:
+ gen_op_cp1_enabled();
+ gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7,
+ (ctx->opcode >> 16) & 1);
+ break;
+
+#ifdef MIPS_HAS_MIPS64
+ /* MIPS64 specific opcodes */
+ case OPC_DSLL:
+ case OPC_DSRL ... OPC_DSRA:
+ case OPC_DSLL32:
+ case OPC_DSRL32 ... OPC_DSRA32:
+ gen_arith_imm(ctx, op1, rd, rt, sa);
+ break;
+ case OPC_DSLLV:
+ case OPC_DSRLV ... OPC_DSRAV:
+ case OPC_DADD ... OPC_DSUBU:
+ gen_arith(ctx, op1, rd, rs, rt);
+ break;
+ case OPC_DMULT ... OPC_DDIVU:
+ gen_muldiv(ctx, op1, rs, rt);
break;
-
-#if defined (TARGET_MIPS64)
- case 0x14: /* MIPS64 specific opcodes */
- case 0x16:
- case 0x17:
- case 0x1C ... 0x1F:
- case 0x2C ... 0x2F:
- case 0x37:
- case 0x39 ... 0x3B:
- case 0x3E ... 0x3F:
#endif
default: /* Invalid */
MIPS_INVAL("special");
@@ -2357,23 +3469,20 @@
break;
}
break;
- case 0x1C: /* Special2 opcode */
- op1 = ctx->opcode & 0x3F;
+ case OPC_SPECIAL2:
+ op1 = MASK_SPECIAL2(ctx->opcode);
switch (op1) {
-#if defined (MIPS_USES_R4K_EXT)
- /* Those instructions are not part of MIPS32 core */
- case 0x00 ... 0x01: /* Multiply and add/sub */
- case 0x04 ... 0x05:
- gen_muldiv(ctx, op1 | EXT_SPECIAL2, rs, rt);
+ case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */
+ case OPC_MSUB ... OPC_MSUBU:
+ gen_muldiv(ctx, op1, rs, rt);
break;
- case 0x02: /* MUL */
- gen_arith(ctx, op1 | EXT_SPECIAL2, rd, rs, rt);
+ case OPC_MUL:
+ gen_arith(ctx, op1, rd, rs, rt);
break;
- case 0x20 ... 0x21: /* CLO / CLZ */
- gen_cl(ctx, op1 | EXT_SPECIAL2, rd, rs);
+ case OPC_CLZ ... OPC_CLO:
+ gen_cl(ctx, op1, rd, rs);
break;
-#endif
- case 0x3F: /* SDBBP */
+ case OPC_SDBBP:
/* XXX: not clear which exception should be raised
* when in debug mode...
*/
@@ -2384,22 +3493,109 @@
}
/* Treat as a noop */
break;
+#ifdef MIPS_HAS_MIPS64
+ case OPC_DCLZ ... OPC_DCLO:
+ gen_cl(ctx, op1, rd, rs);
+ break;
+#endif
default: /* Invalid */
MIPS_INVAL("special2");
generate_exception(ctx, EXCP_RI);
break;
}
break;
- case 0x01: /* B REGIMM opcode */
- op1 = ((ctx->opcode >> 16) & 0x1F);
+ case OPC_SPECIAL3:
+ op1 = MASK_SPECIAL3(ctx->opcode);
+ switch (op1) {
+ case OPC_EXT:
+ case OPC_INS:
+ gen_bitops(ctx, op1, rt, rs, sa, rd);
+ break;
+ case OPC_BSHFL:
+ op2 = MASK_BSHFL(ctx->opcode);
+ switch (op2) {
+ case OPC_WSBH:
+ GEN_LOAD_REG_TN(T1, rt);
+ gen_op_wsbh();
+ break;
+ case OPC_SEB:
+ GEN_LOAD_REG_TN(T1, rt);
+ gen_op_seb();
+ break;
+ case OPC_SEH:
+ GEN_LOAD_REG_TN(T1, rt);
+ gen_op_seh();
+ break;
+ default: /* Invalid */
+ MIPS_INVAL("bshfl");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ GEN_STORE_TN_REG(rd, T0);
+ break;
+ case OPC_RDHWR:
+ switch (rd) {
+ case 0:
+ gen_op_rdhwr_cpunum();
+ break;
+ case 1:
+ gen_op_rdhwr_synci_step();
+ break;
+ case 2:
+ gen_op_rdhwr_cc();
+ break;
+ case 3:
+ gen_op_rdhwr_ccres();
+ break;
+ default: /* Invalid */
+ MIPS_INVAL("rdhwr");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ GEN_STORE_TN_REG(rt, T0);
+ break;
+#ifdef MIPS_HAS_MIPS64
+ case OPC_DEXTM ... OPC_DEXT:
+ case OPC_DINSM ... OPC_DINS:
+ gen_bitops(ctx, op1, rt, rs, sa, rd);
+ break;
+ case OPC_DBSHFL:
+ op2 = MASK_DBSHFL(ctx->opcode);
+ switch (op2) {
+ case OPC_DSBH:
+ GEN_LOAD_REG_TN(T1, rt);
+ gen_op_dsbh();
+ break;
+ case OPC_DSHD:
+ GEN_LOAD_REG_TN(T1, rt);
+ gen_op_dshd();
+ break;
+ default: /* Invalid */
+ MIPS_INVAL("dbshfl");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ GEN_STORE_TN_REG(rd, T0);
+#endif
+ default: /* Invalid */
+ MIPS_INVAL("special3");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ break;
+ case OPC_REGIMM:
+ op1 = MASK_REGIMM(ctx->opcode);
switch (op1) {
- case 0x00 ... 0x03: /* REGIMM branches */
- case 0x10 ... 0x13:
- gen_compute_branch(ctx, op1 | EXT_REGIMM, rs, -1, imm << 2);
+ case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */
+ case OPC_BLTZAL ... OPC_BGEZALL:
+ gen_compute_branch(ctx, op1, rs, -1, imm << 2);
return;
- case 0x08 ... 0x0C: /* Traps */
- case 0x0E:
- gen_trap(ctx, op1 | EXT_REGIMM, rs, -1, imm);
+ case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */
+ case OPC_TNEI:
+ gen_trap(ctx, op1, rs, -1, imm);
+ break;
+ case OPC_SYNCI:
+ /* treat as noop */
break;
default: /* Invalid */
MIPS_INVAL("REGIMM");
@@ -2407,48 +3603,78 @@
break;
}
break;
- case 0x10: /* CP0 opcode */
- op1 = ((ctx->opcode >> 21) & 0x1F);
+ case OPC_CP0:
+ op1 = MASK_CP0(ctx->opcode);
switch (op1) {
- case 0x00:
- case 0x04:
- gen_cp0(ctx, op1 | EXT_CP0, rt, rd);
+ case OPC_MFC0:
+ case OPC_MTC0:
+#ifdef MIPS_HAS_MIPS64
+ case OPC_DMFC0:
+ case OPC_DMTC0:
+#endif
+ gen_cp0(ctx, op1, rt, rd);
+ break;
+ case OPC_C0_FIRST ... OPC_C0_LAST:
+ gen_cp0(ctx, MASK_C0(ctx->opcode), rt, rd);
+ break;
+ case OPC_MFMC0:
+ op2 = MASK_MFMC0(ctx->opcode);
+ switch (op2) {
+ case OPC_DI:
+ gen_op_di();
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
+ break;
+ case OPC_EI:
+ gen_op_ei();
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
+ break;
+ default: /* Invalid */
+ MIPS_INVAL("MFMC0");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ GEN_STORE_TN_REG(rt, T0);
break;
+ /* Shadow registers (not implemented). */
+ case OPC_RDPGPR:
+ case OPC_WRPGPR:
default:
- gen_cp0(ctx, (ctx->opcode & 0x3F) | EXT_CP0, rt, rd);
+ generate_exception(ctx, EXCP_RI);
break;
}
break;
- case 0x08 ... 0x0F: /* Arithmetic with immediate opcode */
- gen_arith_imm(ctx, op, rt, rs, imm);
- break;
- case 0x02 ... 0x03: /* Jump */
- offset = (int32_t)(ctx->opcode & 0x03FFFFFF) << 2;
- gen_compute_branch(ctx, op, rs, rt, offset);
- return;
- case 0x04 ... 0x07: /* Branch */
- case 0x14 ... 0x17:
- gen_compute_branch(ctx, op, rs, rt, imm << 2);
- return;
- case 0x20 ... 0x2E: /* Load and stores */
- case 0x30:
- case 0x38:
- gen_ldst(ctx, op, rt, rs, imm);
- break;
- case 0x2F: /* Cache operation */
- /* Treat as a noop */
- break;
- case 0x33: /* Prefetch */
+ case OPC_ADDI ... OPC_LUI: /* Arithmetic with immediate opcode */
+ gen_arith_imm(ctx, op, rt, rs, imm);
+ break;
+ case OPC_J ... OPC_JAL: /* Jump */
+ offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
+ gen_compute_branch(ctx, op, rs, rt, offset);
+ return;
+ case OPC_BEQ ... OPC_BGTZ: /* Branch */
+ case OPC_BEQL ... OPC_BGTZL:
+ gen_compute_branch(ctx, op, rs, rt, imm << 2);
+ return;
+ case OPC_LB ... OPC_LWR: /* Load and stores */
+ case OPC_SB ... OPC_SW:
+ case OPC_SWR:
+ case OPC_LL:
+ case OPC_SC:
+ gen_ldst(ctx, op, rt, rs, imm);
+ break;
+ case OPC_CACHE:
+ /* Treat as a noop */
+ break;
+ case OPC_PREF:
/* Treat as a noop */
break;
- case 0x3F: /* HACK */
- break;
/* Floating point. */
- case 0x31: /* LWC1 */
- case 0x35: /* LDC1 */
- case 0x39: /* SWC1 */
- case 0x3D: /* SDC1 */
+ case OPC_LWC1:
+ case OPC_LDC1:
+ case OPC_SWC1:
+ case OPC_SDC1:
#if defined(MIPS_USES_FPU)
save_cpu_state(ctx, 1);
gen_op_cp1_enabled();
@@ -2458,65 +3684,80 @@
#endif
break;
- case 0x11: /* CP1 opcode */
+ case OPC_CP1:
#if defined(MIPS_USES_FPU)
save_cpu_state(ctx, 1);
gen_op_cp1_enabled();
- op1 = ((ctx->opcode >> 21) & 0x1F);
+ op1 = MASK_CP1(ctx->opcode);
switch (op1) {
- case 0x00: /* mfc1 */
- case 0x02: /* cfc1 */
- case 0x04: /* mtc1 */
- case 0x06: /* ctc1 */
- gen_cp1(ctx, op1 | EXT_CP1, rt, rd);
+ case OPC_MFC1:
+ case OPC_CFC1:
+ case OPC_MTC1:
+ case OPC_CTC1:
+ gen_cp1(ctx, op1, rt, rd);
break;
- case 0x08: /* bc */
- gen_compute_branch1(ctx, rt, imm << 2);
+ case OPC_BC1:
+ gen_compute_branch1(ctx, MASK_CP1_BCOND(ctx->opcode), imm << 2);
return;
- case 0x10: /* 16: fmt=single fp */
- case 0x11: /* 17: fmt=double fp */
- case 0x14: /* 20: fmt=32bit fixed */
- case 0x15: /* 21: fmt=64bit fixed */
- gen_farith(ctx, op1, rt, rd, sa, ctx->opcode & 0x3f);
+ case OPC_S_FMT:
+ case OPC_D_FMT:
+ case OPC_W_FMT:
+ case OPC_L_FMT:
+ gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa);
break;
default:
generate_exception_err(ctx, EXCP_RI, 1);
break;
}
- break;
#else
generate_exception_err(ctx, EXCP_CpU, 1);
#endif
break;
/* COP2. */
- case 0x32: /* LWC2 */
- case 0x36: /* LDC2 */
- case 0x3A: /* SWC2 */
- case 0x3E: /* SDC2 */
- case 0x12: /* CP2 opcode */
- /* Not implemented */
+ case OPC_LWC2:
+ case OPC_LDC2:
+ case OPC_SWC2:
+ case OPC_SDC2:
+ case OPC_CP2:
+ /* COP2: Not implemented. */
generate_exception_err(ctx, EXCP_CpU, 2);
break;
- case 0x13: /* CP3 opcode */
+ case OPC_CP3:
+ gen_op_cp1_enabled();
+ op1 = MASK_CP3(ctx->opcode);
+ switch (op1) {
/* Not implemented */
- generate_exception_err(ctx, EXCP_CpU, 3);
+ default:
+ generate_exception_err(ctx, EXCP_RI, 1);
+ break;
+ }
break;
-#if defined (TARGET_MIPS64)
- case 0x18 ... 0x1B:
- case 0x27:
- case 0x34:
- case 0x37:
- /* MIPS64 opcodes */
-#endif
-#if defined (MIPS_HAS_JALX)
- case 0x1D:
- /* JALX: not implemented */
+#ifdef MIPS_HAS_MIPS64
+ /* MIPS64 opcodes */
+ case OPC_LWU:
+ case OPC_LDL ... OPC_LDR:
+ case OPC_SDL ... OPC_SDR:
+ case OPC_LLD:
+ case OPC_LD:
+ case OPC_SCD:
+ case OPC_SD:
+ gen_ldst(ctx, op, rt, rs, imm);
+ break;
+ case OPC_DADDI ... OPC_DADDIU:
+ gen_arith_imm(ctx, op, rt, rs, imm);
+ break;
+#endif
+#ifdef MIPS_HAS_MIPS16
+ case OPC_JALX:
+ /* MIPS16: Not implemented. */
+#endif
+#ifdef MIPS_HAS_MDMX
+ case OPC_MDMX:
+ /* MDMX: Not implemented. */
#endif
- case 0x1E:
- /* ASE specific */
default: /* Invalid */
MIPS_INVAL("");
generate_exception(ctx, EXCP_RI);
@@ -2708,7 +3949,6 @@
return gen_intermediate_code_internal(env, tb, 1);
}
-#ifdef MIPS_USES_FPU
void fpu_dump_state(CPUState *env, FILE *f,
int (*fpu_fprintf)(FILE *f, const char *fmt, ...),
int flags)
@@ -2722,19 +3962,19 @@
fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d\n",
env->fcr0, env->fcr31,
- (env->CP0_Status & (1<<CP0St_FR)) != 0);
+ (env->CP0_Status & (1 << CP0St_FR)) != 0);
fpu_fprintf(f, "FT0: "); printfpr(&env->ft0);
fpu_fprintf(f, "FT1: "); printfpr(&env->ft1);
fpu_fprintf(f, "FT2: "); printfpr(&env->ft2);
- for(i=0; i < 32; i+=2) {
- fpu_fprintf(f, "f%02d: ", i);
+ for(i = 0; i < 32; i += 2) {
+ fpu_fprintf(f, "%s: ", fregnames[i]);
printfpr(FPR(env, i));
}
#undef printfpr
}
-void dump_fpu(CPUState *env)
+void dump_fpu (CPUState *env)
{
if (loglevel) {
fprintf(logfile, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %d\n",
@@ -2742,7 +3982,6 @@
fpu_dump_state(env, logfile, fprintf, 0);
}
}
-#endif /* MIPS_USES_FPU */
void cpu_dump_state (CPUState *env, FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
@@ -2773,9 +4012,8 @@
c0_status, env->CP0_Cause, env->CP0_EPC);
cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n",
env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
-#ifdef MIPS_USES_FPU
- fpu_dump_state(env, f, cpu_fprintf, flags);
-#endif
+ if (c0_status & (1 << CP0St_CU1))
+ fpu_dump_state(env, f, cpu_fprintf, flags);
}
CPUMIPSState *cpu_mips_init (void)
@@ -2803,16 +4041,12 @@
env->tlb_in_use = MIPS_TLB_NB;
#endif
env->CP0_Wired = 0;
+ /* SMP not implemented */
+ env->CP0_EBase = 0x80000000;
env->CP0_Config0 = MIPS_CONFIG0;
-#if defined (MIPS_CONFIG1)
- env->CP0_Config1 = MIPS_CONFIG1;
-#endif
-#if defined (MIPS_CONFIG2)
- env->CP0_Config2 = MIPS_CONFIG2;
-#endif
-#if defined (MIPS_CONFIG3)
- env->CP0_Config3 = MIPS_CONFIG3;
-#endif
+ env->CP0_Config1 = MIPS_CONFIG1;
+ env->CP0_Config2 = MIPS_CONFIG2;
+ env->CP0_Config3 = MIPS_CONFIG3;
env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
env->CP0_WatchLo = 0;
env->hflags = MIPS_HFLAG_ERL;
@@ -2826,4 +4060,7 @@
#ifdef MIPS_USES_FPU
env->fcr0 = MIPS_FCR0;
#endif
+ /* XXX some guesswork here, values are CPU specific */
+ env->SYNCI_Step = 16;
+ env->CCRes = 2;
}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2006-11-21 15:22 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-11-21 15:22 [Qemu-devel] [PATCH 6/6] A cumulative MIPS patchset Thiemo Seufer
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.