]>
Commit | Line | Data |
---|---|---|
bd3239d2 MF |
1 | #include <stdint.h> |
2 | typedef struct { | |
3 | uint32_t pc_exec, pc, r[32]; | |
4 | } engine_state; | |
5 | static uint32_t engine_getbits(uint32_t fetched, int base, int width) | |
6 | { | |
7 | return (fetched >> base) & ((((uint32_t) 0x1) << width) - 1); | |
8 | } | |
9 | static void *engine_decode(void **ijops, void **rops, uint32_t fetched) | |
10 | { | |
11 | int ijcode = engine_getbits(fetched, 26, 6); | |
12 | void *ij = ijops[ijcode], *r = rops[engine_getbits(fetched, 0, 6)]; | |
13 | if (0 == ijcode) | |
14 | return r; | |
15 | else | |
16 | return ij; | |
17 | } | |
18 | static int32_t engine_sign(uint32_t u, int width) | |
19 | { | |
20 | uint32_t msb = ((uint32_t) 0x1) << (width - 1); | |
21 | return (u ^ msb) - msb; | |
22 | } | |
23 | static void engine_monitor(uint32_t pc_done, uint32_t pc_exec, uint32_t pc, | |
24 | uint32_t inst) | |
25 | { | |
26 | int i; | |
27 | return; | |
28 | //printf("%08x:%x-%x-%x\n", inst, pc_done * 4, pc_exec * 4, pc * 4); | |
29 | } | |
30 | /* | |
31 | http://www.d.umn.edu/~gshute/mips/instruction-types.xhtml | |
32 | https://www.student.cs.uwaterloo.ca/~isg/res/mips/opcodes | |
33 | http://www.mrc.uidaho.edu/mrc/people/jff/digital/MIPSir.html | |
34 | */ | |
35 | int engine(engine_state * statep, uint32_t * memory) | |
36 | { | |
37 | int i; | |
38 | int rtn = 0; | |
39 | void *ijops[64], *rops[64]; | |
40 | register uint32_t inst asm("edx"); | |
41 | register uint32_t pc_exec asm("ebx") = statep->pc_exec; | |
42 | register uint32_t pc asm("ecx") = statep->pc; | |
43 | uint32_t *r = statep->r; | |
44 | /* */ | |
45 | #define COME(name) op_##name: { uint32_t ninst = memory[pc], pc_done = pc_exec; void *nlabel = engine_decode(ijops, rops, ninst); pc_exec = pc++ | |
46 | #define JUMP(name) engine_monitor(pc_done, pc_exec, pc, inst); r[0] = 0; inst = ninst; asm volatile ("#" #name); goto *nlabel; } while (0) | |
47 | /* */ | |
48 | #define REG_S (r[engine_getbits(inst, 21, 5)]) | |
49 | #define REG_T (r[engine_getbits(inst, 16, 5)]) | |
50 | #define REG_D (r[engine_getbits(inst, 11, 5)]) | |
51 | #define IMM_A (engine_getbits(inst, 6, 5)) | |
52 | #define IMM_I ((uint16_t) inst) | |
53 | #define IMM_SI ((int16_t) inst) | |
54 | #define IMM_J (engine_getbits(inst, 0, 26)) | |
55 | /* */ | |
56 | for (i = 0; i < 64; i++) | |
57 | ijops[i] = rops[i] = &&op_undef; | |
58 | #define OP(code,mnemonic) ijops[code] = &&op_##mnemonic | |
59 | OP(0x02, j); | |
60 | OP(0x03, jal); | |
61 | OP(0x04, beq); | |
62 | OP(0x05, bne); | |
63 | OP(0x09, addiu); | |
64 | OP(0x0c, andi); | |
65 | OP(0x0d, ori); | |
66 | OP(0x0f, lui); | |
67 | #undef OP | |
68 | #define OP(code,mnemonic) rops[code] = &&op_##mnemonic | |
69 | OP(0x00, sll); | |
70 | OP(0x02, srl); | |
71 | OP(0x08, jr); | |
72 | OP(0x0c, syscall); | |
73 | OP(0x21, addu); | |
74 | OP(0x26, xor); | |
75 | #undef OP | |
76 | inst = memory[pc_exec]; | |
77 | r[0] = 0; | |
78 | goto *engine_decode(ijops, rops, inst); | |
79 | /* interrupt */ | |
80 | COME(syscall); | |
81 | pc = pc_exec; | |
82 | pc_exec = pc_done; | |
83 | goto end; | |
84 | JUMP(syscall); | |
85 | COME(undef); | |
86 | pc = pc_exec; | |
87 | pc_exec = pc_done; | |
88 | rtn = 1; | |
89 | goto end; | |
90 | JUMP(undef); | |
91 | /* jump */ | |
92 | COME(j); | |
93 | pc = (pc_exec & 0xfc000000) | IMM_J; | |
94 | JUMP(j); | |
95 | COME(jal); | |
96 | r[31] = pc * 4; | |
97 | pc = (pc_exec & 0xfc000000) | IMM_J; | |
98 | JUMP(jal); | |
99 | COME(jr); | |
100 | pc = REG_S / 4; | |
101 | JUMP(jr); | |
102 | /* branch */ | |
103 | #define STEM_BRANCH(op,name) \ | |
104 | COME(name); { uint32_t leap = pc_exec + IMM_SI; if (REG_S op REG_T) pc = leap; } JUMP(name) | |
105 | STEM_BRANCH( ==, beq); | |
106 | STEM_BRANCH(!=, bne); | |
107 | /* register to register */ | |
108 | COME(addiu); | |
109 | REG_T = REG_S + IMM_SI; | |
110 | JUMP(addiu); | |
111 | COME(addu); | |
112 | REG_D = REG_S + REG_T; | |
113 | JUMP(addu); | |
114 | COME(andi); | |
115 | REG_T = REG_S & IMM_I; | |
116 | JUMP(andi); | |
117 | COME(lui); | |
118 | REG_T = IMM_I << 16; | |
119 | JUMP(lui); | |
120 | COME(ori); | |
121 | REG_T = REG_S | IMM_I; | |
122 | JUMP(ori); | |
123 | COME(sll); | |
124 | REG_D = REG_T << IMM_A; | |
125 | JUMP(sll); | |
126 | COME(srl); | |
127 | REG_D = REG_T >> IMM_A; | |
128 | JUMP(srl); | |
129 | COME(xor); | |
130 | REG_D = REG_S ^ REG_T; | |
131 | JUMP(xor); | |
132 | /* */ | |
133 | end: | |
134 | statep->pc_exec = pc_exec; | |
135 | statep->pc = pc; | |
136 | return rtn; | |
137 | } |