#define FEATURE_HASFPU (1 << 1) /* 0 = no FPU; 1 = include FPU */
#define FEATURE_FPSINGLE (1 << 1) /* 0 = double; 1 = single (only used if FEATURE_HASFPU defined) */
#define FEATURE_GP64 (1 << 2) /* 0 = GPRLEN 32; 1 = GPRLEN 64 */
-#define FEATURE_FP64 (1 << 3) /* 0 = FPRLEN 32; 1 = FPRLEN 64 (only used if FEATURE_HASFPU defined */
#define FEATURE_FAST (1 << 17) /* 0 = normal; 1 = disable features that slow performance */
#define FEATURE_WARN_STALL (1 << 24) /* 0 = nothing; 1 = generate warnings when pipeline would stall */
#define FEATURE_WARN_LOHI (1 << 25) /* 0 = nothing; 1 = generate warnings when LO/HI corrupted */
#define FEATURE_WARN_R31 (1 << 28) /* 0 = nothing; 1 = generate warnings if r31 used dangerously */
#define FEATURE_WARN_RESULT (1 << 29) /* 0 = nothing; 1 = generate warnings when undefined results may occur */
+#if 1
+#define FEATURE_WARNINGS (FEATURE_WARN_STALL | FEATURE_WARN_LOHI | FEATURE_WARN_ZERO | FEATURE_WARN_R31)
+#else
#define FEATURE_WARNINGS (FEATURE_WARN_STALL | FEATURE_WARN_LOHI | FEATURE_WARN_ZERO | FEATURE_WARN_R31 | FEATURE_WARN_RESULT)
+#endif
/* FEATURE_WARN_STALL */
/* If MIPS I we want to raise a warning if an attempt is made to
#include <getopt.h>
#include <limits.h>
#include <errno.h>
-#include "opcode/mips.h" /* From Cygnus progressive tree */
+#include "opcode/mips.h"
-/* The following manifests do not appear in "progressive/include/opcode/mips.h" */
+/* The following manifests do not appear in "include/opcode/mips.h" */
#define OP_SH_LOCC (8) /* FP condition code */
#define OP_SH_HICC (18) /* FP condition code */
#define OP_MASK_CC (0x07)
-#define OP_SH_CC (8) /* FP condition code */
-#define OP_MASK_CC (0x07)
+
+#define OP_SH_COP1NORM (25) /* Normal COP1 encoding */
+#define OP_MASK_COP1NORM (0x01) /* a single bit */
+#define OP_SH_COP1SPEC (21) /* Special COP1 encodings (within format field) */
+#define OP_MASK_COP1SPEC (0x0F) /* Bits we are interested in */
+#define OP_MASK_COP1SCLR (0x04) /* Bits to be explicitly cleared */
+#define OP_MASK_COP1CMP (0x3) /* Unfortunately another conditional field needed to decode the FP instructions */
+#define OP_SH_COP1CMP (4)
+
#define OP_SH_FORMAT (21) /* FP short format field */
#define OP_MASK_FORMAT (0x07)
+
#define OP_SH_TRUE (16)
#define OP_MASK_TRUE (0x01)
+
#define OP_SH_GE (17)
#define OP_MASK_GE (0x01)
+
#define OP_SH_UNSIGNED (16)
#define OP_MASK_UNSIGNED (0x01)
+
#define OP_SH_HINT (16)
#define OP_MASK_HINT (0x1F)
+#if 0
#ifndef TRUE
#define TRUE (1 == 1)
#define FALSE (1 == 0)
#endif
+#endif
/*---------------------------------------------------------------------------*/
/* Values for the "flags" field: */
#define OP_NONE (0 << 0) /* To keep the source tidy */
#define OP_GPR (1 << 0) /* Get operand from integer register bank */
-#define OP_FGR (1 << 1) /* Get operand from FP register bank */
-#define OP_SIGNX (1 << 2) /* Sign-extend the operand */
-#define OP_SHIFT2 (1 << 3) /* Shift field left by 2 */
-#define OP_BITS5 (1 << 4) /* Only take the lo 5-bits of the operand */
+#define OP_SIGNX (1 << 1) /* Sign-extend the operand */
+#define OP_SHIFT2 (1 << 2) /* Shift field left by 2 */
+#define OP_BITS5 (1 << 3) /* Only take the lo 5-bits of the operand */
struct operand_encoding opfields[] = {
- {'0',-1,-1,"" ,"" ,(OP_NONE)}, /* special case for explicit zero */
- {'1',-1,-1,"" ,"" ,(OP_NONE)}, /* special case for explicit one */
- {'?',-1,-1,"" ,"" ,(OP_NONE)}, /* undefined (do not care at this level) */
+ {'0',-1,-1,"", "", (OP_NONE)}, /* special case for explicit zero */
+ {'1',-1,-1,"", "", (OP_NONE)}, /* special case for explicit one */
+ {'?',-1,-1,"", "", (OP_NONE)}, /* undefined (do not care at this level) */
/* The rest are the explicit operand fields: */
- {'a', 6, 5,"int" ,"op1" ,(OP_NONE)}, /* shift amount (or hint) */
- {'b',21, 5,"t_fpreg","base" ,(OP_FGR)}, /* FP base/fr register */
- {'c',16, 1,"int" ,"boolean" ,(OP_NONE)}, /* TRUE or FALSE boolean */
- {'d',11, 5,"int" ,"destreg" ,(OP_NONE)}, /* integer destination/rd register */
- {'e', 0,16,"t_reg" ,"offset" ,(OP_SIGNX)}, /* signed offset (lo-3bits must be zero) */
- {'f',25, 1,"int" ,"add" ,(OP_NONE)}, /* TRUE if ADD instruction, FALSE if move or branch */
- {'g',16, 5,"t_reg" ,"op2" ,(OP_GPR)}, /* integer source rt register */
- {'h', 0,16,"t_reg" ,"offset" ,(OP_SIGNX)}, /* signed offset (lo-1bit must be zero) */
- {'i', 0,16,"t_reg" ,"op2" ,(OP_SIGNX)}, /* signed immediate (op2) */
- {'j', 0,26,"ut_reg" ,"op1" ,(OP_SHIFT2)},/* shifted left 2 bits and combined with hi-order bits of address in the delay slot */
- {'k',16, 5,"t_fpreg","index" ,(OP_FGR)}, /* FP index register */
- {'l', 0,16,"t_reg" ,"offset" ,(OP_SIGNX | OP_SHIFT2)}, /* signed offset shifted left 2 to make 18bit signed offset */
- {'m',21, 3,"int" ,"format" ,(OP_NONE)}, /* FP format field */
- {'n',16, 5,"int" ,"hint" ,(OP_NONE)}, /* hint */
- {'o',21, 5,"t_reg" ,"op1" ,(OP_GPR | OP_BITS5)}, /* integer source/rs register (but never treated as 32bit word) */
- {'p', 8, 3,"int" ,"condition_code",(OP_NONE)}, /* FP condition code field */
- {'q',18, 3,"int" ,"condition_code",(OP_NONE)}, /* FP condition code field */
- {'r', 6, 5,"int" ,"destreg" ,(OP_NONE)}, /* FP fd register */
- {'s',21, 5,"t_reg" ,"op1" ,(OP_GPR)}, /* integer source/rs register */
- {'t',16, 5,"int" ,"destreg" ,(OP_NONE)}, /* integer target rt (destination) register */
- {'u', 0, 4,"int" ,"cmpflags" ,(OP_NONE)}, /* FP comparison control flags */
- {'v',11, 5,"t_fpreg","op1" ,(OP_FGR)}, /* FP fs register or hint */
- {'w', 0,16,"t_reg" ,"offset" ,(OP_SIGNX)}, /* signed offset (lo-2bits must be zero) */
- {'x',24, 1,"int" ,"branch" ,(OP_NONE)}, /* TRUE if branch instruction - FALSE if move or add */
- {'y', 0,16,"t_reg" ,"offset" ,(OP_SIGNX)}, /* signed offset */
- {'z', 0,16,"ut_reg" ,"op2" ,(OP_NONE)}, /* unsigned immediate (zero extended) */
+ {'a', 6, 5,"int", "op1", (OP_NONE)}, /* shift amount (or hint) */
+ {'b',21, 5,"int", "fr", (OP_NONE)}, /* fr register */
+ {'c',16, 1,"int", "boolean", (OP_NONE)}, /* TRUE or FALSE boolean */
+ {'d',11, 5,"int", "destreg", (OP_NONE)}, /* integer destination/rd register */
+ {'e', 0,16,"t_reg", "offset", (OP_SIGNX)}, /* signed offset (lo-3bits must be zero) */
+ {'f',17, 1,"int", "likely", (OP_NONE)}, /* set if branch LIKELY */
+ {'g',16, 5,"t_reg", "op2", (OP_GPR)}, /* integer source rt register */
+ {'h', 0,16,"t_reg", "offset", (OP_SIGNX)}, /* signed offset (lo-1bit must be zero) */
+ {'i', 0,16,"t_reg", "op2", (OP_SIGNX)}, /* signed immediate (op2) */
+ {'j', 0,26,"ut_reg","op1", (OP_SHIFT2)},/* shifted left 2 bits and combined with hi-order bits of address in the delay slot */
+ {'k',16, 5,"int", "ft", (OP_NONE)},
+ {'l', 0,16,"t_reg", "offset", (OP_SIGNX | OP_SHIFT2)}, /* signed offset shifted left 2 to make 18bit signed offset */
+ {'m',21, 3,"int", "format", (OP_NONE)}, /* FP format field */
+ {'n',16, 5,"int", "hint", (OP_NONE)}, /* hint */
+ {'o',21, 5,"t_reg", "op1", (OP_GPR | OP_BITS5)}, /* integer source/rs register (but never treated as 32bit word) */
+ {'p', 8, 3,"int", "condition_code",(OP_NONE)}, /* FP condition code field */
+ {'q',18, 3,"int", "condition_code",(OP_NONE)}, /* FP condition code field */
+ {'r', 6, 5,"int", "destreg", (OP_NONE)}, /* FP fd register */
+ {'s',21, 5,"t_reg", "op1", (OP_GPR)}, /* integer source/rs register */
+ {'t',16, 5,"int", "destreg", (OP_NONE)}, /* integer target rt (destination) register */
+ {'u', 0, 4,"int", "cmpflags", (OP_NONE)}, /* FP comparison control flags */
+ {'v',11, 5,"int", "fs", (OP_NONE)}, /* FP fs register (or PREFX hint) */
+ {'w', 0,16,"t_reg", "offset", (OP_SIGNX)}, /* signed offset (lo-2bits must be zero) */
+ {'x',23, 1,"int", "to", (OP_NONE)}, /* TRUE if move To; FALSE if move From */
+ {'y', 0,16,"t_reg", "offset", (OP_SIGNX)}, /* signed offset */
+ {'z', 0,16,"ut_reg","op2", (OP_NONE)}, /* unsigned immediate (zero extended) */
};
/* Main instruction encoding types: */
REGIMM,
COP1,
COP1X,
+ COP1S, /* These instructions live in the reserved FP format values: 0..15,18-19,22-31 */
UNKNOWN
} inst_type;
CACHE, /* co-processor 0 CACHE instruction */
MADD16, /* VR4100 specific multiply-add extensions */
FPMOVE,
+ FPMOVEC,
FPFLOOR,
FPCEIL,
FPTRUNC,
FPMUL,
FPSUB,
FPADD,
- FPMAB, /* Special encoding for MOVE, ADD and BRANCH instructions */
FPPREFX,
- FPSTORE,
- FPLOAD,
FPRECIP,
FPSQRT,
FPCONVERT,
/* Flags field: */
#define NONE (0 << 0) /* Zero value (used to keep source tidy) */
#define SIM_SH_SIZE (0)
-#define SIM_MASK_SIZE (0x3)
-#define BYTE (0)
-#define HALFWORD (1)
-#define WORD (2)
-#define DOUBLEWORD (3)
+#define SIM_MASK_SIZE (0x7)
+#define BYTE (0) /* 8bit */
+#define HALFWORD (1) /* 16bit */
+#define WORD (2) /* 32bit */
+#define DOUBLEWORD (3) /* 64bit */
+#define SINGLE (4) /* single precision FP */
+#define DOUBLE (5) /* double precision FP */
/* Shorthand to get the size field from the flags value: */
#define GETDATASIZE() ((MIPS_DECODE[loop].flags >> SIM_SH_SIZE) & SIM_MASK_SIZE)
/* The rest are single bit flags: */
-#define COPROC (1 << 2)
#define MULTIPLY (1 << 3) /* actually FP multiply ADD/SUB modifier */
#define EQ (1 << 4)
#define GT (1 << 5)
#define WORD32 (1 << 23)
#define FP (1 << 24) /* Floating Point operation */
#define FIXED (1 << 25) /* fixed point arithmetic */
-#define SINGLE (1 << 26) /* single precision FP */
-#define DOUBLE (1 << 27) /* double precision FP */
-/**** Bits 28, 29 and 30 available ****/
+#define COPROC (1 << 26)
+#define INTEGER (1 << 27)
+#define CONDITIONAL (1 << 28)
+#define RECIP (1 << 29)
+#define CONTROL (1 << 30)
#define NOARG (1 << 31) /* Instruction has no (defined) operands */
+/* NOTE: We can overload the use of certain of these flags, since not
+ all options are applicable to all instruction types. This will free
+ up more space for new flags. */
typedef struct instruction {
char *name; /* ASCII mnemonic name */
/* The instructions are alphabetical, and not in instruction bit-order: */
{"ABS", 1,"01000110mmm00000dddddaaaaa000101",COP1, FPABS, (FP)},
{"ADD", 1,"000000sssssgggggddddd00000100000",SPECIAL,ADD, (WORD | WORD32 | OVERFLOW)}, /* rd = rs + rt */
- {"%s", 1,"010001fxmmmnnnnndddddaaaaa000000",COP1, FPMAB, (FP)},
+ {"ADD", 1,"01000110mmmkkkkkvvvvvrrrrr000000",COP1, FPADD, (FP)},
{"ADDI", 1,"001000ssssstttttiiiiiiiiiiiiiiii",NORMAL, ADD, (WORD | WORD32 | OVERFLOW)},
{"ADDU", 1,"000000sssssgggggddddd00000100001",SPECIAL,ADD, (WORD | WORD32)}, /* rd = rs + rt */
{"ADDIU", 1,"001001ssssstttttiiiiiiiiiiiiiiii",NORMAL, ADD, (WORD | WORD32)},
{"AND", 1,"000000sssssgggggddddd00000100100",SPECIAL,AND, (NONE)}, /* rd = rs AND rt */
{"ANDI", 1,"001100ssssstttttzzzzzzzzzzzzzzzz",NORMAL, AND, (NONE)},
+ {"BC1", 1,"01000101000qqqfcllllllllllllllll",COP1S, BRANCH, (FP)},
{"BEQ", 1,"000100sssssgggggllllllllllllllll",NORMAL, BRANCH, (EQ)},
{"BEQL", 2,"010100sssssgggggllllllllllllllll",NORMAL, BRANCH, (EQ | LIKELY)},
{"BGEZ", 1,"000001sssss00001llllllllllllllll",REGIMM, BRANCH, (GT | EQ)},
{"CVT.S", 1,"01000110mmm00000vvvvvrrrrr100000",COP1, FPCONVERT,(FP | SINGLE)},
{"CVT.W", 1,"01000110mmm00000vvvvvrrrrr100100",COP1, FPCONVERT,(FP | FIXED | WORD)},
{"C.%s", 1,"01000110mmmkkkkkvvvvvppp0011uuuu",COP1, FPCOMPARE,(FP)},
+ {"CxC1", 1,"01000100x10kkkkkvvvvv00000000000",COP1S, FPMOVEC, (FP | WORD | CONTROL)},
{"DADD", 3,"000000sssssgggggddddd00000101100",SPECIAL,ADD, (DOUBLEWORD | OVERFLOW)},
{"DADDI", 3,"011000ssssstttttiiiiiiiiiiiiiiii",NORMAL, ADD, (DOUBLEWORD | OVERFLOW)},
{"DADDU", 3,"000000sssssgggggddddd00000101101",SPECIAL,ADD, (DOUBLEWORD | UNSIGNED)},
{"DMADD16", (ARCH_VR4100 | 3),"000000sssssggggg0000000000101001",SPECIAL,MADD16, (DOUBLEWORD | HI | LO)},
{"DMULT", 3,"000000sssssggggg0000000000011100",SPECIAL,MUL, (DOUBLEWORD | HI | LO)},
{"DMULTU", 3,"000000sssssggggg0000000000011101",SPECIAL,MUL, (DOUBLEWORD | UNSIGNED | HI | LO)},
+ {"DMxC1", 3,"01000100x01kkkkkvvvvv00000000000",COP1S, FPMOVEC, (FP | DOUBLEWORD)},
{"DSLL", 3,"00000000000gggggdddddaaaaa111000",SPECIAL,SHIFT, (DOUBLEWORD | LEFT | LOGICAL)},
{"DSLLV", 3,"000000sssssgggggddddd00000010100",SPECIAL,SHIFT, (DOUBLEWORD | LEFT | LOGICAL)},
{"DSLL32", 3,"00000000000gggggdddddaaaaa111100",SPECIAL,SHIFT, (DOUBLEWORD | LEFT | LOGICAL | HI32)}, /* rd = rt << (sa + 32) */
{"LDC2", 2,"110110sssssttttteeeeeeeeeeeeeeee",NORMAL, LOAD, (DOUBLEWORD | COPROC)},
{"LDL", 3,"011010ssssstttttyyyyyyyyyyyyyyyy",NORMAL, LOAD, (DOUBLEWORD | LEFT)}, /* NOTE: See "LB" comment */
{"LDR", 3,"011011ssssstttttyyyyyyyyyyyyyyyy",NORMAL, LOAD, (DOUBLEWORD | RIGHT)}, /* NOTE: See "LB" comment */
- {"LDXC1", 4,"010011bbbbbkkkkk00000rrrrr000001",COP1X, FPLOAD, (FP | DOUBLEWORD)},
+ {"LDXC1", 4,"010011sssssggggg00000rrrrr000001",COP1X, LOAD, (FP | DOUBLEWORD | COPROC | REG)},
{"LH", 1,"100001sssssttttthhhhhhhhhhhhhhhh",NORMAL, LOAD, (HALFWORD | SIGNEXTEND)},
{"LHU", 1,"100101sssssttttthhhhhhhhhhhhhhhh",NORMAL, LOAD, (HALFWORD)},
{"LL", 2,"110000ssssstttttwwwwwwwwwwwwwwww",NORMAL, LOAD, (WORD | ATOMIC | SIGNEXTEND)},
{"LWL", 1,"100010ssssstttttyyyyyyyyyyyyyyyy",NORMAL, LOAD, (WORD | LEFT)},
{"LWR", 1,"100110ssssstttttyyyyyyyyyyyyyyyy",NORMAL, LOAD, (WORD | RIGHT)},
{"LWU", 3,"100111ssssstttttwwwwwwwwwwwwwwww",NORMAL, LOAD, (WORD)},
- {"LWXC1", 4,"010011bbbbbkkkkk00000rrrrr000000",COP1X, FPLOAD, (FP | WORD)},
+ {"LWXC1", 4,"010011sssssggggg00000rrrrr000000",COP1X, LOAD, (FP | WORD | COPROC | REG)},
{"MADD16", (ARCH_VR4100 | 3),"000000sssssggggg0000000000101000",SPECIAL,MADD16, (WORD | HI | LO)},
{"MADD.D", 4,"010011bbbbbkkkkkvvvvvrrrrr100001",COP1X, FPADD, (FP | MULTIPLY | DOUBLE)},
{"MADD.S", 4,"010011bbbbbkkkkkvvvvvrrrrr100000",COP1X, FPADD, (FP | MULTIPLY | SINGLE)},
{"MTLO", 1,"000000sssss000000000000000010011",SPECIAL,MOVE, (LO)},
{"MOV", 1,"01000110mmm00000vvvvvrrrrr000110",COP1, FPMOVE, (FP)},
{"MOVN", 4,"000000sssssgggggddddd00000001011",SPECIAL,MOVE, (NOT | EQ)},
- {"MOVN", 4,"01000110mmmkkkkkvvvvvrrrrr010011",COP1, FPMOVE, (FP | NOT)},
- {"MOV%c", 4,"000000sssssqqq0cddddd00000000001",SPECIAL,FPMOVE, (FP)}, /* Test FP condition code, and conditionally move integer register */
- {"MOV%c", 4,"01000110mmmqqq0cvvvvvrrrrr010001",COP1, FPMOVE, (FP)}, /* to test an FP condition and conditionally move an FP value */
+ {"MOVN", 4,"01000110mmmgggggvvvvvrrrrr010011",COP1, FPMOVE, (FP | NOT | EQ)},
+ {"MOV%c", 4,"000000sssssqqq0cddddd00000000001",SPECIAL,FPMOVE, (FP | CONDITIONAL | INTEGER)},
+ {"MOV%c", 4,"01000110mmmqqq0cvvvvvrrrrr010001",COP1, FPMOVE, (FP | CONDITIONAL)},
{"MOVZ", 4,"000000sssssgggggddddd00000001010",SPECIAL,MOVE, (EQ)},
- {"MOVZ", 4,"01000110mmmkkkkkvvvvvrrrrr010010",COP1, FPMOVE, (FP)},
+ {"MOVZ", 4,"01000110mmmgggggvvvvvrrrrr010010",COP1, FPMOVE, (FP | EQ)},
{"MSUB.D", 4,"010011bbbbbkkkkkvvvvvrrrrr101001",COP1X, FPSUB, (FP | MULTIPLY | DOUBLE)},
{"MSUB.S", 4,"010011bbbbbkkkkkvvvvvrrrrr101000",COP1X, FPSUB, (FP | MULTIPLY | SINGLE)},
{"MUL", 1,"01000110mmmkkkkkvvvvvrrrrr000010",COP1, FPMUL, (FP | HI | LO)},
{"MULT", 1,"000000sssssggggg0000000000011000",SPECIAL,MUL, (WORD | WORD32 | HI | LO)},
{"MULTU", 1,"000000sssssggggg0000000000011001",SPECIAL,MUL, (WORD | WORD32 | HI | LO)},
- {"NEG", 1,"01000110mmm00000vvvvvrrrrr000111",COP1, FPNEG, (FP | FIXED | DOUBLEWORD)},
+ {"MxC1", 1,"01000100x00kkkkkvvvvv00000000000",COP1S, FPMOVEC, (FP | WORD)},
+ {"NEG", 1,"01000110mmm00000vvvvvrrrrr000111",COP1, FPNEG, (FP)},
{"NMADD.D", 4,"010011bbbbbkkkkkvvvvvrrrrr110001",COP1X, FPADD, (FP | NOT | MULTIPLY | DOUBLE)},
{"NMADD.S", 4,"010011bbbbbkkkkkvvvvvrrrrr110000",COP1X, FPADD, (FP | NOT | MULTIPLY | SINGLE)},
{"NMSUB.D", 4,"010011bbbbbkkkkkvvvvvrrrrr111001",COP1X, FPSUB, (FP | NOT | MULTIPLY | DOUBLE)},
{"OR", 1,"000000sssssgggggddddd00000100101",SPECIAL,OR, (NONE)},
{"ORI", 1,"001101ssssstttttzzzzzzzzzzzzzzzz",NORMAL, OR, (NONE)},
{"PREF", 4,"110011sssssnnnnnyyyyyyyyyyyyyyyy",NORMAL, PREFETCH, (NONE)},
- {"PREFX", 4,"010011bbbbbkkkkkvvvvv00000001111",COP1X, FPPREFX, (FP)},
+ {"PREFX", 4,"010011sssssgggggvvvvv00000001111",COP1X, FPPREFX, (FP)},
{"RECIP", 4,"01000110mmm00000vvvvvrrrrr010101",COP1, FPRECIP, (FP)},
{"ROUND.L", 3,"01000110mmm00000vvvvvrrrrr001000",COP1, FPROUND, (FP | FIXED | DOUBLEWORD)},
{"ROUND.W", 2,"01000110mmm00000vvvvvrrrrr001100",COP1, FPROUND, (FP | FIXED | WORD)},
- {"RSQRT", 4,"01000110mmm00000vvvvvrrrrr010110",COP1, FPSQRT, (FP)},
+ {"RSQRT", 4,"01000110mmm00000vvvvvrrrrr010110",COP1, FPSQRT, (FP | RECIP)},
{"SB", 1,"101000sssssgggggyyyyyyyyyyyyyyyy",NORMAL, STORE, (BYTE)},
{"SC", 2,"111000sssssgggggwwwwwwwwwwwwwwww",NORMAL, STORE, (WORD | ATOMIC)},
{"SCD", 3,"111100sssssgggggeeeeeeeeeeeeeeee",NORMAL, STORE, (DOUBLEWORD | ATOMIC)},
{"SDC2", 2,"111110sssssttttteeeeeeeeeeeeeeee",NORMAL, STORE, (DOUBLEWORD | COPROC)},
{"SDL", 3,"101100sssssgggggyyyyyyyyyyyyyyyy",NORMAL, STORE, (DOUBLEWORD | LEFT)},
{"SDR", 3,"101101sssssgggggyyyyyyyyyyyyyyyy",NORMAL, STORE, (DOUBLEWORD | RIGHT)},
- {"SDXC1", 4,"010011bbbbbkkkkkvvvvv00000001001",COP1X, FPSTORE, (FP | DOUBLEWORD)},
+ {"SDXC1", 4,"010011sssssgggggvvvvv00000001001",COP1X, STORE, (FP | DOUBLEWORD | COPROC | REG)},
{"SH", 1,"101001sssssggggghhhhhhhhhhhhhhhh",NORMAL, STORE, (HALFWORD)},
{"SLL", 1,"00000000000gggggdddddaaaaa000000",SPECIAL,SHIFT, (WORD | LEFT | LOGICAL)}, /* rd = rt << sa */
{"SLLV", 1,"000000ooooogggggddddd00000000100",SPECIAL,SHIFT, (WORD | LEFT | LOGICAL)}, /* rd = rt << rs - with "SLL" depends on "s" and "a" field values */
{"SLTU", 1,"000000sssssgggggddddd00000101011",SPECIAL,SET, (LT | UNSIGNED)},
{"SLTIU", 1,"001011ssssstttttiiiiiiiiiiiiiiii",NORMAL, SET, (LT | UNSIGNED)},
{"SQRT", 2,"01000110mmm00000vvvvvrrrrr000100",COP1, FPSQRT, (FP)},
- {"SRA", 1,"00000000000gggggdddddaaaaa000011",SPECIAL,SHIFT, (WORD | WORD32 | WORD | RIGHT | ARITHMETIC)},
- {"SRAV", 1,"000000ooooogggggddddd00000000111",SPECIAL,SHIFT, (WORD | WORD32 | WORD | RIGHT | ARITHMETIC)},
- {"SRL", 1,"00000000000gggggdddddaaaaa000010",SPECIAL,SHIFT, (WORD | WORD32 | WORD | RIGHT | LOGICAL)},
- {"SRLV", 1,"000000ooooogggggddddd00000000110",SPECIAL,SHIFT, (WORD | WORD32 | WORD | RIGHT | LOGICAL)},
+ {"SRA", 1,"00000000000gggggdddddaaaaa000011",SPECIAL,SHIFT, (WORD | WORD32 | RIGHT | ARITHMETIC)},
+ {"SRAV", 1,"000000ooooogggggddddd00000000111",SPECIAL,SHIFT, (WORD | WORD32 | RIGHT | ARITHMETIC)},
+ {"SRL", 1,"00000000000gggggdddddaaaaa000010",SPECIAL,SHIFT, (WORD | WORD32 | RIGHT | LOGICAL)},
+ {"SRLV", 1,"000000ooooogggggddddd00000000110",SPECIAL,SHIFT, (WORD | WORD32 | RIGHT | LOGICAL)},
{"SUB", 1,"000000sssssgggggddddd00000100010",SPECIAL,SUB, (WORD | WORD32 | OVERFLOW)},
{"SUB", 1,"01000110mmmkkkkkvvvvvrrrrr000001",COP1, FPSUB, (FP)},
{"SUBU", 1,"000000sssssgggggddddd00000100011",SPECIAL,SUB, (WORD | WORD32)},
{"SWC2", 1,"111010ssssstttttwwwwwwwwwwwwwwww",NORMAL, STORE, (WORD | COPROC)},
{"SWL", 1,"101010sssssgggggyyyyyyyyyyyyyyyy",NORMAL, STORE, (WORD | LEFT)},
{"SWR", 1,"101110sssssgggggyyyyyyyyyyyyyyyy",NORMAL, STORE, (WORD | RIGHT)},
- {"SWXC1", 4,"010011bbbbbkkkkkvvvvv00000001000",COP1X, FPSTORE, (FP)},
+ {"SWXC1", 4,"010011sssssgggggvvvvv00000001000",COP1X, STORE, (FP | WORD | COPROC | REG)},
{"SYNC", 2,"000000000000000000000aaaaa001111",SPECIAL,SYNC, (NONE)}, /* z = 5bit stype field */
{"SYSCALL", 1,"000000????????????????????001100",SPECIAL,SYSCALL, (NOARG)},
{"TEQ", 2,"000000sssssggggg??????????110100",SPECIAL,TRAP, (EQ)},
if (oefield < (sizeof(opfields) / sizeof(struct operand_encoding))) {
if ((lastoe != -1) && (lastoe != oefield))
if ((loop - lastsp) != (opfields[lastoe].flen)) {
- fprintf(stderr,"Invalid field length %d for bitmap field '%c' (0x%02X) (should be %d)\n",(loop - lastsp),(((bitmap[31 - loop] < 0x20) || (bitmap[31 - loop] >= 0x7F)) ? '.' : bitmap[31 - loop]),bitmap[31 - loop],opfields[lastoe].flen);
+ fprintf(stderr,"Invalid field length %d for bitmap field '%c' (0x%02X) (should be %d) : bitmap = \"%s\"\n",(loop - lastsp),(((bitmap[31 - loop] < 0x20) || (bitmap[31 - loop] >= 0x7F)) ? '.' : bitmap[31 - loop]),bitmap[31 - loop],opfields[lastoe].flen,bitmap);
exit(4);
}
if (opfields[loop].flags & OP_SIGNX)
printf("SIGNEXTEND((%s)",opfields[loop].type);
- if (opfields[loop].flags & (OP_GPR | OP_FGR))
- printf("%s[",((opfields[loop].flags & OP_GPR) ? "GPR" : "FGR"));
+ if (opfields[loop].flags & OP_GPR)
+ printf("GPR[");
if (opfields[loop].flags & OP_SHIFT2)
printf("(");
if (opfields[loop].flags & OP_SHIFT2)
printf(" << 2)");
- if (opfields[loop].flags & (OP_GPR | OP_FGR))
+ if (opfields[loop].flags & OP_GPR)
printf("]");
if (opfields[loop].flags & OP_BITS5)
int doisa = (doarch & MASK_ISA);
int limit = (sizeof(MIPS_DECODE) / sizeof(instruction));
int gprlen=((features & FEATURE_GP64) ? 64 : 32);
- int fprlen=((features & FEATURE_FP64) ? 64 : 32);
int proc64 = ((features & FEATURE_PROC32) ? 0 : -1);
int dofp = (features & FEATURE_HASFPU);
int fpsingle = (features & FEATURE_FPSINGLE);
+ int maxisa;
int loop;
if (limit < 1) {
exit(3);
}
- fprlen = ((features & FEATURE_FP64) ? 64 : 32);
- if (fprlen != gprlen)
- fprintf(stderr,"Warning: FPR (%d) and GPR (%d) are different sizes\n",fprlen,gprlen);
-
/* NOTE: "proc64" also differentiates between 32- and 64-bit wide memory */
+ maxisa = 0;
+ for (loop = 0; (loop < limit); loop++)
+ if ((MIPS_DECODE[loop].isa & MASK_ISA) > maxisa)
+ maxisa = (MIPS_DECODE[loop].isa & MASK_ISA);
+
+ if (doisa == 0)
+ doisa = maxisa;
+
printf("#if defined(SIM_MANIFESTS)\n");
+ printf("#define MIPSISA (%d)\n",doisa);
if (proc64)
printf("#define PROCESSOR_64BIT (1 == 1)\n");
printf("#define LOADDRMASK (0x%08X)\n",(proc64 ? 0x7 : 0x3));
+ /* The FP registers are the same width as the CPU registers: */
printf("#define GPRLEN (%d)\n",gprlen);
- printf("#define FPRLEN (%d)\n",fprlen);
printf("typedef %s t_reg;\n",((gprlen == 64) ? "word64" : "int"));
printf("typedef %s ut_reg;\n",((gprlen == 64) ? "uword64" : "unsigned int"));
- printf("typedef %s t_fpreg;\n",((fprlen == 64) ? "word64" : "int"));
+ printf("typedef %s t_fpreg;\n",((gprlen == 64) ? "word64" : "int"));
if (dofp)
printf("#define HASFPU (1 == 1)\n");
if (features & FEATURE_FAST)
printf("/* Actual instruction decoding block */\n");
printf("{\n");
- printf("int num = ((instruction >> %d) & 0x%08X);\n",OP_SH_OP,OP_MASK_OP);
- printf("if (num == 0x00) num = (%d + ((instruction >> %d) & 0x%08X));\n",(OP_MASK_OP + 1),OP_SH_SPEC,OP_MASK_SPEC);
- printf("else if (num == 0x01) num = (%d + ((instruction >> %d) & 0x%08X));\n",((OP_MASK_OP + 1) + (OP_MASK_SPEC + 1)),OP_SH_RT,OP_MASK_RT);
- printf("else if (num == 0x11) num = (%d + ((instruction >> %d) & 0x%08X));\n",((OP_MASK_OP + 1) + (OP_MASK_SPEC + 1) + (OP_MASK_RT + 1)),OP_SH_SPEC,OP_MASK_SPEC);
- printf("else if (num == 0x13) num = (%d + ((instruction >> %d) & 0x%08X));\n",((OP_MASK_OP + 1) + (OP_MASK_SPEC + 1) + (OP_MASK_RT + 1) + (OP_MASK_SPEC + 1)),OP_SH_SPEC,OP_MASK_SPEC);
- printf("/* Total possible switch entries: %d */\n",((OP_MASK_OP + 1) + (OP_MASK_SPEC + 1) + (OP_MASK_RT + 1) + (OP_MASK_SPEC + 1) + (OP_MASK_SPEC + 1))) ;
+ {
+ int limit;
+ printf("int num = ((instruction >> %d) & 0x%08X);\n",OP_SH_OP,OP_MASK_OP);
+ limit = (OP_MASK_OP + 1);
+ printf("if (num == 0x00) num = (%d + ((instruction >> %d) & 0x%08X));\n",limit,OP_SH_SPEC,OP_MASK_SPEC);
+ limit += (OP_MASK_SPEC + 1);
+ printf("else if (num == 0x01) num = (%d + ((instruction >> %d) & 0x%08X));\n",limit,OP_SH_RT,OP_MASK_RT);
+ limit += (OP_MASK_RT + 1);
+ printf("else if (num == 0x11) {\n");
+ printf(" if ((instruction & (0x%08X << %d)) == 0x%08X)\n",OP_MASK_COP1NORM,OP_SH_COP1NORM,(OP_MASK_COP1NORM << OP_SH_COP1NORM));
+ printf(" if ((instruction & (0x%08X << %d)) == 0x%08X)\n",OP_MASK_COP1CMP,OP_SH_COP1CMP,(OP_MASK_COP1CMP << OP_SH_COP1CMP));
+ printf(" num = (%d + ((instruction >> %d) & 0x%08X));\n",limit,OP_SH_SPEC,(OP_MASK_SPEC & (OP_MASK_COP1CMP << OP_SH_COP1CMP)));
+ printf(" else\n");
+ printf(" num = (%d + ((instruction >> %d) & 0x%08X));\n",limit,OP_SH_SPEC,OP_MASK_SPEC);
+ limit += (OP_MASK_SPEC + 1);
+ printf(" else\n");
+ /* To keep this code quick, we just clear out the "to" bit
+ here. The proper (though slower) code would be to have another
+ conditional, checking whether this instruction is a branch or
+ not, before limiting the range to the bottom two bits of the
+ move operation. */
+ printf(" num = (%d + (((instruction >> %d) & 0x%08X) & ~0x%08X));\n",limit,OP_SH_COP1SPEC,OP_MASK_COP1SPEC,OP_MASK_COP1SCLR);
+ limit += (OP_MASK_COP1SPEC + 1);
+ printf("} else if (num == 0x13) num = (%d + ((instruction >> %d) & 0x%08X));\n",limit,OP_SH_SPEC,OP_MASK_SPEC);
+ limit += (OP_MASK_SPEC + 1);
+ printf("/* Total possible switch entries: %d */\n",limit) ;
+ }
printf("switch (num)\n") ;
printf("{\n");
valid, before checking if the instruction matches any of the
architecture specific flags. NOTE: We allow a selected ISA of
zero to be used to match all standard instructions. */
- if (((((MIPS_DECODE[loop].isa & MASK_ISA) <= doisa) || (doisa == 0)) && (((MIPS_DECODE[loop].isa & ~MASK_ISA) == 0) || ((MIPS_DECODE[loop].isa & ~MASK_ISA) & doarch) != 0)) && (!(MIPS_DECODE[loop].flags & FP) || ((MIPS_DECODE[loop].flags & FP) && dofp))) {
+ if ((((MIPS_DECODE[loop].isa & MASK_ISA) <= doisa) && (((MIPS_DECODE[loop].isa & ~MASK_ISA) == 0) || ((MIPS_DECODE[loop].isa & ~MASK_ISA) & doarch) != 0)) && (!(MIPS_DECODE[loop].flags & FP) || ((MIPS_DECODE[loop].flags & FP) && dofp))) {
unsigned int onemask;
unsigned int zeromask;
unsigned int dontmask;
number = (((OP_MASK_OP + 1) + (OP_MASK_SPEC + 1) + (OP_MASK_RT + 1)) + ((onemask >> OP_SH_SPEC) & OP_MASK_SPEC)) ;
break ;
+ case COP1S :
+ mask = ((OP_MASK_OP << OP_SH_OP) | (OP_MASK_COP1SPEC << OP_SH_COP1SPEC)) ;
+ number = (((OP_MASK_OP + 1) + (OP_MASK_SPEC + 1) + (OP_MASK_RT + 1) + (OP_MASK_SPEC + 1)) + ((onemask >> OP_SH_COP1SPEC) & OP_MASK_COP1SPEC)) ;
+ break;
+
case COP1X :
mask = ((OP_MASK_OP << OP_SH_OP) | (OP_MASK_SPEC << OP_SH_SPEC)) ;
- number = (((OP_MASK_OP + 1) + (OP_MASK_SPEC + 1) + (OP_MASK_RT + 1) + (OP_MASK_SPEC + 1)) + ((onemask >> OP_SH_SPEC) & OP_MASK_SPEC)) ;
+ number = (((OP_MASK_OP + 1) + (OP_MASK_SPEC + 1) + (OP_MASK_RT + 1) + (OP_MASK_COP1SPEC + 1) + (OP_MASK_SPEC + 1)) + ((onemask >> OP_SH_SPEC) & OP_MASK_SPEC)) ;
break ;
default :
just raise a warning. NOTE: This is a different check to the
later decoding, which checks for the final address being
valid. */
- if ((flags & (fieldval('e') | fieldval('w') | fieldval('h'))) && ((doisa == 4) || (doisa == 0))) {
+ if ((flags & (fieldval('e') | fieldval('w') | fieldval('h'))) && (doisa >= 4)) {
printf(" if (instruction & 0x%1X)\n",((flags & fieldval('e')) ? 0x7 : ((flags & fieldval('w')) ? 0x3 : 0x1)));
printf(" {\n");
/* NOTE: If we change this to a SignalException(), we must
#endif
/* The extended condition codes only appeared in ISA IV */
- if ((flags & fieldval('p')) && ((doisa < 4) && (doisa != 0))) {
+ if ((flags & fieldval('p')) && (doisa < 4)) {
printf(" if (condition_code != 0)\n");
printf(" {\n");
printf(" SignalException(ReservedInstruction,instruction);\n");
exit(1);
}
+#if 1
+ /* The R4000 book differs slightly from the MIPS IV ISA
+ manual. An example is the sign-extension of a 64-bit processor
+ SUBU operation, and what is meant by an Undefined Result. This
+ is now provided purely as a warning. After examining a HW
+ implementation, this is now purely a warning... and the actual
+ operation is performed, with possibly undefined results. */
+ if (((MIPS_DECODE[loop].flags & WORD32) && proc64) && (features & FEATURE_WARN_RESULT)) {
+ /* The compiler should optimise out an OR with zero */
+ printf(" if (%s | %s)\n",((flags & fieldval('s')) ? "NOTWORDVALUE(op1)" : "0"),((flags & fieldval('g')) ? "NOTWORDVALUE(op2)" : "0"));
+ printf(" UndefinedResult();\n") ;
+ }
+#else
/* Check that the source is a 32bit value */
if ((MIPS_DECODE[loop].flags & WORD32) && proc64) {
- /* This relies on the compiler optimising out an OR with zero */
+ /* The compiler should optimise out an OR with zero */
printf(" if (%s | %s)\n",((flags & fieldval('s')) ? "NOTWORDVALUE(op1)" : "0"),((flags & fieldval('g')) ? "NOTWORDVALUE(op2)" : "0"));
printf(" UndefinedResult();\n") ;
printf(" else\n") ;
}
+#endif
printf(" {\n") ;
switch (MIPS_DECODE[loop].type) {
/* TODO: To make these easier to edit and maintain, they should
actually be provided as source macros (or inline functions)
- OUTSIDE this main switch statement. */
+ OUTSIDE this main switch statement. The PPC simulator has a
+ neater scheme for describing the instruction sequences. */
case ADD:
- case SUB :
+ case SUB:
{
char *basetype = "unknown";
switch (GETDATASIZE()) {
basetype = "long long";
break;
default :
- fprintf(stderr,"Opcode table error: size of SUB operands not known (%d)\n",GETDATASIZE());
+ fprintf(stderr,"Opcode table error: size of ADD/SUB operands not known (%d)\n",GETDATASIZE());
exit(1);
}
if ((MIPS_DECODE[loop].type) == ADD) {
printf(" unsigned %s temp = (unsigned %s)(op1 + op2);\n",basetype,basetype);
printf(" signed %s tempS = (signed %s)temp;\n",basetype,basetype);
- printf(" if (((op1 < 0) == (op2 < 0)) && ((tempS < 0) != (op1 < 0)))\n");
- printf(" SignalException(IntegerOverflow);\n");
- printf(" else\n");
+ if (MIPS_DECODE[loop].flags & OVERFLOW) {
+ printf(" if (((op1 < 0) == (op2 < 0)) && ((tempS < 0) != (op1 < 0)))\n");
+ printf(" SignalException(IntegerOverflow);\n");
+ printf(" else\n");
+ }
if (!proc64 || (MIPS_DECODE[loop].flags & UNSIGNED) || (GETDATASIZE() == DOUBLEWORD))
printf(" GPR[destreg] = (%s)temp;\n",regtype);
else /* only sign-extend when placing 32bit result in 64bit processor */
}
break ;
- case MUL :
+ case MUL:
if (features & FEATURE_WARN_LOHI) {
printf(" CHECKHILO(\"Multiplication\");\n");
}
printf(" }\n");
break ;
- case DIV :
+ case DIV:
{
int boolU = (MIPS_DECODE[loop].flags & UNSIGNED);
}
break ;
- case SHIFT :
+ case SHIFT:
{
int datalen = GETDATASIZE();
int bits = ((datalen == WORD) ? 32 : 64);
if (MIPS_DECODE[loop].flags & HI32)
printf(" op1 |= (1 << 6);\n");
- /* TODO: We should not need to perform the pre-masking with
- 0xFFFFFFFF when shifting left. The sign-extension code (if
- required) will replace any remaining hi-bits. */
- printf(" GPR[destreg] = ((unsigned long long)(op2%s) %s op1);\n",((bits == 32) ? " & 0xFFFFFFFF" : ""),((MIPS_DECODE[loop].flags & LEFT) ? "<<" : ">>"));
+ /* We do not need to perform pre-masking with 0xFFFFFFFF when
+ dealing with 32bit shift lefts, since the sign-extension
+ code will replace any remaining hi-bits: */
+ if (MIPS_DECODE[loop].flags & LEFT)
+ printf(" GPR[destreg] = ((unsigned long long)op2 << op1);\n");
+ else
+ printf(" GPR[destreg] = ((unsigned long long)(op2%s) >> op1);\n",((bits == 32) ? " & 0xFFFFFFFF" : ""));
/* For ARITHMETIC shifts, we must duplicate the sign-bit */
if (MIPS_DECODE[loop].flags & ARITHMETIC)
}
break ;
- case MOVE :
+ case MOVE:
if (MIPS_DECODE[loop].flags & (HI | LO)) {
char *regname = ((MIPS_DECODE[loop].flags & LO) ? "LO" : "HI");
if (flags & fieldval('d'))
}
break ;
- case SYNC :
+ case SYNC:
printf(" SyncOperation(op1);\n");
break ;
- case SYSCALL :
+ case SYSCALL:
printf(" SignalException(SystemCall);\n");
break ;
- case BREAK :
+ case BREAK:
printf(" SignalException(BreakPoint);\n");
break ;
- case TRAP :
+ case TRAP:
{
int boolNOT = (MIPS_DECODE[loop].flags & NOT);
int boolEQ = (MIPS_DECODE[loop].flags & EQ);
}
break ;
- case SET :
+ case SET:
{
int boolU = (MIPS_DECODE[loop].flags & UNSIGNED);
}
break ;
- case AND :
+ case AND:
printf(" GPR[destreg] = (op1 & op2);\n");
break ;
- case OR :
+ case OR:
printf(" GPR[destreg] = (%sop1 | op2);\n",((MIPS_DECODE[loop].flags & NOT) ? "~" : ""));
break ;
- case XOR :
+ case XOR:
printf(" GPR[destreg] = (op1 ^ op2);\n");
break ;
- case DECODE :
+ case DECODE:
printf(" decode_coproc(instruction);\n");
break ;
- case CACHE :
+ case CACHE:
/* 16-bit offset is sign-extended and added to the base register to make a virtual address */
/* The virtual address is translated to a physical address using the TLB */
/* The hint specifies a cache operation for that address */
printf(" CacheOp(hint,vaddr,paddr,instruction);\n");
break;
- case MADD16 : /* VR4100 specific multiply-add instructions */
+ case MADD16: /* VR4100 specific multiply-add instructions */
/* Some of this code is shared with the standard multiply
routines, so an effort should be made to merge where
possible. */
printf(" }\n");
break;
- case RSVD : /* "Reserved Instruction" on MIPS IV, or if co-proc 3 absent. Otherwise "CoProcessorUnusable" */
- if ((doisa < 4) && (doisa != 0)) {
+ case RSVD: /* "Reserved Instruction" on MIPS IV, or if co-proc 3 absent. Otherwise "CoProcessorUnusable" */
+ if (doisa < 4) {
printf(" if (CoProcPresent(3))\n");
printf(" SignalException(CoProcessorUnusable);\n");
printf(" else\n");
printf(" SignalException(ReservedInstruction,instruction);\n");
break ;
- case JUMP :
+ case JUMP:
if (MIPS_DECODE[loop].flags & LINK) {
if (!(MIPS_DECODE[loop].flags & REG))
printf(" int destreg = 31;\n");
printf(" DELAYSLOT();\n");
break ;
- case BRANCH : /* execute delay slot instruction before branch unless (LIKELY && branch_not_taken) */
- if ((MIPS_DECODE[loop].flags & NOT) && !(MIPS_DECODE[loop].flags & EQ)) {
- fprintf(stderr,"NOT specified when not EQ in \"%s\"\n",MIPS_DECODE[loop].name);
- exit(7);
+ case BRANCH: /* execute delay slot instruction before branch unless (LIKELY && branch_not_taken) */
+ if (MIPS_DECODE[loop].flags & FP) {
+ if (doisa < 4) {
+ printf(" if (condition_code != 0)\n");
+ printf(" SignalException(ReservedInstruction,instruction);\n");
+ printf(" else {\n");
+ }
+ /* "PREVCOC1()" should be the COC1 value at the start of the preceding instruction */
+ printf(" int condition = (%s == boolean);\n",((doisa < 4) ? "PREVCOC1()" : "GETFCC(condition_code)"));
+ } else {
+ if ((MIPS_DECODE[loop].flags & NOT) && !(MIPS_DECODE[loop].flags & EQ)) {
+ fprintf(stderr,"NOT specified when not EQ in \"%s\"\n",MIPS_DECODE[loop].name);
+ exit(7);
+ }
+ if ((MIPS_DECODE[loop].flags & NOT) && (MIPS_DECODE[loop].flags & (GT | LT))) {
+ fprintf(stderr,"NOT specified with GT or LT in \"%s\"\n",MIPS_DECODE[loop].name);
+ exit(7);
+ }
+ /* GT LT */
+ if (MIPS_DECODE[loop].flags & GT)
+ printf(" int condition = (op1 >%s 0);\n",((MIPS_DECODE[loop].flags & EQ) ? "=" : ""));
+ else
+ if (MIPS_DECODE[loop].flags & LT)
+ printf(" int condition = (op1 <%s 0);\n",((MIPS_DECODE[loop].flags & EQ) ? "=" : ""));
+ else
+ if (MIPS_DECODE[loop].flags & EQ)
+ printf(" int condition = (op1 %c= op2);\n",((MIPS_DECODE[loop].flags & NOT) ? '!' : '='));
}
- if ((MIPS_DECODE[loop].flags & NOT) && (MIPS_DECODE[loop].flags & (GT | LT))) {
- fprintf(stderr,"NOT specified with GT or LT in \"%s\"\n",MIPS_DECODE[loop].name);
- exit(7);
- }
-
- /* GT LT */
- if (MIPS_DECODE[loop].flags & GT)
- printf(" int condition = (op1 >%s 0);\n",((MIPS_DECODE[loop].flags & EQ) ? "=" : ""));
- else
- if (MIPS_DECODE[loop].flags & LT)
- printf(" int condition = (op1 <%s 0);\n",((MIPS_DECODE[loop].flags & EQ) ? "=" : ""));
- else
- if (MIPS_DECODE[loop].flags & EQ)
- printf(" int condition = (op1 %c= op2);\n",((MIPS_DECODE[loop].flags & NOT) ? '!' : '='));
if (MIPS_DECODE[loop].flags & LINK) {
if (features & FEATURE_WARN_R31) {
printf(" DSPC = (PC + offset);\n");
printf(" DELAYSLOT();\n");
printf(" }\n");
- if (MIPS_DECODE[loop].flags & LIKELY) {
+ if ((MIPS_DECODE[loop].flags & FP) && (doisa != 1)) {
+ printf(" else if (likely) {\n");
+ printf(" NULLIFY();\n");
+ printf(" }\n");
+ } else if (MIPS_DECODE[loop].flags & LIKELY) {
printf(" else\n");
printf(" NULLIFY();\n");
}
+ if ((MIPS_DECODE[loop].flags & FP) && (doisa < 4))
+ printf(" }\n");
break ;
- /* TODO: After writing the main pass through this memory
- transfer block, quite a few bugs were discovered, and fixed
- in situ. This code should be gone through and tidied and
- optimised. */
- case PREFETCH : /* The beginning is shared with normal load operations */
- case LOAD :
- case STORE :
+ case PREFETCH: /* The beginning is shared with normal load operations */
+ case LOAD:
+ case STORE:
{
int isload = ((MIPS_DECODE[loop].type == LOAD) || (MIPS_DECODE[loop].type == PREFETCH));
int datalen;
break ;
}
- printf(" uword64 vaddr = ((unsigned long long)op1 + offset);\n");
+ if (MIPS_DECODE[loop].flags & REG)
+ printf(" uword64 vaddr = ((unsigned long long)op1 + op2);\n");
+ else
+ printf(" uword64 vaddr = ((unsigned long long)op1 + offset);\n");
printf(" uword64 paddr;\n");
printf(" int uncached;\n");
printf(" {\n");
printf(" %s memval;\n",(proc64 ? "uword64" : "unsigned int"));
- if (MIPS_DECODE[loop].flags & COPROC) {
- if ((datalen != 4) && (datalen != 8)) {
- fprintf(stderr,"Co-processor operation not WORD or DOUBLEWORD in length \"%s\"\n",MIPS_DECODE[loop].name);
- exit(6);
- }
+ if ((MIPS_DECODE[loop].flags & COPROC) && ((datalen != 4) && (datalen != 8))) {
+ fprintf(stderr,"Co-processor transfer operation not WORD or DOUBLEWORD in length \"%s\"\n",MIPS_DECODE[loop].name);
+ exit(6);
+ }
- if (isload) {
- printf(" memval = LoadMemory(uncached,%s,paddr,vaddr,isDATA,isREAL);\n",accesslength);
- /* NOTE: The R4000 user manual has the COP_LW occuring
- in the same cycle as the rest of the instruction,
- yet the MIPS IV shows the operation happening on the
- next cycle. To keep the simulator simple, this code
- follows the R4000 manual. Experimentation with a
- silicon implementation will be needed to ascertain
- the correct operation. */
- printf(" COP_L%c(((instruction >> 26) & 0x3),destreg,memval);\n",((datalen == 8) ? 'D' : 'W'));
- } else {
- printf(" memval = COP_S%c(((instruction >> 26) & 0x3),destreg);\n",((datalen == 8) ? 'D' : 'W'));
- printf(" StoreMemory(uncached,%s,memval,paddr,vaddr,isREAL);\n",accesslength);
+ if (MIPS_DECODE[loop].flags & (LEFT | RIGHT)) {
+ if ((MIPS_DECODE[loop].flags & LEFT) && (MIPS_DECODE[loop].flags & RIGHT)) {
+ fprintf(stderr,"Memory transfer with both LEFT and RIGHT specified \"%s\"\n",MIPS_DECODE[loop].name);
+ exit(4);
}
- } else
- if (MIPS_DECODE[loop].flags & (LEFT | RIGHT)) {
- if ((MIPS_DECODE[loop].flags & LEFT) && (MIPS_DECODE[loop].flags & RIGHT)) {
- fprintf(stderr,"Memory transfer with both LEFT and RIGHT specified \"%s\"\n",MIPS_DECODE[loop].name);
- exit(4);
- }
- switch (datalen) {
- case 8 :
- if (!proc64) {
- fprintf(stderr,"DOUBLEWORD shifted memory transfers only valid for 64-bit processors \"%s\"\n",MIPS_DECODE[loop].name);
- exit(4);
+ switch (datalen) {
+ case 8:
+ if (!proc64) {
+ fprintf(stderr,"DOUBLEWORD shifted memory transfers only valid for 64-bit processors \"%s\"\n",MIPS_DECODE[loop].name);
+ exit(4);
+ }
+ /* fall through to... */
+ case 4:
+ {
+ char *maskstr = ((datalen == 8) ? "((uword64)-1)" : "0xFFFFFFFF");
+
+ printf(" uword64 mask = %d;\n",((datalen == 8) ? 0x7 : 0x3));
+ printf(" unsigned int reverse = (ReverseEndian ? mask : 0);\n");
+ printf(" unsigned int bigend = (BigEndianCPU ? mask : 0);\n");
+ printf(" int byte;\n");
+ printf(" paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverse));\n");
+ printf(" byte = ((vaddr & mask) ^ bigend);\n");
+ printf(" if (%sBigEndianMem)\n",((MIPS_DECODE[loop].flags & LEFT) ? "!" : ""));
+ printf(" paddr &= ~mask;\n");
+
+ if (isload) {
+ if (MIPS_DECODE[loop].flags & LEFT)
+ printf(" memval = LoadMemory(uncached,byte,paddr,vaddr,isDATA,isREAL);\n");
+ else
+ printf(" memval = LoadMemory(uncached,(%d - byte),paddr,vaddr,isDATA,isREAL);\n",(datalen - 1));
}
- /* fall through to... */
- case 4 :
- {
- char *maskstr = ((datalen == 8) ? "((uword64)-1)" : "0xFFFFFFFF");
-
- printf(" uword64 mask = %d;\n",((datalen == 8) ? 0x7 : 0x3));
- printf(" unsigned int reverse = (ReverseEndian ? mask : 0);\n");
- printf(" unsigned int bigend = (BigEndianCPU ? mask : 0);\n");
- printf(" int byte;\n");
- printf(" paddr = ((paddr & ~mask) | ((paddr & mask) ^ reverse));\n");
- printf(" byte = ((vaddr & mask) ^ bigend);\n");
- printf(" if (%sBigEndianMem)\n",((MIPS_DECODE[loop].flags & LEFT) ? "!" : ""));
- printf(" paddr &= ~mask;\n");
+ if (MIPS_DECODE[loop].flags & LEFT) {
if (isload) {
- if (MIPS_DECODE[loop].flags & LEFT)
- printf(" memval = LoadMemory(uncached,byte,paddr,vaddr,isDATA,isREAL);\n");
- else
- printf(" memval = LoadMemory(uncached,(%d - byte),paddr,vaddr,isDATA,isREAL);\n",(datalen - 1));
- }
-
- if (MIPS_DECODE[loop].flags & LEFT) {
- if (isload) {
- /* For WORD transfers work out if the value
- will be in the top or bottom of the
- DOUBLEWORD returned: */
- if (proc64 && (datalen == 4)) {
- printf(" if ((vaddr & (1 << 2)) ^ (BigEndianCPU << 2)) {\n");
- printf(" memval >>= 32;\n");
- printf(" }\n");
- }
- printf(" GPR[destreg] = ((memval << ((%d - byte) * 8)) | (GPR[destreg] & (((uword64)1 << ((%d - byte) * 8)) - 1)));\n",(datalen - 1),(datalen - 1));
- if (proc64 && (datalen == 4))
- printf(" GPR[destreg] = SIGNEXTEND(GPR[destreg],32);\n");
- } else { /* store */
- printf(" memval = (op2 >> (8 * (%d - byte)));\n",(datalen - 1));
- /* TODO: This is duplicated in the LOAD code
- above - and the RIGHT LOAD and STORE code
- below. It should be merged if possible. */
- if (proc64 && (datalen == 4)) {
- printf(" if ((vaddr & (1 << 2)) ^ (BigEndianCPU << 2)) {\n");
- printf(" memval <<= 32;\n");
- printf(" }\n");
- }
- printf(" StoreMemory(uncached,byte,memval,paddr,vaddr,isREAL);\n");
+ /* For WORD transfers work out if the value will
+ be in the top or bottom of the DOUBLEWORD
+ returned: */
+ if (proc64 && (datalen == 4)) {
+ printf(" if ((vaddr & (1 << 2)) ^ (BigEndianCPU << 2)) {\n");
+ printf(" memval >>= 32;\n");
+ printf(" }\n");
+ }
+ printf(" GPR[destreg] = ((memval << ((%d - byte) * 8)) | (GPR[destreg] & (((uword64)1 << ((%d - byte) * 8)) - 1)));\n",(datalen - 1),(datalen - 1));
+ if (proc64 && (datalen == 4))
+ printf(" GPR[destreg] = SIGNEXTEND(GPR[destreg],32);\n");
+ } else { /* store */
+ printf(" memval = (op2 >> (8 * (%d - byte)));\n",(datalen - 1));
+ /* TODO: This is duplicated in the LOAD code
+ above - and the RIGHT LOAD and STORE code
+ below. It should be merged if possible. */
+ if (proc64 && (datalen == 4)) {
+ printf(" if ((vaddr & (1 << 2)) ^ (BigEndianCPU << 2)) {\n");
+ printf(" memval <<= 32;\n");
+ printf(" }\n");
}
- } else { /* RIGHT */
- if (isload) {
- if (proc64 && (datalen == 4)) {
- printf(" if ((vaddr & (1 << 2)) ^ (BigEndianCPU << 2)) {\n");
- printf(" memval >>= 32;\n");
- printf(" }\n");
- }
- printf(" {\n");
- printf(" uword64 srcmask;\n");
- /* All of this extra code is just a bodge
- required because some hosts don't allow ((v) << 64).
- The SPARC just leaves the (v) value un-touched. */
- printf(" if (byte == 0)\n");
- printf(" srcmask = 0;\n");
- printf(" else\n");
- printf(" srcmask = ((uword64)-1 << (8 * (%d - byte)));\n",datalen);
- printf(" GPR[destreg] = ((GPR[destreg] & srcmask) | (memval >> (8 * byte)));\n",datalen);
- printf(" }\n");
- if (proc64 && (datalen == 4))
- printf(" GPR[destreg] = SIGNEXTEND(GPR[destreg],32);\n");
- } else { /* store */
- printf(" memval = (op2 << (byte * 8));\n");
- printf(" StoreMemory(uncached,(%s - byte),memval,paddr,vaddr,isREAL);\n",accesslength);
+ printf(" StoreMemory(uncached,byte,memval,paddr,vaddr,isREAL);\n");
+ }
+ } else { /* RIGHT */
+ if (isload) {
+ if (proc64 && (datalen == 4)) {
+ printf(" if ((vaddr & (1 << 2)) ^ (BigEndianCPU << 2)) {\n");
+ printf(" memval >>= 32;\n");
+ printf(" }\n");
}
+ printf(" {\n");
+ printf(" uword64 srcmask;\n");
+ /* All of this extra code is just a bodge
+ required because some hosts don't allow
+ ((v) << 64). The SPARC just leaves the (v)
+ value un-touched. */
+ printf(" if (byte == 0)\n");
+ printf(" srcmask = 0;\n");
+ printf(" else\n");
+ printf(" srcmask = ((uword64)-1 << (8 * (%d - byte)));\n",datalen);
+ printf(" GPR[destreg] = ((GPR[destreg] & srcmask) | (memval >> (8 * byte)));\n",datalen);
+ printf(" }\n");
+ if (proc64 && (datalen == 4))
+ printf(" GPR[destreg] = SIGNEXTEND(GPR[destreg],32);\n");
+ } else { /* store */
+ printf(" memval = (op2 << (byte * 8));\n");
+ printf(" StoreMemory(uncached,(%s - byte),memval,paddr,vaddr,isREAL);\n",accesslength);
}
}
- break;
-
- default :
- fprintf(stderr,"Shifted memory transfer not WORD or DOUBLEWORD in length \"%s\"\n",MIPS_DECODE[loop].name);
- exit(6);
}
- } else { /* normal memory transfer */
- if (((datalen == 8) || ((datalen == 4) & MIPS_DECODE[loop].flags & UNSIGNED)) && !proc64) {
- fprintf(stderr,"Operation not available with 32bit wide memory access \"%s\"\n",MIPS_DECODE[loop].name);
- exit(4);
- /* TODO: The R4000 documentation suggests the LWU
- executed when in 32bit processor mode should cause
- a ReservedInstruction exception. This will mean
- adding a run-time check into the code sequence. */
- }
-
- if (isload) {
- printf(" uword64 mask = %d;\n",(proc64 ? 0x7 : 0x3));
- printf(" unsigned int shift = %d;\n",(datalen >> 1));
- printf(" unsigned int reverse = (ReverseEndian ? (mask >> shift) : 0);\n");
- printf(" unsigned int bigend = (BigEndianCPU ? (mask >> shift) : 0);\n");
- printf(" unsigned int byte;\n");
+ break;
- if (datalen != 8) /* not for DOUBLEWORD */
- printf(" paddr = ((paddr & ~mask) | ((paddr & mask) ^ (reverse << shift)));\n");
+ default:
+ fprintf(stderr,"Shifted memory transfer not WORD or DOUBLEWORD in length \"%s\"\n",MIPS_DECODE[loop].name);
+ exit(6);
+ }
+ } else { /* normal memory transfer */
+ if (((datalen == 8) || ((datalen == 4) & (MIPS_DECODE[loop].flags & UNSIGNED))) && !proc64) {
+ fprintf(stderr,"Operation not available with 32bit wide memory access \"%s\"\n",MIPS_DECODE[loop].name);
+ exit(4);
+ /* TODO: The R4000 documentation states that a LWU
+ instruction executed when in a 32bit processor mode
+ should cause a ReservedInstruction exception. This
+ will mean adding a run-time check into the code
+ sequence. */
+ }
- printf(" memval = LoadMemory(uncached,%s,paddr,vaddr,isDATA,isREAL);\n",accesslength);
+ if (isload) {
+ printf(" uword64 mask = %d;\n",(proc64 ? 0x7 : 0x3));
+ printf(" unsigned int shift = %d;\n",(datalen >> 1));
+ printf(" unsigned int reverse = (ReverseEndian ? (mask >> shift) : 0);\n");
+ printf(" unsigned int bigend = (BigEndianCPU ? (mask >> shift) : 0);\n");
+ printf(" unsigned int byte;\n");
- /* The following will only make sense if the "LoadMemory" above returns a DOUBLEWORD entity */
- if (datalen != 8) { /* not for DOUBLEWORD */
- int valmask;
- switch (datalen) {
- case 1 :
- valmask = 0xFF;
- break;
+ if (datalen != 8) /* not for DOUBLEWORD */
+ printf(" paddr = ((paddr & ~mask) | ((paddr & mask) ^ (reverse << shift)));\n");
- case 2 :
- valmask = 0xFFFF;
- break;
+ printf(" memval = LoadMemory(uncached,%s,paddr,vaddr,isDATA,isREAL);\n",accesslength);
- case 4 :
- valmask = 0xFFFFFFFF;
- break;
+ /* The following will only make sense if the
+ "LoadMemory" above returns a DOUBLEWORD entity */
+ if (datalen != 8) { /* not for DOUBLEWORD */
+ int valmask;
+ switch (datalen) {
+ case 1:
+ valmask = 0xFF;
+ break;
+
+ case 2:
+ valmask = 0xFFFF;
+ break;
+
+ case 4:
+ valmask = 0xFFFFFFFF;
+ break;
+
+ default:
+ fprintf(stderr,"Unrecognised datalen (%d) when processing \"%s\"\n",datalen,MIPS_DECODE[loop].name);
+ exit(4);
+ }
+ printf(" byte = ((vaddr & mask) ^ (bigend << shift));\n");
+ /* NOTE: The R4000 user manual has the COP_LW
+ occuring in the same cycle as the rest of the
+ instruction, yet the MIPS IV shows the operation
+ happening on the next cycle. To keep the simulator
+ simple, this code follows the R4000
+ manual. Experimentation with a silicon
+ implementation will be needed to ascertain the
+ correct operation. */
+ if (MIPS_DECODE[loop].flags & COPROC)
+ printf(" COP_LW(((instruction >> 26) & 0x3),destreg,(unsigned int)");
+ else
+ printf(" GPR[destreg] = (");
+
+ if (MIPS_DECODE[loop].flags & SIGNEXTEND)
+ printf("SIGNEXTEND(");
+ printf("((memval >> (8 * byte)) & 0x%08X)",valmask);
+ if (MIPS_DECODE[loop].flags & SIGNEXTEND)
+ printf(",%d)",(datalen * 8));
+ printf(");\n");
+ } else {
+ if (MIPS_DECODE[loop].flags & COPROC)
+ printf(" COP_LD(((instruction >> 26) & 0x3),destreg,memval);;\n");
+ else
+ printf(" GPR[destreg] = memval;\n");
+ }
+ } else { /* store operation */
+ if ((datalen == 1) || (datalen == 2)) {
+ /* SH and SB */
+ printf(" uword64 mask = %d;\n",(proc64 ? 0x7 : 0x3));
+ printf(" unsigned int shift = %d;\n",(datalen >> 1));
+ printf(" unsigned int reverse = (ReverseEndian ? (mask >> shift) : 0);\n");
+ printf(" unsigned int bigend = (BigEndianCPU ? (mask >> shift) : 0);\n");
+ printf(" unsigned int byte;\n");
- default :
- fprintf(stderr,"Unrecognised datalen (%d) when processing \"%s\"\n",datalen,MIPS_DECODE[loop].name);
- exit(4);
- }
- printf(" byte = ((vaddr & mask) ^ (bigend << shift));\n");
- printf(" GPR[destreg] = ");
- if (MIPS_DECODE[loop].flags & SIGNEXTEND)
- printf("SIGNEXTEND(");
- printf("((memval >> (8 * byte)) & 0x%08X)",valmask);
- if (MIPS_DECODE[loop].flags & SIGNEXTEND)
- printf(",%d)",(datalen * 8));
- printf(";\n");
- } else
- printf(" GPR[destreg] = memval;\n");
- } else { /* store operation */
- if ((datalen == 1) || (datalen == 2)) {
- /* SH and SB */
- printf(" uword64 mask = %d;\n",(proc64 ? 0x7 : 0x3));
- printf(" unsigned int shift = %d;\n",(datalen >> 1));
- printf(" unsigned int reverse = (ReverseEndian ? (mask >> shift) : 0);\n");
- printf(" unsigned int bigend = (BigEndianCPU ? (mask >> shift) : 0);\n");
+ printf(" paddr = ((paddr & ~mask) | ((paddr & mask) ^ (reverse << shift)));\n");
+ printf(" byte = ((vaddr & mask) ^ (bigend << shift));\n");
+ printf(" memval = (op2 << (8 * byte));\n");
+ } else
+ if (proc64 && (datalen == 4)) { /* proc64 SC and SW */
printf(" unsigned int byte;\n");
-
- printf(" paddr = ((paddr & ~mask) | ((paddr & mask) ^ (reverse << shift)));\n");
- printf(" byte = ((vaddr & mask) ^ (bigend << shift));\n");
- printf(" memval = (op2 << (8 * byte));\n");
- } else
- if (proc64 && (datalen == 4)) { /* proc64 SC and SW */
- printf(" unsigned int byte;\n");
- printf(" paddr = ((paddr & ~0x7) | ((paddr & 0x7) ^ (ReverseEndian << 2)));\n");
- printf(" byte = ((vaddr & 0x7) ^ (BigEndianCPU << 2));\n");
+ printf(" paddr = ((paddr & ~0x7) | ((paddr & 0x7) ^ (ReverseEndian << 2)));\n");
+ printf(" byte = ((vaddr & 0x7) ^ (BigEndianCPU << 2));\n");
+ if (MIPS_DECODE[loop].flags & COPROC)
+ printf(" memval = (((unsigned long long)COP_SW(((instruction >> 26) & 0x3),%s)) << (8 * byte));\n",((MIPS_DECODE[loop].flags & FP) ? "fs" : "destreg"));
+ else
printf(" memval = (op2 << (8 * byte));\n");
- } else /* !proc64 SC and SW, plus proc64 SD and SCD */
- printf(" memval = op2;\n");
-
- if (MIPS_DECODE[loop].flags & ATOMIC)
- printf(" if (LLBIT)\n");
-
- printf(" {\n");
- printf(" StoreMemory(uncached,%s,memval,paddr,vaddr,isREAL);\n",accesslength);
- printf(" }\n");
- }
+ } else { /* !proc64 SC and SW, plus proc64 SD and SCD */
+ if (MIPS_DECODE[loop].flags & COPROC)
+ printf(" memval = (unsigned long long)COP_S%c(((instruction >> 26) & 0x3),%s);\n",((datalen == 8) ? 'D' : 'W'),((MIPS_DECODE[loop].flags & FP) ? "fs" : "destreg"));
+ else
+ printf(" memval = op2;\n");
+ }
+
+ if (MIPS_DECODE[loop].flags & ATOMIC)
+ printf(" if (LLBIT)\n");
+
+ printf(" {\n");
+ printf(" StoreMemory(uncached,%s,memval,paddr,vaddr,isREAL);\n",accesslength);
+ printf(" }\n");
+ }
- if (MIPS_DECODE[loop].flags & ATOMIC) {
- if ((datalen != 4) && (datalen != 8)) {
- fprintf(stderr,"ATOMIC can only be applied to WORD and DOUBLEWORD instructions \"%s\"\n",MIPS_DECODE[loop].name);
- exit(4);
- } else
- if (isload)
- printf(" LLBIT = 1;\n");
- else {
- /* The documentation states that:
-
- SC *WILL* fail if coherent store into the same
- block occurs, or if an exception occurs between
- the LL and SC instructions.
-
- SC *MAY* fail if a load, store or prefetch is
- executed on the processor (VR4300 doesn't seem
- to), or if the instructions between the LL and
- SC are not in a 2048byte contiguous VM range.
-
- SC *MUST* have been preceded by an LL
- (i.e. LLBIT will be set), and it must use the
- same Vaddr, Paddr and cache-coherence algorithm
- as the LL (which means we should store this
- information from the load-conditional).
- */
- printf(" GPR[(instruction >> %d) & 0x%08X] = LLBIT;\n",OP_SH_RT,OP_MASK_RT);
- }
- }
- }
+ if (MIPS_DECODE[loop].flags & ATOMIC) {
+ if ((datalen != 4) && (datalen != 8)) {
+ fprintf(stderr,"ATOMIC can only be applied to WORD and DOUBLEWORD instructions \"%s\"\n",MIPS_DECODE[loop].name);
+ exit(4);
+ } else
+ if (isload)
+ printf(" LLBIT = 1;\n");
+ else {
+ /* The documentation states that:
+
+ SC *WILL* fail if coherent store into the same
+ block occurs, or if an exception occurs between
+ the LL and SC instructions.
+
+ SC *MAY* fail if a load, store or prefetch is
+ executed on the processor (VR4300 doesn't seem
+ to), or if the instructions between the LL and
+ SC are not in a 2048byte contiguous VM range.
+
+ SC *MUST* have been preceded by an LL
+ (i.e. LLBIT will be set), and it must use the
+ same Vaddr, Paddr and cache-coherence algorithm
+ as the LL (which means we should store this
+ information from the load-conditional).
+ */
+ printf(" GPR[(instruction >> %d) & 0x%08X] = LLBIT;\n",OP_SH_RT,OP_MASK_RT);
+ }
+ }
+ }
printf(" }\n");
}
printf(" }\n");
}
break ;
-/* Following are FP instructions. It may be simpler to provide these
- as explicit function calls, rather than coding explicit simulations
- at this point. This will help keep this generator simpler, at the
- cost of some simulation performance. */
-
- case FPMOVE :
- printf(" printf(\"TODO: FPMOVE operation %s */\\n\");\n",MIPS_DECODE[loop].name) ;
-/*
- MOV - MOV.fmt
- MOVN - MOVN.fmt
- MOV%c - integer <-> integer MOVF and MOVT
- MOV%c - FP <-> FP MOVF.fmt and MOVT.fmt
-*/
+ case FPPREFX:
+ /* This code could be merged with the PREFIX generation above: */
+ printf(" uword64 vaddr = ((unsigned long long)op1 + (unsigned long long)op2);\n");
+ printf(" uword64 paddr;\n");
+ printf(" int uncached;\n");
+ printf(" if (AddressTranslation(vaddr,isDATA,isLOAD,&paddr,&uncached,isTARGET,isREAL))\n");
+ printf(" Prefetch(uncached,paddr,vaddr,isDATA,fs);\n");
break ;
- case FPMAB :
- printf("/* FPMAB */\n");
- printf("if (add) {\n");
- printf(" word64 fpop1 = ValueFPR(hint,format);\n");
- printf(" word64 fpop2 = ValueFPR(destreg,format);\n");
- printf(" StoreFPR(op1,format,(fpop1 + fpop2));\n");
- printf("} else if (branch) {\n");
- printf(" printf(\"TODO: FP Branch support\\n\");\n");
- printf("} else { /* MOVE */\n");
- /* TODO: Since the following is so large - maybe it should be punted to a specific routine */
- printf(" if ((op1 != 0x0) || (format & (1 << 1)))\n");
- printf(" SignalException(ReservedInstruction,instruction);\n");
- printf(" else\n");
- printf(" {\n");
- printf(" int dprec = (format & (1 << 0));\n");
- printf(" int to = (format & (1 << 2));\n");
- printf(" if (dprec)\n");
- printf(" {\n");
- printf(" if (to)\n");
- printf(" {\n");
- if ((doisa < 4) && (doisa != 0))
- {
- printf(" if (SizeFGR() == 64)\n");
- printf(" FGR[destreg] = GPR[hint];\n");
- printf(" else\n");
- printf(" if ((destreg & 0x1) == 0)\n");
- printf(" {\n");
- printf(" FGR[destreg + 1] = (GPR[hint] >> 32);\n");
- printf(" FGR[destreg] = (GPR[hint] & 0xFFFFFFFF);\n");
- printf(" }\n");
- printf(" else\n");
- printf(" UndefinedResult();\n");
- }
- else
- {
- printf("printf(\"TODO .. pending operation for next cycle\\n\");\n");
- }
- printf(" }\n");
- printf(" else\n");
- printf(" {\n");
- if ((doisa < 4) && (doisa != 0))
- {
- printf(" if (SizeFGR() == 64)\n");
- printf(" GPR[hint] = FGR[destreg];\n");
- printf(" else\n");
- printf(" if ((destreg & 0x1) == 0)\n");
- printf(" GPR[hint] = ((FGR[destreg + 1] << 32) | FGR[destreg]);\n");
- printf(" else\n");
- printf(" UndefinedResult();\n");
- }
- else
- {
- printf(" pending_reg = hint;\n");
- printf(" if (SizeFGR() == 64)\n");
- printf(" pending_data = FGR[destreg];\n");
- printf(" else\n");
- printf(" if ((destreg & 0x1) == 0)\n");
- printf(" pending_data = ((FGR[destreg + 1] << 32) | FGR[destreg]);\n");
- printf(" else\n");
- printf(" UndefinedResult();\n");
- }
- printf(" }\n");
- printf(" }\n");
- printf(" else /* single precision */\n");
- printf(" {\n");
- printf(" if (to)\n");
- printf(" {\n");
- if ((doisa < 4) && (doisa != 0))
- {
- printf(" if (SizeFGR() == 64)\n");
- printf(" FGR[destreg] = (0xDEADC0DE | (GPR[hint] & 0xFFFFFFFF));\n");
- printf(" else\n");
- printf(" FGR[destreg] = (GPR[hint] & 0xFFFFFFFF);\n");
- }
- else
- {
- printf(" pending_reg = (FPREG | destreg);\n");
- printf(" if (SizeFGR() == 64)\n");
- printf(" pending_data = (0xDEADC0DE | (GPR[hint] & 0xFFFFFFFF));\n");
- printf(" else\n");
- printf(" pending_data = (GPR[hint] & 0xFFFFFFFF);\n");
- }
- printf(" }\n");
- printf(" else\n");
- if ((doisa ==4) || (doisa == 0)) /* in this cycle */
- {
- printf(" GPR[hint] = SIGNEXTEND(FGR[destreg],32);\n");
- }
- else /* write-back occurs in next cycle */
- {
- printf(" pending_reg = hint;\n");
- printf(" pending_data = SIGNEXTEND(FGR[destreg],32);\n");
- }
- printf(" }\n");
- printf(" }\n");
- printf("}\n");
- break;
-
- case FPFLOOR :
- printf(" printf(\"TODO: FPFLOOR operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
- /* Lots of checks on paramater validity must be performed */
- break ;
-
- case FPCEIL :
- printf(" printf(\"TODO: FPCEIL operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+ case FPMOVEC:
+ if (MIPS_DECODE[loop].flags & CONTROL) {
+ /* The following "magic" of interpreting the FP
+ control-register number would not be needed if we were not
+ trying to match our internal register numbers with those
+ used by GDB. */
+ printf(" if (to) {\n");
+ if (doisa < 4) {
+ printf(" if (fs == 0) {\n");
+ printf(" PENDING_FILL((fs + FCR0IDX),(GPR[ft]&0xFFFFFFFF));\n");
+ printf(" } else if (fs == 31) {\n");
+ printf(" PENDING_FILL((fs + FCR31IDX),(GPR[ft]&0xFFFFFFFF));\n");
+ printf(" } /* else NOP */\n");
+ printf(" PENDING_FILL(COCIDX,0); /* special case */\n");
+ } else {
+ printf(" if (fs == 0) {\n");
+ printf(" FCR0 = (GPR[ft] & 0xFFFFFFFF);\n");
+ printf(" } else if (fs == 31) {\n");
+ printf(" FCR31 = (GPR[ft] & 0xFFFFFFFF);\n");
+ printf(" } /* else NOP */\n");
+ printf(" SETFCC(0,((FCR31 & (1 << 23)) ? 1 : 0)); /* COC[1] */\n");
+ }
+ printf(" } else { /* control from */\n");
+ if (doisa < 4) {
+ printf(" if (fs == 0) {\n");
+ printf(" PENDING_FILL(ft,SIGNEXTEND(FCR0,32));\n");
+ printf(" } else if (fs == 31) {\n");
+ printf(" PENDING_FILL(ft,SIGNEXTEND(FCR31,32));\n");
+ printf(" } /* else NOP */\n");
+ } else {
+ printf(" if (fs == 0) {\n");
+ printf(" GPR[ft] = SIGNEXTEND(FCR0,32);\n");
+ printf(" } else if (fs == 31) {\n");
+ printf(" GPR[ft] = SIGNEXTEND(FCR31,32);\n");
+ printf(" } /* else NOP */\n");
+ }
+ printf(" }\n");
+ } else {
+ printf(" if (to) {\n");
+ if (GETDATASIZE() == WORD) {
+ if (doisa < 4) {
+ printf(" if (SizeFGR() == 64) {\n");
+ printf(" PENDING_FILL((fs + FGRIDX),((unsigned long long)((unsigned long long)0xDEADC0DE << 32) | (GPR[ft]&0xFFFFFFFF)));\n");
+ printf(" } else { \n");
+ printf(" PENDING_FILL((fs + FGRIDX),(GPR[ft]&0xFFFFFFFF));\n");
+ printf(" }\n");
+ } else {
+ printf(" if (SizeFGR() == 64)\n");
+ printf(" FGR[fs] = ((unsigned long long)((unsigned long long)0xDEADC0DE << 32) | (GPR[ft] & 0xFFFFFFFF));\n");
+ printf(" else\n");
+ printf(" FGR[fs] = (GPR[ft] & 0xFFFFFFFF);\n");
+ printf(" fpr_state[fs] = fmt_uninterpreted;\n");
+ }
+ } else if (GETDATASIZE() == DOUBLEWORD) {
+ if (doisa < 4) {
+ printf(" if (SizeFGR() == 64) {\n");
+ printf(" PENDING_FILL((fs + FGRIDX),GPR[ft]);\n");
+ printf(" } else\n");
+ printf(" if ((fs & 0x1) == 0)\n");
+ printf(" {\n");
+ printf(" PENDING_FILL(((fs + 1) + FGRIDX),(GPR[ft]>>32));\n");
+ printf(" PENDING_FILL((fs + FGRIDX),(GPR[ft]&0xFFFFFFFF));\n");
+ printf(" }\n");
+ if (features & FEATURE_WARN_RESULT) {
+ printf(" else\n");
+ printf(" UndefinedResult();\n");
+ }
+ } else {
+ printf(" if (SizeFGR() == 64) {\n");
+ printf(" FGR[fs] = GPR[ft];\n");
+ printf(" fpr_state[fs] = fmt_uninterpreted;\n");
+ printf(" } else\n");
+ printf(" if ((fs & 0x1) == 0)\n");
+ printf(" {\n");
+ printf(" FGR[fs + 1] = (GPR[ft] >> 32);\n");
+ printf(" FGR[fs] = (GPR[ft] & 0xFFFFFFFF);\n");
+ printf(" fpr_state[fs + 1] = fmt_uninterpreted;\n");
+ printf(" fpr_state[fs] = fmt_uninterpreted;\n");
+ printf(" }\n");
+ if (features & FEATURE_WARN_RESULT) {
+ printf(" else\n");
+ printf(" UndefinedResult();\n");
+ }
+ }
+ } else {
+ fprintf(stderr,"Invalid data width specified in FPU Move operation\n");
+ exit(1);
+ }
+ printf(" } else {\n");
+ if (GETDATASIZE() == WORD) {
+ if (doisa < 4) /* write-back occurs in next cycle */
+ printf(" PENDING_FILL(ft,SIGNEXTEND(FGR[fs],32));\n");
+ else /* in this cycle */
+ printf(" GPR[ft] = SIGNEXTEND(FGR[fs],32);\n");
+ } else if (GETDATASIZE() == DOUBLEWORD) {
+ if (doisa < 4) {
+ printf(" if (SizeFGR() == 64) {\n");
+ printf(" PENDING_FILL(ft,FGR[fs]);\n");
+ printf(" } else\n");
+ printf(" if ((fs & 0x1) == 0) {\n");
+ printf(" PENDING_FILL(ft,((FGR[fs+1]<<32)|FGR[fs]));\n");
+ printf(" } else {\n");
+ printf(" PENDING_FILL(ft,((unsigned long long)0xDEADC0DE << 32) | 0xBAD0BAD0);\n");
+ if (features & FEATURE_WARN_RESULT)
+ printf(" UndefinedResult();\n");
+ printf(" }\n");
+ } else {
+ printf(" if (SizeFGR() == 64)\n");
+ printf(" GPR[ft] = FGR[fs];\n");
+ printf(" else\n");
+ printf(" if ((fs & 0x1) == 0)\n");
+ printf(" GPR[ft] = ((FGR[fs + 1] << 32) | FGR[fs]);\n");
+ printf(" else {\n");
+ printf(" GPR[ft] = (((unsigned long long)0xDEADC0DE << 32) | 0xBAD0BAD0);\n");
+ if (features & FEATURE_WARN_RESULT)
+ printf(" UndefinedResult();\n");
+ printf(" }\n");
+ }
+ } else {
+ fprintf(stderr,"Invalid data width specified in FPU Move operation\n");
+ exit(1);
+ }
+ printf(" }\n");
+ }
break ;
- case FPTRUNC :
- printf(" printf(\"TODO: FPTRUNC operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+ case FPMOVE:
+ if (MIPS_DECODE[loop].flags & CONDITIONAL) {
+ if (MIPS_DECODE[loop].flags & INTEGER) { /* moving GPR - testing FGR */
+ printf(" if (GETFCC(condition_code) == boolean)\n");
+ printf(" GPR[destreg] = op1;\n");
+ } else {
+ if (MIPS_DECODE[loop].flags & EQ) /* moving FGR - testing GPR */
+ printf(" if (op2 %c= 0)\n",((MIPS_DECODE[loop].flags & NOT) ? '!' : '='));
+ else
+ printf(" if (GETFCC(condition_code) == boolean)\n");
+ printf(" StoreFPR(destreg,format,ValueFPR(fs,format));\n");
+ printf(" else\n");
+ printf(" StoreFPR(destreg,format,ValueFPR(destreg,format));\n");
+ }
+ } else { /* simple MOVE */
+ printf(" StoreFPR(destreg,format,ValueFPR(fs,format));\n");
+ }
break ;
- case FPROUND :
- printf(" printf(\"TODO: FPROUND operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+ case FPNEG:
+ printf(" if ((format != fmt_single) && (format != fmt_double))\n");
+ printf(" SignalException(ReservedInstruction,instruction);\n");
+ printf(" else\n");
+ printf(" StoreFPR(destreg,format,Negate(ValueFPR(fs,format),format));\n");
break ;
- case FPNEG :
- printf(" printf(\"TODO: FPNEG operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+ case FPABS:
+ printf(" if ((format != fmt_single) && (format != fmt_double))\n");
+ printf(" SignalException(ReservedInstruction,instruction);\n");
+ printf(" else\n");
+ printf(" StoreFPR(destreg,format,AbsoluteValue(ValueFPR(fs,format),format));\n");
break ;
- case FPABS :
- printf(" printf(\"TODO: FPABS operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+ case FPDIV:
+ printf(" if ((format != fmt_single) && (format != fmt_double))\n");
+ printf(" SignalException(ReservedInstruction,instruction);\n");
+ printf(" else\n");
+ printf(" StoreFPR(destreg,format,Divide(ValueFPR(fs,format),ValueFPR(ft,format),format));\n");
break ;
- case FPDIV :
- printf(" printf(\"TODO: FPDIV operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+ case FPMUL:
+ printf(" if ((format != fmt_single) && (format != fmt_double))\n");
+ printf(" SignalException(ReservedInstruction,instruction);\n");
+ printf(" else\n");
+ printf(" StoreFPR(destreg,format,Multiply(ValueFPR(fs,format),ValueFPR(ft,format),format));\n");
break ;
- case FPMUL :
- printf(" printf(\"TODO: FPMUL operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+ case FPRECIP:
+ printf(" if ((format != fmt_single) && (format != fmt_double))\n");
+ printf(" SignalException(ReservedInstruction,instruction);\n");
+ printf(" else\n");
+ printf(" StoreFPR(destreg,format,Recip(ValueFPR(fs,format),format));\n");
break ;
- case FPSUB :
- printf(" printf(\"TODO: FPSUB operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+ case FPSQRT:
+ printf(" if ((format != fmt_single) && (format != fmt_double))\n");
+ printf(" SignalException(ReservedInstruction,instruction);\n");
+ printf(" else\n");
+ printf(" StoreFPR(destreg,format,%s(SquareRoot(ValueFPR(fs,format),format)));\n",((MIPS_DECODE[loop].flags & RECIP) ? "Recip" : ""));
break ;
- case FPADD :
- printf(" printf(\"TODO: FPADD operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
- break ;
+ case FPCEIL:
+ case FPFLOOR:
+ case FPTRUNC:
+ case FPROUND:
+ {
+ char *op = "";
+ char *type = "";
- case FPPREFX :
- printf(" printf(\"TODO: FPPREFX operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
- break ;
+ switch (MIPS_DECODE[loop].type) {
+ case FPCEIL:
+ op = "FP_RM_TOPINF";
+ break;
+ case FPFLOOR:
+ op = "FP_RM_TOMINF";
+ break;
+ case FPTRUNC:
+ op = "FP_RM_TOZERO";
+ break;
+ case FPROUND:
+ op = "FP_RM_NEAREST";
+ break;
+ default:
+ fprintf(stderr,"Error: Handled missing for FP reason code %d\n",MIPS_DECODE[loop].type);
+ exit(1);
+ }
- case FPSTORE :
- printf(" printf(\"TODO: FPSTORE operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+ switch (GETDATASIZE()) {
+ case WORD :
+ type = "fmt_word";
+ break;
+ case DOUBLEWORD :
+ type = "fmt_long";
+ break;
+ default:
+ fprintf(stderr,"Error in instruction encoding table for FP %s operation (not WORD or DOUBLEWORD)\n",op);
+ exit(1);
+ }
+ printf(" if ((format != fmt_single) && (format != fmt_double))\n");
+ printf(" SignalException(ReservedInstruction,instruction);\n");
+ printf(" else\n");
+ printf(" StoreFPR(destreg,%s,Convert(%s,ValueFPR(fs,format),format,%s));\n",type,op,type);
+ }
break ;
- case FPLOAD :
- printf(" printf(\"TODO: FPLOAD operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
- break ;
+ case FPCONVERT:
+ {
+ char *type = "";
+ switch (GETDATASIZE()) {
+ case SINGLE:
+ type = "fmt_single";
+ break;
+ case DOUBLE:
+ type = "fmt_double";
+ break;
+ case WORD:
+ type = "fmt_word";
+ break;
+ case DOUBLEWORD:
+ type = "fmt_long";
+ break;
+ default :
+ fprintf(stderr,"Error: Unknown data size %d in FPCONVERT instruction\n",GETDATASIZE());
+ exit(1);
+ }
- case FPRECIP :
- printf(" printf(\"TODO: FPRECIP operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+ /* Not all combinations of conversion are valid at the
+ moment: When converting to a fixed-point format, only
+ floating-point sources are allowed. */
+ printf(" if ((format == %s) | %s)\n",type,((MIPS_DECODE[loop].flags & FIXED) ? "((format == fmt_long) || (format == fmt_word))": "0"));
+ printf(" SignalException(ReservedInstruction,instruction);\n");
+ printf(" else\n");
+ printf(" StoreFPR(destreg,%s,Convert(GETRM(),ValueFPR(fs,format),format,%s));\n",type,type);
+ }
break ;
- case FPSQRT :
- printf(" printf(\"TODO: FPSQRT operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+ case FPSUB:
+ if (MIPS_DECODE[loop].flags & MULTIPLY) {
+ char *type = "";
+ switch (GETDATASIZE()) {
+ case SINGLE:
+ type = "fmt_single";
+ break;
+ case DOUBLE:
+ type = "fmt_double";
+ break;
+ default:
+ fprintf(stderr,"Error: Invalid data size %d for FPSUB operation\n",GETDATASIZE());
+ exit(1);
+ }
+ printf(" StoreFPR(destreg,%s,%s(Sub(Multiply(ValueFPR(fs,%s),ValueFPR(ft,%s),%s),ValueFPR(fr,%s),%s),%s));\n",type,((MIPS_DECODE[loop].flags & NOT) ? "Negate" : ""),type,type,type,type,type,type);
+ } else {
+ printf(" if ((format != fmt_single) && (format != fmt_double))\n");
+ printf(" SignalException(ReservedInstruction,instruction);\n");
+ printf(" else\n");
+ printf(" StoreFPR(destreg,format,Sub(ValueFPR(fs,format),ValueFPR(ft,format),format));\n");
+ }
break ;
- case FPCONVERT :
- printf(" printf(\"TODO: FPCONVERT operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+ case FPADD:
+ if (MIPS_DECODE[loop].flags & MULTIPLY) {
+ char *type = "";
+ switch (GETDATASIZE()) {
+ case SINGLE:
+ type = "fmt_single";
+ break;
+ case DOUBLE:
+ type = "fmt_double";
+ break;
+ default:
+ fprintf(stderr,"Error: Invalid data size %d for FPADD operation in instruction table\n",GETDATASIZE());
+ exit(1);
+ }
+ printf(" StoreFPR(destreg,%s,%s(Add(Multiply(ValueFPR(fs,%s),ValueFPR(ft,%s),%s),ValueFPR(fr,%s),%s),%s));\n",type,((MIPS_DECODE[loop].flags & NOT) ? "Negate" : ""),type,type,type,type,type,type);
+ } else {
+ printf(" if ((format != fmt_single) && (format != fmt_double))\n");
+ printf(" SignalException(ReservedInstruction,instruction);\n");
+ printf(" else\n");
+ printf(" StoreFPR(destreg,format,Add(ValueFPR(fs,format),ValueFPR(ft,format),format));\n");
+ }
break ;
- case FPCOMPARE :
- printf(" printf(\"TODO: FPCOMPARE operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
- /* "cmpflags" encodes the comparison */
- /* if "cmpflags & (1 << 3)" then MIPS IV only */
+ case FPCOMPARE:
/* For the MIPS I,II or III there *MUST* be at least one
instruction between the compare that sets a condition code
- and the branch that tests it. */
+ and the branch that tests it. NOTE: However the hardware
+ does not detect this condition. */
+ /* Explicitly limit the operation to S and D formats: */
+ printf(" if ((format != fmt_single) && (format != fmt_double))\n");
+ printf(" SignalException(ReservedInstruction,instruction);\n") ;
+ printf(" else {\n");
+ if (doisa < 4) {
+ printf(" if ((cmpflags & (1 << 3)) || (condition_code != 0))\n");
+ printf(" SignalException(ReservedInstruction,instruction);\n") ;
+ printf(" else\n");
+ }
+ printf(" {\n");
+ printf(" int ignore = 0;\n");
+ printf(" int less = 0;\n");
+ printf(" int equal = 0;\n");
+ printf(" int unordered = 1;\n");
+ printf(" unsigned long long ofs = ValueFPR(fs,format);\n");
+ printf(" unsigned long long oft = ValueFPR(ft,format);\n");
+ printf(" if (NaN(ofs,format) || NaN(oft,format)) {\n");
+ printf(" if (FCSR & FP_ENABLE(IO)) {\n");
+ printf(" FCSR |= FP_CAUSE(IO);\n");
+ printf(" SignalException(FPE);\n");
+ printf(" ignore = 1;\n");
+ printf(" }\n");
+ printf(" } else {\n");
+ printf(" less = Less(ofs,oft,format);\n");
+ printf(" equal = Equal(ofs,oft,format);\n");
+ printf(" unordered = 0;\n");
+ printf(" }\n");
+ printf(" if (!ignore) {\n");
+ printf(" int condition = (((cmpflags & (1 << 2)) && less) || ((cmpflags & (1 << 1)) && equal) || ((cmpflags & (1 << 0)) && unordered));\n");
+ printf(" SETFCC(condition_code,condition);\n");
+ printf(" }\n");
+ printf(" }\n");
+ printf(" }\n");
break ;
- default :
+ default:
fprintf(stderr,"Unrecognised opcode type %d\n",MIPS_DECODE[loop].type) ;
exit(6) ;
}
{"gp64", T_NONE, FEATURE_GP64,FEATURE_GP64,"\t\t\tSelect 64bit GP registers"},
{"gp32", T_NONE, FEATURE_GP64,0,"\t\t\tSelect 32bit GP registers"},
{"no-fp", T_NONE, FEATURE_HASFPU,0,"\t\tDisable FP simulation"},
- {"fp64", T_NONE, (FEATURE_FP64 | FEATURE_HASFPU),(FEATURE_FP64 | FEATURE_HASFPU),"\t\t\tSelect 64bit FP registers"},
- {"fp32", T_NONE, (FEATURE_FP64 | FEATURE_HASFPU),FEATURE_HASFPU,"\t\t\tSelect 32bit FP registers"},
{"single-float",T_NONE, (FEATURE_FPSINGLE | FEATURE_HASFPU),(FEATURE_FPSINGLE | FEATURE_HASFPU),"\t\tSelect single precision only FPU"},
{"double-float",T_NONE, (FEATURE_FPSINGLE | FEATURE_HASFPU),FEATURE_HASFPU,"\t\tSelect double precision FPU"},
{0, T_NONE, 0,0}
features |= FEATURE_FPSINGLE;
if (features & FEATURE_PROC32)
- features &= ~(FEATURE_FP64 | FEATURE_GP64);
+ features &= ~FEATURE_GP64;
else
- features |= (FEATURE_FP64 | FEATURE_GP64);
+ features |= FEATURE_GP64;
while (1) {
int this_option_optind = (optind ? optind : 1);
doarch = ((doarch & ~MASK_ISA) | num);
if ((num == 0) || (num > 2)) {
- if ((features & FEATURE_PROC32) || !(features & FEATURE_GP64) || !(features & FEATURE_FP64))
- fprintf(stderr,"%s: Warning: -mips%d forcing -mfp64, -mgp64\n",progname,num);
- features |= (FEATURE_GP64 | FEATURE_FP64);
+ if ((features & FEATURE_PROC32) || !(features & FEATURE_GP64))
+ fprintf(stderr,"%s: Warning: -mips%d forcing -mgp64\n",progname,num);
+ features |= FEATURE_GP64;
features &= ~FEATURE_PROC32;
} else {
- if (!(features & FEATURE_PROC32) || (features & FEATURE_GP64) || (features & FEATURE_FP64))
- fprintf(stderr,"%s: Warning: -mips%d forcing -mfp32, -mgp32\n",progname,num);
- features &= ~(FEATURE_GP64 | FEATURE_FP64);
+ if (!(features & FEATURE_PROC32) || (features & FEATURE_GP64))
+ fprintf(stderr,"%s: Warning: -mips%d forcing -mgp32\n",progname,num);
+ features &= ~FEATURE_GP64;
features |= FEATURE_PROC32;
}
} else {
--- /dev/null
+/*> interp.c <*/
+/* Simulator for the MIPS architecture.
+
+ This file is part of the MIPS sim
+
+ THIS SOFTWARE IS NOT COPYRIGHTED
+
+ Cygnus offers the following for use in the public domain. Cygnus
+ makes no warranty with regard to the software or it's performance
+ and the user accepts the software "AS IS" with all faults.
+
+ CYGNUS DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO
+ THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+ $Revision$
+ $Author$
+ $Date$
+
+NOTEs:
+
+We only need to take account of the target endianness when moving data
+between the simulator and the host. We do not need to worry about the
+endianness of the host, since this sim code and GDB are executing in
+the same process.
+
+The IDT monitor (found on the VR4300 board), seems to lie about
+register contents. It seems to treat the registers as sign-extended
+32-bit values. This cause *REAL* problems when single-stepping 64-bit
+code on the hardware.
+
+*/
+
+/* The TRACE and PROFILE manifests enable the provision of extra
+ features. If they are not defined then a simpler (quicker)
+ simulator is constructed without the required run-time checks,
+ etc. */
+#if 1 /* 0 to allow user build selection, 1 to force inclusion */
+#define TRACE (1)
+#define PROFILE (1)
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <ansidecl.h>
+#include <signal.h>
+#include <ctype.h>
+#include <limits.h>
+#include <math.h>
+
+#include "getopt.h"
+#include "libiberty.h"
+
+#include "remote-sim.h" /* GDB simulator interface */
+#include "callback.h" /* GDB simulator callback interface */
+
+#include "support.h" /* internal support manifests */
+
+/* Get the simulator engine description, without including the code: */
+#define SIM_MANIFESTS
+#include "engine.c"
+#undef SIM_MANIFESTS
+
+/* The following reserved instruction value is used when a simulator
+ trap is required. NOTE: Care must be taken, since this value may be
+ used in later revisions of the MIPS ISA. */
+#define RSVD_INSTRUCTION (0x7C000000)
+#define RSVD_INSTRUCTION_AMASK (0x03FFFFFF)
+
+/* NOTE: These numbers depend on the processor architecture being
+ simulated: */
+#define Interrupt (0)
+#define TLBModification (1)
+#define TLBLoad (2)
+#define TLBStore (3)
+#define AddressLoad (4)
+#define AddressStore (5)
+#define InstructionFetch (6)
+#define DataReference (7)
+#define SystemCall (8)
+#define BreakPoint (9)
+#define ReservedInstruction (10)
+#define CoProcessorUnusable (11)
+#define IntegerOverflow (12) /* Arithmetic overflow (IDT monitor raises SIGFPE) */
+#define Trap (13)
+#define FPE (15)
+#define Watch (23)
+
+/* The following exception code is actually private to the simulator
+ world. It is *NOT* a processor feature, and is used to signal
+ run-time errors in the simulator. */
+#define SimulatorFault (0xFFFFFFFF)
+
+/* The following are generic to all versions of the MIPS architecture
+ to date: */
+/* Memory Access Types (for CCA): */
+#define Uncached (0)
+#define CachedNoncoherent (1)
+#define CachedCoherent (2)
+#define Cached (3)
+
+#define isINSTRUCTION (1 == 0) /* FALSE */
+#define isDATA (1 == 1) /* TRUE */
+
+#define isLOAD (1 == 0) /* FALSE */
+#define isSTORE (1 == 1) /* TRUE */
+
+#define isREAL (1 == 0) /* FALSE */
+#define isRAW (1 == 1) /* TRUE */
+
+#define isTARGET (1 == 0) /* FALSE */
+#define isHOST (1 == 1) /* TRUE */
+
+/* The "AccessLength" specifications for Loads and Stores. NOTE: This
+ is the number of bytes minus 1. */
+#define AccessLength_BYTE (0)
+#define AccessLength_HALFWORD (1)
+#define AccessLength_TRIPLEBYTE (2)
+#define AccessLength_WORD (3)
+#define AccessLength_QUINTIBYTE (4)
+#define AccessLength_SEXTIBYTE (5)
+#define AccessLength_SEPTIBYTE (6)
+#define AccessLength_DOUBLEWORD (7)
+
+#if defined(HASFPU)
+/* FPU registers must be one of the following types. All other values
+ are reserved (and undefined). */
+typedef enum {
+ fmt_single = 0,
+ fmt_double = 1,
+ fmt_word = 4,
+ fmt_long = 5,
+ /* The following are well outside the normal acceptable format
+ range, and are used in the register status vector. */
+ fmt_unknown = 0x10000000,
+ fmt_uninterpreted = 0x20000000,
+} FP_formats;
+#endif /* HASFPU */
+
+/* NOTE: We cannot avoid globals, since the GDB "sim_" interface does
+ not allow a private variable to be passed around. This means that
+ simulators under GDB can only be single-threaded. However, it would
+ be possible for the simulators to be multi-threaded if GDB allowed
+ for a private pointer to be maintained. i.e. a general "void **ptr"
+ variable that GDB passed around in the argument list to all of
+ sim_xxx() routines. It could be initialised to NULL by GDB, and
+ then updated by sim_open() and used by the other sim_xxx() support
+ functions. This would allow new features in the simulator world,
+ like storing a context - continuing execution to gather a result,
+ and then going back to the point where the context was saved and
+ changing some state before continuing. i.e. the ability to perform
+ UNDOs on simulations. It would also allow the simulation of
+ shared-memory multi-processor systems. */
+
+static host_callback *callback = NULL; /* handle onto the current callback structure */
+
+/* The warning system should be improved, to allow more information to
+ be passed about the cause: */
+#define WARNING(m) { callback->printf_filtered(callback,"SIM Warning: %s\n",(m)); }
+
+/* This is nasty, since we have to rely on matching the register
+ numbers used by GDB. Unfortunately, depending on the MIPS target
+ GDB uses different register numbers. We cannot just include the
+ relevant "gdb/tm.h" link, since GDB may not be configured before
+ the sim world, and also the GDB header file requires too much other
+ state. */
+/* TODO: Sort out a scheme for *KNOWING* the mapping between real
+ registers, and the numbers that GDB uses. At the moment due to the
+ order that the tools are built, we cannot rely on a configured GDB
+ world whilst constructing the simulator. This means we have to
+ assume the GDB register number mapping. */
+#define LAST_EMBED_REGNUM (89)
+
+/* To keep this default simulator simple, and fast, we use a direct
+ vector of registers. The internal simulator engine then uses
+ manifests to access the correct slot. */
+ut_reg registers[LAST_EMBED_REGNUM + 1];
+int register_widths[LAST_EMBED_REGNUM + 1];
+
+#define GPR (®isters[0])
+#if defined(HASFPU)
+#define FGRIDX (38)
+#define FGR (®isters[FGRIDX])
+#endif /* HASFPU */
+#define LO (registers[33])
+#define HI (registers[34])
+#define PC (registers[37])
+#define CAUSE (registers[36])
+#define SRIDX (32)
+#define SR (registers[SRIDX]) /* CPU status register */
+#define FCR0IDX (71)
+#define FCR0 (registers[FCR0IDX]) /* really a 32bit register */
+#define FCR31IDX (70)
+#define FCR31 (registers[FCR31IDX]) /* really a 32bit register */
+#define FCSR (FCR31)
+#define COCIDX (LAST_EMBED_REGNUM + 2) /* special case : outside the normal range */
+
+/* The following are pseudonyms for standard registers */
+#define ZERO (registers[0])
+#define V0 (registers[2])
+#define A0 (registers[4])
+#define A1 (registers[5])
+#define A2 (registers[6])
+#define A3 (registers[7])
+#define SP (registers[29])
+#define RA (registers[31])
+
+ut_reg EPC = 0; /* Exception PC */
+
+#if defined(HASFPU)
+/* Keep the current format state for each register: */
+FP_formats fpr_state[32];
+#endif /* HASFPU */
+
+/* VR4300 CP0 configuration register: */
+unsigned int CONFIG = 0;
+
+/* The following are internal simulator state variables: */
+ut_reg IPC = 0; /* internal Instruction PC */
+ut_reg DSPC = 0; /* delay-slot PC */
+
+
+/* TODO : these should be the bitmasks for these bits within the
+ status register. At the moment the following are VR4300
+ bit-positions: */
+#define status_KSU_mask (0x3) /* mask for KSU bits */
+#define status_KSU_shift (3) /* shift for field */
+#define ksu_kernel (0x0)
+#define ksu_supervisor (0x1)
+#define ksu_user (0x2)
+#define ksu_unknown (0x3)
+
+#define status_RE (1 << 25) /* Reverse Endian in user mode */
+#define status_FR (1 << 26) /* enables MIPS III additional FP registers */
+#define status_SR (1 << 20) /* soft reset or NMI */
+#define status_BEV (1 << 22) /* Location of general exception vectors */
+#define status_TS (1 << 21) /* TLB shutdown has occurred */
+#define status_ERL (1 << 2) /* Error level */
+#define status_RP (1 << 27) /* Reduced Power mode */
+
+#define config_EP_mask (0xF)
+#define config_EP_shift (27)
+#define config_EP_D (0x0)
+#define config_EP_DxxDxx (0x6)
+
+#define config_BE (1 << 15)
+
+#define cause_BD ((unsigned)1 << 31) /* Exception in branch delay slot */
+
+#if defined(HASFPU)
+/* Macro to update FPSR condition-code field. This is complicated by
+ the fact that there is a hole in the index range of the bits within
+ the FCSR register. Also, the number of bits visible depends on the
+ MIPS ISA version being supported. */
+#define SETFCC(cc,v) {\
+ int bit = ((cc == 0) ? 23 : (24 + (cc)));\
+ FCSR = ((FCSR & ~(1 << bit)) | ((v) << bit));\
+ }
+#define GETFCC(cc) (((((cc) == 0) ? (FCSR & (1 << 23)) : (FCSR & (1 << (24 + (cc))))) != 0) ? 1 : 0)
+
+/* This should be the COC1 value at the start of the preceding
+ instruction: */
+#define PREVCOC1() ((state & simPCOC1) ? 1 : 0)
+#endif /* HASFPU */
+
+/* Standard FCRS bits: */
+#define IR (0) /* Inexact Result */
+#define UF (1) /* UnderFlow */
+#define OF (2) /* OverFlow */
+#define DZ (3) /* Division by Zero */
+#define IO (4) /* Invalid Operation */
+#define UO (5) /* Unimplemented Operation */
+
+/* Get masks for individual flags: */
+#if 1 /* SAFE version */
+#define FP_FLAGS(b) (((unsigned)(b) < 5) ? (1 << ((b) + 2)) : 0)
+#define FP_ENABLE(b) (((unsigned)(b) < 5) ? (1 << ((b) + 7)) : 0)
+#define FP_CAUSE(b) (((unsigned)(b) < 6) ? (1 << ((b) + 12)) : 0)
+#else
+#define FP_FLAGS(b) (1 << ((b) + 2))
+#define FP_ENABLE(b) (1 << ((b) + 7))
+#define FP_CAUSE(b) (1 << ((b) + 12))
+#endif
+
+#define FP_FS (1 << 24) /* MIPS III onwards : Flush to Zero */
+
+#define FP_MASK_RM (0x3)
+#define FP_SH_RM (0)
+#define FP_RM_NEAREST (0) /* Round to nearest (Round) */
+#define FP_RM_TOZERO (1) /* Round to zero (Trunc) */
+#define FP_RM_TOPINF (2) /* Round to Plus infinity (Ceil) */
+#define FP_RM_TOMINF (3) /* Round to Minus infinity (Floor) */
+#define GETRM() (int)((FCSR >> FP_SH_RM) & FP_MASK_RM)
+
+/* Slots for delayed register updates. For the moment we just have a
+ fixed number of slots (rather than a more generic, dynamic
+ system). This keeps the simulator fast. However, we only allow for
+ the register update to be delayed for a single instruction
+ cycle. */
+#define PSLOTS (5) /* Maximum number of instruction cycles */
+int pending_in;
+int pending_out;
+int pending_total;
+int pending_slot_count[PSLOTS];
+int pending_slot_reg[PSLOTS];
+ut_reg pending_slot_value[PSLOTS];
+
+/* The following are not used for MIPS IV onwards: */
+#define PENDING_FILL(r,v) {\
+printf("DBG: FILL BEFORE pending_in = %d, pending_out = %d, pending_total = %d\n",pending_in,pending_out,pending_total);\
+ if (pending_slot_reg[pending_in] != (LAST_EMBED_REGNUM + 1))\
+ callback->printf_filtered(callback,"SIM Warning: Attempt to over-write pending value\n");\
+ pending_slot_count[pending_in] = 2;\
+ pending_slot_reg[pending_in] = (r);\
+ pending_slot_value[pending_in] = (v);\
+printf("DBG: FILL reg %d value = 0x%08X%08X\n",(r),(unsigned int)(((unsigned long long)(v))>>32),(unsigned int)((v)&0xFFFFFFFF));\
+ pending_total++;\
+ pending_in++;\
+ if (pending_in == PSLOTS)\
+ pending_in = 0;\
+printf("DBG: FILL AFTER pending_in = %d, pending_out = %d, pending_total = %d\n",pending_in,pending_out,pending_total);\
+ }
+
+int LLBIT = 0;
+/* LLBIT = Load-Linked bit. A bit of "virtual" state used by atomic
+ read-write instructions. It is set when a linked load occurs. It is
+ tested and cleared by the conditional store. It is cleared (during
+ other CPU operations) when a store to the location would no longer
+ be atomic. In particular, it is cleared by exception return
+ instructions. */
+
+int HIACCESS = 0;
+int LOACCESS = 0;
+/* The HIACCESS and LOACCESS counts are used to ensure that
+ corruptions caused by using the HI or LO register to close to a
+ following operation are spotted. */
+
+/* If either of the preceding two instructions have accessed the HI or
+ LO registers, then the values they see should be
+ undefined. However, to keep the simulator world simple, we just let
+ them use the value read and raise a warning to notify the user: */
+#define CHECKHILO(s) {\
+ if ((HIACCESS != 0) || (LOACCESS != 0))\
+ callback->printf_filtered(callback,"SIM Warning: %s over-writing HI and LO registers values\n",(s));\
+ /* Set the access counts, since we are about\
+ to update the HI and LO registers: */\
+ HIACCESS = LOACCESS = 3; /* 3rd instruction will be safe */\
+ }
+
+/* NOTE: We keep the following status flags as bit values (1 for true,
+ 0 for false). This allows them to be used in binary boolean
+ operations without worrying about what exactly the non-zero true
+ value is. */
+
+/* UserMode */
+#define UserMode ((((SR & status_KSU_mask) >> status_KSU_shift) == ksu_user) ? 1 : 0)
+
+/* BigEndianMem */
+/* Hardware configuration. Affects endianness of LoadMemory and
+ StoreMemory and the endianness of Kernel and Supervisor mode
+ execution. The value is 0 for little-endian; 1 for big-endian. */
+#define BigEndianMem ((CONFIG & config_BE) ? 1 : 0)
+/* NOTE: Problems will occur if the simulator memory model does not
+ match the host program expectation. i.e. if the host is writing
+ big-endian values to a little-endian memory model. */
+
+/* ReverseEndian */
+/* This mode is selected if in User mode with the RE bit being set in
+ SR (Status Register). It reverses the endianness of load and store
+ instructions. */
+#define ReverseEndian (((SR & status_RE) && UserMode) ? 1 : 0)
+
+/* BigEndianCPU */
+/* The endianness for load and store instructions (0=little;1=big). In
+ User mode this endianness may be switched by setting the state_RE
+ bit in the SR register. Thus, BigEndianCPU may be computed as
+ (BigEndienMem EOR ReverseEndian). */
+#define BigEndianCPU (BigEndianMem ^ ReverseEndian) /* Already bits */
+
+#if !defined(FASTSIM) || defined(PROFILE)
+/* At the moment these values will be the same, since we do not have
+ access to the pipeline cycle count information from the simulator
+ engine. */
+unsigned int instruction_fetches = 0;
+unsigned int pipeline_ticks = 0;
+#endif
+
+/* Flags in the "state" variable: */
+#define simSTOP (1 << 0) /* 0 = execute; 1 = stop simulation */
+#define simSTEP (1 << 1) /* 0 = run; 1 = single-step */
+#define simHALTEX (1 << 2) /* 0 = run; 1 = halt on exception */
+#define simHALTIN (1 << 3) /* 0 = run; 1 = halt on interrupt */
+#define simTRACE (1 << 8) /* 0 = do nothing; 1 = trace address activity */
+#define simPROFILE (1 << 9) /* 0 = do nothing; 1 = gather profiling samples */
+#define simHOSTBE (1 << 10) /* 0 = little-endian; 1 = big-endian (host endianness) */
+/* Whilst simSTOP is not set, the simulator control loop should just
+ keep simulating instructions. The simSTEP flag is used to force
+ single-step execution. */
+#define simBE (1 << 16) /* 0 = little-endian; 1 = big-endian (target endianness) */
+#define simPCOC0 (1 << 17) /* COC[1] from current */
+#define simPCOC1 (1 << 18) /* COC[1] from previous */
+#define simDELAYSLOT (1 << 24) /* 0 = do nothing; 1 = delay slot entry exists */
+#define simSKIPNEXT (1 << 25) /* 0 = do nothing; 1 = skip instruction */
+#define simEXCEPTION (1 << 26) /* 0 = no exception; 1 = exception has occurred */
+#define simEXIT (1 << 27) /* 0 = do nothing; 1 = run-time exit() processing */
+
+unsigned int state = (0 | simBE); /* big-endian simulator by default */
+unsigned int rcexit = 0; /* _exit() reason code holder */
+
+#define DELAYSLOT() {\
+ if (state & simDELAYSLOT) callback->printf_filtered(callback,"SIM Warning: Delay slot already activated (branch in delay slot?)\n");\
+ state |= simDELAYSLOT;\
+ }
+
+#define NULLIFY() {\
+ state &= ~simDELAYSLOT;\
+ state |= simSKIPNEXT;\
+ }
+
+/* Very simple memory model to start with: */
+unsigned char *membank = NULL;
+ut_reg membank_base = 0xA0000000;
+unsigned membank_size = (1 << 20); /* (16 << 20); */ /* power-of-2 */
+
+/* Simple run-time monitor support */
+unsigned char *monitor = NULL;
+ut_reg monitor_base = 0xBFC00000;
+unsigned monitor_size = (1 << 9); /* power-of-2 */
+
+#if defined(TRACE)
+char *tracefile = "trace.din"; /* default filename for trace log */
+FILE *tracefh = NULL;
+#endif /* TRACE */
+
+#if defined(PROFILE)
+unsigned profile_frequency = 256;
+unsigned profile_nsamples = (128 << 10);
+unsigned short *profile_hist = NULL;
+ut_reg profile_minpc;
+ut_reg profile_maxpc;
+int profile_shift = 0; /* address shift amount */
+#endif /* PROFILE */
+
+/*---------------------------------------------------------------------------*/
+/*-- GDB simulator interface ------------------------------------------------*/
+/*---------------------------------------------------------------------------*/
+
+static void dotrace PARAMS((FILE *tracefh,int type,unsigned int address,int width,char *comment,...));
+extern void sim_error PARAMS((char *fmt,...));
+static void ColdReset PARAMS((void));
+static int AddressTranslation PARAMS((unsigned long long vAddr,int IorD,int LorS,unsigned long long *pAddr,int *CCA,int host,int raw));
+static void StoreMemory PARAMS((int CCA,int AccessLength,unsigned long long MemElem,unsigned long long pAddr,unsigned long long vAddr,int raw));
+static unsigned long long LoadMemory PARAMS((int CCA,int AccessLength,unsigned long long pAddr,unsigned long long vAddr,int IorD,int raw));
+static void SignalException PARAMS((int exception,...));
+static void simulate PARAMS((void));
+static long getnum(char *value);
+extern void sim_size(unsigned int newsize);
+extern void sim_set_profile(int frequency);
+static unsigned int power2(unsigned int value);
+
+void
+sim_open (args)
+ char *args;
+{
+ if (callback == NULL) {
+ fprintf(stderr,"SIM Error: sim_open() called without callbacks attached\n");
+ return;
+ }
+
+ /* The following ensures that the standard file handles for stdin,
+ stdout and stderr are initialised: */
+ callback->init(callback);
+
+ state = 0;
+ CHECKSIM();
+ if (state & simEXCEPTION) {
+ fprintf(stderr,"This simulator is not suitable for this host configuration\n");
+ exit(1);
+ }
+
+ {
+ int data = 0x12;
+ if (*((char *)&data) != 0x12)
+ state |= simHOSTBE; /* big-endian host */
+ }
+
+#if defined(HASFPU)
+ /* Check that the host FPU conforms to IEEE 754-1985 for the SINGLE
+ and DOUBLE binary formats. This is a bit nasty, requiring that we
+ trust the explicit manifests held in the source: */
+ {
+ unsigned int s[2];
+ s[0] = 0x40805A5A;
+ s[1] = 0x00000000;
+ if (((float)4.01102924346923828125 != *(float *)s) || ((double)523.2939453125 != *(double *)s)) {
+ fprintf(stderr,"The host executing the simulator does not seem to have IEEE 754-1985 std FP\n");
+ exit(1);
+ }
+ }
+#endif /* HASFPU */
+
+ /* This is NASTY, in that we are assuming the size of specific
+ registers: */
+ {
+ int rn;
+ for (rn = 0; (rn < (LAST_EMBED_REGNUM + 1)); rn++) {
+ if (rn < 32)
+ register_widths[rn] = GPRLEN;
+ else if ((rn >= FGRIDX) && (rn < (FGRIDX + 32)))
+ register_widths[rn] = GPRLEN;
+ else if ((rn >= 33) && (rn <= 37))
+ register_widths[rn] = GPRLEN;
+ else if ((rn == SRIDX) || (rn == FCR0IDX) || (rn == FCR31IDX) || ((rn >= 72) && (rn <= 89)))
+ register_widths[rn] = 32;
+ else
+ register_widths[rn] = 0;
+ }
+ }
+
+ /* It would be good if we could select particular named MIPS
+ architecture simulators. However, having a pre-built, fixed
+ engine would mean including multiple engines. If the simulator is
+ changed to a run-time conditional version, then the ability to
+ select a particular architecture would be straightforward. */
+ if (args != NULL) {
+ int c;
+ char *cline;
+ char **argv;
+ int argc;
+ static struct option cmdline[] = {
+ {"help", 0,0,'h'},
+ {"name", 1,0,'n'},
+ {"profile", 0,0,'p'},
+ {"size", 1,0,'s'},
+ {"trace", 0,0,'t'},
+ {"tracefile",1,0,'z'},
+ {"frequency",1,0,'y'},
+ {"samples", 1,0,'x'},
+ {0, 0,0,0}
+ };
+
+ /* Unfortunately, getopt_long() is designed to be used with
+ vectors, where the first option is normally program name (and
+ ignored). We cheat by creating a dummy first argument, so that
+ we can use the standard argument processing. */
+#define DUMMYARG "simulator "
+ cline = (char *)malloc(strlen(args) + strlen(DUMMYARG) + 1);
+ if (cline == NULL) {
+ fprintf(stderr,"Failed to allocate memory for command line buffer\n");
+ exit(1);
+ }
+ sprintf(cline,"%s%s",DUMMYARG,args);
+ argv = buildargv(cline);
+ for (argc = 0; argv[argc]; argc++);
+
+ /* Unfortunately, getopt_long() assumes that it is ignoring the
+ first argument (normally the program name). This means it
+ ignores the first option on our "args" line. */
+ optind = 0; /* Force reset of argument processing */
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc,argv,"hn:s:tp",cmdline,&option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'h':
+ callback->printf_filtered(callback,"Usage:\n\t\
+target sim [-h] [--name=<model>] [--size=<amount>]");
+#if defined(TRACE)
+ callback->printf_filtered(callback," [-t [--tracefile=<name>]]");
+#endif /* TRACE */
+#if defined(PROFILE)
+ callback->printf_filtered(callback," [-p [--frequency=<count>] [--samples=<count>]]");
+#endif /* PROFILE */
+ callback->printf_filtered(callback,"\n");
+ break;
+
+ case 'n':
+ callback->printf_filtered(callback,"Explicit model selection not yet available (Ignoring \"%s\")\n",optarg);
+ break;
+
+ case 's':
+ membank_size = (unsigned)getnum(optarg);
+ break;
+
+ case 't':
+#if defined(TRACE)
+ /* Eventually the simTRACE flag could be treated as a toggle, to
+ allow external control of the program points being traced
+ (i.e. only from main onwards, excluding the run-time setup,
+ etc.). */
+ state |= simTRACE;
+#else /* !TRACE */
+ fprintf(stderr,"\
+Simulator constructed without tracing support (for performance).\n\
+Re-compile simulator with \"-DTRACE\" to enable this option.\n");
+#endif /* !TRACE */
+ break;
+
+ case 'z':
+#if defined(TRACE)
+ if (optarg != NULL) {
+ char *tmp;
+ tmp = (char *)malloc(strlen(optarg) + 1);
+ if (tmp == NULL)
+ callback->printf_filtered(callback,"Failed to allocate buffer for tracefile name \"%s\"\n",optarg);
+ else {
+ strcpy(tmp,optarg);
+ tracefile = tmp;
+ callback->printf_filtered(callback,"Placing trace information into file \"%s\"\n",tracefile);
+ }
+ }
+#endif /* TRACE */
+ break;
+
+ case 'p':
+#if defined(PROFILE)
+ state |= simPROFILE;
+#else /* !PROFILE */
+ fprintf(stderr,"\
+Simulator constructed without profiling support (for performance).\n\
+Re-compile simulator with \"-DPROFILE\" to enable this option.\n");
+#endif /* !PROFILE */
+ break;
+
+ case 'x':
+#if defined(PROFILE)
+ profile_nsamples = (unsigned)getnum(optarg);
+#endif /* PROFILE */
+ break;
+
+ case 'y':
+#if defined(PROFILE)
+ sim_set_profile((int)getnum(optarg));
+#endif /* PROFILE */
+ break;
+
+ default:
+ callback->printf_filtered(callback,"Warning: Simulator getopt returned unrecognised code 0x%08X\n",c);
+ case '?':
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ callback->printf_filtered(callback,"Warning: Ignoring spurious non-option arguments ");
+ while (optind < argc)
+ callback->printf_filtered(callback,"\"%s\" ",argv[optind++]);
+ callback->printf_filtered(callback,"\n");
+ }
+
+ freeargv(argv);
+ }
+
+ /* If the host has "mmap" available we could use it to provide a
+ very large virtual address space for the simulator, since memory
+ would only be allocated within the "mmap" space as it is
+ accessed. This can also be linked to the architecture specific
+ support, required to simulate the MMU. */
+ sim_size(membank_size);
+ /* NOTE: The above will also have enabled any profiling state */
+
+ ColdReset();
+ /* If we were providing a more complete I/O, co-processor or memory
+ simulation, we should perform any "device" initialisation at this
+ point. This can include pre-loading memory areas with particular
+ patterns (e.g. simulating ROM monitors). */
+
+ /* We can start writing to the memory, now that the processor has
+ been reset: */
+ monitor = (unsigned char *)calloc(1,monitor_size);
+ if (!monitor) {
+ fprintf(stderr,"Not enough VM for monitor simulation (%d bytes)\n",monitor_size);
+ } else {
+ int loop;
+ /* Entry into the IDT monitor is via fixed address vectors, and
+ not using machine instructions. To avoid clashing with use of
+ the MIPS TRAP system, we place our own (simulator specific)
+ "undefined" instructions into the relevant vector slots. */
+ for (loop = 0; (loop < monitor_size); loop += 4) {
+ unsigned long long vaddr = (monitor_base + loop);
+ unsigned long long paddr;
+ int cca;
+ if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isRAW))
+ StoreMemory(cca,AccessLength_WORD,(RSVD_INSTRUCTION | (loop >> 2)),paddr,vaddr,isRAW);
+ }
+ }
+
+#if defined(TRACE)
+ if (state & simTRACE) {
+ tracefh = fopen(tracefile,"wb+");
+ if (tracefh == NULL) {
+ callback->printf_filtered(callback,"Failed to create file \"%s\", writing trace information to stderr.\n",tracefile);
+ tracefh = stderr;
+ }
+ }
+#endif /* TRACE */
+
+ return;
+}
+
+/* For the profile writing, we write the data in the host
+ endianness. This unfortunately means we are assuming that the
+ profile file we create is processed on the same host executing the
+ simulator. The gmon.out file format should either have an explicit
+ endianness, or a method of encoding the endianness in the file
+ header. */
+static int
+writeout32(fh,val)
+ FILE *fh;
+ unsigned int val;
+{
+ char buff[4];
+ int res = 1;
+
+ if (state & simHOSTBE) {
+ buff[3] = ((val >> 0) & 0xFF);
+ buff[2] = ((val >> 8) & 0xFF);
+ buff[1] = ((val >> 16) & 0xFF);
+ buff[0] = ((val >> 24) & 0xFF);
+ } else {
+ buff[0] = ((val >> 0) & 0xFF);
+ buff[1] = ((val >> 8) & 0xFF);
+ buff[2] = ((val >> 16) & 0xFF);
+ buff[3] = ((val >> 24) & 0xFF);
+ }
+ if (fwrite(buff,4,1,fh) != 1) {
+ callback->printf_filtered(callback,"Failed to write 4bytes to the profile file\n");
+ res = 0;
+ }
+ return(res);
+}
+
+static int
+writeout16(fh,val)
+ FILE *fh;
+ unsigned short val;
+{
+ char buff[2];
+ int res = 1;
+ if (state & simHOSTBE) {
+ buff[1] = ((val >> 0) & 0xFF);
+ buff[0] = ((val >> 8) & 0xFF);
+ } else {
+ buff[0] = ((val >> 0) & 0xFF);
+ buff[1] = ((val >> 8) & 0xFF);
+ }
+ if (fwrite(buff,2,1,fh) != 1) {
+ callback->printf_filtered(callback,"Failed to write 2bytes to the profile file\n");
+ res = 0;
+ }
+ return(res);
+}
+
+void
+sim_close (quitting)
+ int quitting;
+{
+#ifdef DEBUG
+ printf("DBG: sim_close: entered (quitting = %d)\n",quitting);
+#endif
+
+ /* Cannot assume sim_kill() has been called */
+ /* "quitting" is non-zero if we cannot hang on errors */
+
+ /* Ensure that any resources allocated through the callback
+ mechanism are released: */
+ callback->shutdown(callback);
+
+#if defined(PROFILE)
+ if ((state & simPROFILE) && (profile_hist != NULL)) {
+ unsigned short *p = profile_hist;
+ FILE *pf = fopen("gmon.out","wb");
+ int loop;
+
+ if (pf == NULL)
+ callback->printf_filtered(callback,"Failed to open \"gmon.out\" profile file\n");
+ else {
+ int ok;
+#ifdef DEBUG
+ printf("DBG: minpc = 0x%08X\n",(unsigned int)profile_minpc);
+ printf("DBG: maxpc = 0x%08X\n",(unsigned int)profile_maxpc);
+#endif /* DEBUG */
+ ok = writeout32(pf,(unsigned int)profile_minpc);
+ if (ok)
+ ok = writeout32(pf,(unsigned int)profile_maxpc);
+ if (ok)
+ ok = writeout32(pf,(profile_nsamples * 2) + 12); /* size of sample buffer (+ header) */
+#ifdef DEBUG
+ printf("DBG: nsamples = %d (size = 0x%08X)\n",profile_nsamples,((profile_nsamples * 2) + 12));
+#endif /* DEBUG */
+ for (loop = 0; (ok && (loop < profile_nsamples)); loop++) {
+ ok = writeout16(pf,profile_hist[loop]);
+ if (!ok)
+ break;
+ }
+
+ fclose(pf);
+ }
+
+ free(profile_hist);
+ profile_hist = NULL;
+ state &= ~simPROFILE;
+ }
+#endif /* PROFILE */
+
+#if defined(TRACE)
+ if (tracefh != stderr)
+ fclose(tracefh);
+ state &= ~simTRACE;
+#endif /* TRACE */
+
+ if (membank)
+ cfree(membank);
+ membank = NULL;
+
+ return;
+}
+
+void
+sim_resume (step,signal)
+ int step, signal;
+{
+#ifdef DEBUG
+ printf("DBG: sim_resume entered: step = %d, signal = %d (membank = 0x%08X)\n",step,signal,membank);
+#endif /* DEBUG */
+
+ if (step)
+ state |= simSTEP; /* execute only a single instruction */
+ else
+ state &= ~(simSTOP | simSTEP); /* execute until event */
+
+ state |= (simHALTEX | simHALTIN); /* treat interrupt event as exception */
+
+ /* Start executing instructions from the current state (set
+ explicitly by register updates, or by sim_create_inferior): */
+
+ simulate();
+ return;
+}
+
+int
+sim_write (addr,buffer,size)
+ SIM_ADDR addr;
+ unsigned char *buffer;
+ int size;
+{
+ int index = size;
+ unsigned long long vaddr = (unsigned long long)addr;
+
+ /* Return the number of bytes written, or zero if error. */
+#ifdef DEBUG
+ callback->printf_filtered(callback,"sim_write(0x%08X%08X,buffer,%d);\n",(unsigned int)((unsigned long long)(addr)>>32),(unsigned int)(addr&0xFFFFFFFF),size);
+#endif
+
+ /* We provide raw read and write routines, since we do not want to
+ count the GDB memory accesses in our statistics gathering. */
+
+ /* There is a lot of code duplication in the individual blocks
+ below, but the variables are declared locally to a block to give
+ the optimiser the best chance of improving the code. We have to
+ perform slow byte reads from the host memory, to ensure that we
+ get the data into the correct endianness for the (simulated)
+ target memory world. */
+
+ /* Mask count to get odd byte, odd halfword, and odd word out of the
+ way. We can then perform doubleword transfers to and from the
+ simulator memory for optimum performance. */
+ if (index && (index & 1)) {
+ unsigned long long paddr;
+ int cca;
+ if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isRAW)) {
+ unsigned long long value = ((unsigned long long)(*buffer++));
+ StoreMemory(cca,AccessLength_BYTE,value,paddr,vaddr,isRAW);
+ }
+ vaddr++;
+ index &= ~1; /* logical operations usually quicker than arithmetic on RISC systems */
+ }
+ if (index && (index & 2)) {
+ unsigned long long paddr;
+ int cca;
+ if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isRAW)) {
+ unsigned long long value;
+ /* We need to perform the following magic to ensure that that
+ bytes are written into same byte positions in the target memory
+ world, regardless of the endianness of the host. */
+ if (BigEndianMem) {
+ value = ((unsigned long long)(*buffer++) << 8);
+ value |= ((unsigned long long)(*buffer++) << 0);
+ } else {
+ value = ((unsigned long long)(*buffer++) << 0);
+ value |= ((unsigned long long)(*buffer++) << 8);
+ }
+ StoreMemory(cca,AccessLength_HALFWORD,value,paddr,vaddr,isRAW);
+ }
+ vaddr += 2;
+ index &= ~2;
+ }
+ if (index && (index & 4)) {
+ unsigned long long paddr;
+ int cca;
+ if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isRAW)) {
+ unsigned long long value;
+ if (BigEndianMem) {
+ value = ((unsigned long long)(*buffer++) << 24);
+ value |= ((unsigned long long)(*buffer++) << 16);
+ value |= ((unsigned long long)(*buffer++) << 8);
+ value |= ((unsigned long long)(*buffer++) << 0);
+ } else {
+ value = ((unsigned long long)(*buffer++) << 0);
+ value |= ((unsigned long long)(*buffer++) << 8);
+ value |= ((unsigned long long)(*buffer++) << 16);
+ value |= ((unsigned long long)(*buffer++) << 24);
+ }
+ StoreMemory(cca,AccessLength_WORD,value,paddr,vaddr,isRAW);
+ }
+ vaddr += 4;
+ index &= ~4;
+ }
+ for (;index; index -= 8) {
+ unsigned long long paddr;
+ int cca;
+ if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isRAW)) {
+ unsigned long long value;
+ if (BigEndianMem) {
+ value = ((unsigned long long)(*buffer++) << 56);
+ value |= ((unsigned long long)(*buffer++) << 48);
+ value |= ((unsigned long long)(*buffer++) << 40);
+ value |= ((unsigned long long)(*buffer++) << 32);
+ value |= ((unsigned long long)(*buffer++) << 24);
+ value |= ((unsigned long long)(*buffer++) << 16);
+ value |= ((unsigned long long)(*buffer++) << 8);
+ value |= ((unsigned long long)(*buffer++) << 0);
+ } else {
+ value = ((unsigned long long)(*buffer++) << 0);
+ value |= ((unsigned long long)(*buffer++) << 8);
+ value |= ((unsigned long long)(*buffer++) << 16);
+ value |= ((unsigned long long)(*buffer++) << 24);
+ value |= ((unsigned long long)(*buffer++) << 32);
+ value |= ((unsigned long long)(*buffer++) << 40);
+ value |= ((unsigned long long)(*buffer++) << 48);
+ value |= ((unsigned long long)(*buffer++) << 56);
+ }
+ StoreMemory(cca,AccessLength_DOUBLEWORD,value,paddr,vaddr,isRAW);
+ }
+ vaddr += 8;
+ }
+
+ return(size);
+}
+
+int
+sim_read (addr,buffer,size)
+ SIM_ADDR addr;
+ unsigned char *buffer;
+ int size;
+{
+ int index;
+
+ /* Return the number of bytes read, or zero if error. */
+#ifdef DEBUG
+ callback->printf_filtered(callback,"sim_read(0x%08X%08X,buffer,%d);\n",(unsigned int)((unsigned long long)(addr)>>32),(unsigned int)(addr&0xFFFFFFFF),size);
+#endif /* DEBUG */
+
+ /* TODO: Perform same optimisation as the sim_write() code
+ above. NOTE: This will require a bit more work since we will need
+ to ensure that the source physical address is doubleword aligned
+ before, and then deal with trailing bytes. */
+ for (index = 0; (index < size); index++) {
+ unsigned long long vaddr,paddr,value;
+ int cca;
+ vaddr = (unsigned long long)addr + index;
+ if (AddressTranslation(vaddr,isDATA,isLOAD,&paddr,&cca,isTARGET,isRAW)) {
+ value = LoadMemory(cca,AccessLength_BYTE,paddr,vaddr,isDATA,isRAW);
+ buffer[index] = (unsigned char)(value&0xFF);
+ } else
+ break;
+ }
+
+ return(index);
+}
+
+void
+sim_store_register (rn,memory)
+ int rn;
+ unsigned char *memory;
+{
+#ifdef DEBUG
+ callback->printf_filtered(callback,"sim_store_register(%d,*memory=0x%08X%08X);\n",rn,*((unsigned int *)memory),*((unsigned int *)(memory + 4)));
+#endif /* DEBUG */
+
+ /* Unfortunately this suffers from the same problem as the register
+ numbering one. We need to know what the width of each logical
+ register number is for the architecture being simulated. */
+ if (register_widths[rn] == 0)
+ callback->printf_filtered(callback,"Warning: Invalid register width for %d (register store ignored)\n",rn);
+ else {
+ if (register_widths[rn] == 32)
+ registers[rn] = *((unsigned int *)memory);
+ else
+ registers[rn] = *((unsigned long long *)memory);
+ }
+
+ return;
+}
+
+void
+sim_fetch_register (rn,memory)
+ int rn;
+ unsigned char *memory;
+{
+#ifdef DEBUG
+ callback->printf_filtered(callback,"sim_fetch_register(%d=0x%08X%08X,mem) : place simulator registers into memory\n",rn,(unsigned int)(registers[rn]>>32),(unsigned int)(registers[rn]&0xFFFFFFFF));
+#endif /* DEBUG */
+
+ if (register_widths[rn] == 0)
+ callback->printf_filtered(callback,"Warning: Invalid register width for %d (register fetch ignored)\n",rn);
+ else {
+ if (register_widths[rn] == 32)
+ *((unsigned int *)memory) = (registers[rn] & 0xFFFFFFFF);
+ else /* 64bit register */
+ *((unsigned long long *)memory) = registers[rn];
+ }
+ return;
+}
+
+void
+sim_stop_reason (reason,sigrc)
+ enum sim_stop *reason;
+ int *sigrc;
+{
+/* We can have "*reason = {sim_exited, sim_stopped, sim_signalled}", so
+ sim_exited *sigrc = argument to exit()
+ sim_stopped *sigrc = exception number
+ sim_signalled *sigrc = signal number
+*/
+ if (state & simEXCEPTION) {
+ /* If "sim_signalled" is used, GDB expects normal SIGNAL numbers,
+ and not the MIPS specific exception codes. */
+#if 1
+ /* For some reason, sending GDB a sim_signalled reason cause it to
+ terminate out. */
+ *reason = sim_stopped;
+#else
+ *reason = sim_signalled;
+#endif
+ switch ((CAUSE >> 2) & 0x1F) {
+ case Interrupt:
+ *sigrc = SIGINT; /* wrong type of interrupt, but it will do for the moment */
+ break;
+
+ case TLBModification:
+ case TLBLoad:
+ case TLBStore:
+ case AddressLoad:
+ case AddressStore:
+ case InstructionFetch:
+ case DataReference:
+ *sigrc = SIGBUS;
+ break;
+
+ case ReservedInstruction:
+ case CoProcessorUnusable:
+ *sigrc = SIGILL;
+ break;
+
+ case IntegerOverflow:
+ case FPE:
+ *sigrc = SIGFPE;
+ break;
+
+ case Trap:
+ case Watch:
+ case SystemCall:
+ case BreakPoint:
+ *sigrc = SIGTRAP;
+ break;
+
+ default : /* Unknown internal exception */
+ *sigrc = SIGQUIT;
+ break;
+ }
+ } else if (state & simEXIT) {
+ printf("DBG: simEXIT (%d)\n",rcexit);
+ *reason = sim_exited;
+ *sigrc = rcexit;
+ } else { /* assume single-stepping */
+ *reason = sim_stopped;
+ *sigrc = SIGTRAP;
+ }
+ state &= ~(simEXCEPTION | simEXIT);
+ return;
+}
+
+void
+sim_info (verbose)
+ int verbose;
+{
+ /* Accessed from the GDB "info files" command: */
+
+ callback->printf_filtered(callback,"MIPS %d-bit simulator\n",(PROCESSOR_64BIT ? 64 : 32));
+
+ callback->printf_filtered(callback,"%s endian memory model\n",(BigEndianMem ? "Big" : "Little"));
+
+ callback->printf_filtered(callback,"0x%08X bytes of memory at 0x%08X%08X\n",(unsigned int)membank_size,(unsigned int)(membank_base>>32),(unsigned int)(membank_base&0xFFFFFFFF));
+
+#if !defined(FASTSIM)
+ callback->printf_filtered(callback,"Instruction fetches = %d\n",instruction_fetches);
+ callback->printf_filtered(callback,"Pipeline ticks = %d\n",pipeline_ticks);
+ /* It would be a useful feature, if when performing multi-cycle
+ simulations (rather than single-stepping) we keep the start and
+ end times of the execution, so that we can give a performance
+ figure for the simulator. */
+#endif /* !FASTSIM */
+
+ /* print information pertaining to MIPS ISA and architecture being simulated */
+ /* things that may be interesting */
+ /* instructions executed - if available */
+ /* cycles executed - if available */
+ /* pipeline stalls - if available */
+ /* virtual time taken */
+ /* profiling size */
+ /* profiling frequency */
+ /* profile minpc */
+ /* profile maxpc */
+
+ return;
+}
+
+int
+sim_load (prog,from_tty)
+ char *prog;
+ int from_tty;
+{
+ /* Return non-zero if the caller should handle the load. Zero if
+ we have loaded the image. */
+ return(-1);
+}
+
+void
+sim_create_inferior (start_address,argv,env)
+ SIM_ADDR start_address;
+ char **argv;
+ char **env;
+{
+#ifdef DEBUG
+ printf("DBG: sim_create_inferior entered: start_address = 0x%08X\n",start_address);
+#endif /* DEBUG */
+
+ /* Prepare to execute the program to be simulated */
+ /* argv and env are NULL terminated lists of pointers */
+
+#if 1
+ PC = (unsigned long long)start_address;
+#else
+ /* TODO: Sort this properly. SIM_ADDR may already be a 64bit value: */
+ PC = SIGNEXTEND(start_address,32);
+#endif
+ /* NOTE: GDB normally sets the PC explicitly. However, this call is
+ used by other clients of the simulator. */
+
+ if (argv || env) {
+ callback->printf_filtered(callback,"sim_create_inferior() : passed arguments ignored\n");
+#if 1 /* def DEBUG */
+ {
+ char **cptr;
+ for (cptr = argv; (cptr && *cptr); cptr++)
+ printf("DBG: arg \"%s\"\n",*cptr);
+ }
+#endif /* DEBUG */
+ /* We should really place the argv slot values into the argument
+ registers, and onto the stack as required. However, this
+ assumes that we have a stack defined, which is not necessarily
+ true at the moment. */
+ }
+
+ return;
+}
+
+void
+sim_kill ()
+{
+#if 1
+ /* This routine should be for terminating any existing simulation
+ thread. Since we are single-threaded only at the moment, this is
+ not an issue. It should *NOT* be used to terminate the
+ simulator. */
+#else /* do *NOT* call sim_close */
+ sim_close(1); /* Do not hang on errors */
+ /* This would also be the point where any memory mapped areas used
+ by the simulator should be released. */
+#endif
+ return;
+}
+
+int
+sim_get_quit_code ()
+{
+ /* The standard MIPS PCS (Procedure Calling Standard) uses V0(r2) as
+ the function return value. However, it may be more correct for
+ this to return the argument to the exit() function (if
+ called). */
+ return(V0);
+}
+
+void
+sim_set_callbacks (p)
+ host_callback *p;
+{
+ callback = p;
+ return;
+}
+
+typedef enum {e_terminate,e_help,e_setmemsize,e_reset} e_cmds;
+
+static struct t_sim_command {
+ e_cmds id;
+ const char *name;
+ const char *help;
+} sim_commands[] = {
+ {e_help, "help", ": Show MIPS simulator private commands"},
+ {e_setmemsize,"set-memory-size","<n> : Specify amount of memory simulated"},
+ {e_reset, "reset-system", ": Reset the simulated processor"},
+ {e_terminate, NULL}
+};
+
+void
+sim_do_command (cmd)
+ char *cmd;
+{
+ struct t_sim_command *cptr;
+
+ if (!(cmd && *cmd != '\0'))
+ cmd = "help";
+
+ /* NOTE: Accessed from the GDB "sim" commmand: */
+ for (cptr = sim_commands; cptr && cptr->name; cptr++)
+ if (strncmp(cmd,cptr->name,strlen(cptr->name)) == 0) {
+ cmd += strlen(cptr->name);
+ switch (cptr->id) {
+ case e_help: /* no arguments */
+ { /* no arguments */
+ struct t_sim_command *lptr;
+ callback->printf_filtered(callback,"List of MIPS simulator commands:\n");
+ for (lptr = sim_commands; lptr->name; lptr++)
+ callback->printf_filtered(callback,"%s %s\n",lptr->name,lptr->help);
+ }
+ break;
+
+ case e_setmemsize: /* memory size argument */
+ {
+ unsigned int newsize = (unsigned int)getnum(cmd);
+ sim_size(newsize);
+ }
+ break;
+
+ case e_reset: /* no arguments */
+ ColdReset();
+ /* NOTE: See the comments in sim_open() relating to device
+ initialisation. */
+ break;
+
+ default:
+ callback->printf_filtered(callback,"FATAL: Matched \"%s\", but failed to match command id %d.\n",cmd,cptr->id);
+ break;
+ }
+ break;
+ }
+
+ if (!(cptr->name))
+ callback->printf_filtered(callback,"Error: \"%s\" is not a valid MIPS simulator command.\n",cmd);
+
+ return;
+}
+
+/*---------------------------------------------------------------------------*/
+/* NOTE: The following routines do not seem to be used by GDB at the
+ moment. However, they may be useful to the standalone simulator
+ world. */
+
+
+/* The profiling format is described in the "gmon_out.h" header file */
+void
+sim_set_profile (n)
+ int n;
+{
+#if defined(PROFILE)
+ profile_frequency = n;
+ state |= simPROFILE;
+#endif /* PROFILE */
+ return;
+}
+
+void
+sim_set_profile_size (n)
+ int n;
+{
+#if defined(PROFILE)
+ if (state & simPROFILE) {
+ int bsize;
+
+ /* Since we KNOW that the memory banks are a power-of-2 in size: */
+ profile_nsamples = power2(n);
+ profile_minpc = membank_base;
+ profile_maxpc = (membank_base + membank_size);
+
+ /* Just in-case we are sampling every address: NOTE: The shift
+ right of 2 is because we only have word-aligned PC addresses. */
+ if (profile_nsamples > (membank_size >> 2))
+ profile_nsamples = (membank_size >> 2);
+
+ /* Since we are dealing with power-of-2 values: */
+ profile_shift = (((membank_size >> 2) / profile_nsamples) - 1);
+
+ bsize = (profile_nsamples * sizeof(unsigned short));
+ if (profile_hist == NULL)
+ profile_hist = (unsigned short *)calloc(64,(bsize / 64));
+ else
+ profile_hist = (unsigned short *)realloc(profile_hist,bsize);
+ if (profile_hist == NULL) {
+ callback->printf_filtered(callback,"Failed to allocate VM for profiling buffer (0x%08X bytes)\n",bsize);
+ state &= ~simPROFILE;
+ }
+ }
+#endif /* PROFILE */
+
+ return;
+}
+
+void
+sim_size(newsize)
+ unsigned int newsize;
+{
+ char *new;
+ /* Used by "run", and internally, to set the simulated memory size */
+ newsize = power2(newsize);
+ if (membank == NULL)
+ new = (char *)calloc(64,(membank_size / 64));
+ else
+ new = (char *)realloc(membank,newsize);
+ if (new == NULL) {
+ if (membank == NULL)
+ callback->printf_filtered(callback,"Not enough VM for simulation memory of 0x%08X bytes\n",membank_size);
+ else
+ callback->printf_filtered(callback,"Failed to resize memory (still 0x%08X bytes)\n",membank_size);
+ } else {
+ membank_size = (unsigned)newsize;
+ membank = new;
+ callback->printf_filtered(callback,"Memory size now 0x%08X bytes\n",membank_size);
+#if defined(PROFILE)
+ /* Ensure that we sample across the new memory range */
+ sim_set_profile_size(profile_nsamples);
+#endif /* PROFILE */
+ }
+
+ return;
+}
+
+int
+sim_trace()
+{
+ /* This routine is called by the "run" program, when detailed
+ execution information is required. Rather than executing a single
+ instruction, and looping around externally... we just start
+ simulating, returning TRUE when the simulator stops (for whatever
+ reason). */
+
+#if defined(TRACE)
+ /* Ensure tracing is enabled, if available */
+ if (tracefh != NULL)
+ state |= simTRACE;
+#endif /* TRACE */
+
+ state &= ~(simSTOP | simSTEP); /* execute until event */
+ state |= (simHALTEX | simHALTIN); /* treat interrupt event as exception */
+ /* Start executing instructions from the current state (set
+ explicitly by register updates, or by sim_create_inferior): */
+ simulate();
+
+ return(1);
+}
+
+/*---------------------------------------------------------------------------*/
+/*-- Private simulator support interface ------------------------------------*/
+/*---------------------------------------------------------------------------*/
+
+static void
+sim_monitor(reason)
+ unsigned int reason;
+{
+ /* The IDT monitor actually allows two instructions per vector
+ slot. However, the simulator currently causes a trap on each
+ individual instruction. We cheat, and lose the bottom bit. */
+ reason >>= 1;
+
+ /* The following callback functions are available, however the
+ monitor we are simulating does not make use of them: get_errno,
+ isatty, lseek, rename, system, time and unlink */
+ switch (reason) {
+ case 6: /* int open(char *path,int flags) */
+ {
+ const char *ptr;
+ unsigned long long paddr;
+ int cca;
+ if (AddressTranslation(A0,isDATA,isLOAD,&paddr,&cca,isHOST,isREAL))
+ V0 = callback->open(callback,(char *)((int)paddr),(int)A1);
+ else
+ callback->printf_filtered(callback,"WARNING: Attempt to pass pointer that does not reference simulated memory\n");
+ }
+ break;
+
+ case 7: /* int read(int file,char *ptr,int len) */
+ {
+ const char *ptr;
+ unsigned long long paddr;
+ int cca;
+ if (AddressTranslation(A1,isDATA,isLOAD,&paddr,&cca,isHOST,isREAL))
+ V0 = callback->read(callback,(int)A0,(char *)((int)paddr),(int)A2);
+ else
+ callback->printf_filtered(callback,"WARNING: Attempt to pass pointer that does not reference simulated memory\n");
+ }
+ break;
+
+ case 8: /* int write(int file,char *ptr,int len) */
+ {
+ const char *ptr;
+ unsigned long long paddr;
+ int cca;
+ if (AddressTranslation(A1,isDATA,isLOAD,&paddr,&cca,isHOST,isREAL))
+ V0 = callback->write(callback,(int)A0,(const char *)((int)paddr),(int)A2);
+ else
+ callback->printf_filtered(callback,"WARNING: Attempt to pass pointer that does not reference simulated memory\n");
+ }
+ break;
+
+ case 10: /* int close(int file) */
+ V0 = callback->close(callback,(int)A0);
+ break;
+
+ case 11: /* char inbyte(void) */
+ {
+ char tmp;
+ if (callback->read_stdin(callback,&tmp,sizeof(char)) != sizeof(char)) {
+ callback->printf_filtered(callback,"WARNING: Invalid return from character read\n");
+ V0 = -1;
+ }
+ else
+ V0 = tmp;
+ }
+ break;
+
+ case 12: /* void outbyte(char chr) : write a byte to "stdout" */
+ {
+ char tmp = (char)(A0 & 0xFF);
+ callback->write_stdout(callback,&tmp,sizeof(char));
+ }
+ break;
+
+ case 17: /* void _exit() */
+ callback->printf_filtered(callback,"sim_monitor(17): _exit(int reason) to be coded\n");
+ state |= (simSTOP | simEXIT); /* stop executing code */
+ rcexit = (unsigned int)(A0 & 0xFFFFFFFF);
+ break;
+
+ case 55: /* void get_mem_info(unsigned int *ptr) */
+ /* in: A0 = pointer to three word memory location */
+ /* out: [A0 + 0] = size */
+ /* [A0 + 4] = instruction cache size */
+ /* [A0 + 8] = data cache size */
+ {
+ unsigned long long vaddr = A0;
+ unsigned long long paddr, value;
+ int cca;
+ int failed = 0;
+
+ /* NOTE: We use RAW memory writes here, but since we are not
+ gathering statistics for the monitor calls we are simulating,
+ it is not an issue. */
+
+ /* Memory size */
+ if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isREAL)) {
+ value = (unsigned long long)membank_size;
+ StoreMemory(cca,AccessLength_WORD,value,paddr,vaddr,isRAW);
+ /* We re-do the address translations, in-case the block
+ overlaps a memory boundary: */
+ value = 0;
+ vaddr += (AccessLength_WORD + 1);
+ if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isREAL)) {
+ StoreMemory(cca,AccessLength_WORD,value,paddr,vaddr,isRAW);
+ vaddr += (AccessLength_WORD + 1);
+ if (AddressTranslation(vaddr,isDATA,isSTORE,&paddr,&cca,isTARGET,isREAL))
+ StoreMemory(cca,AccessLength_WORD,value,paddr,vaddr,isRAW);
+ else
+ failed = -1;
+ } else
+ failed = -1;
+ } else
+ failed = -1;
+
+ if (failed)
+ callback->printf_filtered(callback,"WARNING: Invalid pointer passed into monitor call\n");
+ }
+ break;
+
+ default:
+ callback->printf_filtered(callback,"TODO: sim_monitor(%d) : PC = 0x%08X%08X\n",reason,(unsigned int)(IPC>>32),(unsigned int)(IPC&0xFFFFFFFF));
+ callback->printf_filtered(callback,"(Arguments : A0 = 0x%08X%08X : A1 = 0x%08X%08X : A2 = 0x%08X%08X : A3 = 0x%08X%08X)\n",(unsigned int)(A0>>32),(unsigned int)(A0&0xFFFFFFFF),(unsigned int)(A1>>32),(unsigned int)(A1&0xFFFFFFFF),(unsigned int)(A2>>32),(unsigned int)(A2&0xFFFFFFFF),(unsigned int)(A3>>32),(unsigned int)(A3&0xFFFFFFFF));
+ break;
+ }
+ return;
+}
+
+void
+sim_error(fmt)
+ char *fmt;
+{
+ va_list ap;
+ va_start(ap,fmt);
+ callback->printf_filtered(callback,"SIM Error: ");
+ callback->printf_filtered(callback,fmt,ap);
+ va_end(ap);
+ SignalException(SimulatorFault,"");
+ return;
+}
+
+static unsigned int
+power2(value)
+ unsigned int value;
+{
+ int loop,tmp;
+
+ /* Round *UP* to the nearest power-of-2 if not already one */
+ if (value != (value & ~(value - 1))) {
+ for (tmp = value, loop = 0; (tmp != 0); loop++)
+ tmp >>= 1;
+ value = (1 << loop);
+ }
+
+ return(value);
+}
+
+static long
+getnum(value)
+ char *value;
+{
+ long num;
+ char *end;
+
+ num = strtol(value,&end,10);
+ if (end == value)
+ callback->printf_filtered(callback,"Warning: Invalid number \"%s\" ignored, using zero\n",value);
+ else {
+ if (*end && ((tolower(*end) == 'k') || (tolower(*end) == 'm'))) {
+ if (tolower(*end) == 'k')
+ num *= (1 << 10);
+ else
+ num *= (1 << 20);
+ end++;
+ }
+ if (*end)
+ callback->printf_filtered(callback,"Warning: Spurious characters \"%s\" at end of number ignored\n",end);
+ }
+
+ return(num);
+}
+
+/*-- trace support ----------------------------------------------------------*/
+
+/* The TRACE support is provided (if required) in the memory accessing
+ routines. Since we are also providing the architecture specific
+ features, the architecture simulation code can also deal with
+ notifying the TRACE world of cache flushes, etc. Similarly we do
+ not need to provide profiling support in the simulator engine,
+ since we can sample in the instruction fetch control loop. By
+ defining the TRACE manifest, we add tracing as a run-time
+ option. */
+
+#if defined(TRACE)
+/* Tracing by default produces "din" format (as required by
+ dineroIII). Each line of such a trace file *MUST* have a din label
+ and address field. The rest of the line is ignored, so comments can
+ be included if desired. The first field is the label which must be
+ one of the following values:
+
+ 0 read data
+ 1 write data
+ 2 instruction fetch
+ 3 escape record (treated as unknown access type)
+ 4 escape record (causes cache flush)
+
+ The address field is a 32bit (lower-case) hexadecimal address
+ value. The address should *NOT* be preceded by "0x".
+
+ The size of the memory transfer is not important when dealing with
+ cache lines (as long as no more than a cache line can be
+ transferred in a single operation :-), however more information
+ could be given following the dineroIII requirement to allow more
+ complete memory and cache simulators to provide better
+ results. i.e. the University of Pisa has a cache simulator that can
+ also take bus size and speed as (variable) inputs to calculate
+ complete system performance (a much more useful ability when trying
+ to construct an end product, rather than a processor). They
+ currently have an ARM version of their tool called ChARM. */
+
+static
+void dotrace(tracefh,type,address,width,comment)
+ FILE *tracefh;
+ int type;
+ unsigned int address;
+ int width;
+ char *comment;
+{
+ if (state & simTRACE) {
+ va_list ap;
+ fprintf(tracefh,"%d %08x ; width %d ; ",type,address,width);
+ va_start(ap,comment);
+ fprintf(tracefh,comment,ap);
+ va_end(ap);
+ fprintf(tracefh,"\n");
+ }
+ /* NOTE: Since the "din" format will only accept 32bit addresses, and
+ we may be generating 64bit ones, we should put the hi-32bits of the
+ address into the comment field. */
+
+ /* TODO: Provide a buffer for the trace lines. We can then avoid
+ performing writes until the buffer is filled, or the file is
+ being closed. */
+
+ /* NOTE: We could consider adding a comment field to the "din" file
+ produced using type 3 markers (unknown access). This would then
+ allow information about the program that the "din" is for, and
+ the MIPs world that was being simulated, to be placed into the
+ trace file. */
+
+ return;
+}
+#endif /* TRACE */
+
+/*---------------------------------------------------------------------------*/
+/*-- simulator engine -------------------------------------------------------*/
+/*---------------------------------------------------------------------------*/
+
+static void
+ColdReset()
+{
+ /* RESET: Fixed PC address: */
+ PC = (((unsigned long long)0xFFFFFFFF<<32) | 0xBFC00000);
+ /* The reset vector address is in the unmapped, uncached memory space. */
+
+ SR &= ~(status_SR | status_TS | status_RP);
+ SR |= (status_ERL | status_BEV);
+ /* VR4300 starts in Big-Endian mode */
+ CONFIG &= ~(config_EP_mask << config_EP_shift);
+ CONFIG |= ((config_EP_D << config_EP_shift) | config_BE);
+ /* TODO: The VR4300 CONFIG register is not modelled fully at the moment */
+
+#if defined(HASFPU) && (GPRLEN == (64))
+ /* Cheat and allow access to the complete register set immediately: */
+ SR |= status_FR; /* 64bit registers */
+#endif /* HASFPU and 64bit FP registers */
+
+ /* Ensure that any instructions with pending register updates are
+ cleared: */
+ {
+ int loop;
+ for (loop = 0; (loop < PSLOTS); loop++)
+ pending_slot_reg[loop] = (LAST_EMBED_REGNUM + 1);
+ pending_in = pending_out = pending_total = 0;
+ }
+
+#if defined(HASFPU)
+ /* Initialise the FPU registers to the unknown state */
+ {
+ int rn;
+ for (rn = 0; (rn < 32); rn++)
+ fpr_state[rn] = fmt_uninterpreted;
+ }
+#endif /* HASFPU */
+
+ return;
+}
+
+/* Description from page A-22 of the "MIPS IV Instruction Set" manual (revision 3.1) */
+/* Translate a virtual address to a physical address and cache
+ coherence algorithm describing the mechanism used to resolve the
+ memory reference. Given the virtual address vAddr, and whether the
+ reference is to Instructions ot Data (IorD), find the corresponding
+ physical address (pAddr) and the cache coherence algorithm (CCA)
+ used to resolve the reference. If the virtual address is in one of
+ the unmapped address spaces the physical address and the CCA are
+ determined directly by the virtual address. If the virtual address
+ is in one of the mapped address spaces then the TLB is used to
+ determine the physical address and access type; if the required
+ translation is not present in the TLB or the desired access is not
+ permitted the function fails and an exception is taken.
+
+ NOTE: This function is extended to return an exception state. This,
+ along with the exception generation is used to notify whether a
+ valid address translation occured */
+
+static int
+AddressTranslation(vAddr,IorD,LorS,pAddr,CCA,host,raw)
+ unsigned long long vAddr;
+ int IorD;
+ int LorS;
+ unsigned long long *pAddr;
+ int *CCA;
+ int host;
+ int raw;
+{
+ int res = -1; /* TRUE : Assume good return */
+
+#ifdef DEBUG
+ callback->printf_filtered(callback,"AddressTranslation(0x%08X%08X,%s,%s,...);\n",(unsigned int)(vAddr >> 32),(unsigned int)(vAddr & 0xFFFFFFFF),(IorD ? "isDATA" : "isINSTRUCTION"),(LorS ? "iSTORE" : "isLOAD"));
+#endif
+
+ /* Check that the address is valid for this memory model */
+
+ /* For a simple (flat) memory model, we simply pass virtual
+ addressess through (mostly) unchanged. */
+ vAddr &= 0xFFFFFFFF;
+ *pAddr = vAddr; /* default for isTARGET */
+ *CCA = Uncached; /* not used for isHOST */
+
+ /* NOTE: This is a duplicate of the code that appears in the
+ LoadMemory and StoreMemory functions. They should be merged into
+ a single function (that can be in-lined if required). */
+ if ((vAddr >= membank_base) && (vAddr < (membank_base + membank_size))) {
+ if (host)
+ *pAddr = (int)&membank[((unsigned int)(vAddr - membank_base) & (membank_size - 1))];
+ } else if ((vAddr >= monitor_base) && (vAddr < (monitor_base + monitor_size))) {
+ if (host)
+ *pAddr = (int)&monitor[((unsigned int)(vAddr - monitor_base) & (monitor_size - 1))];
+ } else {
+#if 1 /* def DEBUG */
+ callback->printf_filtered(callback,"Failed: AddressTranslation(0x%08X%08X,%s,%s,...);\n",(unsigned int)(vAddr >> 32),(unsigned int)(vAddr & 0xFFFFFFFF),(IorD ? "isDATA" : "isINSTRUCTION"),(LorS ? "isSTORE" : "isLOAD"));
+#endif /* DEBUG */
+ res = 0; /* AddressTranslation has failed */
+ *pAddr = -1;
+ if (!raw) /* only generate exceptions on real memory transfers */
+ SignalException((LorS == isSTORE) ? AddressStore : AddressLoad);
+ else
+ callback->printf_filtered(callback,"AddressTranslation for %s %s from 0x%08X%08X failed\n",(IorD ? "data" : "instruction"),(LorS ? "store" : "load"),(unsigned int)(vAddr>>32),(unsigned int)(vAddr&0xFFFFFFFF));
+ }
+
+ return(res);
+}
+
+/* Description from page A-23 of the "MIPS IV Instruction Set" manual (revision 3.1) */
+/* Prefetch data from memory. Prefetch is an advisory instruction for
+ which an implementation specific action is taken. The action taken
+ may increase performance, but must not change the meaning of the
+ program, or alter architecturally-visible state. */
+static void
+Prefetch(CCA,pAddr,vAddr,DATA,hint)
+ int CCA;
+ unsigned long long pAddr;
+ unsigned long long vAddr;
+ int DATA;
+ int hint;
+{
+#ifdef DEBUG
+ callback->printf_filtered(callback,"Prefetch(%d,0x%08X%08X,0x%08X%08X,%d,%d);\n",CCA,(unsigned int)(pAddr >> 32),(unsigned int)(pAddr & 0xFFFFFFFF),(unsigned int)(vAddr >> 32),(unsigned int)(vAddr & 0xFFFFFFFF),DATA,hint);
+#endif /* DEBUG */
+
+ /* For our simple memory model we do nothing */
+ return;
+}
+
+/* Description from page A-22 of the "MIPS IV Instruction Set" manual (revision 3.1) */
+/* Load a value from memory. Use the cache and main memory as
+ specified in the Cache Coherence Algorithm (CCA) and the sort of
+ access (IorD) to find the contents of AccessLength memory bytes
+ starting at physical location pAddr. The data is returned in the
+ fixed width naturally-aligned memory element (MemElem). The
+ low-order two (or three) bits of the address and the AccessLength
+ indicate which of the bytes within MemElem needs to be given to the
+ processor. If the memory access type of the reference is uncached
+ then only the referenced bytes are read from memory and valid
+ within the memory element. If the access type is cached, and the
+ data is not present in cache, an implementation specific size and
+ alignment block of memory is read and loaded into the cache to
+ satisfy a load reference. At a minimum, the block is the entire
+ memory element. */
+static unsigned long long
+LoadMemory(CCA,AccessLength,pAddr,vAddr,IorD,raw)
+ int CCA;
+ int AccessLength;
+ unsigned long long pAddr;
+ unsigned long long vAddr;
+ int IorD;
+ int raw;
+{
+ unsigned long long value;
+
+#ifdef DEBUG
+ if (membank == NULL)
+ callback->printf_filtered(callback,"DBG: LoadMemory(%d,%d,0x%08X%08X,0x%08X%08X,%s,%s)\n",CCA,AccessLength,(unsigned int)(pAddr >> 32),(unsigned int)(pAddr & 0xFFFFFFFF),(unsigned int)(vAddr >> 32),(unsigned int)(vAddr & 0xFFFFFFFF),(IorD ? "isDATA" : "isINSTRUCTION"),(raw ? "isRAW" : "isREAL"));
+#endif /* DEBUG */
+
+#if defined(WARN_MEM)
+ if (CCA != uncached)
+ callback->printf_filtered(callback,"SIM Warning: LoadMemory CCA (%d) is not uncached (currently all accesses treated as cached)\n",CCA);
+
+ if (((pAddr & LOADDRMASK) + AccessLength) > LOADDRMASK) {
+ /* In reality this should be a Bus Error */
+ sim_error("AccessLength of %d would extend over 64bit aligned boundary for physical address 0x%08X%08X\n",AccessLength,(unsigned int)(pAddr>>32),(unsigned int)(pAddr&0xFFFFFFFF));
+ }
+#endif /* WARN_MEM */
+
+ /* Decide which physical memory locations are being dealt with. At
+ this point we should be able to split the pAddr bits into the
+ relevant address map being simulated. If the "raw" variable is
+ set, the memory read being performed should *NOT* update any I/O
+ state or affect the CPU state. This also includes avoiding
+ affecting statistics gathering. */
+
+ /* If instruction fetch then we need to check that the two lo-order
+ bits are zero, otherwise raise a InstructionFetch exception: */
+ if ((IorD == isINSTRUCTION) && ((pAddr & 0x3) != 0))
+ SignalException(InstructionFetch);
+ else {
+ unsigned int index;
+ unsigned char *mem = NULL;
+
+ /* TODO: #assert (isRAW) - check that our boolean is the correct way around */
+
+#if defined(TRACE)
+ if (!raw)
+ dotrace(tracefh,((IorD == isDATA) ? 0 : 2),(unsigned int)(pAddr&0xFFFFFFFF),(AccessLength + 1),"load%s",((IorD == isDATA) ? "" : " instruction"));
+#endif /* TRACE */
+
+ /* NOTE: Quicker methods of decoding the address space can be used
+ when a real memory map is being simulated (i.e. using hi-order
+ address bits to select device). */
+ if ((pAddr >= membank_base) && (pAddr < (membank_base + membank_size))) {
+ index = ((unsigned int)(pAddr - membank_base) & (membank_size - 1));
+ mem = membank;
+ } else if ((pAddr >= monitor_base) && (pAddr < (monitor_base + monitor_size))) {
+ index = ((unsigned int)(pAddr - monitor_base) & (monitor_size - 1));
+ mem = monitor;
+ }
+ if (mem == NULL)
+ sim_error("Simulator memory not found for physical address 0x%08X%08X\n",(unsigned int)(pAddr>>32),(unsigned int)(pAddr&0xFFFFFFFF));
+ else {
+ /* If we obtained the endianness of the host, and it is the same
+ as the target memory system we can optimise the memory
+ accesses. However, without that information we must perform
+ slow transfer, and hope that the compiler optimisation will
+ merge successive loads. */
+ value = 0; /* no data loaded yet */
+
+ /* In reality we should always be loading a doubleword value (or
+ word value in 32bit memory worlds). The external code then
+ extracts the required bytes. However, to keep performance
+ high we only load the required bytes into the relevant
+ slots. */
+ if (BigEndianMem)
+ switch (AccessLength) { /* big-endian memory */
+ case AccessLength_DOUBLEWORD :
+ value |= ((unsigned long long)mem[index++] << 56);
+ case AccessLength_SEPTIBYTE :
+ value |= ((unsigned long long)mem[index++] << 48);
+ case AccessLength_SEXTIBYTE :
+ value |= ((unsigned long long)mem[index++] << 40);
+ case AccessLength_QUINTIBYTE :
+ value |= ((unsigned long long)mem[index++] << 32);
+ case AccessLength_WORD :
+ value |= ((unsigned int)mem[index++] << 24);
+ case AccessLength_TRIPLEBYTE :
+ value |= ((unsigned int)mem[index++] << 16);
+ case AccessLength_HALFWORD :
+ value |= ((unsigned int)mem[index++] << 8);
+ case AccessLength_BYTE :
+ value |= mem[index];
+ break;
+ }
+ else {
+ index += (AccessLength + 1);
+ switch (AccessLength) { /* little-endian memory */
+ case AccessLength_DOUBLEWORD :
+ value |= ((unsigned long long)mem[--index] << 56);
+ case AccessLength_SEPTIBYTE :
+ value |= ((unsigned long long)mem[--index] << 48);
+ case AccessLength_SEXTIBYTE :
+ value |= ((unsigned long long)mem[--index] << 40);
+ case AccessLength_QUINTIBYTE :
+ value |= ((unsigned long long)mem[--index] << 32);
+ case AccessLength_WORD :
+ value |= ((unsigned long long)mem[--index] << 24);
+ case AccessLength_TRIPLEBYTE :
+ value |= ((unsigned long long)mem[--index] << 16);
+ case AccessLength_HALFWORD :
+ value |= ((unsigned long long)mem[--index] << 8);
+ case AccessLength_BYTE :
+ value |= ((unsigned long long)mem[--index] << 0);
+ break;
+ }
+ }
+
+#ifdef DEBUG
+ printf("DBG: LoadMemory() : (offset %d) : value = 0x%08X%08X\n",(int)(pAddr & LOADDRMASK),(unsigned int)(value>>32),(unsigned int)(value&0xFFFFFFFF));
+#endif /* DEBUG */
+
+ /* TODO: We could try and avoid the shifts when dealing with raw
+ memory accesses. This would mean updating the LoadMemory and
+ StoreMemory routines to avoid shifting the data before
+ returning or using it. */
+ if (!raw) { /* do nothing for raw accessess */
+ if (BigEndianMem)
+ value <<= (((7 - (pAddr & LOADDRMASK)) - AccessLength) * 8);
+ else /* little-endian only needs to be shifted up to the correct byte offset */
+ value <<= ((pAddr & LOADDRMASK) * 8);
+ }
+
+#ifdef DEBUG
+ printf("DBG: LoadMemory() : shifted value = 0x%08X%08X\n",(unsigned int)(value>>32),(unsigned int)(value&0xFFFFFFFF));
+#endif DEBUG
+ }
+ }
+
+ return(value);
+}
+
+/* Description from page A-23 of the "MIPS IV Instruction Set" manual (revision 3.1) */
+/* Store a value to memory. The specified data is stored into the
+ physical location pAddr using the memory hierarchy (data caches and
+ main memory) as specified by the Cache Coherence Algorithm
+ (CCA). The MemElem contains the data for an aligned, fixed-width
+ memory element (word for 32-bit processors, doubleword for 64-bit
+ processors), though only the bytes that will actually be stored to
+ memory need to be valid. The low-order two (or three) bits of pAddr
+ and the AccessLength field indicates which of the bytes within the
+ MemElem data should actually be stored; only these bytes in memory
+ will be changed. */
+static void
+StoreMemory(CCA,AccessLength,MemElem,pAddr,vAddr,raw)
+ int CCA;
+ int AccessLength;
+ unsigned long long MemElem;
+ unsigned long long pAddr;
+ unsigned long long vAddr;
+ int raw;
+{
+#ifdef DEBUG
+ callback->printf_filtered(callback,"DBG: StoreMemory(%d,%d,0x%08X%08X,0x%08X%08X,0x%08X%08X,%s)\n",CCA,AccessLength,(unsigned int)(MemElem >> 32),(unsigned int)(MemElem & 0xFFFFFFFF),(unsigned int)(pAddr >> 32),(unsigned int)(pAddr & 0xFFFFFFFF),(unsigned int)(vAddr >> 32),(unsigned int)(vAddr & 0xFFFFFFFF),(raw ? "isRAW" : "isREAL"));
+#endif /* DEBUG */
+
+#if defined(WARN_MEM)
+ if (CCA != uncached)
+ callback->printf_filtered(callback,"SIM Warning: StoreMemory CCA (%d) is not uncached (currently all accesses treated as cached)\n",CCA);
+
+ if (((pAddr & LOADDRMASK) + AccessLength) > LOADDRMASK)
+ sim_error("AccessLength of %d would extend over 64bit aligned boundary for physical address 0x%08X%08X\n",AccessLength,(unsigned int)(pAddr>>32),(unsigned int)(pAddr&0xFFFFFFFF));
+#endif /* WARN_MEM */
+
+#if defined(TRACE)
+ if (!raw)
+ dotrace(tracefh,1,(unsigned int)(pAddr&0xFFFFFFFF),(AccessLength + 1),"store");
+#endif /* TRACE */
+
+ /* See the comments in the LoadMemory routine about optimising
+ memory accesses. Also if we wanted to make the simulator smaller,
+ we could merge a lot of this code with the LoadMemory
+ routine. However, this would slow the simulator down with
+ run-time conditionals. */
+ {
+ unsigned int index;
+ unsigned char *mem = NULL;
+
+ if ((pAddr >= membank_base) && (pAddr < (membank_base + membank_size))) {
+ index = ((unsigned int)(pAddr - membank_base) & (membank_size - 1));
+ mem = membank;
+ } else if ((pAddr >= monitor_base) && (pAddr < (monitor_base + monitor_size))) {
+ index = ((unsigned int)(pAddr - monitor_base) & (monitor_size - 1));
+ mem = monitor;
+ }
+
+ if (mem == NULL)
+ sim_error("Simulator memory not found for physical address 0x%08X%08X\n",(unsigned int)(pAddr>>32),(unsigned int)(pAddr&0xFFFFFFFF));
+ else {
+ int shift = 0;
+
+#ifdef DEBUG
+ printf("DBG: StoreMemory: offset = %d MemElem = 0x%08X%08X\n",(unsigned int)(pAddr & LOADDRMASK),(unsigned int)(MemElem>>32),(unsigned int)(MemElem&0xFFFFFFFF));
+#endif /* DEBUG */
+
+ if (BigEndianMem) {
+ if (raw)
+ shift = ((7 - AccessLength) * 8);
+ else /* real memory access */
+ shift = ((pAddr & LOADDRMASK) * 8);
+ MemElem <<= shift;
+ } else {
+ /* no need to shift raw little-endian data */
+ if (!raw)
+ MemElem >>= ((pAddr & LOADDRMASK) * 8);
+ }
+
+#ifdef DEBUG
+ printf("DBG: StoreMemory: shift = %d MemElem = 0x%08X%08X\n",shift,(unsigned int)(MemElem>>32),(unsigned int)(MemElem&0xFFFFFFFF));
+#endif /* DEBUG */
+
+ if (BigEndianMem) {
+ switch (AccessLength) { /* big-endian memory */
+ case AccessLength_DOUBLEWORD :
+ mem[index++] = (unsigned char)(MemElem >> 56);
+ MemElem <<= 8;
+ case AccessLength_SEPTIBYTE :
+ mem[index++] = (unsigned char)(MemElem >> 56);
+ MemElem <<= 8;
+ case AccessLength_SEXTIBYTE :
+ mem[index++] = (unsigned char)(MemElem >> 56);
+ MemElem <<= 8;
+ case AccessLength_QUINTIBYTE :
+ mem[index++] = (unsigned char)(MemElem >> 56);
+ MemElem <<= 8;
+ case AccessLength_WORD :
+ mem[index++] = (unsigned char)(MemElem >> 56);
+ MemElem <<= 8;
+ case AccessLength_TRIPLEBYTE :
+ mem[index++] = (unsigned char)(MemElem >> 56);
+ MemElem <<= 8;
+ case AccessLength_HALFWORD :
+ mem[index++] = (unsigned char)(MemElem >> 56);
+ MemElem <<= 8;
+ case AccessLength_BYTE :
+ mem[index++] = (unsigned char)(MemElem >> 56);
+ break;
+ }
+ } else {
+ index += (AccessLength + 1);
+ switch (AccessLength) { /* little-endian memory */
+ case AccessLength_DOUBLEWORD :
+ mem[--index] = (unsigned char)(MemElem >> 56);
+ case AccessLength_SEPTIBYTE :
+ mem[--index] = (unsigned char)(MemElem >> 48);
+ case AccessLength_SEXTIBYTE :
+ mem[--index] = (unsigned char)(MemElem >> 40);
+ case AccessLength_QUINTIBYTE :
+ mem[--index] = (unsigned char)(MemElem >> 32);
+ case AccessLength_WORD :
+ mem[--index] = (unsigned char)(MemElem >> 24);
+ case AccessLength_TRIPLEBYTE :
+ mem[--index] = (unsigned char)(MemElem >> 16);
+ case AccessLength_HALFWORD :
+ mem[--index] = (unsigned char)(MemElem >> 8);
+ case AccessLength_BYTE :
+ mem[--index] = (unsigned char)(MemElem >> 0);
+ break;
+ }
+ }
+ }
+ }
+
+ return;
+}
+
+/* Description from page A-26 of the "MIPS IV Instruction Set" manual (revision 3.1) */
+/* Order loads and stores to synchronise shared memory. Perform the
+ action necessary to make the effects of groups of synchronizable
+ loads and stores indicated by stype occur in the same order for all
+ processors. */
+static void
+SyncOperation(stype)
+ int stype;
+{
+#ifdef DEBUG
+ callback->printf_filtered(callback,"SyncOperation(%d) : TODO\n",stype);
+#endif /* DEBUG */
+ return;
+}
+
+/* Description from page A-26 of the "MIPS IV Instruction Set" manual (revision 3.1) */
+/* Signal an exception condition. This will result in an exception
+ that aborts the instruction. The instruction operation pseudocode
+ will never see a return from this function call. */
+static void
+SignalException(exception)
+ int exception;
+{
+ /* Ensure that any active atomic read/modify/write operation will fail: */
+ LLBIT = 0;
+
+ switch (exception) {
+ /* TODO: For testing purposes I have been ignoring TRAPs. In
+ reality we should either simulate them, or allow the user to
+ ignore them at run-time. */
+ case Trap :
+ callback->printf_filtered(callback,"Ignoring instruction TRAP (PC 0x%08X%08X)\n",(unsigned int)(IPC>>32),(unsigned int)(IPC&0xFFFFFFFF));
+ break;
+
+ case ReservedInstruction :
+ {
+ va_list ap;
+ unsigned int instruction;
+ va_start(ap,exception);
+ instruction = va_arg(ap,unsigned int);
+ va_end(ap);
+ /* Provide simple monitor support using ReservedInstruction
+ exceptions. The following code simulates the fixed vector
+ entry points into the IDT monitor by causing a simulator
+ trap, performing the monitor operation, and returning to
+ the address held in the $ra register (standard PCS return
+ address). This means we only need to pre-load the vector
+ space with suitable instruction values. For systems were
+ actual trap instructions are used, we would not need to
+ perform this magic. */
+ if ((instruction & ~RSVD_INSTRUCTION_AMASK) == RSVD_INSTRUCTION) {
+ sim_monitor(instruction & RSVD_INSTRUCTION_AMASK);
+ PC = RA; /* simulate the return from the vector entry */
+ /* NOTE: This assumes that a branch-and-link style
+ instruction was used to enter the vector (which is the
+ case with the current IDT monitor). */
+ break; /* out of the switch statement */
+ } /* else fall through to normal exception processing */
+ callback->printf_filtered(callback,"DBG: ReservedInstruction 0x%08X at IPC = 0x%08X%08X\n",instruction,(unsigned int)(IPC>>32),(unsigned int)(IPC&0xFFFFFFFF));
+ }
+
+ default:
+#if 1 /* def DEBUG */
+ callback->printf_filtered(callback,"DBG: SignalException(%d) IPC = 0x%08X%08X\n",exception,(unsigned int)(IPC>>32),(unsigned int)(IPC&0xFFFFFFFF));
+#endif /* DEBUG */
+ /* Store exception code into current exception id variable (used
+ by exit code): */
+
+ /* TODO: If not simulating exceptions then stop the simulator
+ execution. At the moment we always stop the simulation. */
+ state |= (simSTOP | simEXCEPTION);
+ CAUSE = (exception << 2);
+ if (state & simDELAYSLOT) {
+ CAUSE |= cause_BD;
+ EPC = (IPC - 4); /* reference the branch instruction */
+ } else
+ EPC = IPC;
+ /* The following is so that the simulator will continue from the
+ exception address on breakpoint operations. */
+ PC = EPC;
+ break;
+
+ case SimulatorFault:
+ {
+ va_list ap;
+ char *msg;
+ va_start(ap,exception);
+ msg = va_arg(ap,char *);
+ fprintf(stderr,"FATAL: Simulator error \"%s\"\n",msg);
+ va_end(ap);
+ }
+ exit(1);
+ }
+
+ return;
+}
+
+#if defined(WARN_RESULT)
+/* Description from page A-26 of the "MIPS IV Instruction Set" manual (revision 3.1) */
+/* This function indicates that the result of the operation is
+ undefined. However, this should not affect the instruction
+ stream. All that is meant to happen is that the destination
+ register is set to an undefined result. To keep the simulator
+ simple, we just don't bother updating the destination register, so
+ the overall result will be undefined. If desired we can stop the
+ simulator by raising a pseudo-exception. */
+static void
+UndefinedResult()
+{
+ callback->printf_filtered(callback,"UndefinedResult: IPC = 0x%08X%08X\n",(unsigned int)(IPC>>32),(unsigned int)(IPC&0xFFFFFFFF));
+#if 0 /* Disabled for the moment, since it actually happens a lot at the moment. */
+ state |= simSTOP;
+#endif
+ return;
+}
+#endif /* WARN_RESULT */
+
+static void
+CacheOp(op,pAddr,vAddr,instruction)
+ int op;
+ unsigned long long pAddr;
+ unsigned long long vAddr;
+ unsigned int instruction;
+{
+ /* If CP0 is not useable (User or Supervisor mode) and the CP0
+ enable bit in the Status Register is clear - a coprocessor
+ unusable exception is taken. */
+ callback->printf_filtered(callback,"TODO: Cache availability checking (PC = 0x%08X%08X)\n",(unsigned int)(IPC>>32),(unsigned int)(IPC&0xFFFFFFFF));
+
+ switch (op & 0x3) {
+ case 0: /* instruction cache */
+ switch (op >> 2) {
+ case 0: /* Index Invalidate */
+ case 1: /* Index Load Tag */
+ case 2: /* Index Store Tag */
+ case 4: /* Hit Invalidate */
+ case 5: /* Fill */
+ case 6: /* Hit Writeback */
+ callback->printf_filtered(callback,"SIM Warning: Instruction CACHE operation %d to be coded\n",(op >> 2));
+ break;
+
+ default:
+ SignalException(ReservedInstruction,instruction);
+ break;
+ }
+ break;
+
+ case 1: /* data cache */
+ switch (op >> 2) {
+ case 0: /* Index Writeback Invalidate */
+ case 1: /* Index Load Tag */
+ case 2: /* Index Store Tag */
+ case 3: /* Create Dirty */
+ case 4: /* Hit Invalidate */
+ case 5: /* Hit Writeback Invalidate */
+ case 6: /* Hit Writeback */
+ callback->printf_filtered(callback,"SIM Warning: Data CACHE operation %d to be coded\n",(op >> 2));
+ break;
+
+ default:
+ SignalException(ReservedInstruction,instruction);
+ break;
+ }
+ break;
+
+ default: /* unrecognised cache ID */
+ SignalException(ReservedInstruction,instruction);
+ break;
+ }
+
+ return;
+}
+
+/*-- FPU support routines ---------------------------------------------------*/
+
+#if defined(HASFPU) /* Only needed when building FPU aware simulators */
+
+#if 1
+#define SizeFGR() (GPRLEN)
+#else
+/* They depend on the CPU being simulated */
+#define SizeFGR() ((PROCESSOR_64BIT && ((SR & status_FR) == 1)) ? 64 : 32)
+#endif
+
+/* Numbers are held in normalized form. The SINGLE and DOUBLE binary
+ formats conform to ANSI/IEEE Std 754-1985. */
+/* SINGLE precision floating:
+ * seeeeeeeefffffffffffffffffffffff
+ * s = 1bit = sign
+ * e = 8bits = exponent
+ * f = 23bits = fraction
+ */
+/* SINGLE precision fixed:
+ * siiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+ * s = 1bit = sign
+ * i = 31bits = integer
+ */
+/* DOUBLE precision floating:
+ * seeeeeeeeeeeffffffffffffffffffffffffffffffffffffffffffffffffffff
+ * s = 1bit = sign
+ * e = 11bits = exponent
+ * f = 52bits = fraction
+ */
+/* DOUBLE precision fixed:
+ * siiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
+ * s = 1bit = sign
+ * i = 63bits = integer
+ */
+
+/* Extract sign-bit: */
+#define FP_S_s(v) (((v) & ((unsigned)1 << 31)) ? 1 : 0)
+#define FP_D_s(v) (((v) & ((unsigned long long)1 << 63)) ? 1 : 0)
+/* Extract biased exponent: */
+#define FP_S_be(v) (((v) >> 23) & 0xFF)
+#define FP_D_be(v) (((v) >> 52) & 0x7FF)
+/* Extract unbiased Exponent: */
+#define FP_S_e(v) (FP_S_be(v) - 0x7F)
+#define FP_D_e(v) (FP_D_be(v) - 0x3FF)
+/* Extract complete fraction field: */
+#define FP_S_f(v) ((v) & ~((unsigned)0x1FF << 23))
+#define FP_D_f(v) ((v) & ~((unsigned long long)0xFFF << 52))
+/* Extract numbered fraction bit: */
+#define FP_S_fb(b,v) (((v) & (1 << (23 - (b)))) ? 1 : 0)
+#define FP_D_fb(b,v) (((v) & (1 << (52 - (b)))) ? 1 : 0)
+
+/* Explicit QNaN values used when value required: */
+#define FPQNaN_SINGLE (0x7FBFFFFF)
+#define FPQNaN_WORD (0x7FFFFFFF)
+#define FPQNaN_DOUBLE (((unsigned long long)0x7FF7FFFF << 32) | 0xFFFFFFFF)
+#define FPQNaN_LONG (((unsigned long long)0x7FFFFFFF << 32) | 0xFFFFFFFF)
+
+/* Explicit Infinity values used when required: */
+#define FPINF_SINGLE (0x7F800000)
+#define FPINF_DOUBLE (((unsigned long long)0x7FF00000 << 32) | 0x00000000)
+
+#if 1 /* def DEBUG */
+#define RMMODE(v) (((v) == FP_RM_NEAREST) ? "Round" : (((v) == FP_RM_TOZERO) ? "Trunc" : (((v) == FP_RM_TOPINF) ? "Ceil" : "Floor")))
+#define DOFMT(v) (((v) == fmt_single) ? "single" : (((v) == fmt_double) ? "double" : (((v) == fmt_word) ? "word" : (((v) == fmt_long) ? "long" : (((v) == fmt_unknown) ? "<unknown>" : (((v) == fmt_uninterpreted) ? "<uninterpreted>" : "<format error>"))))))
+#endif /* DEBUG */
+
+static unsigned long long
+ValueFPR(fpr,fmt)
+ int fpr;
+ FP_formats fmt;
+{
+ unsigned long long value;
+ int err = 0;
+
+ /* Treat unused register values, as fixed-point 64bit values: */
+ if ((fmt == fmt_uninterpreted) || (fmt == fmt_unknown))
+#if 1
+ /* If request to read data as "uninterpreted", then use the current
+ encoding: */
+ fmt = fpr_state[fpr];
+#else
+ fmt = fmt_long;
+#endif
+
+ /* For values not yet accessed, set to the desired format: */
+ if (fpr_state[fpr] == fmt_uninterpreted) {
+ fpr_state[fpr] = fmt;
+#ifdef DEBUG
+ printf("DBG: Register %d was fmt_uninterpreted. Now %s\n",fpr,DOFMT(fmt));
+#endif /* DEBUG */
+ }
+ if (fmt != fpr_state[fpr]) {
+ callback->printf_filtered(callback,"Warning: FPR %d (format %s) being accessed with format %s - setting to unknown (PC = 0x%08X%08X)\n",fpr,DOFMT(fpr_state[fpr]),DOFMT(fmt),(unsigned int)(IPC>>32),(unsigned int)(IPC&0xFFFFFFFF));
+ fpr_state[fpr] = fmt_unknown;
+ }
+
+ if (fpr_state[fpr] == fmt_unknown) {
+ /* Set QNaN value: */
+ switch (fmt) {
+ case fmt_single:
+ value = FPQNaN_SINGLE;
+ break;
+
+ case fmt_double:
+ value = FPQNaN_DOUBLE;
+ break;
+
+ case fmt_word:
+ value = FPQNaN_WORD;
+ break;
+
+ case fmt_long:
+ value = FPQNaN_LONG;
+ break;
+
+ default:
+ err = -1;
+ break;
+ }
+ } else if (SizeFGR() == 64) {
+ switch (fmt) {
+ case fmt_single:
+ case fmt_word:
+ value = (FGR[fpr] & 0xFFFFFFFF);
+ break;
+
+ case fmt_uninterpreted:
+ case fmt_double:
+ case fmt_long:
+ value = FGR[fpr];
+ break;
+
+ default :
+ err = -1;
+ break;
+ }
+ } else if ((fpr & 1) == 0) { /* even registers only */
+ switch (fmt) {
+ case fmt_single:
+ case fmt_word:
+ value = (FGR[fpr] & 0xFFFFFFFF);
+ break;
+
+ case fmt_uninterpreted:
+ case fmt_double:
+ case fmt_long:
+ value = ((FGR[fpr+1] << 32) | (FGR[fpr] & 0xFFFFFFFF));
+ break;
+
+ default :
+ err = -1;
+ break;
+ }
+ }
+
+ if (err)
+ SignalException(SimulatorFault,"Unrecognised FP format in ValueFPR()");
+
+#ifdef DEBUG
+ printf("DBG: ValueFPR: fpr = %d, fmt = %s, value = 0x%08X%08X : PC = 0x%08X%08X : SizeFGR() = %d\n",fpr,DOFMT(fmt),(unsigned int)(value>>32),(unsigned int)(value&0xFFFFFFFF),(unsigned int)(IPC>>32),(unsigned int)(IPC&0xFFFFFFFF),SizeFGR());
+#endif /* DEBUG */
+
+ return(value);
+}
+
+static void
+StoreFPR(fpr,fmt,value)
+ int fpr;
+ FP_formats fmt;
+ unsigned long long value;
+{
+ int err = 0;
+
+#ifdef DEBUG
+ printf("DBG: StoreFPR: fpr = %d, fmt = %s, value = 0x%08X%08X : PC = 0x%08X%08X : SizeFGR() = %d\n",fpr,DOFMT(fmt),(unsigned int)(value>>32),(unsigned int)(value&0xFFFFFFFF),(unsigned int)(IPC>>32),(unsigned int)(IPC&0xFFFFFFFF),SizeFGR());
+#endif /* DEBUG */
+
+ if (SizeFGR() == 64) {
+ switch (fmt) {
+ case fmt_single :
+ case fmt_word :
+ FGR[fpr] = (((unsigned long long)0xDEADC0DE << 32) | (value & 0xFFFFFFFF));
+ fpr_state[fpr] = fmt;
+ break;
+
+ case fmt_uninterpreted:
+ case fmt_double :
+ case fmt_long :
+ FGR[fpr] = value;
+ fpr_state[fpr] = fmt;
+ break;
+
+ default :
+ fpr_state[fpr] = fmt_unknown;
+ err = -1;
+ break;
+ }
+ } else if ((fpr & 1) == 0) { /* even register number only */
+ switch (fmt) {
+ case fmt_single :
+ case fmt_word :
+ FGR[fpr+1] = 0xDEADC0DE;
+ FGR[fpr] = (value & 0xFFFFFFFF);
+ fpr_state[fpr + 1] = fmt;
+ fpr_state[fpr] = fmt;
+ break;
+
+ case fmt_uninterpreted:
+ case fmt_double :
+ case fmt_long :
+ FGR[fpr+1] = (value >> 32);
+ FGR[fpr] = (value & 0xFFFFFFFF);
+ fpr_state[fpr + 1] = fmt;
+ fpr_state[fpr] = fmt;
+ break;
+
+ default :
+ fpr_state[fpr] = fmt_unknown;
+ err = -1;
+ break;
+ }
+ } else
+ UndefinedResult();
+
+ if (err)
+ SignalException(SimulatorFault,"Unrecognised FP format in StoreFPR()");
+
+#ifdef DEBUG
+ printf("DBG: StoreFPR: fpr[%d] = 0x%08X%08X (format %s)\n",fpr,(unsigned int)(FGR[fpr]>>32),(unsigned int)(FGR[fpr]&0xFFFFFFFF),DOFMT(fmt));
+#endif /* DEBUG */
+
+ return;
+}
+
+static int
+NaN(op,fmt)
+ unsigned long long op;
+ FP_formats fmt;
+{
+ int boolean = 0;
+
+ /* Check if (((E - bias) == (E_max + 1)) && (fraction != 0)). We
+ know that the exponent field is biased... we we cheat and avoid
+ removing the bias value. */
+ switch (fmt) {
+ case fmt_single:
+ boolean = ((FP_S_be(op) == 0xFF) && (FP_S_f(op) != 0));
+ /* We could use "FP_S_fb(1,op)" to ascertain whether we are
+ dealing with a SNaN or QNaN */
+ break;
+ case fmt_double:
+ boolean = ((FP_D_be(op) == 0x7FF) && (FP_D_f(op) != 0));
+ /* We could use "FP_S_fb(1,op)" to ascertain whether we are
+ dealing with a SNaN or QNaN */
+ break;
+ case fmt_word:
+ boolean = (op == FPQNaN_WORD);
+ break;
+ case fmt_long:
+ boolean = (op == FPQNaN_LONG);
+ break;
+ }
+
+#ifdef DEBUG
+printf("DBG: NaN: returning %d for 0x%08X%08X (format = %s)\n",boolean,(unsigned int)(op>>32),(unsigned int)(op&0xFFFFFFFF),DOFMT(fmt));
+#endif /* DEBUG */
+
+ return(boolean);
+}
+
+static int
+Infinity(op,fmt)
+ unsigned long long op;
+ FP_formats fmt;
+{
+ int boolean = 0;
+
+#ifdef DEBUG
+ printf("DBG: Infinity: format %s 0x%08X%08X (PC = 0x%08X%08X)\n",DOFMT(fmt),(unsigned int)(op>>32),(unsigned int)(op&0xFFFFFFFF),(unsigned int)(IPC>>32),(unsigned int)(IPC&0xFFFFFFFF));
+#endif /* DEBUG */
+
+ /* Check if (((E - bias) == (E_max + 1)) && (fraction == 0)). We
+ know that the exponent field is biased... we we cheat and avoid
+ removing the bias value. */
+ switch (fmt) {
+ case fmt_single:
+ boolean = ((FP_S_be(op) == 0xFF) && (FP_S_f(op) == 0));
+ break;
+ case fmt_double:
+ boolean = ((FP_D_be(op) == 0x7FF) && (FP_D_f(op) == 0));
+ break;
+ default:
+ printf("DBG: TODO: unrecognised format (%s) for Infinity check\n",DOFMT(fmt));
+ break;
+ }
+
+#ifdef DEBUG
+ printf("DBG: Infinity: returning %d for 0x%08X%08X (format = %s)\n",boolean,(unsigned int)(op>>32),(unsigned int)(op&0xFFFFFFFF),DOFMT(fmt));
+#endif /* DEBUG */
+
+ return(boolean);
+}
+
+static int
+Less(op1,op2,fmt)
+ unsigned long long op1;
+ unsigned long long op2;
+ FP_formats fmt;
+{
+ int boolean = 0;
+
+#ifdef DEBUG
+ printf("DBG: Less: %s: op1 = 0x%08X%08X : op2 = 0x%08X%08X\n",DOFMT(fmt),(unsigned int)(op1>>32),(unsigned int)(op1&0xFFFFFFFF),(unsigned int)(op2>>32),(unsigned int)(op2&0xFFFFFFFF));
+#endif /* DEBUG */
+
+ /* TODO: Perform argument error checking */
+
+ /* The format type should already have been checked: */
+ switch (fmt) {
+ case fmt_single:
+ {
+ unsigned int wop1 = (unsigned int)op1;
+ unsigned int wop2 = (unsigned int)op2;
+ boolean = (*(float *)&wop1 < *(float *)&wop2);
+ }
+ break;
+ case fmt_double:
+ boolean = (*(double *)&op1 < *(double *)&op2);
+ break;
+ }
+
+#ifdef DEBUG
+ printf("DBG: Less: returning %d (format = %s)\n",boolean,DOFMT(fmt));
+#endif /* DEBUG */
+
+ return(boolean);
+}
+
+static int
+Equal(op1,op2,fmt)
+ unsigned long long op1;
+ unsigned long long op2;
+ FP_formats fmt;
+{
+ int boolean = 0;
+
+#ifdef DEBUG
+ printf("DBG: Equal: %s: op1 = 0x%08X%08X : op2 = 0x%08X%08X\n",DOFMT(fmt),(unsigned int)(op1>>32),(unsigned int)(op1&0xFFFFFFFF),(unsigned int)(op2>>32),(unsigned int)(op2&0xFFFFFFFF));
+#endif /* DEBUG */
+
+ /* TODO: Perform argument error checking */
+
+ /* The format type should already have been checked: */
+ switch (fmt) {
+ case fmt_single:
+ boolean = ((op1 & 0xFFFFFFFF) == (op2 & 0xFFFFFFFF));
+ break;
+ case fmt_double:
+ boolean = (op1 == op2);
+ break;
+ }
+
+#ifdef DEBUG
+ printf("DBG: Equal: returning %d (format = %s)\n",boolean,DOFMT(fmt));
+#endif /* DEBUG */
+
+ return(boolean);
+}
+
+static unsigned long long
+Negate(op,fmt)
+ unsigned long long op;
+ FP_formats fmt;
+{
+ unsigned long long result;
+
+#ifdef DEBUG
+ printf("DBG: Negate: %s: op = 0x%08X%08X\n",DOFMT(fmt),(unsigned int)(op>>32),(unsigned int)(op&0xFFFFFFFF));
+#endif /* DEBUG */
+
+ /* The format type should already have been checked: */
+ switch (fmt) {
+ case fmt_single:
+ {
+ unsigned int wop = (unsigned int)op;
+ float tmp = ((float)0.0 - *(float *)&wop);
+ result = (unsigned long long)*(unsigned int *)&tmp;
+ }
+ break;
+ case fmt_double:
+ {
+ double tmp = ((double)0.0 - *(double *)&op);
+ result = *(unsigned long long *)&tmp;
+ }
+ break;
+ }
+
+ return(result);
+}
+
+static unsigned long long
+Add(op1,op2,fmt)
+ unsigned long long op1;
+ unsigned long long op2;
+ FP_formats fmt;
+{
+ unsigned long long result;
+
+#ifdef DEBUG
+ printf("DBG: Add: %s: op1 = 0x%08X%08X : op2 = 0x%08X%08X\n",DOFMT(fmt),(unsigned int)(op1>>32),(unsigned int)(op1&0xFFFFFFFF),(unsigned int)(op2>>32),(unsigned int)(op2&0xFFFFFFFF));
+#endif /* DEBUG */
+
+ /* TODO: Perform argument error checking */
+
+ /* The format type should already have been checked: */
+ switch (fmt) {
+ case fmt_single:
+ {
+ unsigned int wop1 = (unsigned int)op1;
+ unsigned int wop2 = (unsigned int)op2;
+ float tmp = (*(float *)&wop1 + *(float *)&wop2);
+ result = (unsigned long long)*(unsigned int *)&tmp;
+ }
+ break;
+ case fmt_double:
+ {
+ double tmp = (*(double *)&op1 + *(double *)&op2);
+ result = *(unsigned long long *)&tmp;
+ }
+ break;
+ }
+
+#ifdef DEBUG
+ printf("DBG: Add: returning 0x%08X%08X (format = %s)\n",(unsigned int)(result>>32),(unsigned int)(result&0xFFFFFFFF),DOFMT(fmt));
+#endif /* DEBUG */
+
+ return(result);
+}
+
+static unsigned long long
+Sub(op1,op2,fmt)
+ unsigned long long op1;
+ unsigned long long op2;
+ FP_formats fmt;
+{
+ unsigned long long result;
+
+#ifdef DEBUG
+ printf("DBG: Sub: %s: op1 = 0x%08X%08X : op2 = 0x%08X%08X\n",DOFMT(fmt),(unsigned int)(op1>>32),(unsigned int)(op1&0xFFFFFFFF),(unsigned int)(op2>>32),(unsigned int)(op2&0xFFFFFFFF));
+#endif /* DEBUG */
+
+ /* TODO: Perform argument error checking */
+
+ /* The format type should already have been checked: */
+ switch (fmt) {
+ case fmt_single:
+ {
+ unsigned int wop1 = (unsigned int)op1;
+ unsigned int wop2 = (unsigned int)op2;
+ float tmp = (*(float *)&wop1 - *(float *)&wop2);
+ result = (unsigned long long)*(unsigned int *)&tmp;
+ }
+ break;
+ case fmt_double:
+ {
+ double tmp = (*(double *)&op1 - *(double *)&op2);
+ result = *(unsigned long long *)&tmp;
+ }
+ break;
+ }
+
+#ifdef DEBUG
+ printf("DBG: Sub: returning 0x%08X%08X (format = %s)\n",(unsigned int)(result>>32),(unsigned int)(result&0xFFFFFFFF),DOFMT(fmt));
+#endif /* DEBUG */
+
+ return(result);
+}
+
+static unsigned long long
+Multiply(op1,op2,fmt)
+ unsigned long long op1;
+ unsigned long long op2;
+ FP_formats fmt;
+{
+ unsigned long long result;
+
+#ifdef DEBUG
+ printf("DBG: Multiply: %s: op1 = 0x%08X%08X : op2 = 0x%08X%08X\n",DOFMT(fmt),(unsigned int)(op1>>32),(unsigned int)(op1&0xFFFFFFFF),(unsigned int)(op2>>32),(unsigned int)(op2&0xFFFFFFFF));
+#endif /* DEBUG */
+
+ /* TODO: Perform argument error checking */
+
+ /* The format type should already have been checked: */
+ switch (fmt) {
+ case fmt_single:
+ {
+ unsigned int wop1 = (unsigned int)op1;
+ unsigned int wop2 = (unsigned int)op2;
+ float tmp = (*(float *)&wop1 * *(float *)&wop2);
+ result = (unsigned long long)*(unsigned int *)&tmp;
+ }
+ break;
+ case fmt_double:
+ {
+ double tmp = (*(double *)&op1 * *(double *)&op2);
+ result = *(unsigned long long *)&tmp;
+ }
+ break;
+ }
+
+#ifdef DEBUG
+ printf("DBG: Multiply: returning 0x%08X%08X (format = %s)\n",(unsigned int)(result>>32),(unsigned int)(result&0xFFFFFFFF),DOFMT(fmt));
+#endif /* DEBUG */
+
+ return(result);
+}
+
+static unsigned long long
+Divide(op1,op2,fmt)
+ unsigned long long op1;
+ unsigned long long op2;
+ FP_formats fmt;
+{
+ unsigned long long result;
+
+#ifdef DEBUG
+ printf("DBG: Divide: %s: op1 = 0x%08X%08X : op2 = 0x%08X%08X\n",DOFMT(fmt),(unsigned int)(op1>>32),(unsigned int)(op1&0xFFFFFFFF),(unsigned int)(op2>>32),(unsigned int)(op2&0xFFFFFFFF));
+#endif /* DEBUG */
+
+ /* TODO: Perform argument error checking */
+
+ /* The format type should already have been checked: */
+ switch (fmt) {
+ case fmt_single:
+ {
+ unsigned int wop1 = (unsigned int)op1;
+ unsigned int wop2 = (unsigned int)op2;
+ float tmp = (*(float *)&wop1 / *(float *)&wop2);
+ result = (unsigned long long)*(unsigned int *)&tmp;
+ }
+ break;
+ case fmt_double:
+ {
+ double tmp = (*(double *)&op1 / *(double *)&op2);
+ result = *(unsigned long long *)&tmp;
+ }
+ break;
+ }
+
+#ifdef DEBUG
+ printf("DBG: Divide: returning 0x%08X%08X (format = %s)\n",(unsigned int)(result>>32),(unsigned int)(result&0xFFFFFFFF),DOFMT(fmt));
+#endif /* DEBUG */
+
+ return(result);
+}
+
+static unsigned long long
+Recip(op,fmt)
+ unsigned long long op;
+ FP_formats fmt;
+{
+ unsigned long long result;
+
+#ifdef DEBUG
+ printf("DBG: Recip: %s: op = 0x%08X%08X\n",DOFMT(fmt),(unsigned int)(op>>32),(unsigned int)(op&0xFFFFFFFF));
+#endif /* DEBUG */
+
+ /* TODO: Perform argument error checking */
+
+ /* The format type should already have been checked: */
+ switch (fmt) {
+ case fmt_single:
+ {
+ unsigned int wop = (unsigned int)op;
+ float tmp = ((float)1.0 / *(float *)&wop);
+ result = (unsigned long long)*(unsigned int *)&tmp;
+ }
+ break;
+ case fmt_double:
+ {
+ double tmp = ((double)1.0 / *(double *)&op);
+ result = *(unsigned long long *)&tmp;
+ }
+ break;
+ }
+
+#ifdef DEBUG
+ printf("DBG: Recip: returning 0x%08X%08X (format = %s)\n",(unsigned int)(result>>32),(unsigned int)(result&0xFFFFFFFF),DOFMT(fmt));
+#endif /* DEBUG */
+
+ return(result);
+}
+
+static unsigned long long
+SquareRoot(op,fmt)
+ unsigned long long op;
+ FP_formats fmt;
+{
+ unsigned long long result;
+
+#ifdef DEBUG
+ printf("DBG: SquareRoot: %s: op = 0x%08X%08X\n",DOFMT(fmt),(unsigned int)(op>>32),(unsigned int)(op&0xFFFFFFFF));
+#endif /* DEBUG */
+
+ /* TODO: Perform argument error checking */
+
+ /* The format type should already have been checked: */
+ switch (fmt) {
+ case fmt_single:
+ {
+ unsigned int wop = (unsigned int)op;
+ float tmp = ((float)sqrt((double)*(float *)&wop));
+ result = (unsigned long long)*(unsigned int *)&tmp;
+ }
+ break;
+ case fmt_double:
+ {
+ double tmp = (sqrt(*(double *)&op));
+ result = *(unsigned long long *)&tmp;
+ }
+ break;
+ }
+
+#ifdef DEBUG
+ printf("DBG: SquareRoot: returning 0x%08X%08X (format = %s)\n",(unsigned int)(result>>32),(unsigned int)(result&0xFFFFFFFF),DOFMT(fmt));
+#endif /* DEBUG */
+
+ return(result);
+}
+
+static unsigned long long
+Convert(rm,op,from,to)
+ int rm;
+ unsigned long long op;
+ FP_formats from;
+ FP_formats to;
+{
+ unsigned long long result;
+
+#ifdef DEBUG
+ printf("DBG: Convert: mode %s : op 0x%08X%08X : from %s : to %s : (PC = 0x%08X%08X)\n",RMMODE(rm),(unsigned int)(op>>32),(unsigned int)(op&0xFFFFFFFF),DOFMT(from),DOFMT(to),(unsigned int)(IPC>>32),(unsigned int)(IPC&0xFFFFFFFF));
+#endif /* DEBUG */
+
+ /* The value "op" is converted to the destination format, rounding
+ using mode "rm". When the destination is a fixed-point format,
+ then a source value of Infinity, NaN or one which would round to
+ an integer outside the fixed point range then an IEEE Invalid
+ Operation condition is raised. */
+ switch (to) {
+ case fmt_single:
+ {
+ float tmp;
+ switch (from) {
+ case fmt_double:
+ tmp = (float)(*(double *)&op);
+ break;
+
+ case fmt_word:
+ tmp = (float)((int)(op & 0xFFFFFFFF));
+ break;
+
+ case fmt_long:
+ tmp = (float)((int)op);
+ break;
+ }
+
+ switch (rm) {
+ case FP_RM_NEAREST:
+ printf("TODO: FPConvert: round(float)\n");
+ break;
+
+ case FP_RM_TOZERO:
+ printf("TODO: FPConvert: trunc(float)\n");
+ break;
+
+ case FP_RM_TOPINF:
+ printf("TODO: FPConvert: ceil(float)\n");
+ break;
+
+ case FP_RM_TOMINF:
+ printf("TODO: FPConvert: floor(float)\n");
+ break;
+ }
+ result = (unsigned long long)*(unsigned int *)&tmp;
+ }
+ break;
+
+ case fmt_double:
+ {
+ double tmp;
+
+ switch (from) {
+ case fmt_single:
+ {
+ unsigned int wop = (unsigned int)op;
+ tmp = (double)(*(float *)&wop);
+ }
+ break;
+
+ case fmt_word:
+ tmp = (double)((long long)SIGNEXTEND((op & 0xFFFFFFFF),32));
+ break;
+
+ case fmt_long:
+ tmp = (double)((long long)op);
+ break;
+ }
+ switch (rm) {
+ case FP_RM_NEAREST:
+ printf("TODO: FPConvert: round(double)\n");
+ break;
+
+ case FP_RM_TOZERO:
+ printf("TODO: FPConvert: trunc(double)\n");
+ break;
+
+ case FP_RM_TOPINF:
+ tmp = ceil(*(double *)&tmp);
+ break;
+
+ case FP_RM_TOMINF:
+ tmp = floor(*(double *)&tmp);
+ break;
+ }
+ result = *(unsigned long long *)&tmp;
+ }
+ break;
+
+ case fmt_word:
+ case fmt_long:
+ if (Infinity(op,from) || NaN(op,from) || (1 == 0/*TODO: check range */)) {
+ printf("DBG: TODO: update FCSR\n");
+ SignalException(FPE);
+ } else {
+ if (to == fmt_word) {
+ unsigned int tmp;
+ switch (from) {
+ case fmt_single:
+ {
+ unsigned int wop = (unsigned int)op;
+ tmp = (unsigned int)*((float *)&wop);
+ }
+ break;
+ case fmt_double:
+ tmp = (unsigned int)*((double *)&op);
+#ifdef DEBUG
+ printf("DBG: from double %.30f (0x%08X%08X) to word: 0x%08X\n",*((double *)&op),(unsigned int)(op>>32),(unsigned int)(op&0xFFFFFFFF),tmp);
+#endif /* DEBUG */
+ break;
+ }
+ result = (unsigned long long)tmp;
+ } else { /* fmt_long */
+ switch (from) {
+ case fmt_single:
+ {
+ unsigned int wop = (unsigned int)op;
+ result = (unsigned long long)*((float *)&wop);
+ }
+ break;
+ case fmt_double:
+ result = (unsigned long long)*((double *)&op);
+ break;
+ }
+ }
+ }
+ break;
+ }
+
+#ifdef DEBUG
+ printf("DBG: Convert: returning 0x%08X%08X (to format = %s)\n",(unsigned int)(result>>32),(unsigned int)(result&0xFFFFFFFF),DOFMT(to));
+#endif /* DEBUG */
+
+ return(result);
+}
+#endif /* HASFPU */
+
+/*-- co-processor support routines ------------------------------------------*/
+
+static int
+CoProcPresent(coproc_number)
+ unsigned int coproc_number;
+{
+ /* Return TRUE if simulator provides a model for the given co-processor number */
+ return(0);
+}
+
+static void
+COP_LW(coproc_num,coproc_reg,memword)
+ int coproc_num, coproc_reg;
+ unsigned int memword;
+{
+ switch (coproc_num) {
+#if defined(HASFPU)
+ case 1:
+#ifdef DEBUG
+ printf("DBG: COP_LW: memword = 0x%08X (unsigned long long)memword = 0x%08X%08X\n",memword,(unsigned int)(((unsigned long long)memword)>>32),(unsigned int)(((unsigned long long)memword)&0xFFFFFFFF));
+#endif
+ StoreFPR(coproc_reg,fmt_uninterpreted,(unsigned long long)memword);
+ break;
+#endif /* HASFPU */
+
+ default:
+ callback->printf_filtered(callback,"COP_LW(%d,%d,0x%08X) at IPC = 0x%08X%08X : TODO (architecture specific)\n",coproc_num,coproc_reg,memword,(unsigned int)(IPC>>32),(unsigned int)(IPC&0xFFFFFFFF));
+ break;
+ }
+
+ return;
+}
+
+static void
+COP_LD(coproc_num,coproc_reg,memword)
+ int coproc_num, coproc_reg;
+ unsigned long long memword;
+{
+ switch (coproc_num) {
+#if defined(HASFPU)
+ case 1:
+ StoreFPR(coproc_reg,fmt_uninterpreted,memword);
+ break;
+#endif /* HASFPU */
+
+ default:
+ callback->printf_filtered(callback,"COP_LD(%d,%d,0x%08X%08X) at IPC = 0x%08X%08X : TODO (architecture specific)\n",coproc_num,coproc_reg,(unsigned int)(memword >> 32),(unsigned int)(memword & 0xFFFFFFFF),(unsigned int)(IPC>>32),(unsigned int)(IPC&0xFFFFFFFF));
+ break;
+ }
+
+ return;
+}
+
+static unsigned int
+COP_SW(coproc_num,coproc_reg)
+ int coproc_num, coproc_reg;
+{
+ unsigned int value = 0;
+ switch (coproc_num) {
+#if defined(HASFPU)
+ case 1:
+#if 1
+ value = (unsigned int)ValueFPR(coproc_reg,fmt_uninterpreted);
+#else
+#if 1
+ value = (unsigned int)ValueFPR(coproc_reg,fpr_state[coproc_reg]);
+#else
+#ifdef DEBUG
+ printf("DBG: COP_SW: reg in format %s (will be accessing as single)\n",DOFMT(fpr_state[coproc_reg]));
+#endif /* DEBUG */
+ value = (unsigned int)ValueFPR(coproc_reg,fmt_single);
+#endif
+#endif
+ break;
+#endif /* HASFPU */
+
+ default:
+ callback->printf_filtered(callback,"COP_SW(%d,%d) at IPC = 0x%08X%08X : TODO (architecture specific)\n",coproc_num,coproc_reg,(unsigned int)(IPC>>32),(unsigned int)(IPC&0xFFFFFFFF));
+ break;
+ }
+
+ return(value);
+}
+
+static unsigned long long
+COP_SD(coproc_num,coproc_reg)
+ int coproc_num, coproc_reg;
+{
+ unsigned long long value = 0;
+ switch (coproc_num) {
+#if defined(HASFPU)
+ case 1:
+#if 1
+ value = ValueFPR(coproc_reg,fmt_uninterpreted);
+#else
+#if 1
+ value = ValueFPR(coproc_reg,fpr_state[coproc_reg]);
+#else
+#ifdef DEBUG
+ printf("DBG: COP_SD: reg in format %s (will be accessing as double)\n",DOFMT(fpr_state[coproc_reg]));
+#endif /* DEBUG */
+ value = ValueFPR(coproc_reg,fmt_double);
+#endif
+#endif
+ break;
+#endif /* HASFPU */
+
+ default:
+ callback->printf_filtered(callback,"COP_SD(%d,%d) at IPC = 0x%08X%08X : TODO (architecture specific)\n",coproc_num,coproc_reg,(unsigned int)(IPC>>32),(unsigned int)(IPC&0xFFFFFFFF));
+ break;
+ }
+
+ return(value);
+}
+
+static void
+decode_coproc(instruction)
+ unsigned int instruction;
+{
+ int coprocnum = ((instruction >> 26) & 3);
+
+ switch (coprocnum) {
+ case 0: /* standard CPU control and cache registers */
+ {
+ /* NOTEs:
+ Standard CP0 registers
+ 0 = Index R4000 VR4100 VR4300
+ 1 = Random R4000 VR4100 VR4300
+ 2 = EntryLo0 R4000 VR4100 VR4300
+ 3 = EntryLo1 R4000 VR4100 VR4300
+ 4 = Context R4000 VR4100 VR4300
+ 5 = PageMask R4000 VR4100 VR4300
+ 6 = Wired R4000 VR4100 VR4300
+ 8 = BadVAddr R4000 VR4100 VR4300
+ 9 = Count R4000 VR4100 VR4300
+ 10 = EntryHi R4000 VR4100 VR4300
+ 11 = Compare R4000 VR4100 VR4300
+ 12 = SR R4000 VR4100 VR4300
+ 13 = Cause R4000 VR4100 VR4300
+ 14 = EPC R4000 VR4100 VR4300
+ 15 = PRId R4000 VR4100 VR4300
+ 16 = Config R4000 VR4100 VR4300
+ 17 = LLAddr R4000 VR4100 VR4300
+ 18 = WatchLo R4000 VR4100 VR4300
+ 19 = WatchHi R4000 VR4100 VR4300
+ 20 = XContext R4000 VR4100 VR4300
+ 26 = PErr or ECC R4000 VR4100 VR4300
+ 27 = CacheErr R4000 VR4100
+ 28 = TagLo R4000 VR4100 VR4300
+ 29 = TagHi R4000 VR4100 VR4300
+ 30 = ErrorEPC R4000 VR4100 VR4300
+ */
+ int code = ((instruction >> 21) & 0x1F);
+ /* R4000 Users Manual (second edition) lists the following CP0
+ instructions:
+ DMFC0 Doubleword Move From CP0 (VR4100 = 01000000001tttttddddd00000000000)
+ DMTC0 Doubleword Move To CP0 (VR4100 = 01000000101tttttddddd00000000000)
+ MFC0 word Move From CP0 (VR4100 = 01000000000tttttddddd00000000000)
+ MTC0 word Move To CP0 (VR4100 = 01000000100tttttddddd00000000000)
+ TLBR Read Indexed TLB Entry (VR4100 = 01000010000000000000000000000001)
+ TLBWI Write Indexed TLB Entry (VR4100 = 01000010000000000000000000000010)
+ TLBWR Write Random TLB Entry (VR4100 = 01000010000000000000000000000110)
+ TLBP Probe TLB for Matching Entry (VR4100 = 01000010000000000000000000001000)
+ CACHE Cache operation (VR4100 = 101111bbbbbpppppiiiiiiiiiiiiiiii)
+ ERET Exception return (VR4100 = 01000010000000000000000000011000)
+ */
+ if (((code == 0x00) || (code == 0x04)) && ((instruction & 0x7FF) == 0)) {
+ int rt = ((instruction >> 16) & 0x1F);
+ int rd = ((instruction >> 11) & 0x1F);
+ if (code == 0x00) { /* MF : move from */
+ callback->printf_filtered(callback,"Warning: MFC0 %d,%d not handled yet (architecture specific)\n",rt,rd);
+ GPR[rt] = 0xDEADC0DE; /* CPR[0,rd] */
+ } else { /* MT : move to */
+ /* CPR[0,rd] = GPR[rt]; */
+ callback->printf_filtered(callback,"Warning: MTC0 %d,%d not handled yet (architecture specific)\n",rt,rd);
+ }
+ } else
+ callback->printf_filtered(callback,"Warning: Unrecognised COP0 instruction 0x%08X at IPC = 0x%08X%08X : No handler present\n",instruction,(unsigned int)(IPC>>32),(unsigned int)(IPC&0xFFFFFFFF));
+ /* TODO: When executed an ERET or RFE instruction we should
+ clear LLBIT, to ensure that any out-standing atomic
+ read/modify/write sequence fails. */
+ }
+ break;
+
+ case 2: /* undefined co-processor */
+ callback->printf_filtered(callback,"Warning: COP2 instruction 0x%08X at IPC = 0x%08X%08X : No handler present\n",instruction,(unsigned int)(IPC>>32),(unsigned int)(IPC&0xFFFFFFFF));
+ break;
+
+ case 1: /* should not occur (FPU co-processor) */
+ case 3: /* should not occur (FPU co-processor) */
+ SignalException(ReservedInstruction,instruction);
+ break;
+ }
+
+ return;
+}
+
+/*-- instruction simulation -------------------------------------------------*/
+
+static void
+simulate ()
+{
+ unsigned int pipeline_count = 1;
+
+#ifdef DEBUG
+ if (membank == NULL) {
+ printf("DBG: simulate() entered with no memory\n");
+ exit(1);
+ }
+#endif /* DEBUG */
+
+#if 0 /* Disabled to check that everything works OK */
+ /* The VR4300 seems to sign-extend the PC on its first
+ access. However, this may just be because it is currently
+ configured in 32bit mode. However... */
+ PC = SIGNEXTEND(PC,32);
+#endif
+
+ /* main controlling loop */
+ do {
+ /* Fetch the next instruction from the simulator memory: */
+ unsigned long long vaddr = (unsigned long long)PC;
+ unsigned long long paddr;
+ int cca;
+ unsigned int instruction;
+ int dsstate = (state & simDELAYSLOT);
+
+#ifdef DEBUG
+ {
+ printf("DBG: state = 0x%08X :",state);
+ if (state & simSTOP) printf(" simSTOP");
+ if (state & simSTEP) printf(" simSTEP");
+ if (state & simHALTEX) printf(" simHALTEX");
+ if (state & simHALTIN) printf(" simHALTIN");
+ if (state & simBE) printf(" simBE");
+ }
+#endif /* DEBUG */
+
+#ifdef DEBUG
+ if (dsstate)
+ callback->printf_filtered(callback,"DBG: DSPC = 0x%08X%08X\n",(unsigned int)(DSPC>>32),(unsigned int)(DSPC&0xFFFFFFFF));
+#endif /* DEBUG */
+
+ if (AddressTranslation(PC,isINSTRUCTION,isLOAD,&paddr,&cca,isTARGET,isREAL)) { /* Copy the action of the LW instruction */
+ unsigned int reverse = (ReverseEndian ? 1 : 0);
+ unsigned int bigend = (BigEndianCPU ? 1 : 0);
+ unsigned long long value;
+ unsigned int byte;
+ paddr = ((paddr & ~0x7) | ((paddr & 0x7) ^ (reverse << 2)));
+ value = LoadMemory(cca,AccessLength_WORD,paddr,vaddr,isINSTRUCTION,isREAL);
+ byte = ((vaddr & 0x7) ^ (bigend << 2));
+ instruction = ((value >> (8 * byte)) & 0xFFFFFFFF);
+ } else {
+ fprintf(stderr,"Cannot translate address for PC = 0x%08X%08X failed\n",(unsigned int)(PC>>32),(unsigned int)(PC&0xFFFFFFFF));
+ exit(1);
+ }
+
+#ifdef DEBUG
+ callback->printf_filtered(callback,"DBG: fetched 0x%08X from PC = 0x%08X%08X\n",instruction,(unsigned int)(PC>>32),(unsigned int)(PC&0xFFFFFFFF));
+#endif /* DEBUG */
+
+#if !defined(FASTSIM) || defined(PROFILE)
+ instruction_fetches++;
+#if defined(PROFILE)
+ if ((state & simPROFILE) && ((instruction_fetches % profile_frequency) == 0) && profile_hist) {
+ int n = ((unsigned int)(PC - profile_minpc) >> (profile_shift + 2));
+ if (n < profile_nsamples) {
+ /* NOTE: The counts for the profiling bins are only 16bits wide */
+ if (profile_hist[n] != USHRT_MAX)
+ (profile_hist[n])++;
+ }
+ }
+#endif /* PROFILE */
+#endif /* !FASTSIM && PROFILE */
+
+ IPC = PC; /* copy PC for this instruction */
+ /* This is required by exception processing, to ensure that we can
+ cope with exceptions in the delay slots of branches that may
+ already have changed the PC. */
+ PC += 4; /* increment ready for the next fetch */
+ /* NOTE: If we perform a delay slot change to the PC, this
+ increment is not requuired. However, it would make the
+ simulator more complicated to try and avoid this small hit. */
+
+ /* Currently this code provides a simple model. For more
+ complicated models we could perform exception status checks at
+ this point, and set the simSTOP state as required. This could
+ also include processing any hardware interrupts raised by any
+ I/O model attached to the simulator context.
+
+ Support for "asynchronous" I/O events within the simulated world
+ could be providing by managing a counter, and calling a I/O
+ specific handler when a particular threshold is reached. On most
+ architectures a decrement and check for zero operation is
+ usually quicker than an increment and compare. However, the
+ process of managing a known value decrement to zero, is higher
+ than the cost of using an explicit value UINT_MAX into the
+ future. Which system is used will depend on how complicated the
+ I/O model is, and how much it is likely to affect the simulator
+ bandwidth.
+
+ If events need to be scheduled further in the future than
+ UINT_MAX event ticks, then the I/O model should just provide its
+ own counter, triggered from the event system. */
+
+ /* MIPS pipeline ticks. To allow for future support where the
+ pipeline hit of individual instructions is known, this control
+ loop manages a "pipeline_count" variable. It is initialised to
+ 1 (one), and will only be changed by the simulator engine when
+ executing an instruction. If the engine does not have access to
+ pipeline cycle count information then all instructions will be
+ treated as using a single cycle. NOTE: A standard system is not
+ provided by the default simulator because different MIPS
+ architectures have different cycle counts for the same
+ instructions. */
+
+#if defined(HASFPU)
+ /* Set previous flag, depending on current: */
+ if (state & simPCOC0)
+ state |= simPCOC1;
+ else
+ state &= ~simPCOC1;
+ /* and update the current value: */
+ if (GETFCC(0))
+ state |= simPCOC0;
+ else
+ state &= ~simPCOC0;
+#endif /* HASFPU */
+
+/* NOTE: For multi-context simulation environments the "instruction"
+ variable should be local to this routine. */
+
+/* Shorthand accesses for engine. Note: If we wanted to use global
+ variables (and a single-threaded simulator engine), then we can
+ create the actual variables with these names. */
+
+ if (!(state & simSKIPNEXT)) {
+ /* Include the simulator engine */
+#include "engine.c"
+#if ((GPRLEN == 64) && !defined(PROCESSOR_64BIT)) || ((GPRLEN == 32) && defined(PROCESSOR_64BIT))
+#error "Mismatch between run-time simulator code and simulation engine"
+#endif
+
+#if defined(WARN_LOHI)
+ /* Decrement the HI/LO validity ticks */
+ if (HIACCESS > 0)
+ HIACCESS--;
+ if (LOACCESS > 0)
+ LOACCESS--;
+#endif /* WARN_LOHI */
+
+#if defined(WARN_ZERO)
+ /* For certain MIPS architectures, GPR[0] is hardwired to zero. We
+ should check for it being changed. It is better doing it here,
+ than within the simulator, since it will help keep the simulator
+ small. */
+ if (ZERO != 0) {
+ callback->printf_filtered(callback,"SIM Warning: The ZERO register has been updated with 0x%08X%08X (PC = 0x%08X%08X)\nSIM Warning: Resetting back to zero\n",(unsigned int)(ZERO>>32),(unsigned int)(ZERO&0xFFFFFFFF),(unsigned int)(IPC>>32),(unsigned int)(IPC&0xFFFFFFFF));
+ ZERO = 0; /* reset back to zero before next instruction */
+ }
+#endif /* WARN_ZERO */
+ } else /* simSKIPNEXT check */
+ state &= ~simSKIPNEXT;
+
+ /* If the delay slot was active before the instruction is
+ executed, then update the PC to its new value: */
+ if (dsstate) {
+#ifdef DEBUG
+ printf("DBG: dsstate set before instruction execution - updating PC to 0x%08X%08X\n",(unsigned int)(DSPC>>32),(unsigned int)(DSPC&0xFFFFFFFF));
+#endif /* DEBUG */
+ PC = DSPC;
+ state &= ~simDELAYSLOT;
+ }
+
+ if (MIPSISA < 4) { /* The following is only required on pre MIPS IV processors: */
+ /* Deal with pending register updates: */
+#ifdef DEBUG
+ printf("DBG: EMPTY BEFORE pending_in = %d, pending_out = %d, pending_total = %d\n",pending_in,pending_out,pending_total);
+#endif /* DEBUG */
+ if (pending_out != pending_in) {
+ int loop;
+ int index = pending_out;
+ int total = pending_total;
+ if (pending_total == 0) {
+ fprintf(stderr,"FATAL: Mis-match on pending update pointers\n");
+ exit(1);
+ }
+ for (loop = 0; (loop < total); loop++) {
+#ifdef DEBUG
+ printf("DBG: BEFORE index = %d, loop = %d\n",index,loop);
+#endif /* DEBUG */
+ if (pending_slot_reg[index] != (LAST_EMBED_REGNUM + 1)) {
+#ifdef DEBUG
+ printf("pending_slot_count[%d] = %d\n",index,pending_slot_count[index]);
+#endif /* DEBUG */
+ if (--(pending_slot_count[index]) == 0) {
+#ifdef DEBUG
+ printf("pending_slot_reg[%d] = %d\n",index,pending_slot_reg[index]);
+ printf("pending_slot_value[%d] = 0x%08X%08X\n",index,(unsigned int)(pending_slot_value[index]>>32),(unsigned int)(pending_slot_value[index]&0xFFFFFFFF));
+#endif /* DEBUG */
+ if (pending_slot_reg[index] == COCIDX) {
+ SETFCC(0,((FCR31 & (1 << 23)) ? 1 : 0));
+ } else {
+ registers[pending_slot_reg[index]] = pending_slot_value[index];
+#if defined(HASFPU)
+ /* The only time we have PENDING updates to FPU
+ registers, is when performing binary transfers. This
+ means we should update the register type field. */
+ if ((pending_slot_reg[index] >= FGRIDX) && (pending_slot_reg[index] < (FGRIDX + 32)))
+ fpr_state[pending_slot_reg[index]] = fmt_uninterpreted;
+#endif /* HASFPU */
+ }
+#ifdef DEBUG
+ printf("registers[%d] = 0x%08X%08X\n",pending_slot_reg[index],(unsigned int)(registers[pending_slot_reg[index]]>>32),(unsigned int)(registers[pending_slot_reg[index]]&0xFFFFFFFF));
+#endif /* DEBUG */
+ pending_slot_reg[index] = (LAST_EMBED_REGNUM + 1);
+ pending_out++;
+ if (pending_out == PSLOTS)
+ pending_out = 0;
+ pending_total--;
+ }
+ }
+#ifdef DEBUG
+ printf("DBG: AFTER index = %d, loop = %d\n",index,loop);
+#endif /* DEBUG */
+ index++;
+ if (index == PSLOTS)
+ index = 0;
+ }
+ }
+#ifdef DEBUG
+ printf("DBG: EMPTY AFTER pending_in = %d, pending_out = %d, pending_total = %d\n",pending_in,pending_out,pending_total);
+#endif /* DEBUG */
+ }
+
+#if !defined(FASTSIM)
+ pipeline_ticks += pipeline_count;
+#endif /* FASTSIM */
+
+ if (state & simSTEP)
+ state |= simSTOP;
+ } while (!(state & simSTOP));
+
+#ifdef DEBUG
+ if (membank == NULL) {
+ printf("DBG: simulate() LEAVING with no memory\n");
+ exit(1);
+ }
+#endif /* DEBUG */
+
+ return;
+}
+
+/*---------------------------------------------------------------------------*/
+/*> EOF interp.c <*/