From be312cfbbf6daf28c7a99464f2f59bd0c1dd355e Mon Sep 17 00:00:00 2001 From: Aryadev Chavali Date: Wed, 1 Nov 2023 21:17:33 +0000 Subject: 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. --- vm/runtime.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- vm/runtime.h | 28 +++++++++++- 2 files changed, 167 insertions(+), 5 deletions(-) (limited to 'vm') diff --git a/vm/runtime.c b/vm/runtime.c index ce8281a..953470c 100644 --- a/vm/runtime.c +++ b/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) \ { \ diff --git a/vm/runtime.h b/vm/runtime.h index c4d28d8..9ac1b47 100644 --- a/vm/runtime.h +++ b/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, -- cgit v1.2.3-13-gbd6f