diff options
Diffstat (limited to 'vm')
-rw-r--r-- | vm/runtime.c | 108 | ||||
-rw-r--r-- | vm/runtime.h | 25 |
2 files changed, 77 insertions, 56 deletions
diff --git a/vm/runtime.c b/vm/runtime.c index e6fb654..240ba6f 100644 --- a/vm/runtime.c +++ b/vm/runtime.c @@ -12,6 +12,7 @@ #include <assert.h> #include <inttypes.h> +#include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -125,9 +126,9 @@ err_t vm_execute(vm_t *vm) } else if (instruction.opcode == OP_JUMP_REGISTER) { - if (instruction.operand.as_byte >= 8) + if (instruction.operand.as_word >= vm->registers.available) return ERR_INVALID_REGISTER_WORD; - word addr = vm->registers.reg[instruction.operand.as_byte]; + word addr = vm->registers.data[instruction.operand.as_word]; return vm_jump(vm, addr); } else if (OPCODE_IS_TYPE(instruction.opcode, OP_JUMP_IF)) @@ -253,8 +254,8 @@ err_t vm_execute_all(vm_t *vm) size_t cycles = 0; #endif #if VERBOSE >= 2 - struct Registers prev_registers = vm->registers; - size_t prev_sptr = 0; + registers_t prev_registers = vm->registers; + size_t prev_sptr = 0; #endif while (program->instructions[program->ptr].opcode != OP_HALT && program->ptr < program->max) @@ -270,8 +271,7 @@ err_t vm_execute_all(vm_t *vm) "----------------------------------------------------------------------" "----------\n", stdout); - if (memcmp(prev_registers.reg, vm->registers.reg, - ARR_SIZE(vm->registers.reg)) != 0) + if (memcmp(&prev_registers, &vm->registers, sizeof(darr_t)) != 0) { vm_print_registers(vm, stdout); prev_registers = vm->registers; @@ -320,14 +320,21 @@ void vm_load_program(vm_t *vm, inst_t *instructions, size_t size) vm->program.ptr = 0; } +void vm_load_registers(vm_t *vm, registers_t registers) +{ + vm->registers = registers; +} + void vm_print_registers(vm_t *vm, FILE *fp) { - struct Registers reg = vm->registers; + registers_t reg = vm->registers; + fprintf(fp, "Registers.used = %luB\nRegisters.available = %luB\n", + vm->registers.used, vm->registers.available); fprintf(fp, "Registers.reg = ["); - for (size_t i = 0; i < VM_REGISTERS; ++i) + for (size_t i = 0; i <= (reg.used / WORD_SIZE); ++i) { - fprintf(fp, "{%lu:%lX}", i, reg.reg[i]); - if (i != VM_REGISTERS - 1) + fprintf(fp, "{%lu:%lX}", i, VM_NTH_REGISTER(reg, i)); + if (i != reg.used - 1) fprintf(fp, ", "); } fprintf(fp, "]\n"); @@ -447,80 +454,93 @@ err_t vm_push_word(vm_t *vm, data_t w) return ERR_OK; } -err_t vm_push_byte_register(vm_t *vm, byte reg) +err_t vm_push_byte_register(vm_t *vm, word reg) { - if (reg >= VM_REGISTERS * 8) + if (reg > vm->registers.used) return ERR_INVALID_REGISTER_BYTE; // Interpret each word based register as 8 byte registers - byte b = WORD_NTH_BYTE(vm->registers.reg[reg / 8], reg % 8); + byte b = vm->registers.data[reg]; return vm_push_byte(vm, DBYTE(b)); } -err_t vm_push_hword_register(vm_t *vm, byte reg) +err_t vm_push_hword_register(vm_t *vm, word reg) { - if (reg >= VM_REGISTERS * 2) + if (reg > (vm->registers.used / HWORD_SIZE)) return ERR_INVALID_REGISTER_HWORD; - // Interpret each word based register as 2 hword registers - hword hw = WORD_NTH_HWORD(vm->registers.reg[reg / 2], reg % 2); + // Interpret the bytes at point reg * HWORD_SIZE as an hword + hword hw = *(hword *)(vm->registers.data + (reg * HWORD_SIZE)); return vm_push_hword(vm, DHWORD(hw)); } -err_t vm_push_word_register(vm_t *vm, byte reg) +err_t vm_push_word_register(vm_t *vm, word reg) { - if (reg >= VM_REGISTERS) + if (reg > (vm->registers.used / WORD_SIZE)) return ERR_INVALID_REGISTER_WORD; - return vm_push_word(vm, DWORD(vm->registers.reg[reg])); + return vm_push_word(vm, DWORD(VM_NTH_REGISTER(vm->registers, reg))); } -err_t vm_mov_byte(vm_t *vm, byte reg) +err_t vm_mov_byte(vm_t *vm, word reg) { - if (reg >= (VM_REGISTERS * 8)) - return ERR_INVALID_REGISTER_BYTE; + if (reg >= vm->registers.used) + { + // Expand capacity + darr_ensure_capacity(&vm->registers, reg - vm->registers.used); + vm->registers.used = MAX(vm->registers.used, reg + 1); + } data_t ret = {0}; err_t err = vm_pop_byte(vm, &ret); if (err) return err; - word *reg_ptr = &vm->registers.reg[reg / 8]; - size_t shift = (reg % 8) * 8; - // This resets the bits in the specific byte register - *reg_ptr = *reg_ptr & ~(0xFF << shift); - // This sets the bits - *reg_ptr = (*reg_ptr) | (ret.as_word << shift); + vm->registers.data[reg] = ret.as_byte; return ERR_OK; } -err_t vm_mov_hword(vm_t *vm, byte reg) +err_t vm_mov_hword(vm_t *vm, word reg) { - if (reg >= (VM_REGISTERS * 2)) - return ERR_INVALID_REGISTER_HWORD; - else if (vm->stack.ptr < sizeof(f64)) - return ERR_STACK_UNDERFLOW; + if (reg >= (vm->registers.used / HWORD_SIZE)) + { + // Expand capacity till we can ensure that this is a valid + // register to use + + // Number of hwords needed ontop of what is allocated: + const size_t hwords = (reg - (vm->registers.used / HWORD_SIZE)); + // Number of bytes needed ontop of what is allocated + const size_t diff = (hwords + 1) * HWORD_SIZE; + + darr_ensure_capacity(&vm->registers, diff); + vm->registers.used = MAX(vm->registers.used, (reg * HWORD_SIZE) + 1); + } data_t ret = {0}; err_t err = vm_pop_hword(vm, &ret); if (err) return err; - word *reg_ptr = &vm->registers.reg[reg / 2]; - size_t shift = (reg % 2) * 2; - // This resets the bits in the specific hword register - *reg_ptr = *reg_ptr & ~(0xFFFFFFFF << shift); - // This sets the bits - *reg_ptr = (*reg_ptr) | (ret.as_word << shift); + // Here we treat vm->registers as a set of hwords + hword *hword_ptr = (hword *)(vm->registers.data + (reg * HWORD_SIZE)); + *hword_ptr = ret.as_hword; return ERR_OK; } -err_t vm_mov_word(vm_t *vm, byte reg) +err_t vm_mov_word(vm_t *vm, word reg) { - if (reg >= VM_REGISTERS) - return ERR_INVALID_REGISTER_WORD; + if (reg >= (vm->registers.used / WORD_SIZE)) + { + // Number of hwords needed ontop of what is allocated: + const size_t words = (reg - (vm->registers.used / WORD_SIZE)); + // Number of bytes needed ontop of what is allocated + const size_t diff = (words + 1) * WORD_SIZE; + + darr_ensure_capacity(&vm->registers, diff); + vm->registers.used = MAX(vm->registers.used, (reg * WORD_SIZE) + 1); + } else if (vm->stack.ptr < sizeof(word)) return ERR_STACK_UNDERFLOW; data_t ret = {0}; err_t err = vm_pop_word(vm, &ret); if (err) return err; - vm->registers.reg[reg] = ret.as_word; + VM_NTH_REGISTER(vm->registers, reg) = ret.as_word; return ERR_OK; } diff --git a/vm/runtime.h b/vm/runtime.h index be907b3..1226ea9 100644 --- a/vm/runtime.h +++ b/vm/runtime.h @@ -33,13 +33,13 @@ typedef enum const char *err_as_cstr(err_t); -#define VM_REGISTERS 8 +typedef darr_t registers_t; +#define VM_NTH_REGISTER(REGISTERS, N) (((word *)((REGISTERS).data))[N]) +#define VM_REGISTERS_AVAILABLE(REGISTERS) (((REGISTERS).available) / WORD_SIZE) + typedef struct { - struct Registers - { - word reg[VM_REGISTERS]; - } registers; + registers_t registers; struct Stack { byte *data; @@ -57,6 +57,7 @@ err_t vm_execute_all(vm_t *); void vm_load_stack(vm_t *, byte *, size_t); void vm_load_program(vm_t *, inst_t *, size_t); +void vm_load_registers(vm_t *, registers_t); // Print routines #define VM_PRINT_PROGRAM_EXCERPT 5 @@ -83,15 +84,15 @@ static const push_f PUSH_ROUTINES[] = { [OP_PUSH_WORD] = vm_push_word, }; -err_t vm_push_byte_register(vm_t *, byte); -err_t vm_push_hword_register(vm_t *, byte); -err_t vm_push_word_register(vm_t *, byte); +err_t vm_push_byte_register(vm_t *, word); +err_t vm_push_hword_register(vm_t *, word); +err_t vm_push_word_register(vm_t *, word); -err_t vm_mov_byte(vm_t *, byte); -err_t vm_mov_hword(vm_t *, byte); -err_t vm_mov_word(vm_t *, byte); +err_t vm_mov_byte(vm_t *, word); +err_t vm_mov_hword(vm_t *, word); +err_t vm_mov_word(vm_t *, word); -typedef err_t (*reg_f)(vm_t *, byte); +typedef err_t (*reg_f)(vm_t *, word); static const reg_f REG_ROUTINES[] = { [OP_PUSH_REGISTER_BYTE] = vm_push_byte_register, [OP_PUSH_REGISTER_HWORD] = vm_push_hword_register, |