aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAryadev Chavali <aryadev@aryadevchavali.com>2023-10-22 21:31:52 +0100
committerAryadev Chavali <aryadev@aryadevchavali.com>2023-10-22 21:45:38 +0100
commitcc847037257b61f06817abdf05ab6657f589ca22 (patch)
tree42f9b09671278b70c8fbb6f8e60fc540c7ae2b65
parent7f1994c7aa1e3f18bc8baf7cb37f9fe093c884eb (diff)
downloadovm-cc847037257b61f06817abdf05ab6657f589ca22.tar.gz
ovm-cc847037257b61f06817abdf05ab6657f589ca22.tar.bz2
ovm-cc847037257b61f06817abdf05ab6657f589ca22.zip
Added runtime errors to virtual machine
Every vm routine now returns an err_t, which is an enumeration of possible error states. ERR_OK represents the good state and is 0 so error checking seems very natural in terms of language `if (err) ...`. Errors bubble up the runtime, with any callers forced to check if an error occurred. This does mean that routines that call other routines cannot provide an accurate trace of the subcaller (based on the fact that an error is generated for the current instruction), but this should be a non issue as no instruction should be complex enough to need proper traces.
-rw-r--r--src/runtime.c496
-rw-r--r--src/runtime.h97
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,