diff options
author | Bad Diode <bd@badd10de.dev> | 2024-06-19 15:56:21 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2024-06-19 15:56:21 +0200 |
commit | 211515623f498d952d507e4bbbf5869a26a8419c (patch) | |
tree | 02db5e81f2f73eb27360697f2c30d9b7272b0214 | |
parent | aeca71546bb8c94d1aeae6fe3e15835a2541317d (diff) | |
download | bdl-211515623f498d952d507e4bbbf5869a26a8419c.tar.gz bdl-211515623f498d952d507e4bbbf5869a26a8419c.zip |
Add a bunch of op types to the VM
-rw-r--r-- | src/main.c | 236 | ||||
-rw-r--r-- | tests/expressions.bad | 8 |
2 files changed, 192 insertions, 52 deletions
@@ -31,7 +31,7 @@ typedef struct Instruction { | |||
31 | typedef union Constant { | 31 | typedef union Constant { |
32 | s64 i; | 32 | s64 i; |
33 | u64 u; | 33 | u64 u; |
34 | double d; | 34 | double f; |
35 | ptrsize ptr; | 35 | ptrsize ptr; |
36 | } Constant; | 36 | } Constant; |
37 | 37 | ||
@@ -43,29 +43,164 @@ typedef struct Chunk { | |||
43 | } Chunk; | 43 | } Chunk; |
44 | 44 | ||
45 | typedef enum OpCode { | 45 | typedef enum OpCode { |
46 | OP_HALT, | 46 | // OP DST A B |
47 | OP_INT_ADD, | 47 | // --------------------------------------------------------------- |
48 | OP_INT_SUB, | 48 | OP_HALT, // halt |
49 | OP_INT_MUL, | 49 | OP_LD8K, // ld8k rx, ca -> u8 rx = ca |
50 | OP_INT_DIV, | 50 | OP_LD16K, // ld16k rx, ca -> u16 rx = ca |
51 | OP_INT_MOD, | 51 | OP_LD32K, // ld32k rx, ca -> u32 rx = ca |
52 | OP_LD64K, // ld64k rx, ca -> u64 rx = ca | ||
53 | OP_LD8I, // ld8i rx, ra, cb -> u8 *p; rx = p[ra + cb] | ||
54 | OP_LD16I, // ld16i rx, ra, cb -> u16 *p; rx = p[ra + cb] | ||
55 | OP_LD32I, // ld32i rx, ra, cb -> u32 *p; rx = p[ra + cb] | ||
56 | OP_LD64I, // ld64i rx, ra, cb -> u64 *p; rx = p[ra + cb] | ||
57 | OP_LD8, // ld8 rx, ra, rb -> u8 *p; rx = p[ra + rb] | ||
58 | OP_LD16, // ld16 rx, ra, rb -> u16 *p; rx = p[ra + rb] | ||
59 | OP_LD32, // ld32 rx, ra, rb -> u32 *p; rx = p[ra + rb] | ||
60 | OP_LD64, // ld64 rx, ra, rb -> u64 *p; rx = p[ra + rb] | ||
61 | OP_ST8I, // st8i rx, ra, cb -> u8 *p; p[ra + cb] = rx | ||
62 | OP_ST16I, // st16i rx, ra, cb -> u16 *p; p[ra + cb] = rx | ||
63 | OP_ST32I, // st32i rx, ra, cb -> u32 *p; p[ra + cb] = rx | ||
64 | OP_ST64I, // st64i rx, ra, cb -> u64 *p; p[ra + cb] = rx | ||
65 | OP_ST8, // st8 rx, ra, rb -> u8 *p; p[ra + rb] = rx | ||
66 | OP_ST16, // st16 rx, ra, rb -> u16 *p; p[ra + rb] = rx | ||
67 | OP_ST32, // st32 rx, ra, rb -> u32 *p; p[ra + rb] = rx | ||
68 | OP_ST64, // st64 rx, ra, rb -> u64 *p; p[ra + rb] = rx | ||
69 | OP_ADDI, // addk rx, ra, cb | ||
70 | OP_SUBI, // subk rx, ra, cb | ||
71 | OP_MULI, // mulk rx, ra, cb | ||
72 | OP_DIVI, // divk rx, ra, cb | ||
73 | OP_MODI, // modk rx, ra, cb | ||
74 | OP_ADD, // add rx, ra, rb | ||
75 | OP_SUB, // sub rx, ra, rb | ||
76 | OP_MUL, // mul rx, ra, rb | ||
77 | OP_DIV, // div rx, ra, rb | ||
78 | OP_MOD, // mod rx, ra, rb | ||
79 | OP_ADDFI, // addk rx, ra, cb | ||
80 | OP_SUBFI, // subk rx, ra, cb | ||
81 | OP_MULFI, // mulk rx, ra, cb | ||
82 | OP_DIVFI, // divk rx, ra, cb | ||
83 | OP_MODFI, // modk rx, ra, cb | ||
84 | OP_ADDF, // add rx, ra, rb | ||
85 | OP_SUBF, // sub rx, ra, rb | ||
86 | OP_MULF, // mul rx, ra, rb | ||
87 | OP_DIVF, // div rx, ra, rb | ||
88 | OP_MODF, // mod rx, ra, rb | ||
89 | OP_MOV8, // mov8 rx, ra -> rx = ra & 0xFF | ||
90 | OP_MOV16, // mov16 rx, ra -> rx = ra & 0xFFFF | ||
91 | OP_MOV32, // mov32 rx, ra -> rx = ra & 0xFFFFFFFF | ||
92 | OP_MOV64, // mov64 rx, ra -> rx = ra & 0xFFFFFFFFFFFFFFFF | ||
52 | } OpCode; | 93 | } OpCode; |
53 | 94 | ||
54 | Str op_str[] = { | 95 | Str op_str[] = { |
55 | [OP_HALT] = cstr("HALT "), [OP_INT_ADD] = cstr("ADD "), | 96 | [OP_HALT] = cstr("HALT "), |
56 | [OP_INT_SUB] = cstr("SUB "), [OP_INT_MUL] = cstr("MUL "), | 97 | // Load ops. |
57 | [OP_INT_DIV] = cstr("DIV "), [OP_INT_MOD] = cstr("MOD "), | 98 | [OP_LD8K] = cstr("LD8K "), |
99 | [OP_LD16K] = cstr("LD16K "), | ||
100 | [OP_LD32K] = cstr("LD32K "), | ||
101 | [OP_LD64K] = cstr("LD64K "), | ||
102 | [OP_LD8I] = cstr("LD8I "), | ||
103 | [OP_LD16I] = cstr("LD16I "), | ||
104 | [OP_LD32I] = cstr("LD32I "), | ||
105 | [OP_LD64I] = cstr("LD64I "), | ||
106 | [OP_LD8] = cstr("LD8 "), | ||
107 | [OP_LD16] = cstr("LD16 "), | ||
108 | [OP_LD32] = cstr("LD32 "), | ||
109 | [OP_LD64] = cstr("LD64 "), | ||
110 | // Store ops. | ||
111 | [OP_ST8I] = cstr("ST8I "), | ||
112 | [OP_ST16I] = cstr("ST16I "), | ||
113 | [OP_ST32I] = cstr("ST32I "), | ||
114 | [OP_ST64I] = cstr("ST64I "), | ||
115 | [OP_ST8] = cstr("ST8 "), | ||
116 | [OP_ST16] = cstr("ST16 "), | ||
117 | [OP_ST32] = cstr("ST32 "), | ||
118 | [OP_ST64] = cstr("ST64 "), | ||
119 | // Arithmetic. | ||
120 | [OP_ADDI] = cstr("ADDI "), | ||
121 | [OP_SUBI] = cstr("SUBI "), | ||
122 | [OP_MULI] = cstr("MULI "), | ||
123 | [OP_DIVI] = cstr("DIVI "), | ||
124 | [OP_MODI] = cstr("MODI "), | ||
125 | [OP_ADD] = cstr("ADD "), | ||
126 | [OP_SUB] = cstr("SUB "), | ||
127 | [OP_MUL] = cstr("MUL "), | ||
128 | [OP_DIV] = cstr("DIV "), | ||
129 | [OP_MOD] = cstr("MOD "), | ||
130 | [OP_ADDFI] = cstr("ADDFI "), | ||
131 | [OP_SUBFI] = cstr("SUBFI "), | ||
132 | [OP_MULFI] = cstr("MULFI "), | ||
133 | [OP_DIVFI] = cstr("DIVFI "), | ||
134 | [OP_MODFI] = cstr("MODFI "), | ||
135 | [OP_ADDF] = cstr("ADDF "), | ||
136 | [OP_SUBF] = cstr("SUBF "), | ||
137 | [OP_MULF] = cstr("MULF "), | ||
138 | [OP_DIVF] = cstr("DIVF "), | ||
139 | // Reg copy/move. | ||
140 | [OP_MODF] = cstr("MODF "), | ||
141 | [OP_MOV8] = cstr("MOV8 "), | ||
142 | [OP_MOV16] = cstr("MOV16 "), | ||
143 | [OP_MOV32] = cstr("MOV32 "), | ||
144 | [OP_MOV64] = cstr("MOV64 "), | ||
58 | }; | 145 | }; |
59 | 146 | ||
60 | void | 147 | void |
61 | disassemble_instruction(Instruction instruction) { | 148 | disassemble_instruction(Instruction instruction) { |
62 | switch (instruction.op) { | 149 | switch (instruction.op) { |
63 | case OP_INT_SUB: | 150 | case OP_MOV8: |
64 | case OP_INT_MUL: | 151 | case OP_MOV16: |
65 | case OP_INT_DIV: | 152 | case OP_MOV32: |
66 | case OP_INT_MOD: | 153 | case OP_MOV64: |
67 | case OP_INT_ADD: | 154 | println("%s r%d, r%d", op_str[instruction.op], instruction.dst, |
68 | println("%s %d %d %d", op_str[instruction.op], instruction.dst, | 155 | instruction.a, instruction.b); |
156 | break; | ||
157 | case OP_LD8K: | ||
158 | case OP_LD16K: | ||
159 | case OP_LD32K: | ||
160 | case OP_LD64K: | ||
161 | println("%s r%d, c%d", op_str[instruction.op], instruction.dst, | ||
162 | instruction.a, instruction.b); | ||
163 | break; | ||
164 | case OP_LD8I: | ||
165 | case OP_LD16I: | ||
166 | case OP_LD32I: | ||
167 | case OP_LD64I: | ||
168 | case OP_ST8I: | ||
169 | case OP_ST16I: | ||
170 | case OP_ST32I: | ||
171 | case OP_ST64I: | ||
172 | case OP_ADDI: | ||
173 | case OP_SUBI: | ||
174 | case OP_MULI: | ||
175 | case OP_DIVI: | ||
176 | case OP_MODI: | ||
177 | case OP_ADDFI: | ||
178 | case OP_SUBFI: | ||
179 | case OP_MULFI: | ||
180 | case OP_DIVFI: | ||
181 | case OP_MODFI: | ||
182 | println("%s r%d, r%d, c%d", op_str[instruction.op], instruction.dst, | ||
183 | instruction.a, instruction.b); | ||
184 | break; | ||
185 | case OP_LD8: | ||
186 | case OP_LD16: | ||
187 | case OP_LD32: | ||
188 | case OP_LD64: | ||
189 | case OP_ST8: | ||
190 | case OP_ST16: | ||
191 | case OP_ST32: | ||
192 | case OP_ST64: | ||
193 | case OP_ADD: | ||
194 | case OP_SUB: | ||
195 | case OP_MUL: | ||
196 | case OP_DIV: | ||
197 | case OP_MOD: | ||
198 | case OP_ADDF: | ||
199 | case OP_SUBF: | ||
200 | case OP_MULF: | ||
201 | case OP_DIVF: | ||
202 | case OP_MODF: | ||
203 | println("%s r%d, r%d, r%d", op_str[instruction.op], instruction.dst, | ||
69 | instruction.a, instruction.b); | 204 | instruction.a, instruction.b); |
70 | break; | 205 | break; |
71 | case OP_HALT: println("%s", op_str[instruction.op]); break; | 206 | case OP_HALT: println("%s", op_str[instruction.op]); break; |
@@ -107,6 +242,25 @@ vm_init(VM *vm, Chunk *chunk) { | |||
107 | vm->ip = vm->chunk->code; | 242 | vm->ip = vm->chunk->code; |
108 | } | 243 | } |
109 | 244 | ||
245 | #define OP_ARITHMETIC(OP, TYPE) \ | ||
246 | do { \ | ||
247 | u8 dst = instruction.dst; \ | ||
248 | u8 src_a = instruction.a; \ | ||
249 | u8 src_b = instruction.b; \ | ||
250 | vm->regs[dst].TYPE = vm->regs[src_a].TYPE OP vm->regs[src_b].TYPE; \ | ||
251 | } while (0); | ||
252 | |||
253 | #define OP_ARITHMETIC_CONST(OP, TYPE) \ | ||
254 | do { \ | ||
255 | u8 dst = instruction.dst; \ | ||
256 | u8 src_a = instruction.a; \ | ||
257 | u8 src_b = instruction.b; \ | ||
258 | vm->regs[dst].TYPE = \ | ||
259 | vm->regs[src_a].TYPE OP vm->chunk->constants[src_b].TYPE; \ | ||
260 | } while (0); | ||
261 | |||
262 | #include <math.h> | ||
263 | |||
110 | void | 264 | void |
111 | vm_run(VM *vm) { | 265 | vm_run(VM *vm) { |
112 | assert(vm); | 266 | assert(vm); |
@@ -119,37 +273,23 @@ vm_run(VM *vm) { | |||
119 | print("IP: %d -> ", vm->ip - vm->chunk->code - 1); | 273 | print("IP: %d -> ", vm->ip - vm->chunk->code - 1); |
120 | disassemble_instruction(instruction); | 274 | disassemble_instruction(instruction); |
121 | #endif | 275 | #endif |
276 | |||
122 | switch (instruction.op) { | 277 | switch (instruction.op) { |
123 | // TODO: Other numeric types | 278 | case OP_ADD: OP_ARITHMETIC(+, i) break; |
124 | case OP_INT_ADD: { | 279 | case OP_SUB: OP_ARITHMETIC(-, i) break; |
125 | u8 dst = instruction.dst; | 280 | case OP_MUL: OP_ARITHMETIC(*, i) break; |
126 | u8 src_a = instruction.a; | 281 | case OP_DIV: OP_ARITHMETIC(/, i) break; |
127 | u8 src_b = instruction.b; | 282 | case OP_MOD: OP_ARITHMETIC(%, i) break; |
128 | vm->regs[dst].i = vm->regs[src_a].i + vm->regs[src_b].i; | 283 | case OP_ADDF: OP_ARITHMETIC(+, f) break; |
129 | } break; | 284 | case OP_SUBF: OP_ARITHMETIC(-, f) break; |
130 | case OP_INT_SUB: { | 285 | case OP_MULF: OP_ARITHMETIC(*, f) break; |
131 | u8 dst = instruction.dst; | 286 | case OP_DIVF: OP_ARITHMETIC(/, f) break; |
132 | u8 src_a = instruction.a; | 287 | case OP_MODF: { |
133 | u8 src_b = instruction.b; | ||
134 | vm->regs[dst].i = vm->regs[src_a].i - vm->regs[src_b].i; | ||
135 | } break; | ||
136 | case OP_INT_MUL: { | ||
137 | u8 dst = instruction.dst; | ||
138 | u8 src_a = instruction.a; | ||
139 | u8 src_b = instruction.b; | ||
140 | vm->regs[dst].i = vm->regs[src_a].i * vm->regs[src_b].i; | ||
141 | } break; | ||
142 | case OP_INT_DIV: { | ||
143 | u8 dst = instruction.dst; | ||
144 | u8 src_a = instruction.a; | ||
145 | u8 src_b = instruction.b; | ||
146 | vm->regs[dst].i = vm->regs[src_a].i / vm->regs[src_b].i; | ||
147 | } break; | ||
148 | case OP_INT_MOD: { | ||
149 | u8 dst = instruction.dst; | 288 | u8 dst = instruction.dst; |
150 | u8 src_a = instruction.a; | 289 | u8 src_a = instruction.a; |
151 | u8 src_b = instruction.b; | 290 | u8 src_b = instruction.b; |
152 | vm->regs[dst].i = vm->regs[src_a].i % vm->regs[src_b].i; | 291 | vm->regs[dst].f = |
292 | fmod(vm->regs[src_a].f, vm->chunk->constants[src_b].f); | ||
153 | } break; | 293 | } break; |
154 | case OP_HALT: { | 294 | case OP_HALT: { |
155 | return; | 295 | return; |
@@ -179,11 +319,11 @@ compile_binary(OpCode op, Chunk *chunk, Node *node, Arena *a) { | |||
179 | sz | 319 | sz |
180 | compile_expr(Chunk *chunk, Node *node, Arena *a) { | 320 | compile_expr(Chunk *chunk, Node *node, Arena *a) { |
181 | switch (node->kind) { | 321 | switch (node->kind) { |
182 | case NODE_ADD: return compile_binary(OP_INT_ADD, chunk, node, a); break; | 322 | case NODE_ADD: return compile_binary(OP_ADD, chunk, node, a); break; |
183 | case NODE_SUB: return compile_binary(OP_INT_SUB, chunk, node, a); break; | 323 | case NODE_SUB: return compile_binary(OP_SUB, chunk, node, a); break; |
184 | case NODE_MUL: return compile_binary(OP_INT_MUL, chunk, node, a); break; | 324 | case NODE_MUL: return compile_binary(OP_MUL, chunk, node, a); break; |
185 | case NODE_DIV: return compile_binary(OP_INT_DIV, chunk, node, a); break; | 325 | case NODE_DIV: return compile_binary(OP_DIV, chunk, node, a); break; |
186 | case NODE_MOD: return compile_binary(OP_INT_MOD, chunk, node, a); break; | 326 | case NODE_MOD: return compile_binary(OP_MOD, chunk, node, a); break; |
187 | case NODE_NUM_INT: { | 327 | case NODE_NUM_INT: { |
188 | chunk->constants[reg_idx] = (Constant){.i = node->value.i}; | 328 | chunk->constants[reg_idx] = (Constant){.i = node->value.i}; |
189 | return reg_idx++; | 329 | return reg_idx++; |
diff --git a/tests/expressions.bad b/tests/expressions.bad index 5b114d1..0213694 100644 --- a/tests/expressions.bad +++ b/tests/expressions.bad | |||
@@ -1,9 +1,9 @@ | |||
1 | 1 + -2 | 1 | 1 + -2 |
2 | 2 | ||
3 | 1 + 2 * 3 | 3 | ; 1 + 2 * 3 |
4 | 4 | ||
5 | 1 + 2 * 3 - 4 | 5 | ; 1 + 2 * 3 - 4 |
6 | 6 | ||
7 | 1 + 2 * (3 - 4) | 7 | ; 1 + 2 * (3 - 4) |
8 | 8 | ||
9 | 1.0 - 1234.56e-3 | 9 | ; 1.0 - 1234.56e-3 |