diff options
Diffstat (limited to 'engines/glk/glulxe/vm.cpp')
-rw-r--r-- | engines/glk/glulxe/vm.cpp | 508 |
1 files changed, 252 insertions, 256 deletions
diff --git a/engines/glk/glulxe/vm.cpp b/engines/glk/glulxe/vm.cpp index 194152ad65..44ea106e69 100644 --- a/engines/glk/glulxe/vm.cpp +++ b/engines/glk/glulxe/vm.cpp @@ -26,295 +26,291 @@ namespace Glk { namespace Glulxe { void Glulxe::setup_vm() { - byte buf[4 * 7]; - - pc = 0; // Clear this, so that error messages are cleaner. - prevpc = 0; - - // Read in all the size constants from the game file header - stream_char_handler = nullptr; - stream_unichar_handler = nullptr; - - _gameFile.seek(0); - if (_gameFile.read(buf, 4 * 7) != (4 * 7)) - fatal_error("The game file header is too short."); - - 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 (endgamefile != gamefile_len) { - nonfatal_warning("The gamefile length does not match the header " - "endgamefile length."); - } - - 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 = (byte *)glulx_malloc(origendmem); - if (!memmap) { - fatal_error("Unable to allocate Glulx memory space."); - } - stack = (byte *)glulx_malloc(stacksize); - if (!stack) { - glulx_free(memmap); - memmap = nullptr; - fatal_error("Unable to allocate Glulx stack space."); - } - stringtable = 0; - - // Initialize various other things in the terp. - init_operands(); - init_serial(); - - // Set up the initial machine state. - vm_restart(); - - /* If the debugger is compiled in, check that the debug data matches - the game. (This only prints warnings for mismatch.) */ - debugger_check_story_file(); - - /* Also, set up any start-time debugger state. This may do a block- - and-debug, if the user has requested that. */ - debugger_setup_start_state(); + byte buf[4 * 7]; + + pc = 0; // Clear this, so that error messages are cleaner. + prevpc = 0; + + // Read in all the size constants from the game file header + stream_char_handler = nullptr; + stream_unichar_handler = nullptr; + + _gameFile.seek(0); + if (_gameFile.read(buf, 4 * 7) != (4 * 7)) + fatal_error("The game file header is too short."); + + 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 (endgamefile != gamefile_len) { + nonfatal_warning("The gamefile length does not match the header " + "endgamefile length."); + } + + 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 = (byte *)glulx_malloc(origendmem); + if (!memmap) { + fatal_error("Unable to allocate Glulx memory space."); + } + stack = (byte *)glulx_malloc(stacksize); + if (!stack) { + glulx_free(memmap); + memmap = nullptr; + fatal_error("Unable to allocate Glulx stack space."); + } + stringtable = 0; + + // Initialize various other things in the terp. + init_operands(); + init_serial(); + + // Set up the initial machine state. + vm_restart(); + + /* If the debugger is compiled in, check that the debug data matches + the game. (This only prints warnings for mismatch.) */ + debugger_check_story_file(); + + /* Also, set up any start-time debugger state. This may do a block- + and-debug, if the user has requested that. */ + debugger_setup_start_state(); } void Glulxe::finalize_vm() { - stream_set_table(0); - - if (memmap) { - glulx_free(memmap); - memmap = nullptr; - } - if (stack) { - glulx_free(stack); - stack = nullptr; - } - - final_serial(); + stream_set_table(0); + + if (memmap) { + glulx_free(memmap); + memmap = nullptr; + } + if (stack) { + glulx_free(stack); + stack = nullptr; + } + + final_serial(); } void Glulxe::vm_restart() { - uint lx; - int res; - int bufpos; - char buf[0x100]; - - /* 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. We do this in 256-byte chunks, because - why rely on OS stream buffering? */ - _gameFile.seek(gamefile_start); - bufpos = 0x100; - - for (lx=0; lx<endgamefile; lx++) { - if (bufpos >= 0x100) { - int count = _gameFile.read(buf, 0x100); - if (count != 0x100) { - fatal_error("The game file ended unexpectedly."); - } - bufpos = 0; - } - - res = buf[bufpos++]; - if (lx >= protectstart && lx < protectend) - continue; - memmap[lx] = res; - } - for (lx=endgamefile; lx<origendmem; lx++) { - memmap[lx] = 0; - } - - /* Reset all the registers */ - stackptr = 0; - frameptr = 0; - pc = 0; - prevpc = 0; - stream_set_iosys(0, 0); - stream_set_table(origstringtable); - valstackbase = 0; - localsbase = 0; - - /* Note that we do not reset the protection range. */ - - /* Push the first function call. (No arguments.) */ - enter_function(startfuncaddr, 0, nullptr); - - /* We're now ready to execute. */ + uint lx; + int res; + int bufpos; + char buf[0x100]; + + /* 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. We do this in 256-byte chunks, because + why rely on OS stream buffering? */ + _gameFile.seek(gamefile_start); + bufpos = 0x100; + + for (lx = 0; lx < endgamefile; lx++) { + if (bufpos >= 0x100) { + int count = _gameFile.read(buf, 0x100); + if (count != 0x100) { + fatal_error("The game file ended unexpectedly."); + } + bufpos = 0; + } + + res = buf[bufpos++]; + if (lx >= protectstart && lx < protectend) + continue; + memmap[lx] = res; + } + for (lx = endgamefile; lx < origendmem; lx++) { + memmap[lx] = 0; + } + + /* Reset all the registers */ + stackptr = 0; + frameptr = 0; + pc = 0; + prevpc = 0; + stream_set_iosys(0, 0); + stream_set_table(origstringtable); + valstackbase = 0; + localsbase = 0; + + /* Note that we do not reset the protection range. */ + + /* Push the first function call. (No arguments.) */ + enter_function(startfuncaddr, 0, nullptr); + + /* We're now ready to execute. */ } uint Glulxe::change_memsize(uint newlen, bool internal) { - uint lx; - unsigned char *newmemmap; + uint lx; + unsigned char *newmemmap; - if (newlen == endmem) - return 0; + if (newlen == endmem) + return 0; #ifdef FIXED_MEMSIZE - return 1; + return 1; #else /* FIXED_MEMSIZE */ - if ((!internal) && heap_is_active()) - fatal_error("Cannot resize Glulx memory space while heap is active."); + if ((!internal) && heap_is_active()) + fatal_error("Cannot resize Glulx memory space while heap is active."); - if (newlen < origendmem) - fatal_error("Cannot resize Glulx memory space smaller than it started."); + if (newlen < origendmem) + fatal_error("Cannot resize Glulx memory space smaller than it started."); - if (newlen & 0xFF) - fatal_error("Can only resize Glulx memory space to a 256-byte boundary."); - - newmemmap = (unsigned char *)glulx_realloc(memmap, newlen); - if (!newmemmap) { - /* The old block is still in place, unchanged. */ - return 1; - } - memmap = newmemmap; + if (newlen & 0xFF) + fatal_error("Can only resize Glulx memory space to a 256-byte boundary."); - if (newlen > endmem) { - for (lx=endmem; lx<newlen; lx++) { - memmap[lx] = 0; - } - } + newmemmap = (unsigned char *)glulx_realloc(memmap, newlen); + if (!newmemmap) { + /* The old block is still in place, unchanged. */ + return 1; + } + memmap = newmemmap; - endmem = newlen; + if (newlen > endmem) { + for (lx = endmem; lx < newlen; lx++) { + memmap[lx] = 0; + } + } - return 0; + endmem = newlen; + + return 0; #endif /* FIXED_MEMSIZE */ } uint *Glulxe::pop_arguments(uint count, uint addr) { - uint ix; - uint argptr; - uint *array; - - #define MAXARGS (32) - static uint statarray[MAXARGS]; - static uint *dynarray = nullptr; - static uint dynarray_size = 0; - - if (count == 0) - return nullptr; - - if (count <= MAXARGS) { - /* Store in the static array. */ - array = statarray; - } - else { - if (!dynarray) { - dynarray_size = count+8; - dynarray = (uint *)glulx_malloc(sizeof(uint) * dynarray_size); - if (!dynarray) - fatal_error("Unable to allocate function arguments."); - array = dynarray; - } - else { - if (dynarray_size >= count) { - /* It fits. */ - array = dynarray; - } - else { - dynarray_size = count+8; - dynarray = (uint *)glulx_realloc(dynarray, sizeof(uint) * 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<count; ix++) { - argptr = stackptr+4*((count-1)-ix); - array[ix] = Stk4(argptr); - } - } - else { - for (ix=0; ix<count; ix++) { - array[ix] = Mem4(addr); - addr += 4; - } - } - - return array; + uint ix; + uint argptr; + uint *array; + +#define MAXARGS (32) + static uint statarray[MAXARGS]; + static uint *dynarray = nullptr; + static uint dynarray_size = 0; + + if (count == 0) + return nullptr; + + if (count <= MAXARGS) { + /* Store in the static array. */ + array = statarray; + } else { + if (!dynarray) { + dynarray_size = count + 8; + dynarray = (uint *)glulx_malloc(sizeof(uint) * dynarray_size); + if (!dynarray) + fatal_error("Unable to allocate function arguments."); + array = dynarray; + } else { + if (dynarray_size >= count) { + /* It fits. */ + array = dynarray; + } else { + dynarray_size = count + 8; + dynarray = (uint *)glulx_realloc(dynarray, sizeof(uint) * 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 < count; ix++) { + argptr = stackptr + 4 * ((count - 1) - ix); + array[ix] = Stk4(argptr); + } + } else { + for (ix = 0; ix < count; ix++) { + array[ix] = Mem4(addr); + addr += 4; + } + } + + return array; } void Glulxe::verify_address(uint addr, uint count) { - if (addr >= 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); - } + if (addr >= 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); + } } void Glulxe::verify_address_write(uint addr, uint count) { - if (addr < ramstart) - fatal_error_i("Memory write to read-only address", addr); - if (addr >= 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); - } + if (addr < ramstart) + fatal_error_i("Memory write to read-only address", addr); + if (addr >= 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); + } } void Glulxe::verify_array_addresses(uint addr, uint count, uint size) { - uint bytecount; - if (addr >= endmem) - fatal_error_i("Memory access out of range", addr); - - if (count == 0) - return; - bytecount = count*size; - - /* If just multiplying by the element size overflows, we have trouble. */ - if (bytecount < count) - fatal_error_i("Memory access way too long", addr); - - /* If the byte length by itself is too long, or if its end overflows, - we have trouble. */ - if (bytecount > endmem || addr+bytecount < addr) - fatal_error_i("Memory access much too long", addr); - /* The simple length test. */ - if (addr+bytecount > endmem) - fatal_error_i("Memory access too long", addr); + uint bytecount; + if (addr >= endmem) + fatal_error_i("Memory access out of range", addr); + + if (count == 0) + return; + bytecount = count * size; + + /* If just multiplying by the element size overflows, we have trouble. */ + if (bytecount < count) + fatal_error_i("Memory access way too long", addr); + + /* If the byte length by itself is too long, or if its end overflows, + we have trouble. */ + if (bytecount > endmem || addr + bytecount < addr) + fatal_error_i("Memory access much too long", addr); + /* The simple length test. */ + if (addr + bytecount > endmem) + fatal_error_i("Memory access too long", addr); } } // End of namespace Glulxe |