From ee8362cc073a02c91038add400f67dc2e6dba683 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Tue, 16 Apr 2019 19:30:44 -0700 Subject: GLK: GLULXE: Added vm methods --- engines/glk/glulxe/vm.cpp | 325 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 engines/glk/glulxe/vm.cpp (limited to 'engines/glk/glulxe/vm.cpp') diff --git a/engines/glk/glulxe/vm.cpp b/engines/glk/glulxe/vm.cpp new file mode 100644 index 0000000000..f332c92248 --- /dev/null +++ b/engines/glk/glulxe/vm.cpp @@ -0,0 +1,325 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "engines/glk/glulxe/glulxe.h" + +namespace Glk { +namespace Glulxe { + +void Glulxe::setup_vm() { + unsigned char buf[4 * 7]; + int res; + + 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 = 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); + if (res != 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 = (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_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 = NULL; + } + if (stack) { + glulx_free(stack); + stack = NULL; + } + + 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? */ + glk_stream_set_position(gamefile, gamefile_start, seekmode_Start); + bufpos = 0x100; + + for (lx=0; lx= 0x100) { + int count = glk_get_buffer_stream(gamefile, 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 endmem) { + for (lx=endmem; lx= 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= 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); + } +} + +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); +} + +} // End of namespace Glulxe +} // End of namespace Glk -- cgit v1.2.3