diff options
-rw-r--r-- | src/runtime.c | 496 | ||||
-rw-r--r-- | src/runtime.h | 97 |
2 files changed, 329 insertions, 264 deletions
diff --git a/src/runtime.c b/src/runtime.c index e68dd25..fde22f3 100644 --- a/src/runtime.c +++ b/src/runtime.c @@ -17,111 +17,156 @@ #include "./runtime.h" -void vm_execute(vm_t *vm) +const char *err_as_cstr(err_t err) +{ + switch (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_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_END_OF_PROGRAM: + return "END_OF_PROGRAM"; + break; + default: + return ""; + } +} + +err_t vm_execute(vm_t *vm) { static_assert(NUMBER_OF_OPCODES == 34, "vm_execute: Out of date"); struct Program *prog = &vm->program; if (prog->ptr >= prog->max) - // TODO: Error (Went past end of program) - return; + return ERR_END_OF_PROGRAM; inst_t instruction = prog->instructions[prog->ptr]; if (OPCODE_IS_TYPE(instruction.opcode, OP_PUSH)) { - PUSH_ROUTINES[instruction.opcode](vm, instruction.operand); prog->ptr++; + return PUSH_ROUTINES[instruction.opcode](vm, instruction.operand); } else if (OPCODE_IS_TYPE(instruction.opcode, OP_PUSH_REGISTER)) { - PUSH_REG_ROUTINES[instruction.opcode](vm, instruction.operand.as_word); prog->ptr++; + return PUSH_REG_ROUTINES[instruction.opcode](vm, + instruction.operand.as_word); } else if (OPCODE_IS_TYPE(instruction.opcode, OP_POP)) { // NOTE: We use the first register to hold the result of this pop data_type_t type = OPCODE_DATA_TYPE(instruction.opcode, OP_POP); + prog->ptr++; switch (type) { case DATA_TYPE_NIL: break; case DATA_TYPE_BYTE: - vm_mov_byte(vm, 0); + return vm_mov_byte(vm, 0); break; case DATA_TYPE_HWORD: - vm_mov_hword(vm, 0); + return vm_mov_hword(vm, 0); break; case DATA_TYPE_WORD: - vm_mov_word(vm, 0); + return vm_mov_word(vm, 0); break; } - prog->ptr++; + return ERR_OK; } else if (OPCODE_IS_TYPE(instruction.opcode, OP_MOV)) { - MOV_ROUTINES[instruction.opcode](vm, instruction.operand.as_byte); prog->ptr++; + return MOV_ROUTINES[instruction.opcode](vm, instruction.operand.as_byte); } else if (OPCODE_IS_TYPE(instruction.opcode, OP_DUP)) { - DUP_ROUTINES[instruction.opcode](vm, instruction.operand.as_word); prog->ptr++; + return DUP_ROUTINES[instruction.opcode](vm, instruction.operand.as_word); } else if (OPCODE_IS_TYPE(instruction.opcode, OP_NOT)) { - NOT_ROUTINES[instruction.opcode](vm); prog->ptr++; + return NOT_ROUTINES[instruction.opcode](vm); } else if (OPCODE_IS_TYPE(instruction.opcode, OP_OR)) { - OR_ROUTINES[instruction.opcode](vm); prog->ptr++; + return OR_ROUTINES[instruction.opcode](vm); } else if (OPCODE_IS_TYPE(instruction.opcode, OP_AND)) { - AND_ROUTINES[instruction.opcode](vm); prog->ptr++; + return AND_ROUTINES[instruction.opcode](vm); } else if (OPCODE_IS_TYPE(instruction.opcode, OP_XOR)) { - XOR_ROUTINES[instruction.opcode](vm); prog->ptr++; + return XOR_ROUTINES[instruction.opcode](vm); } else if (OPCODE_IS_TYPE(instruction.opcode, OP_EQ)) { - EQ_ROUTINES[instruction.opcode](vm); prog->ptr++; + return EQ_ROUTINES[instruction.opcode](vm); } else if (instruction.opcode == OP_JUMP_ABS) { // Set prog->ptr to the jump point requested + if (instruction.operand.as_word >= vm->program.max) + return ERR_INVALID_PROGRAM_ADDRESS; prog->ptr = instruction.operand.as_word; + return ERR_OK; } else if (instruction.opcode == OP_JUMP_STACK) { // Set prog->ptr to the word on top of the stack - prog->ptr = vm_pop_word(vm).as_word; + data_t ret = {0}; + err_t err = vm_pop_word(vm, &ret); + if (err) + return err; + else if (ret.as_word >= vm->program.max) + return ERR_INVALID_PROGRAM_ADDRESS; + prog->ptr = ret.as_word; } else if (instruction.opcode == OP_JUMP_REGISTER) { if (instruction.operand.as_byte >= 8) - // TODO: Error register is not a valid word register - return; - prog->ptr = vm->registers.reg[instruction.operand.as_byte]; + return ERR_INVALID_REGISTER_WORD; + word addr = vm->registers.reg[instruction.operand.as_byte]; + if (addr >= vm->program.max) + return ERR_INVALID_PROGRAM_ADDRESS; + prog->ptr = addr; } else if (instruction.opcode == OP_HALT) { // Do nothing here. Should be caught by callers of vm_execute + return ERR_OK; } - else - { - // TODO: Error (Unknown opcode) - return; - } + return ERR_INVALID_OPCODE; } -void vm_execute_all(vm_t *vm) +err_t vm_execute_all(vm_t *vm) { struct Program *program = &vm->program; + err_t err = ERR_OK; #if VERBOSE == 1 struct Registers prev_registers = vm->registers; size_t cycles = 0; @@ -162,13 +207,16 @@ void vm_execute_all(vm_t *vm) } ++cycles; #endif - vm_execute(vm); + err = vm_execute(vm); + if (err) + return err; } #if VERBOSE >= 1 fprintf(stdout, "[vm_execute_all]: Final VM state(Cycle %lu)\n", cycles); vm_print_all(vm, stdout); #endif + return err; } void vm_load_stack(vm_t *vm, byte *bytes, size_t size) @@ -282,7 +330,6 @@ data_t vm_peek(vm_t *vm, data_type_t type) break; case DATA_TYPE_HWORD: { if (vm->stack.ptr < HWORD_SIZE) - // TODO: Error STACK_UNDERFLOW return DHWORD(0); byte bytes[HWORD_SIZE] = {0}; for (size_t i = 0; i < HWORD_SIZE; ++i) @@ -295,7 +342,6 @@ data_t vm_peek(vm_t *vm, data_type_t type) } case DATA_TYPE_WORD: { if (vm->stack.ptr < WORD_SIZE) - // TODO: Error STACK_UNDERFLOW return DWORD(0); byte bytes[WORD_SIZE] = {0}; for (size_t i = 0; i < WORD_SIZE; ++i) @@ -312,19 +358,18 @@ data_t vm_peek(vm_t *vm, data_type_t type) } } -void vm_push_byte(vm_t *vm, data_t b) +err_t vm_push_byte(vm_t *vm, data_t b) { if (vm->stack.ptr >= vm->stack.max) - // TODO: Error STACK_OVERFLOW - return; + return ERR_STACK_OVERFLOW; vm->stack.data[vm->stack.ptr++] = b.as_byte; + return ERR_OK; } -void vm_push_hword(vm_t *vm, data_t f) +err_t vm_push_hword(vm_t *vm, data_t f) { if (vm->stack.ptr + HWORD_SIZE >= vm->stack.max) - // TODO: Error STACK_OVERFLOW - return; + return ERR_STACK_OVERFLOW; byte bytes[HWORD_SIZE] = {0}; convert_hword_to_bytes(f.as_hword, bytes); for (size_t i = 0; i < HWORD_SIZE; ++i) @@ -332,13 +377,13 @@ void vm_push_hword(vm_t *vm, data_t f) byte b = bytes[HWORD_SIZE - i - 1]; vm_push_byte(vm, DBYTE(b)); } + return ERR_OK; } -void vm_push_word(vm_t *vm, data_t w) +err_t vm_push_word(vm_t *vm, data_t w) { if (vm->stack.ptr + WORD_SIZE >= vm->stack.max) - // TODO: Error STACK_OVERFLOW - return; + return ERR_STACK_OVERFLOW; byte bytes[WORD_SIZE] = {0}; convert_word_to_bytes(w.as_word, bytes); for (size_t i = 0; i < WORD_SIZE; ++i) @@ -346,314 +391,319 @@ void vm_push_word(vm_t *vm, data_t w) byte b = bytes[WORD_SIZE - i - 1]; vm_push_byte(vm, DBYTE(b)); } + return ERR_OK; } #define WORD_NTH_BYTE(WORD, N) (((WORD) >> ((N)*8)) & 0b11111111) #define WORD_NTH_HWORD(WORD, N) \ (((WORD) >> ((N)*2)) & 0b11111111111111111111111111111111) -void vm_push_byte_register(vm_t *vm, byte reg) +err_t vm_push_byte_register(vm_t *vm, byte reg) { if (reg >= VM_REGISTERS * 8) - // TODO: Error (reg is not a valid byte register) - return; - else if (vm->stack.ptr >= vm->stack.max) - // TODO: Error STACK_OVERFLOW - return; + 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); - vm_push_byte(vm, DBYTE(b)); + return vm_push_byte(vm, DBYTE(b)); } -void vm_push_hword_register(vm_t *vm, byte reg) +err_t vm_push_hword_register(vm_t *vm, byte reg) { if (reg >= VM_REGISTERS * 2) - // TODO: Error (reg is not a valid hword register) - return; + return ERR_INVALID_REGISTER_HWORD; else if (vm->stack.ptr >= vm->stack.max) - // TODO: Error STACK_OVERFLOW - return; + return ERR_STACK_OVERFLOW; // Interpret each word based register as 2 hword registers hword hw = WORD_NTH_HWORD(vm->registers.reg[reg / 2], reg % 2); - vm_push_hword(vm, DHWORD(hw)); + return vm_push_hword(vm, DHWORD(hw)); } -void vm_push_word_register(vm_t *vm, byte reg) +err_t vm_push_word_register(vm_t *vm, byte reg) { if (reg >= VM_REGISTERS) - // TODO: Error (reg is not a valid word register) - return; + return ERR_INVALID_REGISTER_WORD; else if (vm->stack.ptr >= vm->stack.max) - // TODO: Error STACK_OVERFLOW - return; - vm_push_word(vm, DWORD(vm->registers.reg[reg])); + return ERR_STACK_OVERFLOW; + return vm_push_word(vm, DWORD(vm->registers.reg[reg])); } -data_t vm_mov_byte(vm_t *vm, byte reg) +err_t vm_mov_byte(vm_t *vm, byte reg) { if (reg >= (VM_REGISTERS * 8)) - // TODO: Error (reg is not a valid byte register) - return DBYTE(0); - else if (vm->stack.ptr == 0) - // TODO: Error (STACK UNDERFLOW) - return DBYTE(0); - data_t ret = vm_pop_byte(vm); + return ERR_INVALID_REGISTER_BYTE; + data_t ret = {0}; + err_t err = vm_pop_byte(vm, &ret); + if (err) + return err; word *reg_ptr = &vm->registers.reg[reg / 8]; *reg_ptr = (*reg_ptr) | (ret.as_word << ((reg % 8) * 8)); - return ret; + return ERR_OK; } -data_t vm_mov_hword(vm_t *vm, byte reg) +err_t vm_mov_hword(vm_t *vm, byte reg) { if (reg >= (VM_REGISTERS * 2)) - // TODO: Error (reg is not a valid hword register) - return DHWORD(0); + return ERR_INVALID_REGISTER_HWORD; else if (vm->stack.ptr < sizeof(f64)) - // TODO: Error (STACK UNDERFLOW) - return DHWORD(0); - data_t ret = vm_pop_hword(vm); + return ERR_STACK_UNDERFLOW; + data_t ret = {0}; + err_t err = vm_pop_hword(vm, &ret); + if (err) + return err; word *reg_ptr = &vm->registers.reg[reg / 2]; *reg_ptr = (*reg_ptr) | (ret.as_word << ((reg % 2) * 2)); - return ret; + return ERR_OK; } -data_t vm_mov_word(vm_t *vm, byte reg) +err_t vm_mov_word(vm_t *vm, byte reg) { if (reg >= VM_REGISTERS) - // TODO: Error (reg is not a valid word register) - return DWORD(0); + return ERR_INVALID_REGISTER_WORD; else if (vm->stack.ptr < sizeof(word)) - // TODO: Error (STACK UNDERFLOW) - return DWORD(0); - data_t ret = vm_pop_word(vm); + 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; - return ret; + return ERR_OK; } -void vm_dup_byte(vm_t *vm, word w) +err_t vm_dup_byte(vm_t *vm, word w) { if (vm->stack.ptr < w + 1) - // TODO: Error STACK_UNDERFLOW - return; - else if (vm->stack.ptr >= vm->stack.max) - // TODO: Error STACK_OVERFLOW - return; - vm_push_byte(vm, DBYTE(vm->stack.data[vm->stack.ptr - 1 - w])); + return ERR_STACK_UNDERFLOW; + return vm_push_byte(vm, DBYTE(vm->stack.data[vm->stack.ptr - 1 - w])); } -void vm_dup_hword(vm_t *vm, word w) +err_t vm_dup_hword(vm_t *vm, word w) { if (vm->stack.ptr < HWORD_SIZE * (w + 1)) - // TODO: Error STACK_UNDERFLOW - return; - else if (vm->stack.ptr + HWORD_SIZE >= vm->stack.max) - // TODO: Error STACK_OVERFLOW - return; + return ERR_STACK_UNDERFLOW; byte bytes[HWORD_SIZE] = {0}; for (size_t i = 0; i < HWORD_SIZE; ++i) bytes[HWORD_SIZE - i - 1] = vm->stack.data[vm->stack.ptr - (HWORD_SIZE * (w + 1)) + i]; - vm_push_hword(vm, DHWORD(convert_bytes_to_hword(bytes))); + return vm_push_hword(vm, DHWORD(convert_bytes_to_hword(bytes))); } -void vm_dup_word(vm_t *vm, word w) +err_t vm_dup_word(vm_t *vm, word w) { if (vm->stack.ptr < WORD_SIZE * (w + 1)) - // TODO: Error STACK_UNDERFLOW - return; - else if (vm->stack.ptr + WORD_SIZE >= vm->stack.max) - // TODO: Error STACK_OVERFLOW - return; + return ERR_STACK_UNDERFLOW; byte bytes[WORD_SIZE] = {0}; for (size_t i = 0; i < WORD_SIZE; ++i) bytes[i] = vm->stack.data[vm->stack.ptr - 1 - (WORD_SIZE * (w + 1)) + i]; - vm_push_word(vm, DWORD(convert_bytes_to_word(bytes))); + return vm_push_word(vm, DWORD(convert_bytes_to_word(bytes))); } -data_t vm_pop_byte(vm_t *vm) +err_t vm_pop_byte(vm_t *vm, data_t *ret) { if (vm->stack.ptr == 0) - // TODO: Error STACK_UNDERFLOW - return DBYTE(0); - return DBYTE(vm->stack.data[--vm->stack.ptr]); + return ERR_STACK_UNDERFLOW; + *ret = DBYTE(vm->stack.data[--vm->stack.ptr]); + return ERR_OK; } -data_t vm_pop_hword(vm_t *vm) +err_t vm_pop_hword(vm_t *vm, data_t *ret) { if (vm->stack.ptr < HWORD_SIZE) - // TODO: Error STACK_UNDERFLOW - return DHWORD(0); + return ERR_STACK_UNDERFLOW; byte bytes[HWORD_SIZE] = {0}; for (size_t i = 0; i < HWORD_SIZE; ++i) { - data_t b = vm_pop_byte(vm); + data_t b = {0}; + vm_pop_byte(vm, &b); bytes[HWORD_SIZE - 1 - i] = b.as_byte; } - return DWORD(convert_bytes_to_hword(bytes)); + *ret = DWORD(convert_bytes_to_hword(bytes)); + return ERR_OK; } -data_t vm_pop_word(vm_t *vm) +err_t vm_pop_word(vm_t *vm, data_t *ret) { if (vm->stack.ptr < WORD_SIZE) - // TODO: Error STACK_UNDERFLOW - return DWORD(0); + return ERR_STACK_UNDERFLOW; byte bytes[WORD_SIZE] = {0}; for (size_t i = 0; i < WORD_SIZE; ++i) { - data_t b = vm_pop_byte(vm); + data_t b = {0}; + vm_pop_byte(vm, &b); bytes[WORD_SIZE - 1 - i] = b.as_byte; } - return DWORD(convert_bytes_to_word(bytes)); + *ret = DWORD(convert_bytes_to_word(bytes)); + return ERR_OK; } -void vm_not_byte(vm_t *vm) +err_t vm_not_byte(vm_t *vm) { - if (vm->stack.ptr == 0) - // TODO: Error STACK_UNDERFLOW - return; - - byte a = vm_pop_byte(vm).as_byte; - vm_push_byte(vm, DBYTE(!a)); + data_t a = {0}; + err_t err = vm_pop_byte(vm, &a); + if (err) + return err; + return vm_push_byte(vm, DBYTE(!a.as_byte)); } -void vm_not_hword(vm_t *vm) +err_t vm_not_hword(vm_t *vm) { - if (vm->stack.ptr < HWORD_SIZE) - // TODO: Error STACK_UNDERFLOW - return; - - hword a = vm_pop_hword(vm).as_hword; - vm_push_hword(vm, DHWORD(!a)); + data_t a = {0}; + err_t err = vm_pop_hword(vm, &a); + if (err) + return err; + return vm_push_hword(vm, DHWORD(!a.as_hword)); } -void vm_not_word(vm_t *vm) +err_t vm_not_word(vm_t *vm) { - if (vm->stack.ptr < WORD_SIZE) - // TODO: Error STACK_UNDERFLOW - return; - - word a = vm_pop_word(vm).as_word; - vm_push_word(vm, DWORD(!a)); + data_t a = {0}; + err_t err = vm_pop_word(vm, &a); + if (err) + return err; + return vm_push_word(vm, DWORD(!a.as_word)); } -void vm_or_byte(vm_t *vm) +err_t vm_or_byte(vm_t *vm) { - if (vm->stack.ptr < 2) - // TODO: Error STACK_UNDERFLOW - return; - byte a = vm_pop_byte(vm).as_byte; - byte b = vm_pop_byte(vm).as_byte; - vm_push_byte(vm, DBYTE(a | b)); + data_t a = {0}, b = {0}; + err_t err = vm_pop_byte(vm, &a); + if (err) + return err; + err = vm_pop_byte(vm, &b); + if (err) + return err; + return vm_push_byte(vm, DBYTE(a.as_byte | b.as_byte)); } -void vm_or_hword(vm_t *vm) +err_t vm_or_hword(vm_t *vm) { - if (vm->stack.ptr < (HWORD_SIZE * 2)) - // TODO: Error STACK_UNDERFLOW - return; - hword a = vm_pop_hword(vm).as_hword; - hword b = vm_pop_hword(vm).as_hword; - vm_push_hword(vm, DHWORD(a | b)); + data_t a = {0}, b = {0}; + err_t err = vm_pop_hword(vm, &a); + if (err) + return err; + err = vm_pop_hword(vm, &b); + if (err) + return err; + return vm_push_hword(vm, DHWORD(a.as_hword | b.as_hword)); } -void vm_or_word(vm_t *vm) +err_t vm_or_word(vm_t *vm) { - if (vm->stack.ptr < (WORD_SIZE * 2)) - // TODO: Error STACK_UNDERFLOW - return; - word a = vm_pop_word(vm).as_word; - word b = vm_pop_word(vm).as_word; - vm_push_word(vm, DWORD(a | b)); + data_t a = {0}, b = {0}; + err_t err = vm_pop_word(vm, &a); + if (err) + return err; + err = vm_pop_word(vm, &b); + if (err) + return err; + return vm_push_word(vm, DWORD(a.as_word | b.as_word)); } -void vm_and_byte(vm_t *vm) +err_t vm_and_byte(vm_t *vm) { - if (vm->stack.ptr < 2) - // TODO: Error STACK_UNDERFLOW - return; - byte a = vm_pop_byte(vm).as_byte; - byte b = vm_pop_byte(vm).as_byte; - vm_push_byte(vm, DBYTE(a & b)); + data_t a = {0}, b = {0}; + err_t err = vm_pop_byte(vm, &a); + if (err) + return err; + err = vm_pop_byte(vm, &b); + if (err) + return err; + return vm_push_byte(vm, DBYTE(a.as_byte & b.as_byte)); } -void vm_and_hword(vm_t *vm) +err_t vm_and_hword(vm_t *vm) { - if (vm->stack.ptr < (HWORD_SIZE * 2)) - // TODO: Error STACK_UNDERFLOW - return; - hword a = vm_pop_hword(vm).as_hword; - hword b = vm_pop_hword(vm).as_hword; - vm_push_hword(vm, DHWORD(a & b)); + data_t a = {0}, b = {0}; + err_t err = vm_pop_hword(vm, &a); + if (err) + return err; + err = vm_pop_hword(vm, &b); + if (err) + return err; + return vm_push_hword(vm, DHWORD(a.as_hword & b.as_hword)); } -void vm_and_word(vm_t *vm) +err_t vm_and_word(vm_t *vm) { - if (vm->stack.ptr < (WORD_SIZE * 2)) - // TODO: Error STACK_UNDERFLOW - return; - word a = vm_pop_word(vm).as_word; - word b = vm_pop_word(vm).as_word; - vm_push_word(vm, DWORD(a & b)); + data_t a = {0}, b = {0}; + err_t err = vm_pop_word(vm, &a); + if (err) + return err; + err = vm_pop_word(vm, &b); + if (err) + return err; + return vm_push_word(vm, DWORD(a.as_word & b.as_word)); } -void vm_xor_byte(vm_t *vm) +err_t vm_xor_byte(vm_t *vm) { - if (vm->stack.ptr < 2) - // TODO: Error STACK_UNDERFLOW - return; - byte a = vm_pop_byte(vm).as_byte; - byte b = vm_pop_byte(vm).as_byte; - vm_push_byte(vm, DBYTE(a ^ b)); + data_t a = {0}, b = {0}; + err_t err = vm_pop_byte(vm, &a); + if (err) + return err; + err = vm_pop_byte(vm, &b); + if (err) + return err; + return vm_push_byte(vm, DBYTE(a.as_byte ^ b.as_byte)); } -void vm_xor_hword(vm_t *vm) +err_t vm_xor_hword(vm_t *vm) { - if (vm->stack.ptr < (HWORD_SIZE * 2)) - // TODO: Error STACK_UNDERFLOW - return; - hword a = vm_pop_hword(vm).as_hword; - hword b = vm_pop_hword(vm).as_hword; - vm_push_hword(vm, DHWORD(a ^ b)); -} + data_t a = {0}, b = {0}; + err_t err = vm_pop_hword(vm, &a); + if (err) + return err; + err = vm_pop_hword(vm, &b); + if (err) + return err; + return vm_push_hword(vm, DHWORD(a.as_hword ^ b.as_hword)); +} -void vm_xor_word(vm_t *vm) +err_t vm_xor_word(vm_t *vm) { - if (vm->stack.ptr < (WORD_SIZE * 2)) - // TODO: Error STACK_UNDERFLOW - return; - word a = vm_pop_word(vm).as_word; - word b = vm_pop_word(vm).as_word; - vm_push_word(vm, DWORD(a ^ b)); -} + data_t a = {0}, b = {0}; + err_t err = vm_pop_word(vm, &a); + if (err) + return err; + err = vm_pop_word(vm, &b); + if (err) + return err; + return vm_push_word(vm, DWORD(a.as_word ^ b.as_word)); +} -void vm_eq_byte(vm_t *vm) +err_t vm_eq_byte(vm_t *vm) { - if (vm->stack.ptr < 2) - // TODO: Error STACK_UNDERFLOW - return; - byte a = vm_pop_byte(vm).as_byte; - byte b = vm_pop_byte(vm).as_byte; - vm_push_byte(vm, DBYTE(a == b)); -} + data_t a = {0}, b = {0}; + err_t err = vm_pop_byte(vm, &a); + if (err) + return err; + err = vm_pop_byte(vm, &b); + if (err) + return err; + return vm_push_byte(vm, DBYTE(a.as_byte == b.as_byte)); +} -void vm_eq_hword(vm_t *vm) +err_t vm_eq_hword(vm_t *vm) { - if (vm->stack.ptr < (HWORD_SIZE * 2)) - // TODO: Error STACK_UNDERFLOW - return; - hword a = vm_pop_hword(vm).as_hword; - hword b = vm_pop_hword(vm).as_hword; - vm_push_hword(vm, DHWORD(a == b)); -} + data_t a = {0}, b = {0}; + err_t err = vm_pop_hword(vm, &a); + if (err) + return err; + err = vm_pop_hword(vm, &b); + if (err) + return err; + return vm_push_hword(vm, DHWORD(a.as_hword == b.as_hword)); +} -void vm_eq_word(vm_t *vm) +err_t vm_eq_word(vm_t *vm) { - if (vm->stack.ptr < (WORD_SIZE * 2)) - // TODO: Error STACK_UNDERFLOW - return; - word a = vm_pop_word(vm).as_word; - word b = vm_pop_word(vm).as_word; - vm_push_word(vm, DWORD(a == b)); + data_t a = {0}, b = {0}; + err_t err = vm_pop_word(vm, &a); + if (err) + return err; + err = vm_pop_word(vm, &b); + if (err) + return err; + return vm_push_word(vm, DWORD(a.as_word == b.as_word)); } diff --git a/src/runtime.h b/src/runtime.h index 2ed0ee4..cba9728 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -19,6 +19,21 @@ #include "./base.h" #include "./inst.h" +typedef enum +{ + ERR_OK = 0, + ERR_STACK_UNDERFLOW, + ERR_STACK_OVERFLOW, + ERR_INVALID_OPCODE, + ERR_INVALID_REGISTER_BYTE, + ERR_INVALID_REGISTER_HWORD, + ERR_INVALID_REGISTER_WORD, + ERR_INVALID_PROGRAM_ADDRESS, + ERR_END_OF_PROGRAM, +} err_t; + +const char *err_as_cstr(err_t); + #define VM_REGISTERS 8 typedef struct { @@ -42,8 +57,8 @@ typedef struct #define VM_REG_HWORD(REG) ((REG)&0b11111111111111111111111111111111) #define VM_REG_WORD(REG) ((REG)) -void vm_execute(vm_t *); -void vm_execute_all(vm_t *); +err_t vm_execute(vm_t *); +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); @@ -58,99 +73,99 @@ 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); +err_t vm_push_byte(vm_t *, data_t); +err_t vm_push_hword(vm_t *, data_t); +err_t vm_push_word(vm_t *, data_t); -typedef void (*push_f)(vm_t *, data_t); +typedef err_t (*push_f)(vm_t *, data_t); static const push_f PUSH_ROUTINES[] = { [OP_PUSH_BYTE] = vm_push_byte, [OP_PUSH_HWORD] = vm_push_hword, [OP_PUSH_WORD] = vm_push_word, }; -void vm_push_byte_register(vm_t *, byte); -void vm_push_hword_register(vm_t *, byte); -void vm_push_word_register(vm_t *, byte); +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); -typedef void (*push_reg_f)(vm_t *, byte); +typedef err_t (*push_reg_f)(vm_t *, byte); static const push_reg_f PUSH_REG_ROUTINES[] = { [OP_PUSH_REGISTER_BYTE] = vm_push_byte_register, [OP_PUSH_REGISTER_HWORD] = vm_push_hword_register, [OP_PUSH_REGISTER_WORD] = vm_push_word_register, }; -data_t vm_pop_byte(vm_t *); -data_t vm_pop_hword(vm_t *); -data_t vm_pop_word(vm_t *); +err_t vm_pop_byte(vm_t *, data_t *); +err_t vm_pop_hword(vm_t *, data_t *); +err_t vm_pop_word(vm_t *, data_t *); -data_t vm_mov_byte(vm_t *, byte); -data_t vm_mov_hword(vm_t *, byte); -data_t vm_mov_word(vm_t *, byte); +err_t vm_mov_byte(vm_t *, byte); +err_t vm_mov_hword(vm_t *, byte); +err_t vm_mov_word(vm_t *, byte); -typedef data_t (*mov_f)(vm_t *, byte); +typedef err_t (*mov_f)(vm_t *, byte); static const mov_f MOV_ROUTINES[] = { [OP_MOV_BYTE] = vm_mov_byte, [OP_MOV_HWORD] = vm_mov_hword, [OP_MOV_WORD] = vm_mov_word, }; -void vm_dup_byte(vm_t *, word); -void vm_dup_hword(vm_t *, word); -void vm_dup_word(vm_t *, word); +err_t vm_dup_byte(vm_t *, word); +err_t vm_dup_hword(vm_t *, word); +err_t vm_dup_word(vm_t *, word); -typedef void (*dup_f)(vm_t *, word); +typedef err_t (*dup_f)(vm_t *, word); static const dup_f DUP_ROUTINES[] = { [OP_DUP_BYTE] = vm_dup_byte, [OP_DUP_HWORD] = vm_dup_hword, [OP_DUP_WORD] = vm_dup_word, }; -void vm_not_byte(vm_t *); -void vm_not_hword(vm_t *); -void vm_not_word(vm_t *); +err_t vm_not_byte(vm_t *); +err_t vm_not_hword(vm_t *); +err_t vm_not_word(vm_t *); -typedef void (*not_f)(vm_t *); +typedef err_t (*not_f)(vm_t *); static const not_f NOT_ROUTINES[] = { [OP_NOT_BYTE] = vm_not_byte, [OP_NOT_HWORD] = vm_not_hword, [OP_NOT_WORD] = vm_not_word, }; -void vm_or_byte(vm_t *); -void vm_or_hword(vm_t *); -void vm_or_word(vm_t *); -typedef void (*or_f)(vm_t *); +err_t vm_or_byte(vm_t *); +err_t vm_or_hword(vm_t *); +err_t vm_or_word(vm_t *); +typedef err_t (*or_f)(vm_t *); static const or_f OR_ROUTINES[] = { [OP_OR_BYTE] = vm_or_byte, [OP_OR_HWORD] = vm_or_hword, [OP_OR_WORD] = vm_or_word, }; -void vm_and_byte(vm_t *); -void vm_and_hword(vm_t *); -void vm_and_word(vm_t *); -typedef void (*and_f)(vm_t *); +err_t vm_and_byte(vm_t *); +err_t vm_and_hword(vm_t *); +err_t vm_and_word(vm_t *); +typedef err_t (*and_f)(vm_t *); static const and_f AND_ROUTINES[] = { [OP_AND_BYTE] = vm_and_byte, [OP_AND_HWORD] = vm_and_hword, [OP_AND_WORD] = vm_and_word, }; -void vm_xor_byte(vm_t *); -void vm_xor_hword(vm_t *); -void vm_xor_word(vm_t *); -typedef void (*xor_f)(vm_t *); +err_t vm_xor_byte(vm_t *); +err_t vm_xor_hword(vm_t *); +err_t vm_xor_word(vm_t *); +typedef err_t (*xor_f)(vm_t *); static const xor_f XOR_ROUTINES[] = { [OP_XOR_BYTE] = vm_xor_byte, [OP_XOR_HWORD] = vm_xor_hword, [OP_XOR_WORD] = vm_xor_word, }; -void vm_eq_byte(vm_t *); -void vm_eq_hword(vm_t *); -void vm_eq_word(vm_t *); -typedef void (*eq_f)(vm_t *); +err_t vm_eq_byte(vm_t *); +err_t vm_eq_hword(vm_t *); +err_t vm_eq_word(vm_t *); +typedef err_t (*eq_f)(vm_t *); static const eq_f EQ_ROUTINES[] = { [OP_EQ_BYTE] = vm_eq_byte, [OP_EQ_HWORD] = vm_eq_hword, |