qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 7/8] Mips improvements


From: Thiemo Seufer
Subject: [Qemu-devel] [PATCH 7/8] Mips improvements
Date: Mon, 15 May 2006 01:52:14 -0000
User-agent: Mutt/1.5.11+cvs20060403

Hello All,

this patch moves mtc0_status and mtc0_cause back to out of line
handling. It also removes many uses of magic constants, and simplifies
the instruction decoding by preserving 32bit instruction words.

It also adds handling for MIPS32R2 instructions, as well as handling
for most CP0 registers defined for R2. The config register announces
the CPU still as R1. A few of the CP0 registers may need further
changes to be R2 compatible. Many of the optional extensions like
SmartMIPS or MT are only implemented up to the instruction decoding
stage.

64bit CPU support is less incomplete than before, besides the 64bit
ops it needs extension of the registers to 64 bit.

The instructions/CPx registers should only be valid for the CPU/ISA
they are defined in, down to MIPS-I, I haven't tackled that yet.


Thiemo


Index: qemu-work/target-mips/translate.c
===================================================================
--- qemu-work.orig/target-mips/translate.c      2006-05-08 03:03:06.000000000 
+0100
+++ qemu-work/target-mips/translate.c   2006-05-08 03:03:09.000000000 +0100
@@ -49,175 +49,298 @@
 
 #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_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)   (op & (OPC_SPECIAL | 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)    (op & (OPC_REGIMM | (0x1F << 16)))
+
 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,
+    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)  (op & (OPC_SPECIAL2 | 0x3F))
+
+enum {
+    /* 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,
+};
+
+/* Special3 opcodes */
+#define MASK_SPECIAL3(op)  (op & (OPC_SPECIAL3 | 0x3F))
+
+enum {
+    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)     (op & (OPC_BSHFL | (0x1F << 6)))
+
+enum {
+    OPC_WSBH     = (0x02 << 6) | OPC_BSHFL,
+    OPC_SEB      = (0x10 << 6) | OPC_BSHFL,
+    OPC_SEH      = (0x18 << 6) | OPC_BSHFL,
 };
 
-/* Branch REGIMM */
+/* DBSHFL opcodes */
+#define MASK_DBSHFL(op)    (op & (OPC_DBSHFL | (0x1F << 6)))
+
+enum {
+    OPC_DSBH     = (0x02 << 6) | OPC_DBSHFL,
+    OPC_DSHD     = (0x05 << 6) | OPC_DBSHFL,
+};
+
+/* Coprocessor 0 (rs field) */
+#define MASK_CP0(op)       (op & (OPC_CP0 | (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)     (op & (OPC_MFMC0 | (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)        (op & (OPC_C0_FIRST | 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_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)       (op & (OPC_CP1 | (0x1F << 21)))
+
 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_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,
 };
 
-const unsigned char *regnames[] =
+#define MASK_CP2(op)       (op & (OPC_CP2 | (0x1F << 21)))
+#define MASK_CP3(op)       (op & (OPC_CP3 | (0x1F << 21)))
+
+const char *regnames[] =
     { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
       "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
       "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
@@ -375,7 +498,7 @@
 }
 #endif
 
-#ifdef TARGET_MIPS64
+#ifdef MIPS_HAS_MIPS64
 OP_LD_TABLE(d);
 OP_LD_TABLE(dl);
 OP_LD_TABLE(dr);
@@ -399,10 +522,10 @@
 OP_ST_TABLE(c);
 
 /* 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);
@@ -417,23 +540,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);
@@ -454,43 +581,33 @@
         op_ldst(sdr);
         opn = "sdr";
         break;
+    case OPC_LWU:
+        op_ldst(lwu);
+        GEN_STORE_TN_REG(rt, T0);
+        opn = "lwu";
+        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";
         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";
@@ -552,13 +669,13 @@
 }
 
 /* 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.
          */
@@ -566,8 +683,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) {
@@ -587,6 +705,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";
@@ -619,9 +748,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);
@@ -632,12 +802,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.
          */
