Implemented instructions in the runtime for memory management
Pretty simple, required some new types of errors. Obviously there's space for a macro for the differing instruction implementations, but these things need to be tested a bit more before I can do that.
This commit is contained in:
144
vm/runtime.c
144
vm/runtime.c
@@ -46,6 +46,10 @@ const char *err_as_cstr(err_t err)
|
||||
break;
|
||||
case ERR_INVALID_PROGRAM_ADDRESS:
|
||||
return "INVALID_PROGRAM_ADDRESS";
|
||||
case ERR_INVALID_PAGE_ADDRESS:
|
||||
return "INVALID_PAGE_ADDRESS";
|
||||
case ERR_OUT_OF_BOUNDS:
|
||||
return "OUT_OF_BOUNDS";
|
||||
case ERR_END_OF_PROGRAM:
|
||||
return "END_OF_PROGRAM";
|
||||
break;
|
||||
@@ -56,7 +60,7 @@ const char *err_as_cstr(err_t err)
|
||||
|
||||
err_t vm_execute(vm_t *vm)
|
||||
{
|
||||
static_assert(NUMBER_OF_OPCODES == 73, "vm_execute: Out of date");
|
||||
static_assert(NUMBER_OF_OPCODES == 83, "vm_execute: Out of date");
|
||||
struct Program *prog = &vm->program;
|
||||
if (prog->ptr >= prog->max)
|
||||
return ERR_END_OF_PROGRAM;
|
||||
@@ -69,7 +73,10 @@ err_t vm_execute(vm_t *vm)
|
||||
}
|
||||
else if (OPCODE_IS_TYPE(instruction.opcode, OP_MOV) ||
|
||||
OPCODE_IS_TYPE(instruction.opcode, OP_PUSH_REGISTER) ||
|
||||
OPCODE_IS_TYPE(instruction.opcode, OP_DUP))
|
||||
OPCODE_IS_TYPE(instruction.opcode, OP_DUP) ||
|
||||
OPCODE_IS_TYPE(instruction.opcode, OP_MALLOC) ||
|
||||
OPCODE_IS_TYPE(instruction.opcode, OP_MSET) ||
|
||||
OPCODE_IS_TYPE(instruction.opcode, OP_MGET))
|
||||
{
|
||||
prog->ptr++;
|
||||
return WORD_ROUTINES[instruction.opcode](vm, instruction.operand.as_word);
|
||||
@@ -105,7 +112,8 @@ err_t vm_execute(vm_t *vm)
|
||||
OPCODE_IS_TYPE(instruction.opcode, OP_GT) ||
|
||||
OPCODE_IS_TYPE(instruction.opcode, OP_GTE) ||
|
||||
OPCODE_IS_TYPE(instruction.opcode, OP_PLUS) ||
|
||||
OPCODE_IS_TYPE(instruction.opcode, OP_MULT))
|
||||
OPCODE_IS_TYPE(instruction.opcode, OP_MULT) ||
|
||||
instruction.opcode == OP_MDELETE)
|
||||
{
|
||||
prog->ptr++;
|
||||
return STACK_ROUTINES[instruction.opcode](vm);
|
||||
@@ -593,6 +601,123 @@ err_t vm_dup_word(vm_t *vm, word w)
|
||||
return vm_push_word(vm, DWORD(convert_bytes_to_word(bytes)));
|
||||
}
|
||||
|
||||
err_t vm_malloc_byte(vm_t *vm, word n)
|
||||
{
|
||||
page_t *page = heap_allocate(&vm->heap, n);
|
||||
return vm_push_word(vm, DWORD((word)page));
|
||||
}
|
||||
|
||||
err_t vm_malloc_hword(vm_t *vm, word n)
|
||||
{
|
||||
page_t *page = heap_allocate(&vm->heap, n * HWORD_SIZE);
|
||||
return vm_push_word(vm, DWORD((word)page));
|
||||
}
|
||||
|
||||
err_t vm_malloc_word(vm_t *vm, word n)
|
||||
{
|
||||
page_t *page = heap_allocate(&vm->heap, n * WORD_SIZE);
|
||||
return vm_push_word(vm, DWORD((word)page));
|
||||
}
|
||||
|
||||
err_t vm_mset_byte(vm_t *vm, word nth)
|
||||
{
|
||||
// Stack layout should be [BYTE, PTR]
|
||||
data_t byte = {0};
|
||||
err_t err = vm_pop_byte(vm, &byte);
|
||||
if (err)
|
||||
return err;
|
||||
data_t ptr = {0};
|
||||
err = vm_pop_word(vm, &ptr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
page_t *page = (page_t *)ptr.as_word;
|
||||
if (nth >= page->available)
|
||||
return ERR_OUT_OF_BOUNDS;
|
||||
page->data[nth] = byte.as_byte;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
err_t vm_mset_hword(vm_t *vm, word nth)
|
||||
{
|
||||
// Stack layout should be [HWORD, PTR]
|
||||
data_t byte = {0};
|
||||
err_t err = vm_pop_hword(vm, &byte);
|
||||
if (err)
|
||||
return err;
|
||||
data_t ptr = {0};
|
||||
err = vm_pop_word(vm, &ptr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
page_t *page = (page_t *)ptr.as_word;
|
||||
if (nth >= (page->available / HWORD_SIZE))
|
||||
return ERR_OUT_OF_BOUNDS;
|
||||
((hword *)page->data)[nth] = byte.as_hword;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
err_t vm_mset_word(vm_t *vm, word nth)
|
||||
{
|
||||
// Stack layout should be [WORD, PTR]
|
||||
data_t byte = {0};
|
||||
err_t err = vm_pop_word(vm, &byte);
|
||||
if (err)
|
||||
return err;
|
||||
data_t ptr = {0};
|
||||
err = vm_pop_word(vm, &ptr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
page_t *page = (page_t *)ptr.as_word;
|
||||
if (nth >= (page->available / WORD_SIZE))
|
||||
return ERR_OUT_OF_BOUNDS;
|
||||
((word *)page->data)[nth] = byte.as_hword;
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
err_t vm_mget_byte(vm_t *vm, word n)
|
||||
{
|
||||
// Stack layout should be [PTR]
|
||||
data_t ptr = {0};
|
||||
err_t err = vm_pop_word(vm, &ptr);
|
||||
if (err)
|
||||
return err;
|
||||
page_t *page = (page_t *)ptr.as_word;
|
||||
if (n >= page->available)
|
||||
return ERR_OUT_OF_BOUNDS;
|
||||
return vm_push_byte(vm, DBYTE(page->data[n]));
|
||||
}
|
||||
|
||||
err_t vm_mget_hword(vm_t *vm, word n)
|
||||
{
|
||||
// Stack layout should be [PTR]
|
||||
data_t ptr = {0};
|
||||
err_t err = vm_pop_word(vm, &ptr);
|
||||
if (err)
|
||||
return err;
|
||||
page_t *page = (page_t *)ptr.as_word;
|
||||
if (n >= (page->available / HWORD_SIZE))
|
||||
return ERR_OUT_OF_BOUNDS;
|
||||
return vm_push_byte(vm, DHWORD(((hword *)page->data)[n]));
|
||||
}
|
||||
|
||||
err_t vm_mget_word(vm_t *vm, word n)
|
||||
{
|
||||
// Stack layout should be [PTR]
|
||||
data_t ptr = {0};
|
||||
err_t err = vm_pop_word(vm, &ptr);
|
||||
if (err)
|
||||
return err;
|
||||
page_t *page = (page_t *)ptr.as_word;
|
||||
if (n >= (page->available / WORD_SIZE))
|
||||
return ERR_OUT_OF_BOUNDS;
|
||||
return vm_push_byte(vm, DHWORD(((word *)page->data)[n]));
|
||||
}
|
||||
|
||||
err_t vm_pop_byte(vm_t *vm, data_t *ret)
|
||||
{
|
||||
if (vm->stack.ptr == 0)
|
||||
@@ -631,6 +756,19 @@ err_t vm_pop_word(vm_t *vm, data_t *ret)
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
err_t vm_mdelete(vm_t *vm)
|
||||
{
|
||||
data_t ptr = {0};
|
||||
err_t err = vm_pop_word(vm, &ptr);
|
||||
if (err)
|
||||
return err;
|
||||
page_t *page = (page_t *)ptr.as_word;
|
||||
bool done = heap_free_page(&vm->heap, page);
|
||||
if (!done)
|
||||
return ERR_INVALID_PAGE_ADDRESS;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
#define VM_NOT_TYPE(TYPEL, TYPEU) \
|
||||
err_t vm_not_##TYPEL(vm_t *vm) \
|
||||
{ \
|
||||
|
||||
28
vm/runtime.h
28
vm/runtime.h
@@ -29,6 +29,8 @@ typedef enum
|
||||
ERR_INVALID_REGISTER_HWORD,
|
||||
ERR_INVALID_REGISTER_WORD,
|
||||
ERR_INVALID_PROGRAM_ADDRESS,
|
||||
ERR_INVALID_PAGE_ADDRESS,
|
||||
ERR_OUT_OF_BOUNDS,
|
||||
ERR_END_OF_PROGRAM,
|
||||
} err_t;
|
||||
|
||||
@@ -100,6 +102,18 @@ err_t vm_dup_byte(vm_t *, word);
|
||||
err_t vm_dup_hword(vm_t *, word);
|
||||
err_t vm_dup_word(vm_t *, word);
|
||||
|
||||
err_t vm_malloc_byte(vm_t *, word);
|
||||
err_t vm_malloc_hword(vm_t *, word);
|
||||
err_t vm_malloc_word(vm_t *, word);
|
||||
|
||||
err_t vm_mset_byte(vm_t *, word);
|
||||
err_t vm_mset_hword(vm_t *, word);
|
||||
err_t vm_mset_word(vm_t *, word);
|
||||
|
||||
err_t vm_mget_byte(vm_t *, word);
|
||||
err_t vm_mget_hword(vm_t *, word);
|
||||
err_t vm_mget_word(vm_t *, word);
|
||||
|
||||
typedef err_t (*word_f)(vm_t *, word);
|
||||
static const word_f WORD_ROUTINES[] = {
|
||||
[OP_PUSH_REGISTER_BYTE] = vm_push_byte_register,
|
||||
@@ -111,8 +125,18 @@ static const word_f WORD_ROUTINES[] = {
|
||||
[OP_DUP_BYTE] = vm_dup_byte,
|
||||
[OP_DUP_HWORD] = vm_dup_hword,
|
||||
[OP_DUP_WORD] = vm_dup_word,
|
||||
[OP_MALLOC_BYTE] = vm_malloc_byte,
|
||||
[OP_MALLOC_HWORD] = vm_malloc_hword,
|
||||
[OP_MALLOC_WORD] = vm_malloc_word,
|
||||
[OP_MGET_BYTE] = vm_mget_byte,
|
||||
[OP_MGET_HWORD] = vm_mget_hword,
|
||||
[OP_MGET_WORD] = vm_mget_word,
|
||||
[OP_MSET_BYTE] = vm_mset_byte,
|
||||
[OP_MSET_HWORD] = vm_mset_hword,
|
||||
[OP_MSET_WORD] = vm_mset_word,
|
||||
};
|
||||
|
||||
err_t vm_mdelete(vm_t *);
|
||||
|
||||
err_t vm_not_byte(vm_t *);
|
||||
err_t vm_not_hword(vm_t *);
|
||||
@@ -175,8 +199,8 @@ err_t vm_mult_word(vm_t *);
|
||||
|
||||
typedef err_t (*stack_f)(vm_t *);
|
||||
static const stack_f STACK_ROUTINES[] = {
|
||||
[OP_NOT_BYTE] = vm_not_byte, [OP_NOT_HWORD] = vm_not_hword,
|
||||
[OP_NOT_WORD] = vm_not_word,
|
||||
[OP_MDELETE] = vm_mdelete, [OP_NOT_BYTE] = vm_not_byte,
|
||||
[OP_NOT_HWORD] = vm_not_hword, [OP_NOT_WORD] = vm_not_word,
|
||||
|
||||
[OP_OR_BYTE] = vm_or_byte, [OP_OR_HWORD] = vm_or_hword,
|
||||
[OP_OR_WORD] = vm_or_word,
|
||||
|
||||
Reference in New Issue
Block a user