diff options
author | Paul Gilbert | 2019-04-14 20:47:39 -0700 |
---|---|---|
committer | Paul Gilbert | 2019-04-17 20:46:06 -0700 |
commit | c3ebb5e68a0b36d992a48b508ab15c13a2edfd9c (patch) | |
tree | 31e84bd43ab6bb3f23883bf041b5f974765e05eb /engines/glk/glulxe | |
parent | 8e11a14939365c3a2994602b5db11a4fe6e8eaac (diff) | |
download | scummvm-rg350-c3ebb5e68a0b36d992a48b508ab15c13a2edfd9c.tar.gz scummvm-rg350-c3ebb5e68a0b36d992a48b508ab15c13a2edfd9c.tar.bz2 scummvm-rg350-c3ebb5e68a0b36d992a48b508ab15c13a2edfd9c.zip |
GLK: GLULXE: Added accel methods
Diffstat (limited to 'engines/glk/glulxe')
-rw-r--r-- | engines/glk/glulxe/accel.cpp | 622 | ||||
-rw-r--r-- | engines/glk/glulxe/glulxe.cpp | 6 | ||||
-rw-r--r-- | engines/glk/glulxe/glulxe.h | 76 | ||||
-rw-r--r-- | engines/glk/glulxe/glulxe_types.h | 77 |
4 files changed, 747 insertions, 34 deletions
diff --git a/engines/glk/glulxe/accel.cpp b/engines/glk/glulxe/accel.cpp new file mode 100644 index 0000000000..e4d60cf13b --- /dev/null +++ b/engines/glk/glulxe/accel.cpp @@ -0,0 +1,622 @@ +/* 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 { + +/** + * Git passes along function arguments in reverse order. To make our lives more interesting + */ +#ifdef ARGS_REVERSED +#define ARG(argv, argc, ix) (argv[(argc-1)-ix]) +#else +#define ARG(argv, argc, ix) (argv[ix]) +#endif + +/** + * Any function can be called with any number of arguments. This macro lets us snarf a given argument, + * or zero if it wasn't supplied. + */ +#define ARG_IF_GIVEN(argv, argc, ix) ((argc > ix) ? (ARG(argv, argc, ix)) : 0) + +acceleration_func Glulxe::accel_find_func(uint index) { + switch (index) { + case 0: return nullptr; // 0 always means no acceleration + case 1: return &Glulxe::func_1_z__region; + case 2: return &Glulxe::func_2_cp__tab; + case 3: return &Glulxe::func_3_ra__pr; + case 4: return &Glulxe::func_4_rl__pr; + case 5: return &Glulxe::func_5_oc__cl; + case 6: return &Glulxe::func_6_rv__pr; + case 7: return &Glulxe::func_7_op__pr; + case 8: return &Glulxe::func_8_cp__tab; + case 9: return &Glulxe::func_9_ra__pr; + case 10: return &Glulxe::func_10_rl__pr; + case 11: return &Glulxe::func_11_oc__cl; + case 12: return &Glulxe::func_12_rv__pr; + case 13: return &Glulxe::func_13_op__pr; + } + return nullptr; +} + +acceleration_func Glulxe::accel_get_func(uint addr) { + int bucknum; + accelentry_t *ptr; + + if (!accelentries) + return nullptr; + + bucknum = (addr % ACCEL_HASH_SIZE); + for (ptr = accelentries[bucknum]; ptr; ptr = ptr->next) { + if (ptr->addr == addr) + return ptr->func; + } + return nullptr; +} + +void Glulxe::accel_iterate_funcs(void (*func)(uint index, uint addr)) { + int bucknum; + accelentry_t *ptr; + + if (!accelentries) + return; + + for (bucknum=0; bucknum<ACCEL_HASH_SIZE; bucknum++) { + for (ptr = accelentries[bucknum]; ptr; ptr = ptr->next) { + if (ptr->func) { + func(ptr->index, ptr->addr); + } + } + } +} + +void Glulxe::accel_set_func(uint index, uint addr) { + int bucknum; + accelentry_t *ptr; + int functype; + acceleration_func new_func = nullptr; + + /* Check the Glulx type identifier byte. */ + functype = Mem1(addr); + if (functype != 0xC0 && functype != 0xC1) { + fatal_error_i("Attempt to accelerate non-function.", addr); + } + + if (!accelentries) { + accelentries = (accelentry_t **)glulx_malloc(ACCEL_HASH_SIZE + * sizeof(accelentry_t *)); + if (!accelentries) + fatal_error("Cannot malloc acceleration table."); + for (bucknum=0; bucknum<ACCEL_HASH_SIZE; bucknum++) + accelentries[bucknum] = nullptr; + } + + new_func = accel_find_func(index); + /* Might be nullptr, if the index is zero or not recognized. */ + + bucknum = (addr % ACCEL_HASH_SIZE); + for (ptr = accelentries[bucknum]; ptr; ptr = ptr->next) { + if (ptr->addr == addr) + break; + } + if (!ptr) { + if (!new_func) { + return; /* no need for a new entry */ + } + ptr = (accelentry_t *)glulx_malloc(sizeof(accelentry_t)); + if (!ptr) + fatal_error("Cannot malloc acceleration entry."); + ptr->addr = addr; + ptr->index = 0; + ptr->func = nullptr; + ptr->next = accelentries[bucknum]; + accelentries[bucknum] = ptr; + } + + ptr->index = index; + ptr->func = new_func; +} + +void Glulxe::accel_set_param(uint index, uint val) { + switch (index) { + case 0: classes_table = val; break; + case 1: indiv_prop_start = val; break; + case 2: class_metaclass = val; break; + case 3: object_metaclass = val; break; + case 4: routine_metaclass = val; break; + case 5: string_metaclass = val; break; + case 6: self = val; break; + case 7: num_attr_bytes = val; break; + case 8: cpv__start = val; break; + } +} + +uint Glulxe::accel_get_param_count() const { + return 9; +} + +uint Glulxe::accel_get_param(uint index) const { + switch (index) { + case 0: return classes_table; + case 1: return indiv_prop_start; + case 2: return class_metaclass; + case 3: return object_metaclass; + case 4: return routine_metaclass; + case 5: return string_metaclass; + case 6: return self; + case 7: return num_attr_bytes; + case 8: return cpv__start; + default: return 0; + } +} + +void Glulxe::accel_error(const char *msg) { + glk_put_char('\n'); + glk_put_string(msg); + glk_put_char('\n'); +} + +int Glulxe::obj_in_class(uint obj) { + // This checks whether obj is contained in Class, not whether it is a member of Class + return (Mem4(obj + 13 + num_attr_bytes) == class_metaclass); +} + +uint Glulxe::get_prop(uint obj, uint id) { + uint cla = 0; + uint prop; + uint call_argv[2]; + + if (id & 0xFFFF0000) { + cla = Mem4(classes_table+((id & 0xFFFF) * 4)); + ARG(call_argv, 2, 0) = obj; + ARG(call_argv, 2, 1) = cla; + if (func_5_oc__cl(2, call_argv) == 0) + return 0; + + id >>= 16; + obj = cla; + } + + ARG(call_argv, 2, 0) = obj; + ARG(call_argv, 2, 1) = id; + prop = func_2_cp__tab(2, call_argv); + if (prop == 0) + return 0; + + if (obj_in_class(obj) && (cla == 0)) { + if ((id < indiv_prop_start) || (id >= indiv_prop_start+8)) + return 0; + } + + if (Mem4(self) != obj) { + if (Mem1(prop + 9) & 1) + return 0; + } + return prop; +} + +uint Glulxe::get_prop_new(uint obj, uint id) { + uint cla = 0; + uint prop; + uint call_argv[2]; + + if (id & 0xFFFF0000) { + cla = Mem4(classes_table+((id & 0xFFFF) * 4)); + ARG(call_argv, 2, 0) = obj; + ARG(call_argv, 2, 1) = cla; + if (func_11_oc__cl(2, call_argv) == 0) + return 0; + + id >>= 16; + obj = cla; + } + + ARG(call_argv, 2, 0) = obj; + ARG(call_argv, 2, 1) = id; + prop = func_8_cp__tab(2, call_argv); + if (prop == 0) + return 0; + + if (obj_in_class(obj) && (cla == 0)) { + if ((id < indiv_prop_start) || (id >= indiv_prop_start+8)) + return 0; + } + + if (Mem4(self) != obj) { + if (Mem1(prop + 9) & 1) + return 0; + } + return prop; +} + +uint Glulxe::func_1_z__region(uint argc, uint *argv) { + uint addr; + uint tb; + + if (argc < 1) + return 0; + + addr = ARG(argv, argc, 0); + if (addr < 36) + return 0; + if (addr >= endmem) + return 0; + + tb = Mem1(addr); + if (tb >= 0xE0) { + return 3; + } + if (tb >= 0xC0) { + return 2; + } + if (tb >= 0x70 && tb <= 0x7F && addr >= ramstart) { + return 1; + } + return 0; +} + +uint Glulxe::func_2_cp__tab(uint argc, uint *argv) { + uint obj; + uint id; + uint otab, max; + + obj = ARG_IF_GIVEN(argv, argc, 0); + id = ARG_IF_GIVEN(argv, argc, 1); + + if (func_1_z__region(1, &obj) != 1) { + accel_error("[** Programming error: tried to find the \".\" of (something) **]"); + return 0; + } + + otab = Mem4(obj + 16); + if (!otab) + return 0; + + max = Mem4(otab); + otab += 4; + /* @binarysearch id 2 otab 10 max 0 0 res; */ + return binary_search(id, 2, otab, 10, max, 0, 0); +} + +uint Glulxe::func_3_ra__pr(uint argc, uint *argv) { + uint obj; + uint id; + uint prop; + + obj = ARG_IF_GIVEN(argv, argc, 0); + id = ARG_IF_GIVEN(argv, argc, 1); + + prop = get_prop(obj, id); + if (prop == 0) + return 0; + + return Mem4(prop + 4); +} + +uint Glulxe::func_4_rl__pr(uint argc, uint *argv) { + uint obj; + uint id; + uint prop; + + obj = ARG_IF_GIVEN(argv, argc, 0); + id = ARG_IF_GIVEN(argv, argc, 1); + + prop = get_prop(obj, id); + if (prop == 0) + return 0; + + return 4 * Mem2(prop + 2); +} + +uint Glulxe::func_5_oc__cl(uint argc, uint *argv) { + uint obj; + uint cla; + uint zr, prop, inlist, inlistlen, jx; + + obj = ARG_IF_GIVEN(argv, argc, 0); + cla = ARG_IF_GIVEN(argv, argc, 1); + + zr = func_1_z__region(1, &obj); + if (zr == 3) + return (cla == string_metaclass) ? 1 : 0; + if (zr == 2) + return (cla == routine_metaclass) ? 1 : 0; + if (zr != 1) + return 0; + + if (cla == class_metaclass) { + if (obj_in_class(obj)) + return 1; + if (obj == class_metaclass) + return 1; + if (obj == string_metaclass) + return 1; + if (obj == routine_metaclass) + return 1; + if (obj == object_metaclass) + return 1; + return 0; + } + if (cla == object_metaclass) { + if (obj_in_class(obj)) + return 0; + if (obj == class_metaclass) + return 0; + if (obj == string_metaclass) + return 0; + if (obj == routine_metaclass) + return 0; + if (obj == object_metaclass) + return 0; + return 1; + } + if ((cla == string_metaclass) || (cla == routine_metaclass)) + return 0; + + if (!obj_in_class(cla)) { + accel_error("[** Programming error: tried to apply 'ofclass' with non-class **]"); + return 0; + } + + prop = get_prop(obj, 2); + if (prop == 0) + return 0; + + inlist = Mem4(prop + 4); + if (inlist == 0) + return 0; + + inlistlen = Mem2(prop + 2); + for (jx = 0; jx < inlistlen; jx++) { + if (Mem4(inlist + (4 * jx)) == cla) + return 1; + } + return 0; +} + +uint Glulxe::func_6_rv__pr(uint argc, uint *argv) { + uint id; + uint addr; + + id = ARG_IF_GIVEN(argv, argc, 1); + + addr = func_3_ra__pr(argc, argv); + + if (addr == 0) { + if ((id > 0) && (id < indiv_prop_start)) + return Mem4(cpv__start + (4 * id)); + + accel_error("[** Programming error: tried to read (something) **]"); + return 0; + } + + return Mem4(addr); +} + +uint Glulxe::func_7_op__pr(uint argc, uint *argv) { + uint obj; + uint id; + uint zr; + + obj = ARG_IF_GIVEN(argv, argc, 0); + id = ARG_IF_GIVEN(argv, argc, 1); + + zr = func_1_z__region(1, &obj); + if (zr == 3) { + /* print is INDIV_PROP_START+6 */ + if (id == indiv_prop_start+6) + return 1; + /* print_to_array is INDIV_PROP_START+7 */ + if (id == indiv_prop_start+7) + return 1; + return 0; + } + if (zr == 2) { + /* call is INDIV_PROP_START+5 */ + return ((id == indiv_prop_start+5) ? 1 : 0); + } + if (zr != 1) + return 0; + + if ((id >= indiv_prop_start) && (id < indiv_prop_start+8)) { + if (obj_in_class(obj)) + return 1; + } + + return ((func_3_ra__pr(argc, argv)) ? 1 : 0); +} + +uint Glulxe::func_8_cp__tab(uint argc, uint *argv) { + uint obj; + uint id; + uint otab, max; + + obj = ARG_IF_GIVEN(argv, argc, 0); + id = ARG_IF_GIVEN(argv, argc, 1); + + if (func_1_z__region(1, &obj) != 1) { + accel_error("[** Programming error: tried to find the \".\" of (something) **]"); + return 0; + } + + otab = Mem4(obj + 4*(3+(int)(num_attr_bytes/4))); + if (!otab) + return 0; + + max = Mem4(otab); + otab += 4; + /* @binarysearch id 2 otab 10 max 0 0 res; */ + return binary_search(id, 2, otab, 10, max, 0, 0); +} + +uint Glulxe::func_9_ra__pr(uint argc, uint *argv) { + uint obj; + uint id; + uint prop; + + obj = ARG_IF_GIVEN(argv, argc, 0); + id = ARG_IF_GIVEN(argv, argc, 1); + + prop = get_prop_new(obj, id); + if (prop == 0) + return 0; + + return Mem4(prop + 4); +} + +uint Glulxe::func_10_rl__pr(uint argc, uint *argv) { + uint obj; + uint id; + uint prop; + + obj = ARG_IF_GIVEN(argv, argc, 0); + id = ARG_IF_GIVEN(argv, argc, 1); + + prop = get_prop_new(obj, id); + if (prop == 0) + return 0; + + return 4 * Mem2(prop + 2); +} + +uint Glulxe::func_11_oc__cl(uint argc, uint *argv) { + uint obj; + uint cla; + uint zr, prop, inlist, inlistlen, jx; + + obj = ARG_IF_GIVEN(argv, argc, 0); + cla = ARG_IF_GIVEN(argv, argc, 1); + + zr = func_1_z__region(1, &obj); + if (zr == 3) + return (cla == string_metaclass) ? 1 : 0; + if (zr == 2) + return (cla == routine_metaclass) ? 1 : 0; + if (zr != 1) + return 0; + + if (cla == class_metaclass) { + if (obj_in_class(obj)) + return 1; + if (obj == class_metaclass) + return 1; + if (obj == string_metaclass) + return 1; + if (obj == routine_metaclass) + return 1; + if (obj == object_metaclass) + return 1; + return 0; + } + if (cla == object_metaclass) { + if (obj_in_class(obj)) + return 0; + if (obj == class_metaclass) + return 0; + if (obj == string_metaclass) + return 0; + if (obj == routine_metaclass) + return 0; + if (obj == object_metaclass) + return 0; + return 1; + } + if ((cla == string_metaclass) || (cla == routine_metaclass)) + return 0; + + if (!obj_in_class(cla)) { + accel_error("[** Programming error: tried to apply 'ofclass' with non-class **]"); + return 0; + } + + prop = get_prop_new(obj, 2); + if (prop == 0) + return 0; + + inlist = Mem4(prop + 4); + if (inlist == 0) + return 0; + + inlistlen = Mem2(prop + 2); + for (jx = 0; jx < inlistlen; jx++) { + if (Mem4(inlist + (4 * jx)) == cla) + return 1; + } + return 0; +} + +uint Glulxe::func_12_rv__pr(uint argc, uint *argv) { + uint id; + uint addr; + + id = ARG_IF_GIVEN(argv, argc, 1); + + addr = func_9_ra__pr(argc, argv); + + if (addr == 0) { + if ((id > 0) && (id < indiv_prop_start)) + return Mem4(cpv__start + (4 * id)); + + accel_error("[** Programming error: tried to read (something) **]"); + return 0; + } + + return Mem4(addr); +} + +uint Glulxe::func_13_op__pr(uint argc, uint *argv) { + uint obj; + uint id; + uint zr; + + obj = ARG_IF_GIVEN(argv, argc, 0); + id = ARG_IF_GIVEN(argv, argc, 1); + + zr = func_1_z__region(1, &obj); + if (zr == 3) { + /* print is INDIV_PROP_START+6 */ + if (id == indiv_prop_start+6) + return 1; + /* print_to_array is INDIV_PROP_START+7 */ + if (id == indiv_prop_start+7) + return 1; + return 0; + } + if (zr == 2) { + /* call is INDIV_PROP_START+5 */ + return ((id == indiv_prop_start+5) ? 1 : 0); + } + if (zr != 1) + return 0; + + if ((id >= indiv_prop_start) && (id < indiv_prop_start+8)) { + if (obj_in_class(obj)) + return 1; + } + + return ((func_9_ra__pr(argc, argv)) ? 1 : 0); +} + +} // End of namespace Glulxe +} // End of namespace Glk diff --git a/engines/glk/glulxe/glulxe.cpp b/engines/glk/glulxe/glulxe.cpp index bb1a65101c..6fdfb05ba5 100644 --- a/engines/glk/glulxe/glulxe.cpp +++ b/engines/glk/glulxe/glulxe.cpp @@ -33,7 +33,11 @@ Glulxe::Glulxe(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, 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) { + stringtable(0), valstackbase(0), localsbase(0), endmem(0), protectstart(0), protectend(0), + // 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), + accelentries(nullptr) { g_vm = this; } diff --git a/engines/glk/glulxe/glulxe.h b/engines/glk/glulxe/glulxe.h index b1f44535e8..839e9eb524 100644 --- a/engines/glk/glulxe/glulxe.h +++ b/engines/glk/glulxe/glulxe.h @@ -59,6 +59,24 @@ public: uint endmem; uint protectstart, protectend; uint prevpc; + + /** + * \defgroup accel fields + * @{ + */ + + uint classes_table; ///< class object array + uint indiv_prop_start; ///< first individual prop ID + uint class_metaclass; ///< "Class" class object + uint object_metaclass; ///< "Object" class object + uint routine_metaclass; ///< "Routine" class object + uint string_metaclass; ///< "String" class object + uint self; ///< address of global "self" + uint num_attr_bytes; ///< number of attributes / 8 + uint cpv__start; ///< array of common prop defaults + accelentry_t **accelentries; + + /**@}*/ protected: /** * \defgroup glkop fields @@ -82,6 +100,52 @@ protected: /**@}*/ protected: /** + * \defgroup accel support methods + * @{ + */ + + void accel_error(const char *msg); + uint func_1_z__region(uint argc, uint *argv); + + /** + * The old set of accel functions (2 through 7) are deprecated; they behave badly if the Inform 6 + * NUM_ATTR_BYTES option (parameter 7) is changed from its default value (7). They will not be removed, + * but new games should use functions 8 through 13 instead + */ + uint func_2_cp__tab(uint argc, uint *argv); + uint func_3_ra__pr(uint argc, uint *argv); + uint func_4_rl__pr(uint argc, uint *argv); + uint func_5_oc__cl(uint argc, uint *argv); + uint func_6_rv__pr(uint argc, uint *argv); + uint func_7_op__pr(uint argc, uint *argv); + + /** + * Here are the newer functions, which support changing NUM_ATTR_BYTES. + These call get_prop_new() instead of get_prop() + */ + uint func_8_cp__tab(uint argc, uint *argv); + uint func_9_ra__pr(uint argc, uint *argv); + uint func_10_rl__pr(uint argc, uint *argv); + uint func_11_oc__cl(uint argc, uint *argv); + uint func_12_rv__pr(uint argc, uint *argv); + uint func_13_op__pr(uint argc, uint *argv); + int obj_in_class(uint obj); + + /** + * Look up a property entry. + */ + uint get_prop(uint obj, uint id); + + /** + * Look up a property entry. This is part of the newer set of accel functions (8 through 13), + * which support increasing NUM_ATTR_BYTES. It is identical to get_prop() except that it calls + * the new versions of func_5 and func_2 + */ + uint get_prop_new(uint obj, uint id); + + /**@}*/ + + /** * \defgroup glkop support methods * @{ */ @@ -467,14 +531,18 @@ public: * @{ */ - typedef uint(*acceleration_func)(uint argc, uint *argv); - void init_accel(void); acceleration_func accel_find_func(uint index); acceleration_func accel_get_func(uint addr); void accel_set_func(uint index, uint addr); void accel_set_param(uint index, uint val); - uint accel_get_param_count(void); - uint accel_get_param(uint index); + + uint accel_get_param_count() const; + uint accel_get_param(uint index) const; + + /** + * Iterate the entire acceleration table, calling the callback for each (non-nullptr) entry. + * This is used only for autosave. + */ void accel_iterate_funcs(void(*func)(uint index, uint addr)); /**@}*/ diff --git a/engines/glk/glulxe/glulxe_types.h b/engines/glk/glulxe/glulxe_types.h index 52a6363833..b06e43536a 100644 --- a/engines/glk/glulxe/glulxe_types.h +++ b/engines/glk/glulxe/glulxe_types.h @@ -28,40 +28,46 @@ namespace Glk { namespace Glulxe { +class Glulxe; - /* Comment this definition to turn off memory-address checking. With - verification on, all reads and writes to main memory will be checked - to ensure they're in range. This is slower, but prevents malformed - game files from crashing the interpreter. */ +/** + * Comment this definition to turn off memory-address checking. With verification on, + * all reads and writes to main memory will be checked to ensure they're in range. + * This is slower, but prevents malformed game files from crashing the interpreter. + */ #define VERIFY_MEMORY_ACCESS (1) - /* Uncomment this definition to permit an exception for memory-address - checking for @glk and @copy opcodes that try to write to memory address 0. - This was a bug in old Superglus-built game files. */ - /* #define TOLERATE_SUPERGLUS_BUG (1) */ - - /* Uncomment this definition to turn on Glulx VM profiling. In this - mode, all function calls are timed, and the timing information is - written to a data file called "profile-raw". - (Build note: on Linux, glibc may require you to also define - _BSD_SOURCE or _DEFAULT_SOURCE or both for the timeradd() macro.) */ - /* #define VM_PROFILING (1) */ - - /* Uncomment this definition to turn on the Glulx debugger. You should - only do this when debugging facilities are desired; it slows down - the interpreter. If you do, you will need to build with libxml2; - see the Makefile. */ - /* #define VM_DEBUGGER (1) */ - - /* Comment this definition to turn off floating-point support. You - might need to do this if you are building on a very limited platform - with no math library. */ +/** + * Uncomment this definition to permit an exception for memory-address checking for @glk and @copy + * opcodes that try to write to memory address 0. This was a bug in old Superglus-built game files. + */ +/* #define TOLERATE_SUPERGLUS_BUG (1) */ + +/** + * Uncomment this definition to turn on Glulx VM profiling. In this mode, all function calls are timed, + * and the timing information is written to a data file called "profile-raw". + * (Build note: on Linux, glibc may require you to also define _BSD_SOURCE or _DEFAULT_SOURCE or both + * for the timeradd() macro.) + */ +/* #define VM_PROFILING (1) */ + +/** + * Uncomment this definition to turn on the Glulx debugger. You should only do this when debugging + * facilities are desired; it slows down the interpreter. If you do, you will need to build with libxml2; + * see the Makefile. + */ +/* #define VM_DEBUGGER (1) */ + +/** + * Comment this definition to turn off floating-point support. You might need to do this if you are building + * on a very limited platform with no math library. */ #define FLOAT_SUPPORT (1) - /* Comment this definition to not cache the original state of RAM in - (real) memory. This saves some memory, but slows down save/restore/undo - operations, which will have to read the original state off disk - every time. */ +/** + * Comment this definition to not cache the original state of RAM in (real) memory. This saves some memory, + * but slows down save/restore/undo operations, which will have to read the original state off disk + * every time. + */ #define SERIALIZE_CACHE_RAM (1) /** @@ -181,6 +187,19 @@ typedef oparg_struct oparg_t; #define MAX_OPERANDS (8) +typedef uint(Glulxe::*acceleration_func)(uint argc, uint *argv); + +struct accelentry_struct { + uint addr; + uint index; + acceleration_func func; + accelentry_struct *next; +}; +typedef accelentry_struct accelentry_t; + +#define ACCEL_HASH_SIZE (511) + + } // End of namespace Glulxe } // End of namespace Glk |