@@ -665,6 +836,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";
@@ -710,9 +901,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);
@@ -724,9 +939,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 */
@@ -762,10 +977,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);
@@ -786,6 +1001,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";
@@ -810,10 +1043,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");
@@ -822,15 +1055,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);
@@ -841,7 +1082,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;
@@ -956,7 +1197,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;
@@ -1006,8 +1247,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;
         }
@@ -1174,81 +1416,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) {
@@ -1260,91 +1751,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;
@@ -1352,8 +2037,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);
@@ -1361,167 +2046,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;
@@ -1529,16 +2630,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) &&
@@ -1562,13 +2663,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)
@@ -1628,12 +2728,28 @@
 
 /* Coprocessor 1 (FPU) */
 
-/* ISA extensions */
+#if defined(MIPS_USES_FPU)
+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);
+}
+#endif
+
+/* 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 */
@@ -1678,7 +2794,7 @@
 {
     int32_t offset;
     int rs, rt, rd, sa;
-    uint16_t op, op1;
+    uint32_t op, op1, op2;
     int16_t imm;
 
     if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) {
@@ -1686,76 +2802,87 @@
         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 0x0C:          /* SYSCALL */
+        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 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);
+        case OPC_MOVCI:
+#if defined(MIPS_USES_FPU)
+           gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7,
+                     (ctx->opcode >> 16) & 1);
 #endif
             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:
+#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;
 #endif
         default:            /* Invalid */
             MIPS_INVAL("special");
@@ -1763,23 +2890,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...
              */
@@ -1790,22 +2914,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 (op1) {
+           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");
@@ -1813,85 +3024,121 @@
             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);
-            break;
-        default:
-            gen_cp0(ctx, (ctx->opcode & 0x3F) | EXT_CP0, rt, rd);
+       case OPC_MFC0:
+       case OPC_MTC0:
+            gen_cp0(ctx, op1, rt, rd);
+            break;
+       case OPC_C0_FIRST ... OPC_C0_LAST:
+            gen_cp0(ctx, MASK_C0(ctx->opcode), rt, rd);
+            break;
+#ifdef MIPS_HAS_MIPS64
+       case OPC_DMFC0:
+       case OPC_DMTC0:
+            gen_cp0(ctx, op1, rt, rd);
+            break;
+#endif
+       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:
+            generate_exception(ctx, EXCP_RI);
             break;
-        }
+       }
         break;
-    case 0x08 ... 0x0F: /* Arithmetic with immediate opcode */
+    case OPC_ADDI ... OPC_LUI: /* Arithmetic with immediate opcode */
         gen_arith_imm(ctx, op, rt, rs, imm);
         break;
-    case 0x02 ... 0x03: /* Jump */
-        offset = (int32_t)(ctx->opcode & 0x03FFFFFF) << 2;
+    case OPC_J ... OPC_JAL: /* Jump */
+        offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
         gen_compute_branch(ctx, op, rs, rt, offset);
         return;
-    case 0x04 ... 0x07: /* Branch */
-    case 0x14 ... 0x17:
+    case OPC_BEQ ... OPC_BGTZ: /* Branch */
+    case OPC_BEQL ... OPC_BGTZL:
         gen_compute_branch(ctx, op, rs, rt, imm << 2);
         return;
-    case 0x20 ... 0x26: /* Load and stores */
-    case 0x28 ... 0x2E:
-    case 0x30:
-    case 0x38:
+    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 0x2F:          /* Cache operation */
+    case OPC_CACHE:
         /* Treat as a noop */
         break;
-    case 0x33:          /* Prefetch */
+    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 0x11:          /* CP1 opcode */
+    case OPC_LWC1:
+    case OPC_LDC1:
+    case OPC_SWC1:
+    case OPC_SDC1:
+    case OPC_CP1:
+    case OPC_CP3:
 #if defined(MIPS_USES_FPU)
-        /* XXX: not correct */
-#else
-        generate_exception_err(ctx, EXCP_CpU, 1);
+        /* Not implemented. */
 #endif
+        generate_exception_err(ctx, EXCP_CpU, 1);
         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 */
