Implemented subroutine instructions in runtime

Very easy overall, printing the call stack not so much.
This commit is contained in:
2023-11-02 23:25:33 +00:00
parent 86977fe3c1
commit 4eee6e1a0a
3 changed files with 94 additions and 17 deletions

View File

@@ -37,8 +37,7 @@ int main(int argc, char *argv[])
const char *filename = argv[1]; const char *filename = argv[1];
#if VERBOSE >= 1 #if VERBOSE >= 1
printf("[%sINTERPRETER%s]: Interpreting `%s`\n", TERM_YELLOW, TERM_RESET, printf("[" TERM_YELLOW "INTERPRETER" TERM_RESET "]: `%s`\n", filename);
filename);
#endif #endif
FILE *fp = fopen(filename, "rb"); FILE *fp = fopen(filename, "rb");
@@ -47,8 +46,8 @@ int main(int argc, char *argv[])
fclose(fp); fclose(fp);
#if VERBOSE >= 1 #if VERBOSE >= 1
printf("\t[%sBYTECODE-READER%s]: Read %lu instructions\n", TERM_GREEN, printf("\t[" TERM_GREEN "SETUP" TERM_RESET "]: Read %lu instructions\n",
TERM_RESET, number); number);
#endif #endif
size_t stack_size = 256; size_t stack_size = 256;
@@ -57,16 +56,22 @@ int main(int argc, char *argv[])
darr_init(&registers, 8 * WORD_SIZE); darr_init(&registers, 8 * WORD_SIZE);
heap_t heap = {0}; heap_t heap = {0};
heap_create(&heap); heap_create(&heap);
size_t call_stack_size = 256;
word *call_stack = calloc(call_stack_size, sizeof(call_stack));
vm_t vm = {0}; vm_t vm = {0};
vm_load_stack(&vm, stack, stack_size); vm_load_stack(&vm, stack, stack_size);
vm_load_program(&vm, instructions, number); vm_load_program(&vm, instructions, number);
vm_load_registers(&vm, registers); vm_load_registers(&vm, registers);
vm_load_heap(&vm, heap); vm_load_heap(&vm, heap);
vm_load_call_stack(&vm, call_stack, call_stack_size);
#if VERBOSE >= 1 #if VERBOSE >= 1
printf("\t[%sVM-SETUP%s]: Loaded stack and program into VM\n", TERM_GREEN, printf("\t[" TERM_GREEN "SETUP" TERM_RESET
TERM_RESET); "]: Loaded stack and program into VM\n");
#endif
#if VERBOSE >= 1
printf("[" TERM_YELLOW "INTERPRETER" TERM_RESET "]: Beginning execution\n");
#endif #endif
err_t err = vm_execute_all(&vm); err_t err = vm_execute_all(&vm);
@@ -78,6 +83,7 @@ int main(int argc, char *argv[])
vm_print_all(&vm, stderr); vm_print_all(&vm, stderr);
ret = 255 - err; ret = 255 - err;
} }
vm_stop(&vm); vm_stop(&vm);
#if VERBOSE >= 1 #if VERBOSE >= 1

View File

