X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=interpreters%2Fglulxe%2Fvm.c;fp=interpreters%2Fglulxe%2Fvm.c;h=4a113f50a019be9a606c37b6f7f4a633ea54e41b;hb=147a8cbf17f2b3379277bf7d37cda9866510f16c;hp=0000000000000000000000000000000000000000;hpb=7de488aa6a1709a4d5c59b5ff59862105c1748c5;p=rodin%2Fchimara.git diff --git a/interpreters/glulxe/vm.c b/interpreters/glulxe/vm.c new file mode 100644 index 0000000..4a113f5 --- /dev/null +++ b/interpreters/glulxe/vm.c @@ -0,0 +1,303 @@ +/* vm.c: Glulxe code related to the VM overall. Also miscellaneous stuff. + Designed by Andrew Plotkin + http://eblong.com/zarf/glulx/index.html +*/ + +#include "glk.h" +#include "glulxe.h" + +/* The memory blocks which contain VM main memory and the stack. */ +unsigned char *memmap = NULL; +unsigned char *stack = NULL; + +/* Various memory addresses which are useful. These are loaded in from + the game file header. */ +glui32 ramstart; +glui32 endgamefile; +glui32 origendmem; +glui32 stacksize; +glui32 startfuncaddr; +glui32 origstringtable; +glui32 checksum; + +/* The VM registers. */ +glui32 stackptr; +glui32 frameptr; +glui32 pc; +glui32 stringtable; +glui32 valstackbase; +glui32 localsbase; +glui32 endmem; +glui32 protectstart, protectend; + +void (*stream_char_handler)(unsigned char ch); +void (*stream_unichar_handler)(glui32 ch); + +/* setup_vm(): + Read in the game file and build the machine, allocating all the memory + necessary. +*/ +void setup_vm() +{ + unsigned char buf[4 * 7]; + int res; + + pc = 0; /* Clear this, so that error messages are cleaner. */ + + /* Read in all the size constants from the game file header. */ + + stream_char_handler = NULL; + stream_unichar_handler = NULL; + + glk_stream_set_position(gamefile, gamefile_start+8, seekmode_Start); + res = glk_get_buffer_stream(gamefile, (char *)buf, 4 * 7); + + ramstart = Read4(buf+0); + endgamefile = Read4(buf+4); + origendmem = Read4(buf+8); + stacksize = Read4(buf+12); + startfuncaddr = Read4(buf+16); + origstringtable = Read4(buf+20); + checksum = Read4(buf+24); + + /* Set the protection range to (0, 0), meaning "off". */ + protectstart = 0; + protectend = 0; + + /* Do a few sanity checks. */ + + if ((ramstart & 0xFF) + || (endgamefile & 0xFF) + || (origendmem & 0xFF) + || (stacksize & 0xFF)) { + nonfatal_warning("One of the segment boundaries in the header is not " + "256-byte aligned."); + } + + if (ramstart < 0x100 || endgamefile < ramstart || origendmem < endgamefile) { + fatal_error("The segment boundaries in the header are in an impossible " + "order."); + } + if (stacksize < 0x100) { + fatal_error("The stack size in the header is too small."); + } + + /* Allocate main memory and the stack. This is where memory allocation + errors are most likely to occur. */ + endmem = origendmem; + memmap = (unsigned char *)glulx_malloc(origendmem); + if (!memmap) { + fatal_error("Unable to allocate Glulx memory space."); + } + stack = (unsigned char *)glulx_malloc(stacksize); + if (!stack) { + glulx_free(memmap); + memmap = NULL; + fatal_error("Unable to allocate Glulx stack space."); + } + stringtable = 0; + + /* Initialize various other things in the terp. */ + init_operands(); + init_accel(); + init_serial(); + + /* Set up the initial machine state. */ + vm_restart(); +} + +/* finalize_vm(): + Deallocate all the memory and shut down the machine. +*/ +void finalize_vm() +{ + if (memmap) { + glulx_free(memmap); + memmap = NULL; + } + if (stack) { + glulx_free(stack); + stack = NULL; + } +} + +/* vm_restart(): + Put the VM into a state where it's ready to begin executing the + game. This is called both at startup time, and when the machine + performs a "restart" opcode. +*/ +void vm_restart() +{ + glui32 lx; + int res; + + /* Deactivate the heap (if it was active). */ + heap_clear(); + + /* Reset memory to the original size. */ + lx = change_memsize(origendmem, FALSE); + if (lx) + fatal_error("Memory could not be reset to its original size."); + + /* Load in all of main memory */ + glk_stream_set_position(gamefile, gamefile_start, seekmode_Start); + for (lx=0; lx= protectstart && lx < protectend) + continue; + memmap[lx] = res; + } + for (lx=endgamefile; lx endmem) { + for (lx=endmem; lx= count) { + /* It fits. */ + array = dynarray; + } + else { + dynarray_size = count+8; + dynarray = glulx_realloc(dynarray, sizeof(glui32) * dynarray_size); + if (!dynarray) + fatal_error("Unable to reallocate function arguments."); + array = dynarray; + } + } + } + + if (!addr) { + if (stackptr < valstackbase+4*count) + fatal_error("Stack underflow in arguments."); + stackptr -= 4*count; + for (ix=0; ix= endmem) + fatal_error_i("Memory access out of range", addr); + if (count > 1) { + addr += (count-1); + if (addr >= endmem) + fatal_error_i("Memory access out of range", addr); + } +} +