-        /* Not implemented */
-        generate_exception_err(ctx, EXCP_CpU, 3);
-        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);
@@ -2129,16 +3376,12 @@
     env->CP0_random = MIPS_TLB_NB - 1;
 #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;
@@ -2149,5 +3392,9 @@
 #if defined(CONFIG_USER_ONLY)
     env->hflags |= MIPS_HFLAG_UM;
 #endif
+    /* XXX some guesswork here, values are CPU specific */
+    env->SYNCI_Step = 16;
+    env->CCRes = 2;
+
     return env;
 }
Index: qemu-work/target-mips/cpu.h
===================================================================
--- qemu-work.orig/target-mips/cpu.h    2006-05-08 03:03:06.000000000 +0100
+++ qemu-work/target-mips/cpu.h 2006-05-08 03:05:16.000000000 +0100
@@ -56,14 +56,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
@@ -71,20 +73,38 @@
 #define CP0St_CU1   29
 #define CP0St_CU0   28
 #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
@@ -96,8 +116,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
@@ -105,14 +127,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
@@ -133,8 +179,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 */
@@ -171,6 +220,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
 };
 
Index: qemu-work/target-mips/helper.c
===================================================================
--- qemu-work.orig/target-mips/helper.c 2006-05-08 03:03:06.000000000 +0100
+++ qemu-work/target-mips/helper.c      2006-05-08 03:05:16.000000000 +0100
@@ -299,15 +299,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-05-08 03:03:06.000000000 
+0100
+++ qemu-work/target-mips/mips-defs.h   2006-05-08 03:04:56.000000000 +0100
@@ -19,40 +19,58 @@
 #define TARGET_LONG_BITS 32
 /* real pages are variable size... */
 #define TARGET_PAGE_BITS 12
-/* Uses MIPS R4Kx ehancements to MIPS32 architecture */
-#define MIPS_USES_R4K_EXT
 /* Uses MIPS R4Kc TLB model */
 #define MIPS_USES_R4K_TLB
 #define MIPS_TLB_NB 16
-/* Have config1, runs in big-endian mode, uses TLB */
-#define MIPS_CONFIG0                                            \
-((1 << CP0C0_M) | (0x000 << CP0C0_K23) | (0x000 << CP0C0_KU) |  \
- (1 << CP0C0_BE) | (0x001 << CP0C0_MT) | (0x010 << CP0C0_K0))
-/* 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
- */
-#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))
+#ifdef TARGET_WORDS_BIGENDIAN
+  /* Have config1, runs in big-endian mode, is MIPS32R1, uses TLB,
+     no virtual icache, uncached coherency */
+# define MIPS_CONFIG0                                             \
+  ((1 << CP0C0_M) | (0x0 << CP0C0_K23) | (0x0 << CP0C0_KU) |      \
+   (1 << CP0C0_BE) | (0x0 << CP0C0_AT) | (0x0 << CP0C0_AR) |      \
+   (0x1 << CP0C0_MT) | (0x2 << CP0C0_K0))
+#else
+  /* Have config1, runs in little-endian mode, is MIPS32R1, uses TLB,
+     no virtual icache, uncached coherency */
+# define MIPS_CONFIG0                                             \
+  ((1 << CP0C0_M) | (0x0 << CP0C0_K23) | (0x0 << CP0C0_KU) |      \
+   (0 << CP0C0_BE) | (0x0 << CP0C0_AT) | (0x0 << CP0C0_AR) |      \
+   (0x1 << CP0C0_MT) | (0x2 << CP0C0_K0))
+#endif
+/* 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, no FPU attached */
+#define MIPS_CONFIG1                                              \
+((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) |            \
+ (0 << CP0C1_FP))
+/* 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 defined (MIPS_CPU == MIPS_R4Kp)
 /* 32 bits target */
 #define TARGET_LONG_BITS 32
 /* real pages are variable size... */
 #define TARGET_PAGE_BITS 12
-/* Uses MIPS R4Kx ehancements to MIPS32 architecture */
-#define MIPS_USES_R4K_EXT
 /* Uses MIPS R4Km FPM MMU model */
 #define MIPS_USES_R4K_FPM
 #else
 #error "MIPS CPU not defined"