@@ -25,25 +25,22 @@ const char *err_as_cstr(err_t err)
{ {
case ERR_OK: case ERR_OK:
return "OK"; return "OK";
break;
case ERR_STACK_UNDERFLOW: case ERR_STACK_UNDERFLOW:
return "STACK_UNDERFLOW"; return "STACK_UNDERFLOW";
break;
case ERR_STACK_OVERFLOW: case ERR_STACK_OVERFLOW:
return "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: case ERR_INVALID_OPCODE:
return "INVALID_OPCODE"; return "INVALID_OPCODE";
break;
case ERR_INVALID_REGISTER_BYTE: case ERR_INVALID_REGISTER_BYTE:
return "INVALID_REGISTER_BYTE"; return "INVALID_REGISTER_BYTE";
break;
case ERR_INVALID_REGISTER_HWORD: case ERR_INVALID_REGISTER_HWORD:
return "INVALID_REGISTER_HWORD"; return "INVALID_REGISTER_HWORD";
break;
case ERR_INVALID_REGISTER_WORD: case ERR_INVALID_REGISTER_WORD:
return "INVALID_REGISTER_WORD"; return "INVALID_REGISTER_WORD";
break;
case ERR_INVALID_PROGRAM_ADDRESS: case ERR_INVALID_PROGRAM_ADDRESS:
return "INVALID_PROGRAM_ADDRESS"; return "INVALID_PROGRAM_ADDRESS";
case ERR_INVALID_PAGE_ADDRESS: case ERR_INVALID_PAGE_ADDRESS:
@@ -52,7 +49,6 @@ const char *err_as_cstr(err_t err)
return "OUT_OF_BOUNDS"; return "OUT_OF_BOUNDS";
case ERR_END_OF_PROGRAM: case ERR_END_OF_PROGRAM:
return "END_OF_PROGRAM"; return "END_OF_PROGRAM";
break;
default: default:
return ""; return "";
} }
@@ -60,7 +56,7 @@ const char *err_as_cstr(err_t err)
err_t vm_execute(vm_t *vm) 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; struct Program *prog = &vm->program;
if (prog->ptr >= prog->max) if (prog->ptr >= prog->max)
return ERR_END_OF_PROGRAM; return ERR_END_OF_PROGRAM;
@@ -153,6 +149,30 @@ err_t vm_execute(vm_t *vm)
else else
++prog->ptr; ++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)) else if (OPCODE_IS_TYPE(instruction.opcode, OP_PRINT))
{ {
data_t datum = {0}; data_t datum = {0};
@@ -259,6 +279,7 @@ err_t vm_execute_all(vm_t *vm)
registers_t prev_registers = vm->registers; registers_t prev_registers = vm->registers;
size_t prev_sptr = 0; size_t prev_sptr = 0;
size_t prev_pages = 0; size_t prev_pages = 0;
size_t prev_cptr = 0;
#endif #endif
while (program->instructions[program->ptr].opcode != OP_HALT && while (program->instructions[program->ptr].opcode != OP_HALT &&
program->ptr < program->max) program->ptr < program->max)
@@ -274,6 +295,15 @@ err_t vm_execute_all(vm_t *vm)
"----------------------------------------------------------------------" "----------------------------------------------------------------------"
"----------\n", "----------\n",
stdout); 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) if (prev_pages != vm->heap.pages)
{ {
vm_print_heap(vm, stdout); vm_print_heap(vm, stdout);
@@ -342,6 +372,12 @@ void vm_load_heap(vm_t *vm, heap_t heap)
vm->heap = 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) void vm_stop(vm_t *vm)
{ {
free(vm->registers.data); free(vm->registers.data);
@@ -460,12 +496,38 @@ void vm_print_heap(vm_t *vm, FILE *fp)
fprintf(fp, "]\n"); 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) void vm_print_all(vm_t *vm, FILE *fp)
{ {
fputs("----------------------------------------------------------------------" fputs("----------------------------------------------------------------------"
"----------\n", "----------\n",
fp); fp);
vm_print_program(vm, fp); vm_print_program(vm, fp);
fputs("----------------------------------------------------------------------"
"----------\n",
fp);
vm_print_call_stack(vm, fp);
fputs("----------------------------------------------------------------------" fputs("----------------------------------------------------------------------"
"----------\n", "----------\n",
fp); fp);

View File

@@ -24,6 +24,8 @@ typedef enum
ERR_OK = 0, ERR_OK = 0,
ERR_STACK_UNDERFLOW, ERR_STACK_UNDERFLOW,
ERR_STACK_OVERFLOW, ERR_STACK_OVERFLOW,
ERR_CALL_STACK_UNDERFLOW,
ERR_CALL_STACK_OVERFLOW,
ERR_INVALID_OPCODE, ERR_INVALID_OPCODE,
ERR_INVALID_REGISTER_BYTE, ERR_INVALID_REGISTER_BYTE,
ERR_INVALID_REGISTER_HWORD, ERR_INVALID_REGISTER_HWORD,
@@ -46,14 +48,19 @@ typedef struct
struct Stack struct Stack
{ {
byte *data; byte *data;
word ptr, max; size_t ptr, max;
} stack; } stack;
heap_t heap; heap_t heap;
struct Program struct Program
{ {
inst_t *instructions; inst_t *instructions;
word ptr, max; size_t ptr, max;
} program; } program;
struct CallStack
{
word *address_pointers;
size_t ptr, max;
} call_stack;
} vm_t; } vm_t;
err_t vm_execute(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_registers(vm_t *, registers_t);
void vm_load_heap(vm_t *, heap_t); void vm_load_heap(vm_t *, heap_t);
void vm_load_program(vm_t *, inst_t *, size_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 *); void vm_stop(vm_t *);
// Print routines // Print routines
@@ -71,6 +79,7 @@ void vm_print_registers(vm_t *, FILE *);
void vm_print_stack(vm_t *, FILE *); void vm_print_stack(vm_t *, FILE *);
void vm_print_program(vm_t *, FILE *); void vm_print_program(vm_t *, FILE *);
void vm_print_heap(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 *); void vm_print_all(vm_t *, FILE *);
// Execution routines // Execution routines