From 4eee6e1a0a17465756f1b4156727c55bc17214f1 Mon Sep 17 00:00:00 2001 From: Aryadev Chavali Date: Thu, 2 Nov 2023 23:25:33 +0000 Subject: Implemented subroutine instructions in runtime Very easy overall, printing the call stack not so much. --- vm/main.c | 18 +++++++++----- vm/runtime.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- vm/runtime.h | 13 ++++++++-- 3 files changed, 94 insertions(+), 17 deletions(-) (limited to 'vm') diff --git a/vm/main.c b/vm/main.c index cb2c3fb..929de89 100644 --- a/vm/main.c +++ b/vm/main.c @@ -37,8 +37,7 @@ int main(int argc, char *argv[]) const char *filename = argv[1]; #if VERBOSE >= 1 - printf("[%sINTERPRETER%s]: Interpreting `%s`\n", TERM_YELLOW, TERM_RESET, - filename); + printf("[" TERM_YELLOW "INTERPRETER" TERM_RESET "]: `%s`\n", filename); #endif FILE *fp = fopen(filename, "rb"); @@ -47,8 +46,8 @@ int main(int argc, char *argv[]) fclose(fp); #if VERBOSE >= 1 - printf("\t[%sBYTECODE-READER%s]: Read %lu instructions\n", TERM_GREEN, - TERM_RESET, number); + printf("\t[" TERM_GREEN "SETUP" TERM_RESET "]: Read %lu instructions\n", + number); #endif size_t stack_size = 256; @@ -57,16 +56,22 @@ int main(int argc, char *argv[]) darr_init(®isters, 8 * WORD_SIZE); heap_t heap = {0}; heap_create(&heap); + size_t call_stack_size = 256; + word *call_stack = calloc(call_stack_size, sizeof(call_stack)); vm_t vm = {0}; vm_load_stack(&vm, stack, stack_size); vm_load_program(&vm, instructions, number); vm_load_registers(&vm, registers); vm_load_heap(&vm, heap); + vm_load_call_stack(&vm, call_stack, call_stack_size); #if VERBOSE >= 1 - printf("\t[%sVM-SETUP%s]: Loaded stack and program into VM\n", TERM_GREEN, - TERM_RESET); + printf("\t[" TERM_GREEN "SETUP" TERM_RESET + "]: Loaded stack and program into VM\n"); +#endif +#if VERBOSE >= 1 + printf("[" TERM_YELLOW "INTERPRETER" TERM_RESET "]: Beginning execution\n"); #endif err_t err = vm_execute_all(&vm); @@ -78,6 +83,7 @@ int main(int argc, char *argv[]) vm_print_all(&vm, stderr); ret = 255 - err; } + vm_stop(&vm); #if VERBOSE >= 1 diff --git a/vm/runtime.c b/vm/runtime.c index c927662..996eb58 100644 --- a/vm/runtime.c +++ b/vm/runtime.c @@ -25,25 +25,22 @@ const char *err_as_cstr(err_t err) { case ERR_OK: return "OK"; - break; case ERR_STACK_UNDERFLOW: return "STACK_UNDERFLOW"; - break; case ERR_STACK_OVERFLOW: return "STACK_OVERFLOW"; - break; + case ERR_CALL_STACK_UNDERFLOW: + return "CALL_STACK_UNDERFLOW"; + case ERR_CALL_STACK_OVERFLOW: + return "CALL_STACK_OVERFLOW"; case ERR_INVALID_OPCODE: return "INVALID_OPCODE"; - break; case ERR_INVALID_REGISTER_BYTE: return "INVALID_REGISTER_BYTE"; - break; case ERR_INVALID_REGISTER_HWORD: return "INVALID_REGISTER_HWORD"; - break; case ERR_INVALID_REGISTER_WORD: return "INVALID_REGISTER_WORD"; - break; case ERR_INVALID_PROGRAM_ADDRESS: return "INVALID_PROGRAM_ADDRESS"; case ERR_INVALID_PAGE_ADDRESS: @@ -52,7 +49,6 @@ const char *err_as_cstr(err_t err) return "OUT_OF_BOUNDS"; case ERR_END_OF_PROGRAM: return "END_OF_PROGRAM"; - break; default: return ""; } @@ -60,7 +56,7 @@ const char *err_as_cstr(err_t err) err_t vm_execute(vm_t *vm) { - static_assert(NUMBER_OF_OPCODES == 95, "vm_execute: Out of date"); + static_assert(NUMBER_OF_OPCODES == 98, "vm_execute: Out of date"); struct Program *prog = &vm->program; if (prog->ptr >= prog->max) return ERR_END_OF_PROGRAM; @@ -153,6 +149,30 @@ err_t vm_execute(vm_t *vm) else ++prog->ptr; } + else if (instruction.opcode == OP_CALL) + { + if (vm->call_stack.ptr >= vm->call_stack.max) + return ERR_CALL_STACK_OVERFLOW; + vm->call_stack.address_pointers[vm->call_stack.ptr++] = vm->program.ptr + 1; + return vm_jump(vm, instruction.operand.as_word); + } + else if (instruction.opcode == OP_CALL_STACK) + { + if (vm->call_stack.ptr >= vm->call_stack.max) + return ERR_CALL_STACK_OVERFLOW; + vm->call_stack.address_pointers[vm->call_stack.ptr++] = vm->program.ptr + 1; + data_t ret = {0}; + err_t err = vm_pop_word(vm, &ret); + if (err) + return err; + return vm_jump(vm, ret.as_word); + } + else if (instruction.opcode == OP_RET) + { + if (vm->call_stack.ptr == 0) + return ERR_CALL_STACK_UNDERFLOW; + return vm_jump(vm, vm->call_stack.address_pointers[--vm->call_stack.ptr]); + } else if (OPCODE_IS_TYPE(instruction.opcode, OP_PRINT)) { data_t datum = {0}; @@ -259,6 +279,7 @@ err_t vm_execute_all(vm_t *vm) registers_t prev_registers = vm->registers; size_t prev_sptr = 0; size_t prev_pages = 0; + size_t prev_cptr = 0; #endif while (program->instructions[program->ptr].opcode != OP_HALT && program->ptr < program->max) @@ -274,6 +295,15 @@ err_t vm_execute_all(vm_t *vm) "----------------------------------------------------------------------" "----------\n", stdout); + if (prev_cptr != vm->call_stack.ptr) + { + vm_print_call_stack(vm, stdout); + prev_cptr = vm->call_stack.ptr; + fputs("------------------------------------------------------------------" + "----" + "----------\n", + stdout); + } if (prev_pages != vm->heap.pages) { vm_print_heap(vm, stdout); @@ -342,6 +372,12 @@ void vm_load_heap(vm_t *vm, heap_t heap) vm->heap = heap; } +void vm_load_call_stack(vm_t *vm, word *buffer, size_t size) +{ + vm->call_stack = + (struct CallStack){.address_pointers = buffer, .ptr = 0, .max = size}; +} + void vm_stop(vm_t *vm) { free(vm->registers.data); @@ -460,12 +496,38 @@ void vm_print_heap(vm_t *vm, FILE *fp) fprintf(fp, "]\n"); } +void vm_print_call_stack(vm_t *vm, FILE *fp) +{ + struct CallStack cs = vm->call_stack; + fprintf(fp, "CallStack.max = %lu\nCallStack.ptr = %lu\nCallStack.data = [", + cs.max, cs.ptr); + if (cs.ptr == 0) + { + fprintf(fp, "]\n"); + return; + } + printf("\n"); + for (size_t i = cs.ptr; i > 0; --i) + { + word w = cs.address_pointers[i - 1]; + fprintf(fp, "\t%lu: %lX", cs.ptr - i, w); + if (i != 1) + fprintf(fp, ", "); + fprintf(fp, "\n"); + } + fprintf(fp, "]\n"); +} + void vm_print_all(vm_t *vm, FILE *fp) { fputs("----------------------------------------------------------------------" "----------\n", fp); vm_print_program(vm, fp); + fputs("----------------------------------------------------------------------" + "----------\n", + fp); + vm_print_call_stack(vm, fp); fputs("----------------------------------------------------------------------" "----------\n", fp); diff --git a/vm/runtime.h b/vm/runtime.h index ce3cb42..c98dfcf 100644 --- a/vm/runtime.h +++ b/vm/runtime.h @@ -24,6 +24,8 @@ typedef enum ERR_OK = 0, ERR_STACK_UNDERFLOW, ERR_STACK_OVERFLOW, + ERR_CALL_STACK_UNDERFLOW, + ERR_CALL_STACK_OVERFLOW, ERR_INVALID_OPCODE, ERR_INVALID_REGISTER_BYTE, ERR_INVALID_REGISTER_HWORD, @@ -46,14 +48,19 @@ typedef struct struct Stack { byte *data; - word ptr, max; + size_t ptr, max; } stack; heap_t heap; struct Program { inst_t *instructions; - word ptr, max; + size_t ptr, max; } program; + struct CallStack + { + word *address_pointers; + size_t ptr, max; + } call_stack; } vm_t; err_t vm_execute(vm_t *); @@ -63,6 +70,7 @@ void vm_load_stack(vm_t *, byte *, size_t); void vm_load_registers(vm_t *, registers_t); void vm_load_heap(vm_t *, heap_t); void vm_load_program(vm_t *, inst_t *, size_t); +void vm_load_call_stack(vm_t *, word *, size_t); void vm_stop(vm_t *); // Print routines @@ -71,6 +79,7 @@ void vm_print_registers(vm_t *, FILE *); void vm_print_stack(vm_t *, FILE *); void vm_print_program(vm_t *, FILE *); void vm_print_heap(vm_t *, FILE *); +void vm_print_call_stack(vm_t *, FILE *); void vm_print_all(vm_t *, FILE *); // Execution routines -- cgit v1.2.3-13-gbd6f