agssim: move register declaration to top
[rofl0r-agsutils.git] / ags_cpu.h
blob20ae3f22cdb7a2772b4091e926541bcd49810994
1 #ifndef AGSCPU_H
2 #define AGSCPU_H
4 // virtual CPU commands
5 #define SCMD_ADD 1 // reg1 += arg2
6 #define SCMD_SUB 2 // reg1 -= arg2
7 #define SCMD_REGTOREG 3 // reg2 = reg1
8 #define SCMD_WRITELIT 4 // m[MAR] = arg2 (copy arg1 bytes)
9 #define SCMD_RET 5 // return from subroutine
10 #define SCMD_LITTOREG 6 // set reg1 to literal value arg2
11 #define SCMD_MEMREAD 7 // reg1 = m[MAR]
12 #define SCMD_MEMWRITE 8 // m[MAR] = reg1
13 #define SCMD_MULREG 9 // reg1 *= reg2
14 #define SCMD_DIVREG 10 // reg1 /= reg2
15 #define SCMD_ADDREG 11 // reg1 += reg2
16 #define SCMD_SUBREG 12 // reg1 -= reg2
17 #define SCMD_BITAND 13 // bitwise reg1 & reg2
18 #define SCMD_BITOR 14 // bitwise reg1 | reg2
19 #define SCMD_ISEQUAL 15 // reg1 == reg2 reg1=1 if true, =0 if not
20 #define SCMD_NOTEQUAL 16 // reg1 != reg2
21 #define SCMD_GREATER 17 // reg1 > reg2
22 #define SCMD_LESSTHAN 18 // reg1 < reg2
23 #define SCMD_GTE 19 // reg1 >= reg2
24 #define SCMD_LTE 20 // reg1 <= reg2
25 #define SCMD_AND 21 // (reg1!=0) && (reg2!=0) -> reg1
26 #define SCMD_OR 22 // (reg1!=0) || (reg2!=0) -> reg1
27 #define SCMD_CALL 23 // jump to subroutine at reg1
28 #define SCMD_MEMREADB 24 // reg1 = m[MAR] (1 byte)
29 #define SCMD_MEMREADW 25 // reg1 = m[MAR] (2 bytes)
30 #define SCMD_MEMWRITEB 26 // m[MAR] = reg1 (1 byte)
31 #define SCMD_MEMWRITEW 27 // m[MAR] = reg1 (2 bytes)
32 #define SCMD_JZ 28 // jump if ax==0 to arg1
33 #define SCMD_PUSHREG 29 // m[sp]=reg1; sp++
34 #define SCMD_POPREG 30 // sp--; reg1=m[sp]
35 #define SCMD_JMP 31 // jump to arg1
36 #define SCMD_MUL 32 // reg1 *= arg2
37 #define SCMD_CALLEXT 33 // call external (imported) function reg1
38 #define SCMD_PUSHREAL 34 // push reg1 onto real stack
39 #define SCMD_SUBREALSTACK 35
40 #define SCMD_LINENUM 36 // debug info - source code line number
41 #define SCMD_CALLAS 37 // call external script function. this instruction is never emitted to bytecodes in files. it's only used via "live-patching" to change CALLEXT insns if the script to call is in a different instance.
42 #define SCMD_THISBASE 38 // current relative address
43 #define SCMD_NUMFUNCARGS 39 // number of arguments for ext func call
44 #define SCMD_MODREG 40 // reg1 %= reg2
45 #define SCMD_XORREG 41 // reg1 ^= reg2
46 #define SCMD_NOTREG 42 // reg1 = !reg1
47 #define SCMD_SHIFTLEFT 43 // reg1 = reg1 << reg2
48 #define SCMD_SHIFTRIGHT 44 // reg1 = reg1 >> reg2
49 #define SCMD_CALLOBJ 45 // op = reg1 (set "this" argument for next function call)
50 #define SCMD_CHECKBOUNDS 46 // check reg1 is between 0 and arg2
51 #define SCMD_MEMWRITEPTR 47 // m[MAR] = reg1 (adjust ptr addr)
52 #define SCMD_MEMREADPTR 48 // reg1 = m[MAR] (adjust ptr addr)
53 #define SCMD_MEMZEROPTR 49 // m[MAR] = 0 (blank ptr)
54 #define SCMD_MEMINITPTR 50 // m[MAR] = reg1 (like memwrite4, but doesn't remove reference/free the old pointer)
55 #define SCMD_LOADSPOFFS 51 // MAR = SP - arg1 (optimization for local var access)
56 #define SCMD_CHECKNULL 52 // error if MAR==0
57 #define SCMD_FADD 53 // reg1 += arg2 (float,int)
58 #define SCMD_FSUB 54 // reg1 -= arg2 (float,int)
59 #define SCMD_FMULREG 55 // reg1 *= reg2 (float)
60 #define SCMD_FDIVREG 56 // reg1 /= reg2 (float)
61 #define SCMD_FADDREG 57 // reg1 += reg2 (float)
62 #define SCMD_FSUBREG 58 // reg1 -= reg2 (float)
63 #define SCMD_FGREATER 59 // reg1 > reg2 (float)
64 #define SCMD_FLESSTHAN 60 // reg1 < reg2 (float)
65 #define SCMD_FGTE 61 // reg1 >= reg2 (float)
66 #define SCMD_FLTE 62 // reg1 <= reg2 (float)
67 #define SCMD_ZEROMEMORY 63 // m[MAR]..m[MAR+(arg1-1)] = 0
68 #define SCMD_CREATESTRING 64 // reg1 = new String(reg1)
69 #define SCMD_STRINGSEQUAL 65 // (char*)reg1 == (char*)reg2 reg1=1 if true, =0 if not
70 #define SCMD_STRINGSNOTEQ 66 // (char*)reg1 != (char*)reg2
71 #define SCMD_CHECKNULLREG 67 // error if reg1 == NULL
72 #define SCMD_LOOPCHECKOFF 68 // no loop checking for this function
73 #define SCMD_MEMZEROPTRND 69 // m[MAR] = 0 (blank ptr, no dispose if = ax)
74 #define SCMD_JNZ 70 // jump to arg1 if ax!=0
75 #define SCMD_DYNAMICBOUNDS 71 // check reg1 is between 0 and m[MAR-4]
76 #define SCMD_NEWARRAY 72 // reg1 = new array of reg1 elements, each of size arg2 (arg3=managed type?)
77 #define SCMD_NEWUSEROBJECT 73 // reg1 = new user object of arg1 size
79 #define SCMD_MAX 74
81 struct opcode_info {
82 const char* mnemonic;
83 const unsigned char argcount;
84 const unsigned char regcount;
87 static const struct opcode_info opcodes[] = {
88 [0] = {"NULL", 0, 0},
89 [SCMD_ADD] = {"addi", 2, 1},
90 [SCMD_SUB] = {"subi", 2, 1},
91 [SCMD_REGTOREG] = {"mr", 2, 2},
92 [SCMD_WRITELIT] = {"memcpy", 2, 0},
93 [SCMD_RET] = {"ret", 0, 0},
94 [SCMD_LITTOREG] = {"li", 2, 1},
95 [SCMD_MEMREAD] = {"memread4", 1, 1},
96 [SCMD_MEMWRITE] = {"memwrite4", 1, 1},
97 [SCMD_MULREG] = {"mul", 2, 2},
98 [SCMD_DIVREG] = {"div", 2, 2},
99 [SCMD_ADDREG] = {"add", 2, 2},
100 [SCMD_SUBREG] = {"sub", 2, 2},
101 [SCMD_BITAND] = {"and", 2, 2},
102 [SCMD_BITOR] = {"or", 2, 2},
103 [SCMD_ISEQUAL] = {"cmpeq", 2, 2},
104 [SCMD_NOTEQUAL] = {"cmpne", 2, 2},
105 [SCMD_GREATER] = {"gt", 2, 2},
106 [SCMD_LESSTHAN] = {"lt", 2, 2},
107 [SCMD_GTE] = {"gte", 2, 2},
108 [SCMD_LTE] = {"lte", 2, 2},
109 [SCMD_AND] = {"land", 2, 2}, /*logical*/
110 [SCMD_OR] = {"lor", 2, 2},
111 [SCMD_CALL] = {"call", 1, 1},
112 [SCMD_MEMREADB] = {"memread1", 1, 1},
113 [SCMD_MEMREADW] = {"memread2", 1, 1},
114 [SCMD_MEMWRITEB] = {"memwrite1", 1, 1},
115 [SCMD_MEMWRITEW] = {"memwrite2", 1, 1},
116 [SCMD_JZ] = {"jzi", 1, 0},
117 [SCMD_PUSHREG] = {"push", 1, 1},
118 [SCMD_POPREG] = {"pop", 1, 1},
119 [SCMD_JMP] = {"jmpi", 1, 0},
120 [SCMD_MUL] = {"muli", 2, 1},
121 [SCMD_CALLEXT] = {"farcall", 1, 1},
122 [SCMD_PUSHREAL] = {"farpush", 1, 1},
123 [SCMD_SUBREALSTACK] = {"farsubsp", 1, 0},
124 [SCMD_LINENUM] = {"sourceline", 1, 0},
125 [SCMD_CALLAS] = {"callscr", 1, 1},
126 [SCMD_THISBASE] = {"thisaddr", 1, 0},
127 [SCMD_NUMFUNCARGS] = {"setfuncargs", 1, 0},
128 [SCMD_MODREG] = {"mod", 2, 2},
129 [SCMD_XORREG] = {"xor", 2, 2},
130 [SCMD_NOTREG] = {"not", 1, 1},
131 [SCMD_SHIFTLEFT] = {"shl", 2, 2},
132 [SCMD_SHIFTRIGHT] = {"shr", 2, 2},
133 [SCMD_CALLOBJ] = {"callobj", 1, 1},
134 [SCMD_CHECKBOUNDS] = {"assertlte", 2, 1},
135 [SCMD_MEMWRITEPTR] = {"ptrset", 1, 1},
136 [SCMD_MEMREADPTR] = {"ptrget", 1, 1},
137 [SCMD_MEMZEROPTR] = {"ptrzero", 0, 0},
138 [SCMD_MEMINITPTR] = {"ptrinit", 1, 1},
139 [SCMD_LOADSPOFFS] = {"ptrstack", 1, 0},
140 [SCMD_CHECKNULL] = {"ptrassert", 0, 0},
141 [SCMD_FADD] = {"faddi", 2, 1},
142 [SCMD_FSUB] = {"fsubi", 2, 1},
143 [SCMD_FMULREG] = {"fmul", 2, 2},
144 [SCMD_FDIVREG] = {"fdiv", 2, 2},
145 [SCMD_FADDREG] = {"fadd", 2, 2},
146 [SCMD_FSUBREG] = {"fsub", 2, 2},
147 [SCMD_FGREATER] = {"fgt", 2, 2},
148 [SCMD_FLESSTHAN] = {"flt", 2, 2},
149 [SCMD_FGTE] = {"fgte", 2, 2},
150 [SCMD_FLTE] = {"flte", 2, 2},
151 [SCMD_ZEROMEMORY] = {"zeromem", 1, 0},
152 [SCMD_CREATESTRING] = {"newstr", 1, 1},
153 [SCMD_STRINGSEQUAL] = {"streq", 2, 2},
154 [SCMD_STRINGSNOTEQ] = {"strne", 2, 2},
155 [SCMD_CHECKNULLREG] = {"assert", 1, 1},
156 [SCMD_LOOPCHECKOFF] = {"loopcheckoff", 0, 0},
157 [SCMD_MEMZEROPTRND] = {"ptrzerond", 0, 0},
158 [SCMD_JNZ] = {"jnzi", 1, 0},
159 [SCMD_DYNAMICBOUNDS] = {"dynamicbounds", 1, 1},
160 [SCMD_NEWARRAY] = {"newarr", 3, 1},
161 [SCMD_NEWUSEROBJECT] = {"newuserobject", 2, 1},
164 /* these are called e.g. SREG_OP in upstream */
165 enum ags_reg {
166 AR_NULL = 0,
167 AR_SP, /* stack ptr */
168 AR_MAR, /* memory address register, i.e. holding pointer for mem* funcs */
169 AR_AX, /* 4 GPRs */
170 AR_BX,
171 AR_CX,
172 AR_OP, /* object pointer for member func calls, i.e. "this".
173 ags engine only sets it via SCMD_CALLOBJ, otherwise, it is only ever pushed/popped */
174 AR_DX,
175 AR_MAX
178 static const char *regnames[AR_MAX] = {
179 [AR_NULL] = "null",
180 [AR_SP] = "sp",
181 [AR_MAR] = "mar",
182 [AR_AX] = "ax",
183 [AR_BX] = "bx",
184 [AR_CX] = "cx",
185 [AR_OP] = "op",
186 [AR_DX] = "dx",
190 #endif