diff options
author | Aryadev Chavali <aryadev@aryadevchavali.com> | 2023-10-22 17:01:15 +0100 |
---|---|---|
committer | Aryadev Chavali <aryadev@aryadevchavali.com> | 2023-10-22 17:34:30 +0100 |
commit | 47c7d6baf7d39da5e2683edc3674494fcd3874ba (patch) | |
tree | da2e739db9dc9c4ab70656dc005c8a5747bb2b41 | |
parent | 95723f36d2aa7e1bcd343b2e072c0bcf28a3b1b5 (diff) | |
download | ovm-47c7d6baf7d39da5e2683edc3674494fcd3874ba.tar.gz ovm-47c7d6baf7d39da5e2683edc3674494fcd3874ba.tar.bz2 ovm-47c7d6baf7d39da5e2683edc3674494fcd3874ba.zip |
Store the result of OP_POP in the last register as a word
Instead of making routines to handle data in the `ret` register, just
store the result of POP into the last word register.
This means we are no longer using vm_pop_* or POP_ROUTINES for the
vm_execute script on OP_POP: instead we'll just use vm_mov_* which
automatically pops the datum for us, while moving the datum to the
last register.
-rw-r--r-- | src/inst.h | 5 | ||||
-rw-r--r-- | src/runtime.c | 115 | ||||
-rw-r--r-- | src/runtime.h | 14 |
3 files changed, 111 insertions, 23 deletions
@@ -69,6 +69,11 @@ const char *opcode_as_cstr(opcode_t); #define OPCODE_IS_TYPE(OPCODE, OP_TYPE) \ (((OPCODE) >= OP_TYPE##_BYTE) && ((OPCODE) <= OP_TYPE##_WORD)) +#define OPCODE_DATA_TYPE(OPCODE, OP_TYPE) \ + ((OPCODE) == OP_TYPE##_BYTE ? DATA_TYPE_BYTE \ + : ((OPCODE) == OP_TYPE##_HWORD) ? DATA_TYPE_HWORD \ + : DATA_TYPE_WORD) + typedef struct { opcode_t opcode; diff --git a/src/runtime.c b/src/runtime.c index b330a61..0a8a40a 100644 --- a/src/runtime.c +++ b/src/runtime.c @@ -38,16 +38,66 @@ void vm_execute(vm_t *vm) } else if (OPCODE_IS_TYPE(instruction.opcode, OP_POP)) { - // NOTE: We use the `ret` register for the result of this pop - data_t d = POP_ROUTINES[instruction.opcode](vm); - vm->registers.ret = d.as_word; + // NOTE: We use the first register to hold the result of this pop + data_type_t type = OPCODE_DATA_TYPE(instruction.opcode, OP_POP); + data_t datum = vm_peek(vm, type); + switch (type) + { + case DATA_TYPE_NIL: + break; + case DATA_TYPE_BYTE: + vm_mov_byte(vm, (VM_REGISTERS * 8) - 1); + break; + case DATA_TYPE_HWORD: + vm_mov_hword(vm, (VM_REGISTERS * 4) - 1); + break; + case DATA_TYPE_WORD: + vm_mov_hword(vm, VM_REGISTERS - 1); + break; + } + vm->registers.ret = datum.as_word; prog->ptr++; } else if (OPCODE_IS_TYPE(instruction.opcode, OP_MOV)) { data_t d = MOV_ROUTINES[instruction.opcode](vm, instruction.operand.as_word); - vm->registers.ret = d.as_word; // will do type punning for me + vm->registers.ret = d.as_word; + prog->ptr++; + } + else if (OPCODE_IS_TYPE(instruction.opcode, OP_NOT)) + { + NOT_ROUTINES[instruction.opcode](vm); + vm->registers.ret = + vm_peek(vm, OPCODE_DATA_TYPE(instruction.opcode, OP_NOT)).as_word; + prog->ptr++; + } + else if (OPCODE_IS_TYPE(instruction.opcode, OP_OR)) + { + OR_ROUTINES[instruction.opcode](vm); + vm->registers.ret = + vm_peek(vm, OPCODE_DATA_TYPE(instruction.opcode, OP_OR)).as_word; + prog->ptr++; + } + else if (OPCODE_IS_TYPE(instruction.opcode, OP_AND)) + { + AND_ROUTINES[instruction.opcode](vm); + vm->registers.ret = + vm_peek(vm, OPCODE_DATA_TYPE(instruction.opcode, OP_AND)).as_word; + prog->ptr++; + } + else if (OPCODE_IS_TYPE(instruction.opcode, OP_XOR)) + { + XOR_ROUTINES[instruction.opcode](vm); + vm->registers.ret = + vm_peek(vm, OPCODE_DATA_TYPE(instruction.opcode, OP_XOR)).as_word; + prog->ptr++; + } + else if (OPCODE_IS_TYPE(instruction.opcode, OP_EQ)) + { + EQ_ROUTINES[instruction.opcode](vm); + vm->registers.ret = + vm_peek(vm, OPCODE_DATA_TYPE(instruction.opcode, OP_EQ)).as_word; prog->ptr++; } else if (instruction.opcode == OP_HALT) @@ -174,6 +224,48 @@ void vm_print_all(vm_t *vm, FILE *fp) fp); } +data_t vm_peek(vm_t *vm, data_type_t type) +{ + switch (type) + { + case DATA_TYPE_NIL: + return DBYTE(0); + break; + case DATA_TYPE_BYTE: + if (vm->stack.ptr == 0) + return DBYTE(0); + return DBYTE(vm->stack.data[vm->stack.ptr - 1]); + break; + case DATA_TYPE_HWORD: + if (vm->stack.ptr < HWORD_SIZE) + // TODO: Error STACK_UNDERFLOW + return DHWORD(0); + hword h = 0; + for (size_t i = 0; i < HWORD_SIZE; ++i) + { + byte b = vm->stack.data[vm->stack.ptr - 1 - i]; + h = h | (((word)b) << (i * 8)); + } + return DWORD(h); + break; + case DATA_TYPE_WORD: + if (vm->stack.ptr < WORD_SIZE) + // TODO: Error STACK_UNDERFLOW + return DWORD(0); + word w = 0; + for (size_t i = 0; i < WORD_SIZE; ++i) + { + byte b = vm->stack.data[vm->stack.ptr - 1 - i]; + w = w | (((word)b) << (i * 8)); + } + return DWORD(w); + break; + default: + return DBYTE(0); + break; + } +} + void vm_push_byte(vm_t *vm, data_t b) { if (vm->stack.ptr >= vm->stack.max) @@ -223,11 +315,7 @@ void vm_push_byte_register(vm_t *vm, byte reg) return; // Interpret each word based register as 8 byte registers - word ind = reg / 8; - word nth_byte = reg % 8; - word reg_ptr = vm->registers.reg[ind]; - - byte b = WORD_NTH_BYTE(reg_ptr, nth_byte); + byte b = WORD_NTH_BYTE(vm->registers.reg[reg / 8], reg % 8); vm_push_byte(vm, DBYTE(b)); } @@ -241,10 +329,7 @@ void vm_push_hword_register(vm_t *vm, byte reg) // TODO: Error STACK_OVERFLOW return; // Interpret each word based register as 2 hword registers - word ind = reg / 2; - word nth_hword = reg % 2; - word reg_ptr = vm->registers.reg[ind]; - hword hw = WORD_NTH_HWORD(reg_ptr, nth_hword); + hword hw = WORD_NTH_HWORD(vm->registers.reg[reg / 2], reg % 2); vm_push_hword(vm, DHWORD(hw)); } @@ -269,7 +354,7 @@ data_t vm_mov_byte(vm_t *vm, byte reg) return DBYTE(0); data_t ret = vm_pop_byte(vm); word *reg_ptr = &vm->registers.reg[reg / 8]; - *reg_ptr = (*reg_ptr) | ((word)ret.as_word) << ((reg % 8) * 8); + *reg_ptr = (*reg_ptr) | (ret.as_word << ((reg % 8) * 8)); return ret; } @@ -283,7 +368,7 @@ data_t vm_mov_hword(vm_t *vm, byte reg) return DHWORD(0); data_t ret = vm_pop_hword(vm); word *reg_ptr = &vm->registers.reg[reg / 2]; - *reg_ptr = (*reg_ptr) | ((word)ret.as_word) << ((reg % 2) * 2); + *reg_ptr = (*reg_ptr) | (ret.as_word << ((reg % 2) * 2)); return ret; } diff --git a/src/runtime.h b/src/runtime.h index 2ec01df..3e4c295 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -24,7 +24,9 @@ typedef struct { struct Registers { + // Used for internal word ret; + // General registers word reg[VM_REGISTERS]; } registers; struct Stack @@ -50,12 +52,15 @@ void vm_load_stack(vm_t *, byte *, size_t); void vm_load_program(vm_t *, inst_t *, size_t); // Print routines +#define VM_PRINT_PROGRAM_EXCERPT 5 void vm_print_registers(vm_t *, FILE *); void vm_print_stack(vm_t *, FILE *); -#define VM_PRINT_PROGRAM_EXCERPT 5 void vm_print_program(vm_t *, FILE *); void vm_print_all(vm_t *, FILE *); +data_t vm_peek(vm_t *, data_type_t); + +// Execution routines void vm_push_byte(vm_t *, data_t); void vm_push_hword(vm_t *, data_t); void vm_push_word(vm_t *, data_t); @@ -93,13 +98,6 @@ data_t vm_pop_byte(vm_t *); data_t vm_pop_hword(vm_t *); data_t vm_pop_word(vm_t *); -typedef data_t (*pop_f)(vm_t *); -static const pop_f POP_ROUTINES[] = { - [OP_POP_BYTE] = vm_pop_byte, - [OP_POP_HWORD] = vm_pop_hword, - [OP_POP_WORD] = vm_pop_word, -}; - void vm_not_byte(vm_t *); void vm_not_hword(vm_t *); void vm_not_word(vm_t *); |