Initial check-in of the MIPS simulator. Work still needs to be done on
authorJackie Smith Cashion <jsmith@redhat.com>
Wed, 8 Nov 1995 15:44:38 +0000 (15:44 +0000)
committerJackie Smith Cashion <jsmith@redhat.com>
Wed, 8 Nov 1995 15:44:38 +0000 (15:44 +0000)
the run-time support code (interp.c) to provide better tracing, and
also to add profiling and architecture specific support. At the moment
the simulator has a fixed size, fixed address memory area, and
simulates a subset of the IDT monitor calls (enough to execute test
programs).

The other major feature (could even be a bug) is that the simulator
makes use of the GCC "long long" extension. Work has been started to
make this a build configuration option... but there is still a lot of
this to be done.

sim/mips/README.Cygnus [new file with mode: 0644]
sim/mips/configure.in [new file with mode: 0644]
sim/mips/gencode.c [new file with mode: 0644]
sim/mips/support.h [new file with mode: 0644]

diff --git a/sim/mips/README.Cygnus b/sim/mips/README.Cygnus
new file mode 100644 (file)
index 0000000..06c5e43
--- /dev/null
@@ -0,0 +1,38 @@
+> README.Cygnus
+-------------------------------------------------------------------------------
+
+The following are the main reasons for constructing the simulator as a
+generator:
+
+1) Avoid large fixed decode source file, with lots of #ifs controlling
+   the compilation. i.e. keep the source cleaner, smaller and easier
+   to parse.
+
+2) Allow optimum code to be created, without run-time checks on
+   instruction types. Ensure that the simulator engine only includes
+   code for the architecture being targetted. e.g. This avoids
+   run-time checks on ISA conformance, aswell as increasing
+   throughput.
+
+3) Allow updates to the instruction sets to be added quickly. Having a
+   table means that the information is together, and is easier to
+   manipulate. Having the table generate the engine, rather than the
+   run-time parse the table gives higher performance at simulation
+   time.
+
+4) Keep all the similar simulation code together. i.e. have a single
+   place where, for example, the addition code is held. This ensures that
+   updates to the simulation are not spread over a large flat source
+   file maintained by the developer.
+
+-------------------------------------------------------------------------------
+
+To keep the simulator simple (and to avoid the slight chance of
+mis-matched files) the manifests describing an engine, and the
+simulator engine itself, are held in the same source file.
+
+This means that the engine must be included twice, with the first pass
+controlled by the SIM_MANIFESTS definition.
+
+-------------------------------------------------------------------------------
+> EOF README.Cygnus
diff --git a/sim/mips/configure.in b/sim/mips/configure.in
new file mode 100644 (file)
index 0000000..7b96e72
--- /dev/null
@@ -0,0 +1,27 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_PREREQ(2.3)dnl
+AC_INIT(Makefile.in)
+
+AC_CONFIG_AUX_DIR(`cd $srcdir;pwd`/../..)
+AC_CANONICAL_SYSTEM
+AC_ARG_PROGRAM
+
+. ${srcdir}/../../bfd/configure.host
+
+AC_PROG_CC
+AC_SUBST(CFLAGS)
+AC_SUBST(HDEFINES)
+AR=${AR-ar}
+AC_SUBST(AR)
+AC_PROG_RANLIB
+
+# Put a plausible default for CC_FOR_BUILD in Makefile.
+AC_C_CROSS
+if test "x$cross_compiling" = "xno"; then
+  CC_FOR_BUILD='$(CC)'
+else
+  CC_FOR_BUILD=gcc
+fi
+AC_SUBST(CC_FOR_BUILD)
+
+AC_OUTPUT(Makefile)
diff --git a/sim/mips/gencode.c b/sim/mips/gencode.c
new file mode 100644 (file)
index 0000000..330fb8b
--- /dev/null
@@ -0,0 +1,2027 @@
+/*> gencode.c <*/
+/*---------------------------------------------------------------------------*/
+/* $Revision$ */
+/*   $Author$ */
+/*     $Date$ */
+/* Copyright (c) 1995, Cygnus Support */
+/*---------------------------------------------------------------------------*/
+
+#if 0
+#define DEBUG (1) /* Just for testing */
+#endif
+
+/* The Makefile currently defines "INSIDE_SIMULATOR" as part of the
+   build. It is not currently used by the MIPS simulator world
+   though. */
+
+/* All output sent to stdout is for the simulator engine. All program
+   related warnings and errors should be sent to stderr. */
+
+/* The simulator decode table is constructed this way to allow the
+   minimal code required for a particular instruction type to be
+   coded.  This avoids a large simulator source file, with lots of
+   build-time conditionals controlling what code is included.  However
+   this two-stage process does mean that care must be taken to ensure
+   that the correct decoding source is generated for a particular MIPS
+   simulator. */
+
+/* Notes:
+
+   We could provide pipeline modelling by splitting the simulation of
+   instructions into seperate bytecodes for each pipeline
+   stage. e.g. for the VR4300 each instruction would generate 5
+   bytecodes, one for each pipeline stage. The simulator control would
+   then insert these into the relevant pipeline slots, and execute a
+   complete slots worth of bytecodes. However, the shape of the
+   pipeline, and what parts of each instruction are executed in each
+   pipeline stage, are different between MIPS implementations. If we
+   were to construct a simulator for a particular MIPS architecture
+   this would be a good solution.
+
+   To avoid having to provide multiple different pipeline models, a
+   simple approach for dealing with the delay slots, and register
+   dependencies has been used. The "MIPS IV Instruction Set" document
+   (Revision 3.1 - January 1995) details the standard MIPS instruction
+   set, and it defines operations in instruction (not pipe-line)
+   cycles. This means we only need to worry about a few cases where
+   the result is not available until after the next instruction, or
+   where registers in the previous two instruction cycles may be
+   corrupted. The case for corruption only occurs with HI or LO
+   register access, so we can just keep a count within the engine for
+   upto two cycles before marking the register as safe. We then only
+   need to check the safety flag when performing an update that
+   involves the HI or LO register. The only other case is the
+   BC1F/BC1T instructions in the FP unit. For ISAs I, II and III there
+   must be an instruction between the FP CMP and the BC1[FT]. We can
+   perform the same instruction cycle count scheme, so we can raise a
+   warning if an attempt is made to access the condition code early
+   (NOTE: The hardware does not interlock on this operation, so the
+   simulator should just raise a warning).
+
+   For the situations where a result is not available until later, we
+   implent a slot to hold pending values. After the PC is incremented,
+   and before the instruction is decoded we can execute the required
+   register update (or remainder of instruction processing). */
+
+/* The FP instruction decoding is also provided by this code.  The
+   instructions are marked as "FP" ones so that we can construct a
+   simulator without an FPU if required.  Similarly we mark
+   instructions as Single or Double precision, since some MIPS
+   processors only have single precision FP hardware. */
+
+/* NOTE: Ideally all state should be passed as parameters. This allows
+   a single simulator engine to be used for multiple concurrent
+   simulations. More importantly, if a suitably powerful control is in
+   place it will allow speculative simulation, since the context can
+   be saved easily, and then restored after performing some
+   simulation. The down-side is that for certain host architectures it
+   can slow the simulator down (e.g. if globals can be accessed faster
+   than local structures). However, this is not actually the case at
+   the moment. The constructed engine uses direct names (that can be
+   macro definitions). This keeps the engine source smalled (using
+   short-hands), and it also allows the user to control whether they
+   want to use global, or indirected memory locations. i.e. whether
+   they want a single- or multi-threaded simulator engine. */
+
+/* The constructed simulator engine contains manifests for each of the
+   features supported. The code that includes the engine can then
+   discover the available features during its build. This information
+   can be used to control run-time features provided by the final
+   simulator. */
+
+/*---------------------------------------------------------------------------*/
+
+/* Program defaults */
+#define DEF_ISA      (3)
+#define DEF_PROC64   (1 == 1)
+#define DEF_FP       (1 == 1)
+#define DEF_FPSINGLE (1 == 0)
+
+#define FEATURE_PROC32      (1 << 0)    /* 0 = 64bit; 1 = 32bit */
+#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_ZERO   (1 << 26)   /* 0 = nothing; 1 = generate warnings if attempt to write register zero */ 
+#define FEATURE_WARN_MEM    (1 << 27)   /* 0 = nothing; 1 = generate warnings when memory problems are noticed */
+#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 */
+
+#define FEATURE_WARNINGS  (FEATURE_WARN_STALL | FEATURE_WARN_LOHI | FEATURE_WARN_ZERO | FEATURE_WARN_R31 | FEATURE_WARN_RESULT)
+
+/* FEATURE_WARN_STALL */
+/* If MIPS I we want to raise a warning if an attempt is made to
+   access Rn in an instruction immediately following an Rn update
+   "WARNING : Invalid value read". The simulator engine is designed
+   that the previous value is read in such cases, to allow programs
+   that make use of this feature to execute. *
+/* If MIPS II or later, attempting to read a register before the
+   update has completed will generate a "WARNING : Processor stall"
+   message (since the processor will lock the pipeline until the value
+   becomes available). */
+
+/* FEATURE_WARN_LOHI */
+/* Warn if an attempt is made to read the HI/LO registers before the
+   update has completed, or if an attempt is made to update the
+   registers whilst an update is occurring. */
+
+/* FEATURE_WARN_ZERO */
+/* Notify the user if an attempt is made to use GPR 0 as a destination. */
+
+/* FEATURE_WARN_R31 */
+/* Notify the user if register r31 (the default procedure call return
+   address) is used unwisely. e.g. If r31 is used as the source in a
+   branch-and-link instruction, it would mean that an exception in the
+   delay slot instruction would not allow the branch to be re-started
+   (since r31 will have been overwritten by the link operation during
+   the first execution of the branch). */
+
+/* FEATURE_WARN_RESULT */
+/* Certain instructions do not raise exceptions when invalid operands
+   are given, they will just result in undefined values being
+   generated. This option controls whether the simulator flags such
+   events. */
+
+/*---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <getopt.h>
+#include <limits.h>
+#include <errno.h>
+#include "opcode/mips.h" /* From Cygnus progressive tree */
+
+/* The following manifests do not appear in "progressive/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_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)
+
+#ifndef TRUE
+#define TRUE  (1 == 1)
+#define FALSE (1 == 0)
+#endif
+
+/*---------------------------------------------------------------------------*/
+
+/* Holding the instruction table this way makes it easier to check the
+   instruction values defined, and to add instructions to the
+   system. However, it makes the process of constructing the simulator
+   a bit more complicated: */
+
+/* The "bitmap" is encoded as follows (NOTE: Only lower-case
+   alphabetic characters should be used, since the letter ordinal is
+   used as a bit position): */
+
+typedef struct operand_encoding {
+ char id; /* character identifier */
+ int fpos; /* first bit position */
+ int flen; /* field length in bits */
+ char * const type;
+ char * const name;
+ unsigned int flags;
+} operand_encoding;
+
+/* 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 */
+
+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) */
+ /* 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) */
+};
+
+/* Main instruction encoding types: */
+typedef enum {
+ NORMAL,
+ SPECIAL,
+ REGIMM,
+ COP1,
+ COP1X,
+ UNKNOWN
+} inst_type;
+
+/* Main instruction families: */
+typedef enum {
+ ADD,                  /* res = operand1 + operand2 */
+ SUB,                   /* res = operand1 - operand2 */
+ MUL,                   /* res = operand1 * operand2 */
+ DIV,                   /* res = operand1 / operand2 */
+ AND,                  /* res = operand1 & operand2 */
+ OR,                   /* res = operand1 | operand2 */
+ XOR,                  /* res = operand1 ^ operand2 */
+ MOVE,                  /* res = operand1 */
+ BRANCH,               /* execute delay slot instruction before branch unless (LIKELY && branch_not_taken) */
+ JUMP,                  /* execute delay slot instruction before jump */
+ LOAD,                  /* load from memory */
+ STORE,                 /* store to memory */
+ PREFETCH,              /* prefetch data into cache */
+ SET,                   /* set register on result of condition code */
+ SHIFT,                 /* perform a logical or arithmetic shift */
+ TRAP,                  /* system exception generation */
+ BREAK,                 /* system breakpoint exception generation */
+ SYSCALL,               /* system exception generation */
+ SYNC,                  /* system cache control */
+ DECODE,                /* co-processor instruction */
+ CACHE,                 /* co-processor 0 CACHE instruction */
+ MADD16,                /* VR4100 specific multiply-add extensions */
+ FPMOVE,
+ FPFLOOR,               
+ FPCEIL,
+ FPTRUNC,
+ FPROUND,
+ FPNEG,
+ FPABS,
+ FPDIV,
+ FPMUL,
+ FPSUB,
+ FPADD,
+ FPMAB,                 /* Special encoding for MOVE, ADD and BRANCH instructions */
+ FPPREFX,
+ FPSTORE,
+ FPLOAD,
+ FPRECIP,
+ FPSQRT,
+ FPCONVERT,
+ FPCOMPARE,
+ RSVD                   /* "Reserved Instruction" on MIPS IV, or if co-proc 3 absent. Otherwise "Reserved Instruction" */
+} opcode_type;
+
+/* 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)
+
+/* 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 LT              (1 << 6)
+#define NOT            (1 << 7)
+#define LIKELY         (1 << 8)
+#define SIGNEXTEND     (1 << 9)
+#define OVERFLOW       (1 << 10)
+#define LINK           (1 << 11)
+#define ATOMIC         (1 << 12)
+#define SHIFT16                (1 << 13)
+#define REG             (1 << 14)
+#define LEFT            (1 << 15)       /* Deliberate explicit encodings to allow check for neither, or both */
+#define RIGHT           (1 << 16)       /* Mutually exclusive with "LEFT" */
+#define LOGICAL         (1 << 17)
+#define ARITHMETIC      (1 << 18)
+#define UNSIGNED        (1 << 19)
+#define HI32            (1 << 20)
+#define HI              (1 << 21)       /* accesses or updates the HI register */
+#define LO              (1 << 22)       /* accesses or updates the LO register */
+#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 NOARG           (1 << 31)       /* Instruction has no (defined) operands */
+
+typedef struct instruction {
+ char         *name;   /* ASCII mnemonic name */
+ unsigned int  isa;    /* MIPS ISA number where instruction introduced */
+ char         *bitmap; /* 32character string describing instruction operands */
+ inst_type     mark;   /* type of MIPS instruction encoding */
+ opcode_type   type;   /* main instruction family */
+ unsigned int  flags;  /* flags describing instruction features */
+} instruction;
+/* The number of pipeline cycles taken by an instruction varies
+   between MIPS processors. This means that the information must be
+   encoded elsewhere, in a CPU specific structure. */
+
+/* NOTE: Undefined instructions cause "Reserved Instruction"
+   exceptions. i.e. if there is no bit-mapping defined then the
+   instruction is deemed to be undefined. */
+
+/* NOTE: The "isa" field is also used to encode flags for particular
+   chip architecture extensions. e.g. the NEC VR4100 specific
+   instructions. Normally chip extensions are added via the COP0
+   space. However, the VR4100 (and possibly other devices) also use
+   the normal instruction space. */
+#define MASK_ISA (0x000000FF) /* Start by leaving 8bits for the ISA ID */
+/* The other bits are allocated downwards, to avoid renumbering if we
+   have to extend the bits allocated to the pure ISA number. */
+#define ARCH_VR4100       ((unsigned)1 << 31) /* NEC VR4100 extension instructions */
+
+/* The HIBERNATE, STANDBY and SUSPEND instructions are encoded in the
+   COP0 space. This means that an external decoder should be added
+   when constructing a full VR4100 simulator. However some arithmetic
+   instructions are encoded in the normal instruction space. */
+
+struct instruction MIPS_DECODE[] = {
+ /* 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)},
+ {"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)},
+ {"BEQ",     1,"000100sssssgggggllllllllllllllll",NORMAL, BRANCH,   (EQ)},
+ {"BEQL",    2,"010100sssssgggggllllllllllllllll",NORMAL, BRANCH,   (EQ | LIKELY)},
+ {"BGEZ",    1,"000001sssss00001llllllllllllllll",REGIMM, BRANCH,   (GT | EQ)},
+ {"BGEZAL",  1,"000001sssss10001llllllllllllllll",REGIMM, BRANCH,   (GT | EQ | LINK)},
+ {"BGEZALL", 2,"000001sssss10011llllllllllllllll",REGIMM, BRANCH,   (GT | EQ | LINK)},
+ {"BGEZL",   2,"000001sssss00011llllllllllllllll",REGIMM, BRANCH,   (GT | EQ | LIKELY)},
+ {"BGTZ",    1,"000111sssss00000llllllllllllllll",NORMAL, BRANCH,   (GT)},
+ {"BGTZL",   2,"010111sssss00000llllllllllllllll",NORMAL, BRANCH,   (GT | LIKELY)},
+ {"BLEZ",    1,"000110sssss00000llllllllllllllll",NORMAL, BRANCH,   (LT | EQ)},
+ {"BLEZL",   2,"010110sssss00000llllllllllllllll",NORMAL, BRANCH,   (LT | EQ | LIKELY)},
+ {"BLTZ",    1,"000001sssss00000llllllllllllllll",REGIMM, BRANCH,   (LT)},
+ {"BLTZAL",  1,"000001sssss10000llllllllllllllll",REGIMM, BRANCH,   (LT | LINK)},
+ {"BLTZALL", 2,"000001sssss10010llllllllllllllll",REGIMM, BRANCH,   (LT | LINK | LIKELY)},
+ {"BLTZL",   2,"000001sssss00010llllllllllllllll",REGIMM, BRANCH,   (LT | LIKELY)},
+ {"BNE",     1,"000101sssssgggggllllllllllllllll",NORMAL, BRANCH,   (NOT | EQ)},
+ {"BNEL",    2,"010101sssssgggggllllllllllllllll",NORMAL, BRANCH,   (NOT | EQ | LIKELY)},
+ {"BREAK",   1,"000000????????????????????001101",SPECIAL,BREAK,    (NOARG)},
+ {"CEIL.L",  3,"01000110mmm00000vvvvvrrrrr001010",COP1,   FPCEIL,   (FP | FIXED | DOUBLEWORD)},
+ {"CEIL.W",  2,"01000110mmm00000vvvvvrrrrr001110",COP1,   FPCEIL,   (FP | FIXED | WORD)},
+ {"COP0",    1,"010000??????????????????????????",NORMAL, DECODE,   (NOARG)},
+ {"COP2",    1,"010010??????????????????????????",NORMAL, DECODE,   (NOARG)},
+ {"CVT.D",   1,"01000110mmm00000vvvvvrrrrr100001",COP1,   FPCONVERT,(FP | DOUBLE)},
+ {"CVT.L",   3,"01000110mmm00000vvvvvrrrrr100101",COP1,   FPCONVERT,(FP | FIXED | DOUBLEWORD)},
+ {"CVT.S",   1,"01000110mmm00000vvvvvrrrrr100000",COP1,   FPCONVERT,(FP | SINGLE)},
+ {"CVT.W",   1,"01000110mmm00000vvvvvrrrrr100100",COP1,   FPCONVERT,(FP | FIXED | WORD)},
+ {"C.%s",    1,"01000110mmmkkkkkvvvvvppp0011uuuu",COP1,   FPCOMPARE,(FP)},
+ {"DADD",    3,"000000sssssgggggddddd00000101100",SPECIAL,ADD,      (DOUBLEWORD | OVERFLOW)},
+ {"DADDI",   3,"011000ssssstttttiiiiiiiiiiiiiiii",NORMAL, ADD,      (DOUBLEWORD | OVERFLOW)},
+ {"DADDU",   3,"000000sssssgggggddddd00000101101",SPECIAL,ADD,      (DOUBLEWORD | UNSIGNED)},
+ {"DADDIU",  3,"011001ssssstttttiiiiiiiiiiiiiiii",NORMAL, ADD,      (DOUBLEWORD | UNSIGNED)},
+ {"DDIV",    3,"000000sssssggggg0000000000011110",SPECIAL,DIV,      (DOUBLEWORD | HI | LO)},
+ {"DDIVU",   3,"000000sssssggggg0000000000011111",SPECIAL,DIV,      (DOUBLEWORD | UNSIGNED | HI | LO)},
+ {"DIV",     1,"000000sssssggggg0000000000011010",SPECIAL,DIV,      (WORD | WORD32 | SIGNEXTEND | HI | LO)},
+ {"DIV",     1,"01000110mmmkkkkkvvvvvrrrrr000011",COP1,   FPDIV,    (FP | WORD | HI | LO)},
+ {"DIVU",    1,"000000sssssggggg0000000000011011",SPECIAL,DIV,      (WORD | WORD32 | UNSIGNED | SIGNEXTEND | HI | LO)},
+ {"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)},
+ {"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) */
+ {"DSRA",    3,"00000000000gggggdddddaaaaa111011",SPECIAL,SHIFT,    (DOUBLEWORD | RIGHT | ARITHMETIC)},
+ {"DSRAV",   3,"000000sssssgggggddddd00000010111",SPECIAL,SHIFT,    (DOUBLEWORD | RIGHT | ARITHMETIC)},
+ {"DSRA32",  3,"00000000000gggggdddddaaaaa111111",SPECIAL,SHIFT,    (DOUBLEWORD | RIGHT | ARITHMETIC | HI32)}, /* rd = rt >> (sa + 32) */
+ {"DSRL",    3,"00000000000gggggdddddaaaaa111010",SPECIAL,SHIFT,    (DOUBLEWORD | RIGHT | LOGICAL)},
+ {"DSRLV",   3,"000000sssssgggggddddd00000010110",SPECIAL,SHIFT,    (DOUBLEWORD | RIGHT | LOGICAL)},
+ {"DSRL32",  3,"00000000000gggggdddddaaaaa111110",SPECIAL,SHIFT,    (DOUBLEWORD | RIGHT | LOGICAL | HI32)},
+ {"DSUB",    3,"000000sssssgggggddddd00000101110",SPECIAL,SUB,      (DOUBLEWORD)},
+ {"DSUBU",   3,"000000sssssgggggddddd00000101111",SPECIAL,SUB,      (DOUBLEWORD | UNSIGNED)},
+ {"FLOOR.L", 3,"01000110mmm00000vvvvvrrrrr001011",COP1,   FPFLOOR,  (FP | FIXED | DOUBLEWORD)},
+ {"FLOOR.W", 2,"01000110mmm00000vvvvvrrrrr001111",COP1,   FPFLOOR,  (FP | FIXED | WORD)},
+ {"J",       1,"000010jjjjjjjjjjjjjjjjjjjjjjjjjj",NORMAL, JUMP,     (NONE)},                   /* NOTE: boundary case due to delay slot address being used */
+ {"JAL",     1,"000011jjjjjjjjjjjjjjjjjjjjjjjjjj",NORMAL, JUMP,     (LINK)},                   /* NOTE: boundary case due to delay slot address being used */
+ {"JALR",    1,"000000sssss00000ddddd00000001001",SPECIAL,JUMP,     (LINK | REG)},
+ {"JR",      1,"000000sssss000000000000000001000",SPECIAL,JUMP,     (NONE)}, /* need to check PC as part of instruction fetch */
+ {"LB",      1,"100000ssssstttttyyyyyyyyyyyyyyyy",NORMAL, LOAD,     (BYTE | SIGNEXTEND)},      /* NOTE: "i" rather than "o" because BYTE addressing is allowed */
+ {"LBU",     1,"100100ssssstttttyyyyyyyyyyyyyyyy",NORMAL, LOAD,     (BYTE)},                   /* NOTE: See "LB" comment */
+ {"LD",      3,"110111sssssttttteeeeeeeeeeeeeeee",NORMAL, LOAD,     (DOUBLEWORD)},
+ {"LDC1",    2,"110101sssssttttteeeeeeeeeeeeeeee",NORMAL, LOAD,     (DOUBLEWORD | COPROC)},
+ {"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)},
+ {"LH",      1,"100001sssssttttthhhhhhhhhhhhhhhh",NORMAL, LOAD,     (HALFWORD | SIGNEXTEND)},
+ {"LHU",     1,"100101sssssttttthhhhhhhhhhhhhhhh",NORMAL, LOAD,     (HALFWORD)},
+ {"LL",      2,"110000ssssstttttwwwwwwwwwwwwwwww",NORMAL, LOAD,     (WORD | ATOMIC | SIGNEXTEND)},
+ {"LLD",     3,"110100sssssttttteeeeeeeeeeeeeeee",NORMAL, LOAD,     (DOUBLEWORD | ATOMIC)},
+ {"LUI",     1,"00111100000tttttiiiiiiiiiiiiiiii",NORMAL, MOVE,     (SHIFT16)}, /* Cheat and specify sign-extension of immediate field */
+ {"LW",      1,"100011ssssstttttwwwwwwwwwwwwwwww",NORMAL, LOAD,     (WORD | SIGNEXTEND)},
+ {"LWC1",    1,"110001ssssstttttwwwwwwwwwwwwwwww",NORMAL, LOAD,     (WORD | COPROC)},
+ {"LWC2",    1,"110010ssssstttttwwwwwwwwwwwwwwww",NORMAL, LOAD,     (WORD | COPROC)},
+ {"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)},
+ {"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)},
+ {"MFHI",    1,"0000000000000000ddddd00000010000",SPECIAL,MOVE,     (HI)},    /* with following, from and to denoted by usage of "s" or "d" */
+ {"MFLO",    1,"0000000000000000ddddd00000010010",SPECIAL,MOVE,     (LO)},
+ {"MTHI",    1,"000000sssss000000000000000010001",SPECIAL,MOVE,     (HI)},
+ {"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 */
+ {"MOVZ",    4,"000000sssssgggggddddd00000001010",SPECIAL,MOVE,     (EQ)},
+ {"MOVZ",    4,"01000110mmmkkkkkvvvvvrrrrr010010",COP1,   FPMOVE,   (FP)},
+ {"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)},
+ {"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)},
+ {"NMSUB.S", 4,"010011bbbbbkkkkkvvvvvrrrrr111000",COP1X,  FPSUB,    (FP | NOT | MULTIPLY | SINGLE)},
+ {"NOR",     1,"000000sssssgggggddddd00000100111",SPECIAL,OR,       (NOT)},
+ {"OR",      1,"000000sssssgggggddddd00000100101",SPECIAL,OR,       (NONE)},
+ {"ORI",     1,"001101ssssstttttzzzzzzzzzzzzzzzz",NORMAL, OR,       (NONE)},
+ {"PREF",    4,"110011sssssnnnnnyyyyyyyyyyyyyyyy",NORMAL, PREFETCH, (NONE)},
+ {"PREFX",   4,"010011bbbbbkkkkkvvvvv00000001111",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)},
+ {"SB",      1,"101000sssssgggggyyyyyyyyyyyyyyyy",NORMAL, STORE,    (BYTE)},
+ {"SC",      2,"111000sssssgggggwwwwwwwwwwwwwwww",NORMAL, STORE,    (WORD | ATOMIC)},
+ {"SCD",     3,"111100sssssgggggeeeeeeeeeeeeeeee",NORMAL, STORE,    (DOUBLEWORD | ATOMIC)},
+ {"SD",      3,"111111sssssgggggeeeeeeeeeeeeeeee",NORMAL, STORE,    (DOUBLEWORD)},
+ {"SDC1",    2,"111101sssssttttteeeeeeeeeeeeeeee",NORMAL, STORE,    (DOUBLEWORD | COPROC)},
+ {"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)},
+ {"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 */
+ {"SLT",     1,"000000sssssgggggddddd00000101010",SPECIAL,SET,      (LT)},
+ {"SLTI",    1,"001010ssssstttttiiiiiiiiiiiiiiii",NORMAL, SET,      (LT)},
+ {"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)},
+ {"SUB",     1,"000000sssssgggggddddd00000100010",SPECIAL,SUB,      (WORD | WORD32 | OVERFLOW)},
+ {"SUB",     1,"01000110mmmkkkkkvvvvvrrrrr000001",COP1,   FPSUB,    (FP)},
+ {"SUBU",    1,"000000sssssgggggddddd00000100011",SPECIAL,SUB,      (WORD | WORD32)},
+ {"SW",      1,"101011sssssgggggwwwwwwwwwwwwwwww",NORMAL, STORE,    (WORD)},
+ {"SWC1",    1,"111001ssssstttttwwwwwwwwwwwwwwww",NORMAL, STORE,    (WORD | COPROC)},
+ {"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)},
+ {"SYNC",    2,"000000000000000000000aaaaa001111",SPECIAL,SYNC,     (NONE)}, /* z = 5bit stype field */
+ {"SYSCALL", 1,"000000????????????????????001100",SPECIAL,SYSCALL,  (NOARG)},
+ {"TEQ",     2,"000000sssssggggg??????????110100",SPECIAL,TRAP,     (EQ)},
+ {"TEQI",    2,"000001sssss01100iiiiiiiiiiiiiiii",REGIMM, TRAP,     (EQ)},
+ {"TGE",     2,"000000sssssggggg??????????110000",SPECIAL,TRAP,     (GT | EQ)},
+ {"TGEI",    2,"000001sssss01000iiiiiiiiiiiiiiii",REGIMM, TRAP,     (GT | EQ)},
+ {"TGEIU",   2,"000001sssss01001iiiiiiiiiiiiiiii",REGIMM, TRAP,     (GT | EQ | UNSIGNED)},
+ {"TGEU",    2,"000000sssssggggg??????????110001",SPECIAL,TRAP,     (GT | EQ | UNSIGNED)},
+ {"TLT",     2,"000000sssssggggg??????????110010",SPECIAL,TRAP,     (LT)},
+ {"TLTI",    2,"000001sssss01010iiiiiiiiiiiiiiii",REGIMM, TRAP,     (LT)},
+ {"TLTIU",   2,"000001sssss01011iiiiiiiiiiiiiiii",REGIMM, TRAP,     (LT | UNSIGNED)},
+ {"TLTU",    2,"000000sssssggggg??????????110011",SPECIAL,TRAP,     (LT | UNSIGNED)},
+ {"TNE",     2,"000000sssssggggg??????????110110",SPECIAL,TRAP,     (NOT | EQ)},
+ {"TNEI",    2,"000001sssss01110iiiiiiiiiiiiiiii",REGIMM, TRAP,     (NOT | EQ)},
+ {"TRUNC.L", 3,"01000110mmm00000vvvvvrrrrr001001",COP1,   FPTRUNC,  (FP | FIXED | DOUBLEWORD)},
+ {"TRUNC.W", 2,"01000110mmm00000vvvvvrrrrr001101",COP1,   FPTRUNC,  (FP | FIXED | WORD)},
+ {"XOR",     1,"000000sssssgggggddddd00000100110",SPECIAL,XOR,      (NONE)},
+ {"XORI",    1,"001110ssssstttttzzzzzzzzzzzzzzzz",NORMAL, XOR,      (NONE)},
+ {"CACHE",   3,"101111sssssnnnnnyyyyyyyyyyyyyyyy",NORMAL, CACHE,    (NONE)},
+ {"<INT>",   1,"111011sssssgggggyyyyyyyyyyyyyyyy",NORMAL, RSVD,     (NONE)},
+};
+
+/*---------------------------------------------------------------------------*/
+
+/* We use the letter ordinal as the bit-position in our flags field: */
+#define fieldval(l)     (1 << ((l) - 'a'))
+
+unsigned int
+convert_bitmap(bitmap,onemask,zeromask,dontmask)
+     char *bitmap;
+     unsigned int *onemask, *zeromask, *dontmask;
+{
+  unsigned int flags = 0x00000000;
+  int loop; /* current bitmap position */
+  int lastsp = -1; /* last bitmap field starting position */
+  int lastoe = -1; /* last bitmap field encoding */
+
+  *onemask = 0x00000000;
+  *zeromask = 0x00000000;
+  *dontmask = 0x00000000;
+
+  if (strlen(bitmap) != 32) {
+    fprintf(stderr,"Invalid bitmap string - not 32 characters long \"%s\"\n",bitmap);
+    exit(3);
+  }
+
+  for (loop = 0; (loop < 32); loop++) {
+    int oefield ;
+    for (oefield = 0; (oefield < (sizeof(opfields) / sizeof(struct operand_encoding))); oefield++)
+     if (bitmap[31 - loop] == opfields[oefield].id)
+      break;
+    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);
+         exit(4);
+       }
+         
+      switch (bitmap[31 - loop]) {
+        case '0' : /* fixed value */
+         *zeromask |= (1 << loop);
+         lastsp = loop;
+         lastoe = -1;
+         break;
+
+        case '1' : /* fixed value */
+         *onemask |= (1 << loop);
+         lastsp = loop;
+         lastoe = -1;
+         break;
+
+        case '?' : /* fixed value */
+         *dontmask |= (1 << loop);
+         lastsp = loop;
+         lastoe = -1;
+         break;
+
+        default : /* check character encoding */
+         {
+           if (opfields[oefield].fpos != -1) {
+             /* If flag not set, then check starting position: */
+             if (!(flags & fieldval(bitmap[31 - loop]))) {
+               if (loop != opfields[oefield].fpos) {
+                 fprintf(stderr,"Bitmap field '%c' (0x%02X) at wrong offset %d in bitmap \"%s\"\n",(((bitmap[31 - loop] < 0x20) || (bitmap[31 - loop] >= 0x7F)) ? '.' : bitmap[31 - loop]),bitmap[31 - loop],loop,bitmap);
+                 exit(4);
+               }
+               flags |= fieldval(bitmap[31 - loop]);
+               lastsp = loop;
+               lastoe = oefield;
+             }
+           }
+           *dontmask |= (1 << loop);
+         }
+         break;
+       }
+    } else {
+      fprintf(stderr,"Unrecognised bitmap character '%c' (0x%02X) at offset %d in bitmap \"%s\"\n",(((bitmap[31 - loop] < 0x20) || (bitmap[31 - loop] >= 0x7F)) ? '.' : bitmap[31 - loop]),bitmap[31 - loop],loop,bitmap);
+      exit(4);
+    }
+  }
+
+ /* NOTE: Since we check for the position and size of fields when
+    parsing the "bitmap" above, we do *NOT* need to check that invalid
+    field combinations have been used. */
+
+ return(flags);
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void
+build_operands(flags)
+     unsigned int flags;
+{
+  int loop;
+  for (loop = 0; (loop < (sizeof(opfields) / sizeof(operand_encoding))); loop++)
+   if ((opfields[loop].fpos != -1) && (flags & fieldval(opfields[loop].id))) {
+     printf("  %s %s = ",opfields[loop].type,opfields[loop].name);
+
+     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_SHIFT2)
+      printf("(");
+
+     printf("((instruction >> %d) & 0x%08X)",opfields[loop].fpos,((1 << opfields[loop].flen) - 1));
+
+     if (opfields[loop].flags & OP_SHIFT2)
+      printf(" << 2)");
+
+     if (opfields[loop].flags & (OP_GPR | OP_FGR))
+      printf("]");
+
+     if (opfields[loop].flags & OP_BITS5)
+      printf("&0x1F");
+
+     if (opfields[loop].flags & OP_SIGNX)
+      printf(",%d)",(opfields[loop].flen + ((opfields[loop].flags & OP_SHIFT2) ? 2 : 0)));
+
+     printf(";\n");
+   }
+
+ return;
+}
+
+/*---------------------------------------------------------------------------*/
+/* doisa = number of MIPS ISA simulator table is being constructed for.
+ * proc64 = TRUE if constructing 64bit processor world.
+ * dofp = boolean, TRUE if FP instructions are to be included.
+ * fpsingle = boolean, TRUE if only single precision FP instructions to be included.
+ */
+
+void
+process_instructions(doarch,features)
+     unsigned int doarch;
+     unsigned int features;
+{
+  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 loop;
+
+  if (limit < 1) {
+    fprintf(stderr,"process_instructions: invalid structure length\n");
+    exit(1);
+  }
+
+  if (proc64 && (gprlen != 64)) {
+    fprintf(stderr,"Error: 64bit processor build specified, with MIPS ISA I or II\n");
+    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 */
+
+  printf("#if defined(SIM_MANIFESTS)\n");
+  if (proc64)
+   printf("#define PROCESSOR_64BIT (1 == 1)\n");
+  printf("#define LOADDRMASK (0x%08X)\n",(proc64 ? 0x7 : 0x3));
+  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"));
+  if (dofp)
+   printf("#define HASFPU (1 == 1)\n");
+  if (features & FEATURE_FAST)
+   printf("#define FASTSIM (1 == 1)\n");
+  if (features & FEATURE_WARN_STALL)
+   printf("#define WARN_STALL (1 == 1)\n");
+  if (features & FEATURE_WARN_LOHI)
+   printf("#define WARN_LOHI (1 == 1)\n");
+  if (features & FEATURE_WARN_ZERO)
+   printf("#define WARN_ZERO (1 == 1)\n");
+  if (features & FEATURE_WARN_MEM)
+   printf("#define WARN_MEM (1 == 1)\n");
+  if (features & FEATURE_WARN_R31)
+   printf("#define WARN_R31 (1 == 1)\n");
+  if (features & FEATURE_WARN_RESULT)
+   printf("#define WARN_RESULT (1 == 1)\n");
+
+  printf("#else /* simulator engine */\n");
+
+  printf("/* Engine generated by \"%s\" at %s */\n","<SHOW PROGRAM ARGS>","<SHOW CURRENT DATE AND TIME>");
+  printf("/* Main instruction decode for %d-bit MIPS ISA %d (Table entry limit = %d) */\n",(proc64 ? 64 : 32),doisa,limit);
+  if (dofp)
+   printf("/* %sFP instructions included */\n",(fpsingle ? "Single precision " : ""));
+  printf("/* NOTE: \"DSPC\" is the delay slot PC address */\n");
+
+ if (proc64) {
+   printf("#if !defined(PROCESSOR_64BIT)\n");
+   printf("#error \"Automatically constructed decoder has been built for a 64bit processor\"\n");
+   printf("#endif\n");
+ }
+
+ 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))) ;
+ printf("switch (num)\n") ;
+ printf("{\n");
+
+ for (loop = 1; (loop < limit); loop++) {
+   /* First check that the ISA number we are constructing for is
+      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))) {
+     unsigned int onemask;
+     unsigned int zeromask;
+     unsigned int dontmask;
+     unsigned int mask;
+     unsigned int number;
+     unsigned int flags = convert_bitmap(MIPS_DECODE[loop].bitmap,&onemask,&zeromask,&dontmask);
+     char *regtype = ((gprlen == 64) ? "uword64" : "unsigned int");
+
+     if ((GETDATASIZE() == DOUBLEWORD) && !proc64) {
+       fprintf(stderr,"DOUBLEWORD width specified for non 64-bit processor for instruction \"%s\"\n",MIPS_DECODE[loop].name);
+       exit(4);
+     }
+
+#if defined(DEBUG)
+     printf("/* DEBUG: onemask  0x%08X */\n",onemask) ;
+     printf("/* DEBUG: zeromask 0x%08X */\n",zeromask) ;
+     printf("/* DEBUG: dontmask 0x%08X */\n",dontmask) ;
+#endif
+
+     switch (MIPS_DECODE[loop].mark) {
+       case NORMAL :
+        mask = (OP_MASK_OP << OP_SH_OP) ;
+        number = ((onemask >> OP_SH_OP) & OP_MASK_OP) ;
+        break ;
+
+       case SPECIAL :
+        mask = ((OP_MASK_OP << OP_SH_OP) | (OP_MASK_SPEC << OP_SH_SPEC)) ;
+        number = ((OP_MASK_OP + 1) + ((onemask >> OP_SH_SPEC) & OP_MASK_SPEC)) ;
+        break ;
+
+       case REGIMM :
+        mask = ((OP_MASK_OP << OP_SH_OP) | (OP_MASK_RT << OP_SH_RT)) ;
+        number = (((OP_MASK_OP + 1) + (OP_MASK_SPEC + 1)) + ((onemask >> OP_SH_RT) & OP_MASK_RT)) ;
+        break ;
+
+       case COP1 :
+        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)) + ((onemask >> OP_SH_SPEC) & OP_MASK_SPEC)) ;
+        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)) ;
+        break ;
+
+       default :
+        fprintf(stderr,"Unrecognised opcode mark %d in table slot %d \"%s\"\n",MIPS_DECODE[loop].mark,loop,MIPS_DECODE[loop].name) ;
+        exit(5) ;
+      }
+
+     printf("case %d : /* \"%s\" %s */\n",number,MIPS_DECODE[loop].name,MIPS_DECODE[loop].bitmap) ;
+
+#if defined(DEBUG)
+     printf("/* DEBUG: mask 0x%08X */\n",mask) ;
+     printf(" printf(\"\\\"%s\\\"\\n\");\n",MIPS_DECODE[loop].name);
+#endif
+
+     /* Check if there are any other explicit bits in the instruction: */
+     if ((~mask & (onemask | zeromask)) != 0x00000000) {
+       printf(" if ((instruction & 0x%08X) != 0x%08X)\n",(onemask | zeromask),onemask) ;
+       printf(" {\n") ;
+       printf("  SignalException(ReservedInstruction,instruction);\n") ;
+       printf(" }\n") ;
+       printf(" else\n") ;
+     }
+
+     if ((flags == 0) && !(MIPS_DECODE[loop].flags & NOARG)) {
+       fprintf(stderr,"Bitmap error: Instruction with no operand fields \"%s\"\n",MIPS_DECODE[loop].name) ;
+       exit(5) ;
+     }
+
+     printf(" {\n") ;
+
+     /* Get hold of the operands */
+     /* NOTE: If we wanted to make the simulator code smaller, we
+      * could pull these into a common sequence before we perform
+      * the instruction decoding. However, this would affect the
+      * performance since unnecessary field extraction would be
+      * occurring for certain instructions.
+      *
+      * Also we do not perform checking for multiple definitions of a
+      * particular operand here, since they are caught by the
+      * compilation of the produced code.
+      */
+     build_operands(flags);
+
+     /* Finish constructing the jump address if required: */
+     if (flags & fieldval('j'))
+      printf("  op1 |= (PC & ~0x0FFFFFFF); /* address of instruction in delay slot for the jump */\n");
+
+     /* Now perform required operand checks: */
+
+/* The following code has been removed, since it seems perfectly
+   reasonable to have a non-aligned offset that is added to another
+   non-aligned base to create an aligned address. Some more
+   information on exactly what the MIPS IV specification requires is
+   needed before deciding on the best strategy. Experimentation with a
+   VR4300 suggests that we do not need to raise the warning. */
+#if 0
+     /* For MIPS IV (and onwards), certain instruction operand values
+        will give undefined results. For the simulator we could
+        generate explicit exceptions (i.e. ReservedInstruction) to
+        make it easier to spot invalid use. However, for the moment we
+        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))) {
+       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
+          ensure that the following opcode processing is not
+          executed. i.e. the code falls straight out to the simulator
+          control loop. */
+       printf("   WARNING(\"Instruction has lo-order offset bits set in instruction\");\n");
+       printf("  }\n");
+     }
+#endif
+
+     /* The extended condition codes only appeared in ISA IV */
+     if ((flags & fieldval('p')) && ((doisa < 4) && (doisa != 0))) {
+       printf("  if (condition_code != 0)\n");
+       printf("  {\n");
+       printf("   SignalException(ReservedInstruction,instruction);\n");
+       printf("  }\n");
+       printf("  else\n");
+     }
+
+     if ((MIPS_DECODE[loop].flags & WORD32) && (GETDATASIZE() != WORD)) {
+       fprintf(stderr,"Error in opcode table: WORD32 set for non-WORD opcode\n");
+       exit(1);
+     }
+
+     /* 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 */
+       printf("  if (%s | %s)\n",((flags & fieldval('s')) ? "NOTWORDVALUE(op1)" : "0"),((flags & fieldval('g')) ? "NOTWORDVALUE(op2)" : "0"));
+       printf("   UndefinedResult();\n") ;
+       printf("  else\n") ;
+     }
+
+     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. */
+
+       case ADD:
+       case SUB :
+        {
+          char *basetype = "unknown";
+          switch (GETDATASIZE()) {
+            case WORD :
+             basetype = "int";
+             break;
+            case DOUBLEWORD :
+             basetype = "long long";
+             break;
+            default :
+             fprintf(stderr,"Opcode table error: size of 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 (!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 */
+             printf("   GPR[destreg] = SIGNEXTEND(((%s)temp),32);\n",regtype);
+          } else { /* SUB */
+            printf("   unsigned %s temp = (unsigned %s)(op1 - op2);\n",basetype,basetype);
+            printf("   signed %s tempS = (signed %s)temp;\n",basetype,basetype);
+            if (MIPS_DECODE[loop].flags & OVERFLOW) { /* different signs => overflow if result_sign != arg_sign */
+              printf("   if (((op1 < 0) != (op2 < 0)) && ((tempS < 0) == (op1 < 0)))\n");
+              printf("    SignalException(IntegerOverflow);\n");
+              printf("   else\n");
+            }
+            /* UNSIGNED 32bit operations on a 64bit processor should
+               *STILL* be sign-extended. We have cheated in the
+               data-structure, by not marking it with UNSIGNED, and not
+               setting OVERFLOW. */
+            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 */
+             printf("   GPR[destreg] = SIGNEXTEND(((%s)temp),32);\n",regtype);
+          }
+        }
+        break ;
+
+       case MUL :
+        if (features & FEATURE_WARN_LOHI) {
+          printf("   CHECKHILO(\"Multiplication\");\n");
+        }
+        printf("   {\n");
+        if (GETDATASIZE() == DOUBLEWORD) {
+          printf("   uword64 mid;\n");
+          printf("   uword64 temp;\n");
+          printf("   LO = ((op1 & 0xFFFFFFFF) * (op2 & 0xFFFFFFFF));\n");
+          printf("   HI = ((op1 >> 32) * (op2 >> 32));\n");
+          printf("   mid = ((op1 >> 32) * (op2 & 0xFFFFFFFF));\n");
+          printf("   temp = (LO + ((mid & 0xFFFFFFFF) << 32));\n");
+          printf("   if ((temp == mid) ? (LO != 0) : (temp < mid))\n");
+          printf("    HI += 1;\n");
+          printf("   HI += ((mid >> 32) & 0xFFFFFFFF);\n");
+          printf("   mid = ((op1 & 0xFFFFFFFF) * (op2 >> 32));\n");
+          printf("   LO = (temp + ((mid & 0xFFFFFFFF) << 32));\n");
+          printf("   if ((LO == mid) ? (temp != 0) : (LO < mid))\n");
+          printf("    HI += 1;\n");
+          printf("   HI += ((mid >> 32) & 0xFFFFFFFF);\n");
+        } else {
+          printf("   uword64 temp = (op1 * op2);\n");
+          printf("   LO = SIGNEXTEND((%s)(temp & 0xFFFFFFFF),32);\n",regtype);
+          printf("   HI = SIGNEXTEND((%s)((temp >> 32) & 0xFFFFFFFF),32);\n",regtype);
+        }
+        printf("   }\n");
+        break ;
+
+       case DIV :
+        {
+         int boolU = (MIPS_DECODE[loop].flags & UNSIGNED);
+
+         if (features & FEATURE_WARN_LOHI) {
+           printf("   CHECKHILO(\"Division\");\n");
+         }
+         printf("   {\n");
+         if (GETDATASIZE() == DOUBLEWORD) {
+           printf("   LO = ((%slong long)op1 / (%slong long)op2);\n",(boolU ? "unsigned " : ""),(boolU ? "unsigned " : ""));
+           printf("   HI = ((%slong long)op1 %c (%slong long)op2);\n",(boolU ? "unsigned " : ""),'%',(boolU ? "unsigned " : ""));
+         } else {
+           printf("   LO = SIGNEXTEND(((%sint)op1 / (%sint)op2),32);\n",(boolU ? "unsigned " : ""),(boolU ? "unsigned " : ""));
+           printf("   HI = SIGNEXTEND(((%sint)op1 %c (%sint)op2),32);\n",(boolU ? "unsigned " : ""),'%',(boolU ? "unsigned " : ""));
+         }
+         printf("   }\n");
+        }
+        break ;
+
+       case SHIFT :
+        {
+         int datalen = GETDATASIZE();
+         int bits = ((datalen == WORD) ? 32 : 64);
+         char *ltype = ((datalen == WORD) ? "unsigned int" : "uword64");
+
+         /* Check that the specified SHIFT is valid: */
+         if ((datalen == BYTE) || (datalen == HALFWORD)) {
+           fprintf(stderr,"Shift \"%s\" specified with BYTE or HALFWORD\n",MIPS_DECODE[loop].name);
+           exit(9);
+         }
+         if ((MIPS_DECODE[loop].flags & LEFT) && (MIPS_DECODE[loop].flags & RIGHT)) {
+           fprintf(stderr,"Shift \"%s\" specified with both LEFT and RIGHT\n",MIPS_DECODE[loop].name);
+           exit(9);
+         }
+         if (!(MIPS_DECODE[loop].flags & LEFT) && !(MIPS_DECODE[loop].flags & RIGHT)) {
+           fprintf(stderr,"Shift \"%s\" specified with neither LEFT or RIGHT\n",MIPS_DECODE[loop].name);
+           exit(9);
+         }
+         if ((MIPS_DECODE[loop].flags & LOGICAL) && (MIPS_DECODE[loop].flags & ARITHMETIC)) {
+           fprintf(stderr,"Shift \"%s\" specified with both LOGICAL and ARITHMETIC\n",MIPS_DECODE[loop].name);
+           exit(9);
+         }
+         if (!(MIPS_DECODE[loop].flags & LOGICAL) && !(MIPS_DECODE[loop].flags & ARITHMETIC)) {
+           fprintf(stderr,"Shift \"%s\" specified with neither LOGICAL or ARITHMETIC\n",MIPS_DECODE[loop].name);
+           exit(9);
+         }
+         if ((MIPS_DECODE[loop].flags & LEFT) && (MIPS_DECODE[loop].flags & ARITHMETIC)) {
+           fprintf(stderr,"Arithmetic LEFT shift \"%s\" specified\n",MIPS_DECODE[loop].name);
+           exit(9);
+         }
+
+         /* If register specified shift, then extract the relevant shift amount: */
+         if (flags & fieldval('s'))
+          printf("   op1 &= 0x%02X;\n",(bits - 1));
+
+         /* If HI32 specified, then shift range is 32..63 */
+         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) ? "<<" : ">>"));
+
+         /* For ARITHMETIC shifts, we must duplicate the sign-bit */
+         if (MIPS_DECODE[loop].flags & ARITHMETIC)
+          printf("   GPR[destreg] |= ((op2 & ((%s)1 << %d)) ? ((((%s)1 << (op1 + 1)) - 1) << (%d - op1)) : 0);\n",ltype,(bits - 1),ltype,(bits - 1));
+
+         /* Ensure WORD values are sign-extended into 64bit registers */
+         if ((bits == 32) && (gprlen == 64))
+          printf("   GPR[destreg] = SIGNEXTEND(GPR[destreg],%d);\n",bits);
+        }
+        break ;
+
+       case MOVE :
+        if (MIPS_DECODE[loop].flags & (HI | LO)) {
+          char *regname = ((MIPS_DECODE[loop].flags & LO) ? "LO" : "HI");
+          if (flags & fieldval('d'))
+           printf("   GPR[destreg] = %s;\n",regname);
+          else {
+            if (features & FEATURE_WARN_LOHI) {
+              printf("   if (%sACCESS != 0)\n",regname);
+              printf("     WARNING(\"MT (move-to) over-writing %s register value\");\n",regname);
+            }
+            printf("   %s = op1;\n",regname);
+          }
+          if (features & FEATURE_WARN_LOHI)
+           printf("   %sACCESS = 3; /* 3rd instruction will be safe */\n",regname);
+        } else
+         if (MIPS_DECODE[loop].flags & SHIFT16)
+          printf("   GPR[destreg] = (op2 << 16);\n");
+         else {
+           /* perform conditional move */
+           if (!(MIPS_DECODE[loop].flags & EQ)) {
+             fprintf(stderr,"Standard conditional %s does not have the equality flag\n",MIPS_DECODE[loop].name);
+             exit(8);
+           }
+           printf("   if (op2 %c= 0)\n",((MIPS_DECODE[loop].flags & NOT) ? '!' : '='));
+           printf("    GPR[destreg] = op1;\n");
+         }
+        break ;
+
+       case SYNC :
+        printf("   SyncOperation(op1);\n");
+        break ;
+
+       case SYSCALL :
+        printf("   SignalException(SystemCall);\n");
+        break ;
+
+       case BREAK :
+        printf("   SignalException(BreakPoint);\n");
+        break ;
+
+       case TRAP :
+        {
+         int boolNOT = (MIPS_DECODE[loop].flags & NOT);
+         int boolEQ  = (MIPS_DECODE[loop].flags & EQ);
+         int boolGT  = (MIPS_DECODE[loop].flags & GT);
+         int boolLT  = (MIPS_DECODE[loop].flags & LT);
+         int boolU   = (MIPS_DECODE[loop].flags & UNSIGNED);
+
+         if (boolGT && boolLT) {
+           fprintf(stderr,"GT and LT specified for \"%s\"\n",MIPS_DECODE[loop].name);
+           exit(8);
+         }
+
+         if (boolNOT && (boolGT || boolLT)) {
+           fprintf(stderr,"NOT specified with GT or LT specified for \"%s\"\n",MIPS_DECODE[loop].name);
+           exit(8);
+         }
+
+         printf("  if ((%slong long)op1 ",(boolU ? "unsigned " : ""));
+         printf("%c%s",(boolNOT ? '!' : (boolLT ? '<' : (boolGT ? '>' : '='))),(boolEQ ? "=" : ""));
+         printf(" (%slong long)op2)\n",(boolU ? "unsigned " : ""));
+         printf("   SignalException(Trap);\n");
+        }
+        break ;
+
+       case SET :
+        {
+         int boolU = (MIPS_DECODE[loop].flags & UNSIGNED);
+
+         if (!(MIPS_DECODE[loop].flags & LT)) {
+           fprintf(stderr,"Set instruction without LT specified \"%s\"\n",MIPS_DECODE[loop].name);
+           exit(8);
+         }
+
+         printf("   if ((%slong long)op1 < (%slong long)op2)\n",(boolU ? "unsigned " : ""),(boolU ? "unsigned " : ""));
+         printf("    GPR[destreg] = 1;\n");
+         printf("   else\n");
+         printf("    GPR[destreg] = 0;\n");
+        }
+       break ;
+
+       case AND :
+        printf("   GPR[destreg] = (op1 & op2);\n");
+       break ;
+
+       case OR :
+        printf("   GPR[destreg] = (%sop1 | op2);\n",((MIPS_DECODE[loop].flags & NOT) ? "~" : ""));
+       break ;
+
+       case XOR :
+        printf("   GPR[destreg] = (op1 ^ op2);\n");
+       break ;
+
+       case DECODE :
+        printf("   decode_coproc(instruction);\n");
+        break ;
+
+       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("    uword64 vaddr = (op1 + offset);\n");
+        printf("    uword64 paddr;\n");
+        printf("    int uncached;\n");
+        /* NOTE: We are assuming that the AddressTranslation is a load: */
+        printf("    if (AddressTranslation(vaddr,isDATA,isLOAD,&paddr,&uncached,isTARGET,isREAL))\n");
+        printf("      CacheOp(hint,vaddr,paddr,instruction);\n");
+        break;
+
+       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. */
+        if (features & FEATURE_WARN_LOHI) {
+          printf("   CHECKHILO(\"Multiply-Add\");\n");
+        }
+        if (features & FEATURE_WARN_RESULT) {
+          /* Give user a warning if either op1 or op2 are not 16bit signed integers */
+          printf("   if (NOTHALFWORDVALUE(op1) || NOTHALFWORDVALUE(op2))\n");
+          printf("     WARNING(\"MADD16 operation with non-16bit operands\");\n");
+        }
+        printf("   {\n");
+        printf("    uword64 temp = (op1 * op2);\n"); /* 16x16 multiply */
+        if (GETDATASIZE() == DOUBLEWORD) {
+          printf("   LO = LO + temp;\n");
+        } else { /* WORD */
+          printf("   temp += (((HI&0xFFFFFFFF) << 32) | (LO & 0xFFFFFFFF));\n");
+          printf("   LO = SIGNEXTEND((%s)(temp & 0xFFFFFFFF),32);\n",regtype);
+          printf("   HI = SIGNEXTEND((%s)((temp >> 32) & 0xFFFFFFFF),32);\n",regtype);
+        }
+        printf("   }\n");
+        break;
+
+       case RSVD : /* "Reserved Instruction" on MIPS IV, or if co-proc 3 absent. Otherwise "CoProcessorUnusable" */
+        if ((doisa < 4) && (doisa != 0)) {
+          printf("   if (CoProcPresent(3))\n");
+          printf("    SignalException(CoProcessorUnusable);\n");
+          printf("   else\n");
+        }
+        printf("   SignalException(ReservedInstruction,instruction);\n");
+       break ;
+
+       case JUMP :
+        if (MIPS_DECODE[loop].flags & LINK) {
+          if (!(MIPS_DECODE[loop].flags & REG))
+           printf("   int destreg = 31;\n");
+          printf("   GPR[destreg] = (PC + 4); /* NOTE: The PC is already 4 ahead within the simulator */\n");
+        }
+
+        printf("   /* NOTE: The jump occurs AFTER the next instruction has been executed */\n");
+        printf("   DSPC = op1;\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);
+        }
+        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("   if (((instruction >> %d) & 0x%08X) == 31)\n",OP_SH_RS,OP_MASK_RS);
+            printf("    WARNING(\"Branch with link using r31 as source operand\");\n");
+          }
+          printf("   GPR[31] = (PC + 4); /* NOTE: PC is already 8 ahead */\n");
+        }
+
+        printf("   /* NOTE: The branch occurs AFTER the next instruction has been executed */\n");
+        printf("   if (condition) {\n");
+        printf("    DSPC = (PC + offset);\n");
+        printf("    DELAYSLOT();\n");
+        printf("   }\n");
+        if (MIPS_DECODE[loop].flags & LIKELY) {
+          printf("   else\n");
+          printf("    NULLIFY();\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 :
+        {
+         int isload = ((MIPS_DECODE[loop].type == LOAD) || (MIPS_DECODE[loop].type == PREFETCH));
+         int datalen;
+         char *accesslength = "<UNKNOWN>";
+
+         switch (GETDATASIZE()) {
+           case BYTE :
+            datalen = 1;
+            accesslength = "AccessLength_BYTE";
+            break ;
+
+           case HALFWORD :
+            datalen = 2;
+            accesslength = "AccessLength_HALFWORD";
+            break ;
+
+           case WORD :
+            datalen = 4;
+            accesslength = "AccessLength_WORD";
+            break ;
+
+           case DOUBLEWORD :
+            datalen = 8;
+            accesslength = "AccessLength_DOUBLEWORD";
+            break ;
+         }
+
+         printf("   uword64 vaddr = ((unsigned long long)op1 + offset);\n");
+         printf("   uword64 paddr;\n");
+         printf("   int uncached;\n");
+
+         /* The following check should only occur on normal (non-shifted) memory loads */
+         if ((datalen != 1) && !(MIPS_DECODE[loop].flags & (LEFT | RIGHT))) {
+           printf("   if ((vaddr & %d) != 0)\n",(datalen - 1));
+           printf("    SignalException(%s);\n",(isload ? "AddressLoad" : "AddressStore"));
+           printf("   else\n") ;
+         }
+
+         printf("   {\n");
+         printf("    if (AddressTranslation(vaddr,isDATA,%s,&paddr,&uncached,isTARGET,isREAL))\n",(isload ? "isLOAD" : "isSTORE"));
+
+         if (MIPS_DECODE[loop].type == PREFETCH)
+          printf("     Prefetch(uncached,paddr,vaddr,isDATA,hint);\n");
+         else {
+           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 (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);
+             }
+           } 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);
+                 }
+                 /* 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));
+                   }
+
+                   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");
+                     }
+                   } 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");
+
+                if (datalen != 8) /* not for DOUBLEWORD */
+                 printf("     paddr = ((paddr & ~mask) | ((paddr & mask) ^ (reverse << shift)));\n");
+
+                printf("     memval = LoadMemory(uncached,%s,paddr,vaddr,isDATA,isREAL);\n",accesslength);
+
+                /* 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");
+                  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("     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("     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");
+              }
+
+              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
+*/
+        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) ;
+        break ;
+
+       case FPTRUNC :
+        printf("   printf(\"TODO: FPTRUNC operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+        break ;
+
+       case FPROUND :
+        printf("   printf(\"TODO: FPROUND operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+        break ;
+
+       case FPNEG :
+        printf("   printf(\"TODO: FPNEG operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+        break ;
+
+       case FPABS :
+        printf("   printf(\"TODO: FPABS operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+        break ;
+
+       case FPDIV :
+        printf("   printf(\"TODO: FPDIV operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+        break ;
+
+       case FPMUL :
+        printf("   printf(\"TODO: FPMUL operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+        break ;
+
+       case FPSUB :
+        printf("   printf(\"TODO: FPSUB operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+        break ;
+
+       case FPADD :
+        printf("   printf(\"TODO: FPADD operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+        break ;
+
+       case FPPREFX :
+        printf("   printf(\"TODO: FPPREFX operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+        break ;
+
+       case FPSTORE :
+        printf("   printf(\"TODO: FPSTORE operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+        break ;
+
+       case FPLOAD :
+        printf("   printf(\"TODO: FPLOAD operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+        break ;
+
+       case FPRECIP :
+        printf("   printf(\"TODO: FPRECIP operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+        break ;
+
+       case FPSQRT :
+        printf("   printf(\"TODO: FPSQRT operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+        break ;
+
+       case FPCONVERT :
+        printf("   printf(\"TODO: FPCONVERT operation %s\\n\");\n",MIPS_DECODE[loop].name) ;
+        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 */
+        /* 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. */
+        break ;
+
+       default :
+       fprintf(stderr,"Unrecognised opcode type %d\n",MIPS_DECODE[loop].type) ;
+        exit(6) ;
+      }
+     printf("  }\n") ;
+     printf(" }\n") ;
+     printf(" break ;\n") ;
+    }
+  }
+
+ printf("default : /* Unrecognised instruction */\n") ;
+ printf(" SignalException(ReservedInstruction,instruction);\n") ;
+ printf(" break ;\n") ;
+ printf("}\n}\n") ;
+ printf("#endif /* simulator engine */\n");
+
+ return ;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/* The command-line feature controls are presented in a similar style
+   to those offered by GCC, in the aim of providing a consistent
+   interface to the user. */
+typedef enum {
+  T_NONE,  /* no argument - mask and value fields control "feature" definition */
+  T_NUM,   /* numeric argument - optionally preceded by '=' - mask field defines maximum value */
+  T_STRING /* string argument - optionally prcededed by '=' */
+} mactypes;
+
+struct {
+  char *name;
+  mactypes type;
+  unsigned int mask;
+  unsigned int value;
+  char *desc;
+} machine_options[] = {
+  {"ips",         T_NUM,   MASK_ISA,0,"\tSelect MIPS ISA version"},
+  {"cpu",         T_STRING,0,0,"\t\tSelect particular MIPS architecture"},
+  {"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}
+};
+
+/* The following architecture identies are those accepted by the "-mcpu" option: */
+struct architectures {
+ const char *name;    /* ASCII string identifier for command-line, no white-space allowed */
+ unsigned int idflag; /* or-ed into "isa" value */
+};
+
+static const struct architectures available_architectures[] = {
+  {"4100",ARCH_VR4100}, /* NEC MIPS VR4100 */
+  {0,     0}            /* terminator */
+};
+
+/*---------------------------------------------------------------------------*/
+
+static void
+usage(name)
+     char *name;
+{
+ int loop;
+
+ fprintf(stderr,"%s: Construct a MIPS simulator engine.\n",name);
+
+ fprintf(stderr,"\
+The output of this program is a block of 'C' code designed to be\n\
+included into the main simulation control loop of a device specific\n\
+simulator.\n");
+
+ fprintf(stderr,"\nOptions:\n");
+ fprintf(stderr," -h --help\t\tProvide this help text\n");
+ fprintf(stderr," -f --fast\t\tProvide the fastest possible engine (i.e. no statistics)\n");
+ fprintf(stderr," -w --warnings\t\tEnable all the simulator engine warnings\n");
+
+ for (loop = 0; (machine_options[loop].name != 0); loop++) {
+   fprintf(stderr," -m%s",machine_options[loop].name);
+   switch (machine_options[loop].type) {
+     case T_NUM :
+       fprintf(stderr,"N (range 0..%d)",machine_options[loop].mask);
+     case T_NONE :
+       break;
+
+     case T_STRING :
+       fprintf(stderr,"=name");
+       break;
+
+     default :
+       fprintf(stderr,"%s: FATAL error: unrecognised machine option type ID %d\n",machine_options[loop].type);
+       exit(1);
+   }
+   fprintf(stderr,"%s\n",machine_options[loop].desc);
+ }
+
+ fprintf(stderr,"\nAvailable \"-mcpu\" architectures: ");
+ for (loop = 0; (available_architectures[loop].name != 0); loop++)
+   fprintf(stderr,"%s ",available_architectures[loop].name);
+ fprintf(stderr,"\n\n");
+
+ fprintf(stderr,"\
+The \"trace\" and \"warnings\" options do not define the output stream.\n\
+They only inform the code that includes the constructed engine to provide\n\
+the required features.\n\n\
+The \"-mips0\" option forces the construction of a simulator supporting\n\
+the highest available MIPS ISA supported.\n");
+
+ return;
+}
+
+/*---------------------------------------------------------------------------*/
+
+int
+main(argc,argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  char *progname = argv[0];
+  unsigned int doarch = DEF_ISA;
+  unsigned int features = 0; /* default state */
+
+  if (DEF_FP)
+   features |= FEATURE_HASFPU;
+  if (!DEF_PROC64)
+   features |= FEATURE_PROC32;
+  if (DEF_FPSINGLE)
+   features |= FEATURE_FPSINGLE;
+
+  if (features & FEATURE_PROC32)
+   features &= ~(FEATURE_FP64 | FEATURE_GP64);
+  else
+   features |= (FEATURE_FP64 | FEATURE_GP64);
+
+  while (1) {
+    int this_option_optind = (optind ? optind : 1);
+    int option_index = 0;
+    static struct option cmdline[] = {
+      {"fast",    0,0,'f'},
+      {"help",    0,0,'h'},
+      {"warnings",0,0,'w'},
+      {0,         0,0,0}
+    };
+   
+    c = getopt_long(argc,argv,"hm:tw",cmdline,&option_index);
+    if (c == -1)
+     break ; /* out of the while loop */
+
+    switch (c) {
+      case 'h' : /* help */
+       usage(progname);
+       exit(0);
+
+      case 'f' : /* fast */
+       features |= FEATURE_FAST;
+       break;
+
+      case 'w' : /* warnings */
+       features |= FEATURE_WARNINGS;
+       /* TODO: Future extension: Allow better control over the warnings generated:
+        disable warnings                -wnone                                  ~FEATURE_WARNINGS
+        all possible warnings           -wall                                   FEATURE_WARNINGS
+       pipeline stall occuring         -wstall                                 FEATURE_WARN_STALL
+       LO/HI corruption                -wlo or -whi or -wlohi or -whilo        FEATURE_WARN_HILO
+        write to zero                   -wzero                                  FEATURE_WARN_ZERO       actually performed in external code - though we should set a manifest
+        bad r31 use                     -wr31                                   FEATURE_WARN_R31
+        undefined results               -wresult                                FEATURE_WARN_RESULT
+       */
+       break;
+
+      case 'm' : /* machine options */
+       {
+         int loop;
+
+         for (loop = 0; (machine_options[loop].name != 0); loop++)
+          if (strncmp(machine_options[loop].name,optarg,strlen(machine_options[loop].name)) == 0) {
+            char *loptarg = (optarg + strlen(machine_options[loop].name));
+            switch (machine_options[loop].type) {
+              case T_NONE :
+               if (*loptarg) {
+                 fprintf(stderr,"%s: Spurious characters \"%s\" at end of -m%s option\n",progname,loptarg,machine_options[loop].name);
+                 exit(1);
+               }
+               features &= ~(machine_options[loop].mask);
+               features |= machine_options[loop].value;
+               break;
+
+              case T_NUM :
+               if (*loptarg && *loptarg == '=')
+                loptarg++;
+
+               if (strcmp(machine_options[loop].name,"ips") == 0) {
+                 unsigned int num;
+
+                 if (!*loptarg) {
+                   fprintf(stderr,"%s: ISA number expected after -mips\n",progname);
+                   exit(1);
+                 }
+
+                 num = strtoul(loptarg,&loptarg,10);
+
+                 if ((num == ULONG_MAX) && (errno = ERANGE)) {
+                   fprintf(stderr,"%s: Invalid number given to -mips option\n",progname);
+                   exit(1);
+                 }
+
+                 if (*loptarg) {
+                   fprintf(stderr,"%s: Spurious trailing characters after ISA number \"%s\"\n",progname,loptarg);
+                   exit(1);
+                 }
+
+                 if (num > MASK_ISA) {
+                   fprintf(stderr,"%s: ISA number %d outside acceptable range (0..%d)\n",progname,num,MASK_ISA);
+                   exit(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);
+                   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);
+                   features |= FEATURE_PROC32;
+                 }
+               } else {
+                 fprintf(stderr,"%s: FATAL: Unrecognised (numeric) machine option -m%s\n",progname,optarg);
+                 exit(1);
+               }
+               break;
+
+              case T_STRING :
+               if (*loptarg && *loptarg == '=')
+                loptarg++;
+
+               if (strcmp(machine_options[loop].name,"cpu") == 0) {
+                 int archloop;
+
+                 if (!*loptarg) {
+                   fprintf(stderr,"%s: Architecture identifier expected after -mcpu\n",progname);
+                   exit(1);
+                 }
+
+                 for (archloop = 0; (available_architectures[archloop].name != 0); archloop++) {
+                   if ((*loptarg == 'v') || (*loptarg == 'V'))
+                    *loptarg++;
+
+                   if (*loptarg && (*loptarg == 'r') || (*loptarg == 'R'))
+                    *loptarg++;
+
+                   if (strcmp(available_architectures[archloop].name,loptarg) == 0) {
+                     doarch |= available_architectures[archloop].idflag;
+                     break;
+                   }
+                 }
+
+                 if (available_architectures[archloop].name == 0) {
+                   fprintf(stderr,"%s: Unrecognised MIPS architecture \"%s\"\n",progname,loptarg);
+                   exit(1);
+                 }
+               } else {
+                 fprintf(stderr,"%s: FATAL: Unrecognised (string) machine option -m%s\n",progname,optarg);
+                 exit(1);
+               }
+               break;
+
+              default :
+               fprintf(stderr,"%s: FATAL error: unrecognised machine option type ID %d\n",progname,machine_options[loop].type);
+               exit(1);
+            }
+            break;
+          }
+
+         if (machine_options[loop].name == 0) {
+           fprintf(stderr,"%s: Unrecognised option: -m%s\n",progname,optarg);
+           exit(1);
+         }
+       }
+       break;
+
+      case '?' :
+       /* An error message should already have been displayed */
+       exit(1);
+
+      default :
+       fprintf(stderr,"%s: FATAL: getopt returned unrecognised code 0x%08X\n",progname,c);
+       exit(1);
+    }
+  }
+
+  if (optind < argc) {
+    fprintf(stderr,"%s: Spurios non-option arguments ",progname);
+    while (optind < argc)
+     fprintf(stderr,"\"%s\" ",argv[optind++]);
+    fprintf(stderr,"\n");
+    exit(1);
+  }
+
+  if ((features & FEATURE_FAST) && (features & FEATURE_WARNINGS))
+   fprintf(stderr,"Warning: Fast model generation selected, along with trace or warnings.\n");
+
+  process_instructions(doarch,features) ;
+  return(0) ;
+}
+
+/*---------------------------------------------------------------------------*/
+/*> EOF gencode.c <*/
diff --git a/sim/mips/support.h b/sim/mips/support.h
new file mode 100644 (file)
index 0000000..e1f0176
--- /dev/null
@@ -0,0 +1,73 @@
+/*> support.h <*/
+
+#ifndef __support_h
+#define __support_h
+
+/* For 64bit values either use the GCC "long long" feature, or have a
+   structure made from two 32bit values. We can then have macros for
+   accessing the LO and HI parts of the value. Also we can provide
+   macros for the basic operations we want to perform on 64bit values
+   (i.e. ADD64,SUB64,SHIFTLEFT64, etc.). This means we should be able
+   to host the simulator on non-GCC compilers, and 32bit only
+   architectures if desired. */
+
+/* Control via a build boolean for the moment */
+#if 1 && defined(__GNUC__)
+
+typedef long long word64;
+typedef unsigned long long uword64;
+
+#define WORD64LO(t)     (unsigned int)((t)&0xFFFFFFFF)
+#define WORD64HI(t)     (unsigned int)((t)>>32)
+
+/* Sign-extend the given value (e) as a value (b) bits long. We cannot
+   assume the HI32bits of the operand are zero, so we must perform a
+   mask to ensure we can use the simple subtraction to sign-extend. */
+#define SIGNEXTEND(e,b) (((e) & ((unsigned long long)1 << ((b) - 1))) ? (((e) & (((unsigned long long)1 << (b)) - 1)) - ((unsigned long long)1 << (b))) : (e))
+
+/* Check if a value will fit within a word (unsigned int): */
+#define NOTWORDVALUE(v) ((((((unsigned long long)(v)>>32) == 0) && !((v) & ((unsigned)1 << 31))) || ((((unsigned long long)(v)>>32) == 0xFFFFFFFF) && ((v) & ((unsigned)1 << 31)))) ? (1 == 0) : (1 == 1))
+
+/* Check if a value will fit within a halfword: */
+#define NOTHALFWORDVALUE(v) ((((((unsigned long long)(v)>>16) == 0) && !((v) & ((unsigned)1 << 15))) || (((((unsigned long long)(v)>>32) == 0xFFFFFFFF) && ((((unsigned long long)(v)>>16) & 0xFFFF) == 0xFFFF)) && ((v) & ((unsigned)1 << 15)))) ? (1 == 0) : (1 == 1))
+
+/* The following should be executed once at the start of day in the
+   main emulator control function. The simulator assumes char is
+   8bits, and from this: */
+#define CHECKSIM() {\
+                     if (sizeof(int) != (4 * sizeof(char)))\
+                      SignalException(SimulatorFault,"sizeof(int) != 4");\
+                     if (sizeof(long long) != (8 * sizeof(char)))\
+                      SignalException(SimulatorFault,"sizeof(long long) != 8");\
+                   }
+
+#else /* non-GCC build */
+
+#error "non-GCC build to be completed" /* avoid using long long */
+
+typedef struct word64 {
+ unsigned int lo;
+ unsigned int hi;
+} word64;
+
+#define WORD64LO(t)     (unsigned int)(t.lo)
+#define WORD64HI(t)     (unsigned int)(t.hi)
+
+/* TODO: Update these to manipulate the split structure values */
+#define SIGNEXTEND(e,b)         /* TODO */
+#define NOTWORDVALUE(v)         /* TODO */
+#define NOTHALFWORDVALUE(v)     /* TODO */
+
+/* The following should be executed once at the start of day in the
+   main emulator control function. The simulator assumes char is
+   8bits, and from this: */
+#define CHECKSIM() {\
+                     if (sizeof(int) != (4 * sizeof(char)))\
+                      SignalException(SimulatorFault,"sizeof(int) != 4");\a
+                   }
+
+#endif /* non-GCC build */
+
+#endif /* __support_h */
+
+/*> EOF support.h <*/