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
83 const unsigned char argcount
;
84 const unsigned char regcount
;
87 static const struct opcode_info opcodes
[] = {
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 */
167 AR_SP
, /* stack ptr */
168 AR_MAR
, /* memory address register, i.e. holding pointer for mem* funcs */
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 */
178 static const char *regnames
[AR_MAX
] = {