-/* Remainder for other flags */
-//#define TARGET_MIPS64
-//define MIPS_USES_FPU
+/* Reminder for other flags */
+//#define MIPS_HAS_MIPS64
+//#define MIPS_USES_FPU
 #endif
 
 #endif /* !defined (__QEMU_MIPS_DEFS_H__) */
Index: qemu-work/target-mips/op.c
===================================================================
--- qemu-work.orig/target-mips/op.c     2006-05-08 03:03:06.000000000 +0100
+++ qemu-work/target-mips/op.c  2006-05-08 03:04:56.000000000 +0100
@@ -299,6 +299,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);
@@ -317,6 +329,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;
@@ -464,6 +489,22 @@
     RETURN();
 }
 
+#if defined(MIPS_USES_FPU)
+void op_movf (void)
+{
+    if (!(env->fcsr & PARAM1))
+        env->gpr[PARAM2] = env->gpr[PARAM3];
+    RETURN();
+}
+
+void op_movt (void)
+{
+    if (env->fcsr & PARAM1)
+        env->gpr[PARAM2] = env->gpr[PARAM3];
+    RETURN();
+}
+#endif
+
 /* Tests */
 #define OP_COND(name, cond) \
 void glue(op_, name) (void) \
@@ -487,28 +528,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)
@@ -586,12 +631,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;
@@ -628,6 +685,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;
@@ -646,6 +715,12 @@
     RETURN();
 }
 
+void op_mfc0_ebase (void)
+{
+    T0 = env->CP0_EBase;
+    RETURN();
+}
+
 void op_mfc0_config0 (void)
 {
     T0 = env->CP0_Config0;
@@ -658,24 +733,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;
@@ -690,6 +789,12 @@
     RETURN();
 }
 
+void op_mfc0_performance0 (void)
+{
+    T0 = env->CP0_Performance0;
+    RETURN();
+}
+
 void op_mfc0_taglo (void)
 {
     T0 = env->CP0_TagLo;
@@ -702,6 +807,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;
@@ -716,37 +833,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();
 }
 
@@ -758,14 +895,7 @@
 
 void op_mtc0_entryhi (void)
 {
-    uint32_t old, val;
-
-    val = T0 & 0xFFFFE0FF;
-    old = env->CP0_EntryHi;
-    env->CP0_EntryHi = val;
-    /* If the ASID changes, flush qemu's TLB.  */
-    if ((old & 0xFF) != (val & 0xFF))
-        CALL_FROM_TB2(tlb_flush, env, 1);
+    CALL_FROM_TB1(do_mtc0_entryhi, T0);
     RETURN();
 }
 
@@ -777,60 +907,27 @@
 
 void op_mtc0_status (void)
 {
-    uint32_t val, old, mask;
+    CALL_FROM_TB1(do_mtc0_status, T0);
+    RETURN();
+}
 
-    val = T0 & 0xFA78FF01;
-    old = env->CP0_Status;
-    if (T0 & (1 << CP0St_UM))
-        env->hflags |= MIPS_HFLAG_UM;
-    else
-        env->hflags &= ~MIPS_HFLAG_UM;
-    if (T0 & (1 << CP0St_ERL))
-        env->hflags |= MIPS_HFLAG_ERL;
-    else
-        env->hflags &= ~MIPS_HFLAG_ERL;
-    if (T0 & (1 << CP0St_EXL))
-        env->hflags |= MIPS_HFLAG_EXL;
-    else
-        env->hflags &= ~MIPS_HFLAG_EXL;
-    env->CP0_Status = val;
-    /* If we unmasked an asserted IRQ, raise it */
-    mask = 0x0000FF00;
-    if (loglevel & CPU_LOG_TB_IN_ASM)
-       CALL_FROM_TB2(do_mtc0_status_debug, old, val);
-    if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) &&
-        !(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);
-    } else if (!(val & (1 << CP0St_IE)) && (old & (1 << CP0St_IE))) {
-        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
-    }
+void op_mtc0_intctl (void)
+{
+    /* vectored interrupts not implemented */
+    env->CP0_IntCtl = 0;
     RETURN();
 }
 
