aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2024-06-19 12:51:51 +0200
committerBad Diode <bd@badd10de.dev>2024-06-19 12:51:51 +0200
commitaeca71546bb8c94d1aeae6fe3e15835a2541317d (patch)
treed3bc6a6d0b4943ded12603225f39ea333fff5c24
parent06220393b4d3e9bdd227f333650883971e37b9f9 (diff)
downloadbdl-aeca71546bb8c94d1aeae6fe3e15835a2541317d.tar.gz
bdl-aeca71546bb8c94d1aeae6fe3e15835a2541317d.zip
Implement the worlds worst register machine
-rw-r--r--src/badlib.h14
-rw-r--r--src/main.c127
2 files changed, 109 insertions, 32 deletions
diff --git a/src/badlib.h b/src/badlib.h
index 25bb92b..522e4bb 100644
--- a/src/badlib.h
+++ b/src/badlib.h
@@ -920,9 +920,12 @@ typedef struct ArrayHeader {
920#define array_cap(ARR) ((ARR) ? array_head(ARR)->cap : 0) 920#define array_cap(ARR) ((ARR) ? array_head(ARR)->cap : 0)
921 921
922// Initialize a dynamic array ARR with N elements. The initialization doesn't 922// Initialize a dynamic array ARR with N elements. The initialization doesn't
923// zero out the data, so thread carefully.. 923// zero out the data, so thread carefully. Use array_zero instead if that's what
924// you need.
924#define array_init(ARR, N, ARENA) \ 925#define array_init(ARR, N, ARENA) \
925 ((ARR) = _array_reserve(N, sizeof(*(ARR)), (ARENA))) 926 ((ARR) = _array_reserve(N, sizeof(*(ARR)), (ARENA)))
927#define array_zero(ARR, N, ARENA) \
928 ((ARR) = _array_reserve_zero(N, sizeof(*(ARR)), (ARENA)))
926 929
927// Push a given element T to the dynamic array ARR. 930// Push a given element T to the dynamic array ARR.
928#define array_push(ARR, T, ARENA) \ 931#define array_push(ARR, T, ARENA) \
@@ -953,6 +956,15 @@ _array_reserve(sz num_elem, sz type_size, Arena *a) {
953} 956}
954 957
955static inline void * 958static inline void *
959_array_reserve_zero(sz num_elem, sz type_size, Arena *a) {
960 u8 *p = arena_calloc(num_elem * type_size + sizeof(ArrayHeader), a);
961 p += sizeof(ArrayHeader);
962 array_head(p)->size = 0;
963 array_head(p)->cap = num_elem;
964 return p;
965}
966
967static inline void *
956_array_maybe_grow(void *arr, sz type_size, Arena *a) { 968_array_maybe_grow(void *arr, sz type_size, Arena *a) {
957 if (!arr) { 969 if (!arr) {
958 arr = _array_reserve(0, 0, a); 970 arr = _array_reserve(0, 0, a);
diff --git a/src/main.c b/src/main.c
index a6e1cf6..2c24eaf 100644
--- a/src/main.c
+++ b/src/main.c
@@ -22,9 +22,9 @@ init(void) {
22} 22}
23 23
24typedef struct Instruction { 24typedef struct Instruction {
25 u8 dst;
25 u8 a; 26 u8 a;
26 u8 b; 27 u8 b;
27 u8 c;
28 u8 op; 28 u8 op;
29} Instruction; 29} Instruction;
30 30
@@ -44,20 +44,29 @@ typedef struct Chunk {
44 44
45typedef enum OpCode { 45typedef enum OpCode {
46 OP_HALT, 46 OP_HALT,
47 OP_ADD_INT, 47 OP_INT_ADD,
48 OP_INT_SUB,
49 OP_INT_MUL,
50 OP_INT_DIV,
51 OP_INT_MOD,
48} OpCode; 52} OpCode;
49 53
50Str op_str[] = { 54Str op_str[] = {
51 [OP_HALT] = cstr("HALT "), 55 [OP_HALT] = cstr("HALT "), [OP_INT_ADD] = cstr("ADD "),
52 [OP_ADD_INT] = cstr("ADD "), 56 [OP_INT_SUB] = cstr("SUB "), [OP_INT_MUL] = cstr("MUL "),
57 [OP_INT_DIV] = cstr("DIV "), [OP_INT_MOD] = cstr("MOD "),
53}; 58};
54 59
55void 60void
56disassemble_instruction(Instruction instruction) { 61disassemble_instruction(Instruction instruction) {
57 switch (instruction.op) { 62 switch (instruction.op) {
58 case OP_ADD_INT: 63 case OP_INT_SUB:
59 println("%s %d %d %d", op_str[instruction.op], instruction.a, 64 case OP_INT_MUL:
60 instruction.b, instruction.c); 65 case OP_INT_DIV:
66 case OP_INT_MOD:
67 case OP_INT_ADD:
68 println("%s %d %d %d", op_str[instruction.op], instruction.dst,
69 instruction.a, instruction.b);
61 break; 70 break;
62 case OP_HALT: println("%s", op_str[instruction.op]); break; 71 case OP_HALT: println("%s", op_str[instruction.op]); break;
63 default: println("Unknown opcode %d", instruction.op); break; 72 default: println("Unknown opcode %d", instruction.op); break;
@@ -79,9 +88,10 @@ disassemble_chunk(Chunk chunk) {
79 } 88 }
80} 89}
81 90
91#define N_CONST 256
82typedef struct VM { 92typedef struct VM {
83 Chunk *chunk; 93 Chunk *chunk;
84 Constant regs[256]; 94 Constant regs[N_CONST];
85 Instruction *ip; 95 Instruction *ip;
86} VM; 96} VM;
87 97
@@ -89,8 +99,9 @@ void
89vm_init(VM *vm, Chunk *chunk) { 99vm_init(VM *vm, Chunk *chunk) {
90 assert(vm); 100 assert(vm);
91 assert(chunk); 101 assert(chunk);
102 assert(chunk->code);
92 vm->chunk = chunk; 103 vm->chunk = chunk;
93 for (sz i = 0; i < array_size(chunk->constants); i++) { 104 for (sz i = 0; i < N_CONST; i++) {
94 vm->regs[i] = chunk->constants[i]; 105 vm->regs[i] = chunk->constants[i];
95 } 106 }
96 vm->ip = vm->chunk->code; 107 vm->ip = vm->chunk->code;
@@ -98,6 +109,9 @@ vm_init(VM *vm, Chunk *chunk) {
98 109
99void 110void
100vm_run(VM *vm) { 111vm_run(VM *vm) {
112 assert(vm);
113 assert(vm->chunk);
114 assert(vm->ip);
101 println("VM running..."); 115 println("VM running...");
102 while (true) { 116 while (true) {
103 Instruction instruction = *vm->ip++; 117 Instruction instruction = *vm->ip++;
@@ -106,19 +120,79 @@ vm_run(VM *vm) {
106 disassemble_instruction(instruction); 120 disassemble_instruction(instruction);
107#endif 121#endif
108 switch (instruction.op) { 122 switch (instruction.op) {
109 case OP_ADD_INT: { 123 // TODO: Other numeric types
110 u8 dst = instruction.a; 124 case OP_INT_ADD: {
111 u8 src_a = instruction.b; 125 u8 dst = instruction.dst;
112 u8 src_b = instruction.c; 126 u8 src_a = instruction.a;
113 vm->regs[dst].u = vm->regs[src_a].u + vm->regs[src_b].u; 127 u8 src_b = instruction.b;
128 vm->regs[dst].i = vm->regs[src_a].i + vm->regs[src_b].i;
129 } break;
130 case OP_INT_SUB: {
131 u8 dst = instruction.dst;
132 u8 src_a = instruction.a;
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;
150 u8 src_a = instruction.a;
151 u8 src_b = instruction.b;
152 vm->regs[dst].i = vm->regs[src_a].i % vm->regs[src_b].i;
114 } break; 153 } break;
115 case OP_HALT: { 154 case OP_HALT: {
116 return; 155 return;
117 } 156 }
157 default: {
158 eprintln("unimplemented OP code: %d", instruction.op);
159 return;
160 }
118 } 161 }
119 } 162 }
120} 163}
121 164
165sz reg_idx = 0;
166sz compile_expr(Chunk *chunk, Node *node, Arena *a);
167
168sz
169compile_binary(OpCode op, Chunk *chunk, Node *node, Arena *a) {
170 sz reg_a = compile_expr(chunk, node->left, a);
171 sz reg_b = compile_expr(chunk, node->right, a);
172 sz reg_dst = reg_idx++;
173 Instruction inst =
174 (Instruction){.op = op, .dst = reg_dst, .a = reg_a, .b = reg_b};
175 array_push(chunk->code, inst, a);
176 return reg_dst;
177}
178
179sz
180compile_expr(Chunk *chunk, Node *node, Arena *a) {
181 switch (node->kind) {
182 case NODE_ADD: return compile_binary(OP_INT_ADD, chunk, node, a); break;
183 case NODE_SUB: return compile_binary(OP_INT_SUB, chunk, node, a); break;
184 case NODE_MUL: return compile_binary(OP_INT_MUL, chunk, node, a); break;
185 case NODE_DIV: return compile_binary(OP_INT_DIV, chunk, node, a); break;
186 case NODE_MOD: return compile_binary(OP_INT_MOD, chunk, node, a); break;
187 case NODE_NUM_INT: {
188 chunk->constants[reg_idx] = (Constant){.i = node->value.i};
189 return reg_idx++;
190 } break;
191 default: break;
192 }
193 return -1;
194}
195
122void 196void
123process_file(Str path) { 197process_file(Str path) {
124 Arena lexer_arena = arena_create(LEXER_MEM, os_allocator); 198 Arena lexer_arena = arena_create(LEXER_MEM, os_allocator);
@@ -181,30 +255,21 @@ process_file(Str path) {
181 } 255 }
182 // TODO: Semantic analysis. 256 // TODO: Semantic analysis.
183 // TODO: Type checking. 257 // TODO: Type checking.
184 // TODO: Compile roots. 258
259 // Compile roots.
260 Arena bytecode_arena = arena_create(LEXER_MEM, os_allocator);
261 Chunk chunk = {.file_name = path};
262 array_zero(chunk.constants, 256, &bytecode_arena);
263 array_zero(chunk.code, 0xffff, &bytecode_arena);
185 sz n_roots = array_size(parser.nodes); 264 sz n_roots = array_size(parser.nodes);
186 for (sz i = 0; i < n_roots; i++) { 265 for (sz i = 0; i < n_roots; i++) {
187 // The parser stores the root nodes as a stack. 266 // The parser stores the root nodes as a stack.
188 Node *root = parser.nodes[i]; 267 Node *root = parser.nodes[i];
189 // compile_expr(Node *root) 268 compile_expr(&chunk, root, &bytecode_arena);
190 (void)root;
191 } 269 }
192
193 // Run bytecode on VM.
194 Arena bytecode_arena = arena_create(LEXER_MEM, os_allocator);
195 Chunk chunk = {.file_name = path};
196 array_init(chunk.constants, 256, &bytecode_arena);
197 array_init(chunk.code, 0xffff, &bytecode_arena);
198
199 // FIXME: Some debugging instructions for now.
200 array_push(chunk.constants, (Constant){.u = 1}, &bytecode_arena);
201 array_push(chunk.constants, (Constant){.u = 2}, &bytecode_arena);
202 Instruction add = (Instruction){.op = OP_ADD_INT, .a = 2, .b = 0, .c = 1};
203 array_push(chunk.code, add, &bytecode_arena);
204 array_push(chunk.code, (Instruction){.op = OP_HALT}, &bytecode_arena); 270 array_push(chunk.code, (Instruction){.op = OP_HALT}, &bytecode_arena);
205 disassemble_chunk(chunk);
206 271
207 // Testing VM execution here. 272 // Run bytecode on VM.
208 VM vm = {0}; 273 VM vm = {0};
209 vm_init(&vm, &chunk); 274 vm_init(&vm, &chunk);
210 println("VM REGISTERS BEFORE:\n%{Mem}", 275 println("VM REGISTERS BEFORE:\n%{Mem}",