aboutsummaryrefslogtreecommitdiff
path: root/engines/glk/glulxe
diff options
context:
space:
mode:
authorPaul Gilbert2019-04-14 20:47:39 -0700
committerPaul Gilbert2019-04-17 20:46:06 -0700
commitc3ebb5e68a0b36d992a48b508ab15c13a2edfd9c (patch)
tree31e84bd43ab6bb3f23883bf041b5f974765e05eb /engines/glk/glulxe
parent8e11a14939365c3a2994602b5db11a4fe6e8eaac (diff)
downloadscummvm-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.cpp622
-rw-r--r--engines/glk/glulxe/glulxe.cpp6
-rw-r--r--engines/glk/glulxe/glulxe.h76
-rw-r--r--engines/glk/glulxe/glulxe_types.h77
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