-void op_mtc0_cause (void)
+void op_mtc0_srsctl (void)
 {
-    uint32_t val, old;
+    /* shadow registers not implemented */
+    env->CP0_SRSCtl = 0;
+    RETURN();
+}
 
-    val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300);
-    old = env->CP0_Cause;
-    env->CP0_Cause = val;
-#if 0
-    {
-        int i, mask;
-
-       /* Check if we ever asserted a software IRQ */
-        for (i = 0; i < 2; i++) {
-            mask = 0x100 << i;
-            if ((val & mask) & !(old & mask))
-                CALL_FROM_TB1(mips_set_irq, i);
-        }
-    }
-#endif
+void op_mtc0_cause (void)
+{
+    CALL_FROM_TB1(do_mtc0_cause, T0);
     RETURN();
 }
 
@@ -840,28 +937,56 @@
     RETURN();
 }
 
+void op_mtc0_ebase (void)
+{
+    /* vectored interrupts not implemented */
+    /* SMP 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);
@@ -878,12 +1003,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;
@@ -923,10 +1072,46 @@
 }
 #endif
 
+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();
+}
+
 /* Specials */
 void op_pmon (void)
 {
     CALL_FROM_TB1(do_pmon, PARAM1);
+    RETURN();
 }
 
 void op_trap (void)
@@ -939,12 +1124,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);
@@ -959,12 +1146,50 @@
         env->hflags &= ~MIPS_HFLAG_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)
@@ -994,10 +1219,114 @@
 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);
+}
+
+void op_dsbh(void)
+{
+    T0 = ((T1 << 8) & ~0x00FF00FF00FF00FFULL) | ((T1 >> 8) & 
0x00FF00FF00FF00FFULL);
+}
+
+void op_dshd(void)
+{
+    T0 = ((T1 << 16) & ~0x0000FFFF0000FFFFULL) | ((T1 >> 16) & 
0x0000FFFF0000FFFFULL);
+}
+
+void op_seb(void)
+{
+    T0 = ((T1 & 0xFF) ^ 0x80) - 0x80;
+}
+
+void op_seh(void)
+{
+    T0 = ((T1 & 0xFFFF) ^ 0x8000) - 0x8000;
 }
Index: qemu-work/target-mips/exec.h
===================================================================
--- qemu-work.orig/target-mips/exec.h   2006-05-08 03:03:06.000000000 +0100
+++ qemu-work/target-mips/exec.h        2006-05-08 03:03:09.000000000 +0100
@@ -61,8 +61,10 @@
 #endif
 void do_mfc0_random(void);
 void do_mfc0_count(void);
-void do_mtc0_status_debug(uint32_t old, uint32_t val);
+void do_mtc0_entryhi(uint32_t in);
+void do_mtc0_status(uint32_t in);
 void do_mtc0_status_irqraise_debug(void);
+void do_mtc0_cause(uint32_t in);
 void do_tlbwi (void);
 void do_tlbwr (void);
 void do_tlbp (void);
Index: qemu-work/target-mips/op_helper.c
===================================================================
--- qemu-work.orig/target-mips/op_helper.c      2006-05-08 03:03:06.000000000 
+0100
+++ qemu-work/target-mips/op_helper.c   2006-05-08 03:12:56.000000000 +0100
@@ -151,16 +151,26 @@
     cpu_abort(env, "mtc0 compare\n");
 }
 
-void do_mtc0_status_debug(uint32_t old, uint32_t val)
+void do_mtc0_entryhi (uint32_t val)
 {
-    cpu_abort(env, "mtc0 status\n");
+    cpu_abort(env, "mtc0 entryhi\n");
 }
 
-void do_mtc0_status_irqraise_debug(void)
+void do_mtc0_status (uint32_t val)
 {
     cpu_abort(env, "mtc0 status\n");
 }
 
