From 936b9731536d914c35b9632e919b510f3ae46506 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Tue, 16 Apr 2019 21:21:58 -0700 Subject: GLK: GLULXE: Add miscellaneous missing methods --- engines/glk/glulxe/accel.cpp | 2 +- engines/glk/glulxe/exec.cpp | 2 +- engines/glk/glulxe/float.cpp | 102 ++++++++++++++++++++++++++++++++++++++- engines/glk/glulxe/funcs.cpp | 2 +- engines/glk/glulxe/gestalt.cpp | 2 +- engines/glk/glulxe/glkop.cpp | 2 +- engines/glk/glulxe/glulxe.cpp | 23 ++++++++- engines/glk/glulxe/glulxe.h | 63 ++++++++++++++++++------ engines/glk/glulxe/heap.cpp | 2 +- engines/glk/glulxe/operand.cpp | 2 +- engines/glk/glulxe/search.cpp | 2 +- engines/glk/glulxe/serial.cpp | 4 +- engines/glk/glulxe/string.cpp | 2 +- engines/glk/glulxe/vm.cpp | 64 ++++++++++++------------ engines/glk/tads/tads2/data.cpp | 6 +-- engines/glk/tads/tads2/regex.cpp | 8 +-- engines/glk/tads/tads2/regex.h | 2 +- 17 files changed, 220 insertions(+), 70 deletions(-) diff --git a/engines/glk/glulxe/accel.cpp b/engines/glk/glulxe/accel.cpp index e4d60cf13b..929c6ab461 100644 --- a/engines/glk/glulxe/accel.cpp +++ b/engines/glk/glulxe/accel.cpp @@ -20,7 +20,7 @@ * */ -#include "engines/glk/glulxe/glulxe.h" +#include "glk/glulxe/glulxe.h" namespace Glk { namespace Glulxe { diff --git a/engines/glk/glulxe/exec.cpp b/engines/glk/glulxe/exec.cpp index 4fefe05e54..f314ca43e2 100644 --- a/engines/glk/glulxe/exec.cpp +++ b/engines/glk/glulxe/exec.cpp @@ -20,7 +20,7 @@ * */ -#include "engines/glk/glulxe/glulxe.h" +#include "glk/glulxe/glulxe.h" namespace Glk { namespace Glulxe { diff --git a/engines/glk/glulxe/float.cpp b/engines/glk/glulxe/float.cpp index c1ffc77be9..36ef2f479b 100644 --- a/engines/glk/glulxe/float.cpp +++ b/engines/glk/glulxe/float.cpp @@ -20,11 +20,111 @@ * */ -#include "glk/glulxe/float.h" +#include "glk/glulxe/glulxe.h" namespace Glk { namespace Glulxe { +uint Glulxe::encode_float(gfloat32 val) { + gfloat32 absval; + uint sign; + int expo; + gfloat32 mant; + uint fbits; + + if (signbit(val)) { + sign = 0x80000000; + absval = -val; + } + else { + sign = 0x0; + absval = val; + } + + if (isinf(val)) { + return sign | 0x7f800000; /* infinity */ + } + + if (isnan(val)) { + return sign | 0x7fc00000; + } + + mant = frexpf(absval, &expo); + + /* Normalize mantissa to be in the range [1.0, 2.0) */ + if (0.5 <= mant && mant < 1.0) { + mant *= 2.0; + expo--; + } + else if (mant == 0.0) { + expo = 0; + } + else { + return sign | 0x7f800000; /* infinity */ + } + + if (expo >= 128) { + return sign | 0x7f800000; /* infinity */ + } + else if (expo < -126) { + /* Denormalized (very small) number */ + mant = ldexpf(mant, 126 + expo); + expo = 0; + } + else if (!(expo == 0 && mant == 0.0)) { + expo += 127; + mant -= 1.0; /* Get rid of leading 1 */ + } + + mant *= 8388608.0; /* 2^23 */ + fbits = (uint)(mant + 0.5); /* round mant to nearest int */ + if (fbits >> 23) { + /* The carry propagated out of a string of 23 1 bits. */ + fbits = 0; + expo++; + if (expo >= 255) { + return sign | 0x7f800000; /* infinity */ + } + } + + return (sign) | ((uint)(expo << 23)) | (fbits); +} + +gfloat32 Glulxe::decode_float(uint val) { + int sign; + int expo; + uint mant; + gfloat32 res; + + /* First byte */ + sign = ((val & 0x80000000) != 0); + expo = (val >> 23) & 0xFF; + mant = val & 0x7FFFFF; + + if (expo == 255) { + if (mant == 0) { + /* Infinity */ + return (sign ? (-INFINITY) : (INFINITY)); + } + else { + /* Not a number */ + return (sign ? (-NAN) : (NAN)); + } + } + + res = (gfloat32)mant / 8388608.0; + + if (expo == 0) { + expo = -126; + } + else { + res += 1.0; + expo -= 127; + } + res = ldexpf(res, expo); + + return (sign ? (-res) : (res)); +} } // End of namespace Glulxe } // End of namespace Glk diff --git a/engines/glk/glulxe/funcs.cpp b/engines/glk/glulxe/funcs.cpp index cb427e24fe..b85844a8c1 100644 --- a/engines/glk/glulxe/funcs.cpp +++ b/engines/glk/glulxe/funcs.cpp @@ -20,7 +20,7 @@ * */ -#include "engines/glk/glulxe/glulxe.h" +#include "glk/glulxe/glulxe.h" namespace Glk { namespace Glulxe { diff --git a/engines/glk/glulxe/gestalt.cpp b/engines/glk/glulxe/gestalt.cpp index 2839c52676..21f8974513 100644 --- a/engines/glk/glulxe/gestalt.cpp +++ b/engines/glk/glulxe/gestalt.cpp @@ -20,7 +20,7 @@ * */ -#include "engines/glk/glulxe/glulxe.h" +#include "glk/glulxe/glulxe.h" namespace Glk { namespace Glulxe { diff --git a/engines/glk/glulxe/glkop.cpp b/engines/glk/glulxe/glkop.cpp index ee7f78bf42..12d4fef0d3 100644 --- a/engines/glk/glulxe/glkop.cpp +++ b/engines/glk/glulxe/glkop.cpp @@ -20,7 +20,7 @@ * */ -#include "engines/glk/glulxe/glulxe.h" +#include "glk/glulxe/glulxe.h" namespace Glk { namespace Glulxe { diff --git a/engines/glk/glulxe/glulxe.cpp b/engines/glk/glulxe/glulxe.cpp index 576b961872..1b82f58c05 100644 --- a/engines/glk/glulxe/glulxe.cpp +++ b/engines/glk/glulxe/glulxe.cpp @@ -29,12 +29,14 @@ namespace Glulxe { Glulxe *g_vm; -Glulxe::Glulxe(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc), +Glulxe::Glulxe(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc), _random("glulxe"), vm_exited_cleanly(false), gamefile(nullptr), gamefile_start(0), gamefile_len(0), memmap(nullptr), stack(nullptr), ramstart(0), endgamefile(0), origendmem(0), stacksize(0), startfuncaddr(0), checksum(0), stackptr(0), frameptr(0), pc(0), prevpc(0), origstringtable(0), stringtable(0), valstackbase(0), localsbase(0), endmem(0), protectstart(0), protectend(0), stream_char_handler(nullptr), stream_unichar_handler(nullptr), + // main + library_autorestore_hook(nullptr), // accel classes_table(0), indiv_prop_start(0), class_metaclass(0), object_metaclass(0), routine_metaclass(0), string_metaclass(0), self(0), num_attr_bytes(0), cpv__start(0), @@ -52,7 +54,20 @@ void Glulxe::runGame() { if (!is_gamefile_valid()) return; - // TODO + setup_vm(); + if (library_autorestore_hook) + library_autorestore_hook(); + + execute_loop(); + finalize_vm(); + + gamefile = NULL; + gamefile_start = 0; + gamefile_len = 0; + init_err = NULL; + vm_exited_cleanly = true; + + profile_quit(); } Common::Error Glulxe::loadGameData(strid_t file) { @@ -128,5 +143,9 @@ void Glulxe::nonfatal_warning_handler(const char *str, const char *arg, bool use warning("%s", msg.c_str()); } +void Glulxe::glulx_sort(void *addr, int count, int size, int(*comparefunc)(const void *p1, const void *p2)) { + qsort(addr, count, size, comparefunc); +} + } // End of namespace Glulxe } // End of namespace Glk diff --git a/engines/glk/glulxe/glulxe.h b/engines/glk/glulxe/glulxe.h index f7684f1830..0690560d14 100644 --- a/engines/glk/glulxe/glulxe.h +++ b/engines/glk/glulxe/glulxe.h @@ -24,6 +24,7 @@ #define GLK_GLULXE #include "common/scummsys.h" +#include "common/random.h" #include "glk/glk_api.h" #include "glk/glulxe/glulxe_types.h" @@ -73,6 +74,20 @@ private: /**@}*/ + /** + * \defgroup main fields + * @{ + */ + + /** + * The library_autorestore_hook is called right after the VM's initial setup. This is an appropriate time + * to autorestore an initial game state, if the library has that capability. (Currently, only iosglk does.) + */ + void(*library_autorestore_hook)(void); + Common::RandomSource _random; + + /**@}*/ + /** * \defgroup accel fields * @{ @@ -327,7 +342,7 @@ protected: uint read_heapstate(dest_t *dest, uint chunklen, int portable, uint *sumlen, uint **summary); uint read_stackstate(dest_t *dest, uint chunklen, int portable); uint write_heapstate_sub(uint sumlen, uint *sumarray, dest_t *dest, int portable); - static int sort_heap_summary(void *p1, void *p2); + static int sort_heap_summary(const void *p1, const void *p2); int read_byte(dest_t *dest, byte *val); int read_short(dest_t *dest, uint16 *val); @@ -675,13 +690,23 @@ public: * @{ */ - void *glulx_malloc(uint len); - void *glulx_realloc(void *ptr, uint len); - void glulx_free(void *ptr); - void glulx_setrandom(uint seed); - uint glulx_random(); - void glulx_sort(void *addr, int count, int size, - int(*comparefunc)(void *p1, void *p2)); + inline void *glulx_malloc(uint len) { + return malloc(len); + } + inline void *glulx_realloc(void *ptr, uint len) { + return realloc(ptr, len); + } + inline void glulx_free(void *ptr) { + free(ptr); + } + inline void glulx_setrandom(uint32 seed) { + _random.setSeed(seed); + } + inline uint glulx_random() { + return _random.getRandomNumber(0xffffffff); + } + + void glulx_sort(void *addr, int count, int size, int(*comparefunc)(const void *p1, const void *p2)); /**@}*/ @@ -846,17 +871,28 @@ public: (but safer) encoding and decoding functions. */ /* #define FLOAT_NOT_NATIVE (1) */ - /* float.c */ - int init_float(); - uint encode_float(gfloat32 val); - gfloat32 decode_float(uint val); + int init_float() { return true; } + + /** + * Encode floats by a lot of annoying bit manipulation. + * The function is adapted from code in Python (Objects/floatobject.c) + */ + static uint encode_float(gfloat32 val); + + /** + * Decode floats by a lot of annoying bit manipulation. + * The function is adapted from code in Python (Objects/floatobject.c) + */ + static gfloat32 decode_float(uint val); /* Uncomment this definition if your powf() function does not support all the corner cases specified by C99. If you uncomment this, osdepend.c will provide a safer implementation of glulx_powf(). */ /* #define FLOAT_COMPILE_SAFER_POWF (1) */ - gfloat32 glulx_powf(gfloat32 val1, gfloat32 val2); + inline gfloat32 glulx_powf(gfloat32 val1, gfloat32 val2) const { + return powf(val1, val2); + } #endif /* FLOAT_SUPPORT */ /**@}*/ @@ -906,7 +942,6 @@ public: /**@}*/ - /** * \defgroup Strings access methods * @{ diff --git a/engines/glk/glulxe/heap.cpp b/engines/glk/glulxe/heap.cpp index 29d9405aca..00b8dcb74c 100644 --- a/engines/glk/glulxe/heap.cpp +++ b/engines/glk/glulxe/heap.cpp @@ -20,7 +20,7 @@ * */ -#include "engines/glk/glulxe/glulxe.h" +#include "glk/glulxe/glulxe.h" namespace Glk { namespace Glulxe { diff --git a/engines/glk/glulxe/operand.cpp b/engines/glk/glulxe/operand.cpp index a48d68e0b9..cee8420d41 100644 --- a/engines/glk/glulxe/operand.cpp +++ b/engines/glk/glulxe/operand.cpp @@ -20,7 +20,7 @@ * */ -#include "engines/glk/glulxe/glulxe.h" +#include "glk/glulxe/glulxe.h" namespace Glk { namespace Glulxe { diff --git a/engines/glk/glulxe/search.cpp b/engines/glk/glulxe/search.cpp index d2f1c85d68..440da553f0 100644 --- a/engines/glk/glulxe/search.cpp +++ b/engines/glk/glulxe/search.cpp @@ -20,7 +20,7 @@ * */ -#include "engines/glk/glulxe/glulxe.h" +#include "glk/glulxe/glulxe.h" namespace Glk { namespace Glulxe { diff --git a/engines/glk/glulxe/serial.cpp b/engines/glk/glulxe/serial.cpp index 6d662166c4..1aa316327c 100644 --- a/engines/glk/glulxe/serial.cpp +++ b/engines/glk/glulxe/serial.cpp @@ -20,7 +20,7 @@ * */ -#include "engines/glk/glulxe/glulxe.h" +#include "glk/glulxe/glulxe.h" namespace Glk { namespace Glulxe { @@ -751,7 +751,7 @@ uint Glulxe::write_heapstate_sub(uint sumlen, uint *sumarray, dest_t *dest, int return 0; } -int Glulxe::sort_heap_summary(void *p1, void *p2) { +int Glulxe::sort_heap_summary(const void *p1, const void *p2) { uint v1 = *(uint *)p1; uint v2 = *(uint *)p2; diff --git a/engines/glk/glulxe/string.cpp b/engines/glk/glulxe/string.cpp index 2c95c3e851..59420fa1b5 100644 --- a/engines/glk/glulxe/string.cpp +++ b/engines/glk/glulxe/string.cpp @@ -20,7 +20,7 @@ * */ -#include "engines/glk/glulxe/glulxe.h" +#include "glk/glulxe/glulxe.h" namespace Glk { namespace Glulxe { diff --git a/engines/glk/glulxe/vm.cpp b/engines/glk/glulxe/vm.cpp index f332c92248..eb4b1121b4 100644 --- a/engines/glk/glulxe/vm.cpp +++ b/engines/glk/glulxe/vm.cpp @@ -20,43 +20,38 @@ * */ -#include "engines/glk/glulxe/glulxe.h" +#include "glk/glulxe/glulxe.h" namespace Glk { namespace Glulxe { void Glulxe::setup_vm() { - unsigned char buf[4 * 7]; - int res; + byte buf[4 * 7]; - pc = 0; /* Clear this, so that error messages are cleaner. */ + 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; + // Read in all the size constants from the game file header + stream_char_handler = nullptr; + stream_unichar_handler = nullptr; - glk_stream_set_position(gamefile, gamefile_start+8, seekmode_Start); - res = glk_get_buffer_stream(gamefile, (char *)buf, 4 * 7); - if (res != 4 * 7) { + _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". */ + 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. */ - + // Do a few sanity checks. if ((ramstart & 0xFF) || (endgamefile & 0xFF) || (origendmem & 0xFF) @@ -81,28 +76,29 @@ void Glulxe::setup_vm() { /* 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); + memmap = (byte *)glulx_malloc(origendmem); if (!memmap) { fatal_error("Unable to allocate Glulx memory space."); } - stack = (unsigned char *)glulx_malloc(stacksize); + stack = (byte *)glulx_malloc(stacksize); if (!stack) { glulx_free(memmap); - memmap = NULL; + memmap = nullptr; fatal_error("Unable to allocate Glulx stack space."); } stringtable = 0; - /* Initialize various other things in the terp. */ + // Initialize various other things in the terp. init_operands(); init_serial(); - /* Set up the initial machine state. */ + // 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(); @@ -113,11 +109,11 @@ void Glulxe::finalize_vm() { if (memmap) { glulx_free(memmap); - memmap = NULL; + memmap = nullptr; } if (stack) { glulx_free(stack); - stack = NULL; + stack = nullptr; } final_serial(); @@ -173,7 +169,7 @@ void Glulxe::vm_restart() { /* Note that we do not reset the protection range. */ /* Push the first function call. (No arguments.) */ - enter_function(startfuncaddr, 0, NULL); + enter_function(startfuncaddr, 0, nullptr); /* We're now ready to execute. */ } @@ -219,17 +215,17 @@ uint Glulxe::change_memsize(uint newlen, bool internal) { } uint *Glulxe::pop_arguments(uint count, uint addr) { - int ix; + uint ix; uint argptr; uint *array; #define MAXARGS (32) static uint statarray[MAXARGS]; - static uint *dynarray = NULL; + static uint *dynarray = nullptr; static uint dynarray_size = 0; if (count == 0) - return NULL; + return nullptr; if (count <= MAXARGS) { /* Store in the static array. */ diff --git a/engines/glk/tads/tads2/data.cpp b/engines/glk/tads/tads2/data.cpp index a2bbf741fe..c60fcb2c5f 100644 --- a/engines/glk/tads/tads2/data.cpp +++ b/engines/glk/tads/tads2/data.cpp @@ -20,9 +20,9 @@ * */ -#include "engines/glk/tads/tads2/data.h" -#include "engines/glk/tads/tads2/types.h" -#include "engines/glk/tads/tads2/vocabulary.h" +#include "glk/tads/tads2/data.h" +#include "glk/tads/tads2/types.h" +#include "glk/tads/tads2/vocabulary.h" #include "common/algorithm.h" namespace Glk { diff --git a/engines/glk/tads/tads2/regex.cpp b/engines/glk/tads/tads2/regex.cpp index c0404202bf..a7f7d99369 100644 --- a/engines/glk/tads/tads2/regex.cpp +++ b/engines/glk/tads/tads2/regex.cpp @@ -67,10 +67,10 @@ Notes numbers. */ -#include "engines/glk/tads/tads2/regex.h" -#include "engines/glk/tads/tads2/ler.h" -#include "engines/glk/tads/tads2/os.h" -//#include "engines/glk/tads/tads2/std.h" +#include "glk/tads/tads2/regex.h" +#include "glk/tads/tads2/ler.h" +#include "glk/tads/tads2/os.h" +//#include "glk/tads/tads2/std.h" #//include "engines/glk/tads/tads2/ler.h" namespace Glk { diff --git a/engines/glk/tads/tads2/regex.h b/engines/glk/tads/tads2/regex.h index 4c48a8985d..cd975e066b 100644 --- a/engines/glk/tads/tads2/regex.h +++ b/engines/glk/tads/tads2/regex.h @@ -24,7 +24,7 @@ #define GLK_TADS_TADS2_REGEX #include "common/array.h" -#include "engines/glk/tads/tads2/ler.h" +#include "glk/tads/tads2/ler.h" namespace Glk { namespace TADS { -- cgit v1.2.3