+#include <stdint.h>
+typedef struct {
+ uint32_t pc_exec, pc, r[32];
+} engine_state;
+static uint32_t engine_getbits(uint32_t fetched, int base, int width)
+{
+ return (fetched >> base) & ((((uint32_t) 0x1) << width) - 1);
+}
+static void *engine_decode(void **ijops, void **rops, uint32_t fetched)
+{
+ int ijcode = engine_getbits(fetched, 26, 6);
+ void *ij = ijops[ijcode], *r = rops[engine_getbits(fetched, 0, 6)];
+ if (0 == ijcode)
+ return r;
+ else
+ return ij;
+}
+static int32_t engine_sign(uint32_t u, int width)
+{
+ uint32_t msb = ((uint32_t) 0x1) << (width - 1);
+ return (u ^ msb) - msb;
+}
+static void engine_monitor(uint32_t pc_done, uint32_t pc_exec, uint32_t pc,
+ uint32_t inst)
+{
+ int i;
+ return;
+ //printf("%08x:%x-%x-%x\n", inst, pc_done * 4, pc_exec * 4, pc * 4);
+}
+/*
+http://www.d.umn.edu/~gshute/mips/instruction-types.xhtml
+https://www.student.cs.uwaterloo.ca/~isg/res/mips/opcodes
+http://www.mrc.uidaho.edu/mrc/people/jff/digital/MIPSir.html
+*/
+int engine(engine_state * statep, uint32_t * memory)
+{
+ int i;
+ int rtn = 0;
+ void *ijops[64], *rops[64];
+ register uint32_t inst asm("edx");
+ register uint32_t pc_exec asm("ebx") = statep->pc_exec;
+ register uint32_t pc asm("ecx") = statep->pc;
+ uint32_t *r = statep->r;
+/* */
+#define COME(name) op_##name: { uint32_t ninst = memory[pc], pc_done = pc_exec; void *nlabel = engine_decode(ijops, rops, ninst); pc_exec = pc++
+#define JUMP(name) engine_monitor(pc_done, pc_exec, pc, inst); r[0] = 0; inst = ninst; asm volatile ("#" #name); goto *nlabel; } while (0)
+/* */
+#define REG_S (r[engine_getbits(inst, 21, 5)])
+#define REG_T (r[engine_getbits(inst, 16, 5)])
+#define REG_D (r[engine_getbits(inst, 11, 5)])
+#define IMM_A (engine_getbits(inst, 6, 5))
+#define IMM_I ((uint16_t) inst)
+#define IMM_SI ((int16_t) inst)
+#define IMM_J (engine_getbits(inst, 0, 26))
+/* */
+ for (i = 0; i < 64; i++)
+ ijops[i] = rops[i] = &&op_undef;
+#define OP(code,mnemonic) ijops[code] = &&op_##mnemonic
+ OP(0x02, j);
+ OP(0x03, jal);
+ OP(0x04, beq);
+ OP(0x05, bne);
+ OP(0x09, addiu);
+ OP(0x0c, andi);
+ OP(0x0d, ori);
+ OP(0x0f, lui);
+#undef OP
+#define OP(code,mnemonic) rops[code] = &&op_##mnemonic
+ OP(0x00, sll);
+ OP(0x02, srl);
+ OP(0x08, jr);
+ OP(0x0c, syscall);
+ OP(0x21, addu);
+ OP(0x26, xor);
+#undef OP
+ inst = memory[pc_exec];
+ r[0] = 0;
+ goto *engine_decode(ijops, rops, inst);
+/* interrupt */
+ COME(syscall);
+ pc = pc_exec;
+ pc_exec = pc_done;
+ goto end;
+ JUMP(syscall);
+ COME(undef);
+ pc = pc_exec;
+ pc_exec = pc_done;
+ rtn = 1;
+ goto end;
+ JUMP(undef);
+/* jump */
+ COME(j);
+ pc = (pc_exec & 0xfc000000) | IMM_J;
+ JUMP(j);
+ COME(jal);
+ r[31] = pc * 4;
+ pc = (pc_exec & 0xfc000000) | IMM_J;
+ JUMP(jal);
+ COME(jr);
+ pc = REG_S / 4;
+ JUMP(jr);
+/* branch */
+#define STEM_BRANCH(op,name) \
+COME(name); { uint32_t leap = pc_exec + IMM_SI; if (REG_S op REG_T) pc = leap; } JUMP(name)
+ STEM_BRANCH( ==, beq);
+ STEM_BRANCH(!=, bne);
+/* register to register */
+ COME(addiu);
+ REG_T = REG_S + IMM_SI;
+ JUMP(addiu);
+ COME(addu);
+ REG_D = REG_S + REG_T;
+ JUMP(addu);
+ COME(andi);
+ REG_T = REG_S & IMM_I;
+ JUMP(andi);
+ COME(lui);
+ REG_T = IMM_I << 16;
+ JUMP(lui);
+ COME(ori);
+ REG_T = REG_S | IMM_I;
+ JUMP(ori);
+ COME(sll);
+ REG_D = REG_T << IMM_A;
+ JUMP(sll);
+ COME(srl);
+ REG_D = REG_T >> IMM_A;
+ JUMP(srl);
+ COME(xor);
+ REG_D = REG_S ^ REG_T;
+ JUMP(xor);
+/* */
+ end:
+ statep->pc_exec = pc_exec;
+ statep->pc = pc;
+ return rtn;
+}