+void do_mtc0_status_irqraise_debug (void)
+{
+    cpu_abort(env, "mtc0 status_irqraise_debug\n");
+}
+
+void do_mtc0_cause (uint32_t val)
+{
+    cpu_abort(env, "mtc0 cause\n");
+}
+
 void do_tlbwi (void)
 {
     cpu_abort(env, "tlbwi\n");
@@ -194,6 +204,63 @@
     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))
+        tlb_flush(env, 1);
+}
+
+void do_mtc0_status (uint32_t in)
+{
+    uint32_t val, old, mask;
+
+    val = in & ((0 << CP0St_CU3) | (0 << CP0St_CU2) | (0 << CP0St_CU1) | (1 << 
CP0St_CU0)
+               | (0 << CP0St_RP) | (0 << CP0St_FR) | (0 << CP0St_RE) | (0 << 
CP0St_MX)
+               | (0 << CP0St_PX) | (1 << CP0St_BEV) | (1 << CP0St_TS) | (1 << 
CP0St_SR)
+               | (1 << CP0St_NMI)
+               | (0xFF << CP0St_IM)
+               | (0 << CP0St_KX) | (0 << CP0St_SX) | (0 << CP0St_UX) | (0 << 
CP0St_UM)
+               | (0 << CP0St_R0) | (0 << CP0St_ERL) | (0 << CP0St_EXL) | (1 << 
CP0St_IE));
+    if (in & (1 << CP0St_UM))
+        env->hflags |= MIPS_HFLAG_UM;
+    else
+        env->hflags &= ~MIPS_HFLAG_UM;
+    if (in & (1 << CP0St_ERL))
+        env->hflags |= MIPS_HFLAG_ERL;
+    else
+        env->hflags &= ~MIPS_HFLAG_ERL;
+    if (in & (1 << CP0St_EXL))
+        env->hflags |= MIPS_HFLAG_EXL;
+    else
+        env->hflags &= ~MIPS_HFLAG_EXL;
+    old = env->CP0_Status;
+    env->CP0_Status = val;
+    /* If we unmasked an asserted IRQ, raise it */
+    mask = 0x0000FF00;
+    if (loglevel & CPU_LOG_TB_IN_ASM)
+        fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n",
+                old, val, env->CP0_Cause, old & mask, val & mask,
+                env->CP0_Cause & mask);
+    if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) &&
+        !(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)
+           do_mtc0_status_irqraise_debug();
+    } else if (!(val & (1 << CP0St_IE)) && (old & (1 << CP0St_IE))) {
+        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+    }
+}
+
 void do_mtc0_status_debug(uint32_t old, uint32_t val)
 {
     const uint32_t mask = 0x0000FF00;
@@ -207,6 +274,33 @@
     fprintf(logfile, "Raise pending IRQs\n");
 }
 
+void do_mtc0_cause (uint32_t in)
+{
+    uint32_t val, old;
+
+    val = (env->CP0_Cause & ((1 << CP0Ca_BD) | (1 << CP0Ca_TI) | (0x3 << 
CP0Ca_CE)
+                            | (1 << CP0Ca_DC) | (1 << CP0Ca_PCI) | (1 << 
CP0Ca_IV)
+                            | (1 << CP0Ca_WP) | (0xFF << CP0Ca_IP) | (0x1F << 
CP0Ca_EC)))
+          | (in & ((1 << CP0Ca_DC) | (1 << CP0Ca_IV)
+                   | (1 << CP0Ca_WP) | (0x3 << CP0Ca_IP)));
+    old = env->CP0_Cause;
+    env->CP0_Cause = val;
+#if 0
+    {
+        int i, mask;
+
+       /* Check if we ever asserted a software IRQ */
+        for (i = 0; i < 2; i++) {
+            mask = 0x100 << i;
+            if ((val & mask) & !(old & mask))
+                CALL_FROM_TB1(mips_set_irq, i);
+        }
+    }
+#endif
+    RETURN();
+}
+
+
 /* TLB management */
 #if defined(MIPS_USES_R4K_TLB)
 static void invalidate_tlb (int idx)




reply via email to

[Prev in Thread] Current Thread [Next in Thread]