1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 /* Based on Glulx intrepreter version 0.5.4 */ 24 25 #ifndef GLK_GLULXE 26 #define GLK_GLULXE 27 28 #include "common/scummsys.h" 29 #include "common/random.h" 30 #include "glk/glk_api.h" 31 #include "glk/glulx/glulx_types.h" 32 33 namespace Glk { 34 namespace Glulx { 35 36 class Glulx; 37 typedef void (Glulx::*CharHandler)(unsigned char); 38 typedef void (Glulx::*UnicharHandler)(uint32); 39 40 /** 41 * Glulx game interpreter 42 */ 43 class Glulx : public GlkAPI { 44 private: 45 /** 46 * \defgroup vm fields 47 * @{ 48 */ 49 50 bool vm_exited_cleanly; 51 uint gamefile_start, gamefile_len; 52 UnicharHandler glkio_unichar_han_ptr; 53 char *init_err, *init_err2; 54 CharHandler stream_char_handler; 55 56 byte *memmap; 57 byte *stack; 58 UnicharHandler stream_unichar_handler; 59 60 uint ramstart; 61 uint endgamefile; 62 uint origendmem; 63 uint stacksize; 64 uint startfuncaddr; 65 uint checksum; 66 uint stackptr; 67 uint frameptr; 68 uint pc; 69 uint origstringtable; 70 uint stringtable; 71 uint valstackbase; 72 uint localsbase; 73 uint endmem; 74 uint protectstart, protectend; 75 uint prevpc; 76 77 /**@}*/ 78 79 /** 80 * \defgroup main fields 81 * @{ 82 */ 83 84 /** 85 * The library_autorestore_hook is called right after the VM's initial setup. This is an appropriate time 86 * to autorestore an initial game state, if the library has that capability. (Currently, only iosglk does.) 87 */ 88 void(*library_autorestore_hook)(void); 89 90 /**@}*/ 91 92 /** 93 * \defgroup accel fields 94 * @{ 95 */ 96 97 uint classes_table; ///< class object array 98 uint indiv_prop_start; ///< first individual prop ID 99 uint class_metaclass; ///< "Class" class object 100 uint object_metaclass; ///< "Object" class object 101 uint routine_metaclass; ///< "Routine" class object 102 uint string_metaclass; ///< "String" class object 103 uint self; ///< address of global "self" 104 uint num_attr_bytes; ///< number of attributes / 8 105 uint cpv__start; ///< array of common prop defaults 106 accelentry_t **accelentries; 107 108 /**@}*/ 109 110 /** 111 * \defgroup heap fields 112 * @{ 113 */ 114 115 uint heap_start; ///< zero for inactive heap 116 int alloc_count; 117 118 /* The heap_head/heap_tail is a doubly-linked list of blocks, both 119 free and allocated. It is kept in address order. It should be 120 complete -- that is, the first block starts at heap_start, and each 121 block ends at the beginning of the next block, until the last one, 122 which ends at endmem. 123 124 (Heap_start is never the same as end_mem; if there is no heap space, 125 then the heap is inactive and heap_start is zero.) 126 127 Adjacent free blocks may be merged at heap_alloc() time. 128 129 ### To make alloc more efficient, we could keep a separate 130 free-list. To make free more efficient, we could keep a hash 131 table of allocations. 132 */ 133 heapblock_t *heap_head; 134 heapblock_t *heap_tail; 135 136 /**@}*/ 137 138 /** 139 * \defgroup operand fields 140 * @{ 141 */ 142 143 /** 144 * This is a handy array in which to look up operandlists quickly. It stores the operandlists 145 * for the first 128 opcodes, which are the ones used most frequently. 146 */ 147 const operandlist_t *fast_operandlist[0x80]; 148 149 /**@}*/ 150 151 /** 152 * \defgroup serial fields 153 * @{ 154 */ 155 156 /** 157 * This can be adjusted before startup by platform-specific startup code -- that is, preference code. 158 */ 159 int max_undo_level; 160 161 int undo_chain_size; 162 int undo_chain_num; 163 byte **undo_chain; 164 165 /** 166 * This will contain a copy of RAM (ramstate to endmem) as it exists in the game file. 167 */ 168 byte *ramcache; 169 170 /**@}*/ 171 172 /** 173 * \defgroup string fields 174 * @{ 175 */ 176 177 uint iosys_mode; 178 uint iosys_rock; 179 180 /** 181 * The current string-decoding tables, broken out into a fast and easy-to-use form. 182 */ 183 bool tablecache_valid; 184 cacheblock_t tablecache; 185 186 /* This misbehaves if a Glk function has more than one S argument. */ 187 #define STATIC_TEMP_BUFSIZE (127) 188 char temp_buf[STATIC_TEMP_BUFSIZE + 1]; 189 190 /**@}*/ 191 192 Common::String _savegameDescription; 193 protected: 194 /** 195 * \defgroup glkop fields 196 * @{ 197 */ 198 199 /** 200 * The library_select_hook is called every time the VM blocks for input. 201 * The app might take this opportunity to autosave, for example. 202 */ 203 void (*library_select_hook)(uint); 204 205 arrayref_t *arrays; 206 207 /** 208 * The list of hash tables, for the classes. 209 */ 210 int num_classes; 211 classtable_t **classes; 212 213 /**@}*/ 214 215 /** 216 * \defgroup accel support methods 217 * @{ 218 */ 219 220 void accel_error(const char *msg); 221 uint func_1_z__region(uint argc, uint *argv); 222 223 /** 224 * The old set of accel functions (2 through 7) are deprecated; they behave badly if the Inform 6 225 * NUM_ATTR_BYTES option (parameter 7) is changed from its default value (7). They will not be removed, 226 * but new games should use functions 8 through 13 instead 227 */ 228 uint func_2_cp__tab(uint argc, uint *argv); 229 uint func_3_ra__pr(uint argc, uint *argv); 230 uint func_4_rl__pr(uint argc, uint *argv); 231 uint func_5_oc__cl(uint argc, uint *argv); 232 uint func_6_rv__pr(uint argc, uint *argv); 233 uint func_7_op__pr(uint argc, uint *argv); 234 235 /** 236 * Here are the newer functions, which support changing NUM_ATTR_BYTES. 237 These call get_prop_new() instead of get_prop() 238 */ 239 uint func_8_cp__tab(uint argc, uint *argv); 240 uint func_9_ra__pr(uint argc, uint *argv); 241 uint func_10_rl__pr(uint argc, uint *argv); 242 uint func_11_oc__cl(uint argc, uint *argv); 243 uint func_12_rv__pr(uint argc, uint *argv); 244 uint func_13_op__pr(uint argc, uint *argv); 245 int obj_in_class(uint obj); 246 247 /** 248 * Look up a property entry. 249 */ 250 uint get_prop(uint obj, uint id); 251 252 /** 253 * Look up a property entry. This is part of the newer set of accel functions (8 through 13), 254 * which support increasing NUM_ATTR_BYTES. It is identical to get_prop() except that it calls 255 * the new versions of func_5 and func_2 256 */ 257 uint get_prop_new(uint obj, uint id); 258 259 /**@}*/ 260 261 /** 262 * \defgroup glkop support methods 263 * @{ 264 */ 265 266 /** 267 * Build a hash table to hold a set of Glk objects. 268 */ 269 classtable_t *new_classtable(uint firstid); 270 271 /** 272 * Find a Glk object in the appropriate hash table. 273 */ 274 void *classes_get(int classid, uint objid); 275 276 /** 277 * Put a Glk object in the appropriate hash table. If origid is zero, invent a new 278 * unique ID for it. 279 */ 280 classref_t *classes_put(int classid, void *obj, uint origid); 281 282 /** 283 * Delete a Glk object from the appropriate hash table. 284 */ 285 void classes_remove(int classid, void *obj); 286 287 long glulxe_array_locate(void *array, uint len, char *typecode, gidispatch_rock_t objrock, int *elemsizeref); 288 gidispatch_rock_t glulxe_array_restore(long bufkey, uint len, char *typecode, void **arrayref); 289 290 char *grab_temp_c_array(uint addr, uint len, int passin); 291 void release_temp_c_array(char *arr, uint addr, uint len, int passout); 292 uint *grab_temp_i_array(uint addr, uint len, int passin); 293 void release_temp_i_array(uint *arr, uint addr, uint len, int passout); 294 void **grab_temp_ptr_array(uint addr, uint len, int objclass, int passin); 295 void release_temp_ptr_array(void **arr, uint addr, uint len, int objclass, int passout); 296 297 /** 298 * This reads through the prototype string, and pulls Floo objects off the stack. It also works out the maximal number 299 * of gluniversal_t objects which could be used by the Glk call in question. It then allocates space for them. 300 */ 301 void prepare_glk_args(const char *proto, dispatch_splot_t *splot); 302 303 /** 304 * This long and unpleasant function translates a set of Floo objects into a gluniversal_t array. It's recursive, too, 305 * to deal with structures. 306 */ 307 void parse_glk_args(dispatch_splot_t *splot, const char **proto, int depth, int *argnumptr, uint subaddress, int subpassin); 308 309 /** 310 * This is about the reverse of parse_glk_args(). 311 */ 312 void unparse_glk_args(dispatch_splot_t *splot, const char **proto, int depth, 313 int *argnumptr, uint subaddress, int subpassout); 314 315 /** 316 * Create a string identifying this game. We use the first 64 bytes of the memory map, encoded as hex, 317 */ 318 char *get_game_id(); 319 320 uint ReadMemory(uint addr); 321 void WriteMemory(uint addr, uint val); 322 char *CaptureCArray(uint addr, uint len, int passin); 323 void ReleaseCArray(char *ptr, uint addr, uint len, int passout); 324 uint *CaptureIArray(uint addr, uint len, int passin); 325 void ReleaseIArray(uint *ptr, uint addr, uint len, int passout); 326 void **CapturePtrArray(uint addr, uint len, int objclass, int passin); 327 void ReleasePtrArray(void **ptr, uint addr, uint len, int objclass, int passout); 328 uint ReadStructField(uint addr, uint fieldnum); 329 void WriteStructField(uint addr, uint fieldnum, uint val); 330 char *DecodeVMString(uint addr); 331 void ReleaseVMString(char *ptr); 332 uint32 *DecodeVMUstring(uint addr); 333 void ReleaseVMUstring(uint32 *ptr); 334 335 /**@}*/ 336 337 /** 338 * \defgroup search support methods 339 * @{ 340 */ 341 342 /** 343 * This massages the key into a form that's easier to handle. When it returns, the key will 344 * be stored in keybuf if keysize <= 4; otherwise, it will be in memory. 345 */ 346 void fetchkey(unsigned char *keybuf, uint key, uint keysize, uint options); 347 348 /**@}*/ 349 350 /** 351 * \defgroup serial support methods 352 * @{ 353 */ 354 355 uint write_memstate(dest_t *dest); 356 uint write_heapstate(dest_t *dest, int portable); 357 uint write_stackstate(dest_t *dest, int portable); 358 uint read_memstate(dest_t *dest, uint chunklen); 359 uint read_heapstate(dest_t *dest, uint chunklen, int portable, uint *sumlen, uint **summary); 360 uint read_stackstate(dest_t *dest, uint chunklen, int portable); 361 uint write_heapstate_sub(uint sumlen, uint *sumarray, dest_t *dest, int portable); 362 static int sort_heap_summary(const void *p1, const void *p2); 363 364 int read_byte(dest_t *dest, byte *val); 365 int read_short(dest_t *dest, uint16 *val); 366 int read_long(dest_t *dest, uint *val); 367 368 int write_byte(dest_t *dest, byte val); 369 int write_short(dest_t *dest, uint16 val); 370 int write_long(dest_t *dest, uint val); 371 372 int read_buffer(dest_t *dest, byte *ptr, uint len); 373 int reposition_write(dest_t *dest, uint pos); 374 int write_buffer(dest_t *dest, const byte *ptr, uint len); 375 376 /**@}*/ 377 378 /** 379 * \defgroup string support methods 380 * @{ 381 */ 382 383 void stream_setup_unichar(); 384 385 void nopio_char_han(unsigned char ch); 386 void filio_char_han(unsigned char ch); 387 void nopio_unichar_han(uint32 ch); 388 void filio_unichar_han(uint32 ch); 389 void glkio_unichar_nouni_han(uint32 val); 390 391 void dropcache(cacheblock_t *cablist); 392 void buildcache(cacheblock_t *cablist, uint nodeaddr, int depth, int mask); 393 void dumpcache(cacheblock_t *cablist, int count, int indent); 394 395 /**@}*/ 396 public: 397 /** 398 * Constructor 399 */ 400 Glulx(OSystem *syst, const GlkGameDescription &gameDesc); 401 402 /** 403 * Run the game 404 */ 405 void runGame() override; 406 407 /** 408 * Returns the running interpreter type 409 */ getInterpreterType()410 InterpreterType getInterpreterType() const override { 411 return INTERPRETER_GLULX; 412 } 413 414 /** 415 * Loads Quetzal chunks from the passed savegame 416 */ 417 Common::Error loadGameChunks(QuetzalReader &quetzal) override; 418 419 /** 420 * Writes out the Quetzal chunks within a savegame 421 */ 422 Common::Error saveGameChunks(QuetzalWriter &quetzal) override; 423 424 /** 425 * Load a savegame from the passed Quetzal file chunk stream 426 */ 427 Common::Error readSaveData(Common::SeekableReadStream *rs) override; 428 429 /** 430 * Save the game. The passed write stream represents access to the UMem chunk 431 * in the Quetzal save file that will be created 432 */ 433 Common::Error writeGameData(Common::WriteStream *ws) override; 434 435 /** 436 * \defgroup Main access methods 437 * @{ 438 */ 439 440 /** 441 * Display an error in the error window, and then exit. 442 */ 443 void NORETURN_PRE fatal_error_handler(const char *str, const char *arg, bool useVal, int val); 444 445 /** 446 * Display a warning in the error window, and then continue. 447 */ 448 void nonfatal_warning_handler(const char *str, const char *arg, bool useVal, int val); 449 450 /** 451 * \defgroup Files access methods 452 * @{ 453 */ 454 455 /** 456 * Validates the game file, and if it's invalid, displays an error dialog 457 */ 458 bool is_gamefile_valid(); 459 460 /**@}*/ 461 462 /** 463 * \defgroup Vm access methods 464 * @{ 465 */ 466 467 /** 468 * Read in the game file and build the machine, allocating all the memory necessary. 469 */ 470 void setup_vm(); 471 472 /** 473 * Deallocate all the memory and shut down the machine. 474 */ 475 void finalize_vm(); 476 477 /** 478 * Put the VM into a state where it's ready to begin executing the game. This is called 479 * both at startup time, and when the machine performs a "restart" opcode. 480 */ 481 void vm_restart(); 482 483 /** 484 * Change the size of the memory map. This may not be available at all; #define FIXED_MEMSIZE 485 * if you want the interpreter to unconditionally refuse. The internal flag should be true only 486 * when the heap-allocation system is calling. Returns 0 for success; otherwise, the operation failed. 487 */ 488 uint change_memsize(uint newlen, bool internal); 489 490 /** 491 * If addr is 0, pop N arguments off the stack, and put them in an array. If non-0, take N arguments 492 * from that main memory address instead. This has to dynamically allocate if there are more than 493 * 32 arguments, but that shouldn't be a problem. 494 */ 495 uint *pop_arguments(uint count, uint addr); 496 497 /** 498 * Make sure that count bytes beginning with addr all fall within the current memory map. 499 * This is called at every memory (read) access if VERIFY_MEMORY_ACCESS is defined in the header file. 500 */ 501 void verify_address(uint addr, uint count); 502 503 /** 504 * Make sure that count bytes beginning with addr all fall within RAM. This is called at every memory 505 * write if VERIFY_MEMORY_ACCESS is defined in the header file. 506 */ 507 void verify_address_write(uint addr, uint count); 508 509 /** 510 * Make sure that an array of count elements (size bytes each), starting at addr, does not fall 511 * outside the memory map. This goes to some trouble that verify_address() does not, because we need 512 * to be wary of lengths near -- or beyond -- 0x7FFFFFFF. 513 */ 514 void verify_array_addresses(uint addr, uint count, uint size); 515 516 /**@}*/ 517 518 /** 519 * \defgroup Exec access methods 520 * @{ 521 */ 522 523 /** 524 * The main interpreter loop. This repeats until the program is done 525 */ 526 void execute_loop(); 527 528 /**@}*/ 529 530 /** 531 * \defgroup Operand access methods 532 * @{ 533 */ 534 535 /** 536 * Set up the fast-lookup array of operandlists. This is called just once, when the terp starts up. 537 */ 538 void init_operands(); 539 540 /** 541 * Return the operandlist for a given opcode. For opcodes in the range 00..7F, it's faster 542 * to use the array fast_operandlist[]. 543 */ 544 const operandlist_t *lookup_operandlist(uint opcode); 545 546 /** 547 * Read the list of operands of an instruction, and put the values in args. This assumes 548 * that the PC is at the beginning of the operand mode list (right after an opcode number.) 549 * Upon return, the PC will be at the beginning of the next instruction. 550 * 551 * This also assumes that args points at an allocated array of MAX_OPERANDS oparg_t structures. 552 */ 553 void parse_operands(oparg_t *opargs, const operandlist_t *oplist); 554 555 /** 556 * Store a result value, according to the desttype and destaddress given. This is usually used to store 557 * the result of an opcode, but it's also used by any code that pulls a call-stub off the stack. 558 */ 559 void store_operand(uint desttype, uint destaddr, uint storeval); 560 561 void store_operand_s(uint desttype, uint destaddr, uint storeval); 562 void store_operand_b(uint desttype, uint destaddr, uint storeval); 563 564 /**@}*/ 565 566 /** 567 * \defgroup Func access methods 568 * @{ 569 */ 570 571 /** 572 * This writes a new call frame onto the stack, at stackptr. It leaves frameptr pointing 573 * to the frame (ie, the original stackptr value.) argc and argv are an array of arguments. 574 * Note that if argc is zero, argv may be nullptr. 575 */ 576 void enter_function(uint addr, uint argc, uint *argv); 577 578 /** 579 * Pop the current call frame off the stack. This is very simple. 580 */ 581 void leave_function(); 582 583 /** 584 * Push the magic four values on the stack: result destination, PC, and frameptr. 585 */ 586 void push_callstub(uint desttype, uint destaddr); 587 588 /** 589 * Remove the magic four values from the stack, and use them. The returnvalue, whatever it is, 590 * is put at the result destination; the PC and frameptr registers are set. 591 */ 592 void pop_callstub(uint returnvalue); 593 594 /** 595 * Remove the magic four values, but interpret them as a string restart state. 596 * Returns zero if it's a termination stub, or returns the restart address. The bitnum is extra. 597 */ 598 uint pop_callstub_string(int *bitnum); 599 600 /**@}*/ 601 602 /** 603 * \defgroup Heap access methods 604 * @{ 605 */ 606 607 /** 608 * Set the heap state to inactive, and free the block lists. This is called when the game 609 * starts or restarts. 610 */ 611 void heap_clear(); 612 613 /** 614 * Returns whether the heap is active. 615 */ 616 int heap_is_active() const; 617 618 /** 619 * Returns the start address of the heap, or 0 if the heap is not active. 620 */ 621 uint heap_get_start() const; 622 623 /** 624 * Allocate a block. If necessary, activate the heap and/or extend memory. This may not be 625 * available at all; #define FIXED_MEMSIZE if you want the interpreter to unconditionally refuse. 626 * Returns the memory address of the block, or 0 if the operation failed. 627 */ 628 uint heap_alloc(uint len); 629 630 /** 631 * Free a heap block. If necessary, deactivate the heap. 632 */ 633 void heap_free(uint addr); 634 635 /** 636 * Create an array of words, in the VM serialization format: 637 * 638 * heap_start 639 * alloc_count 640 * addr of first block 641 * len of first block 642 * ... 643 * 644 * (Note that these are uint values -- native byte ordering. Also, the blocks will be in address order, 645 * which is a stricter guarantee than the VM specifies; that'll help in heap_apply_summary().) 646 * 647 * If the heap is inactive, store nullptr. Return 0 for success; otherwise, the operation failed. 648 * 649 * The array returned in summary must be freed with glulx_free() after the caller uses it. 650 */ 651 int heap_get_summary(uint *valcount, uint **summary); 652 653 /** 654 * Given an array of words in the above format, set up the heap to contain it. As noted above, 655 * the caller must ensure that the blocks are in address order. When this is called, the heap 656 * must be inactive. 657 * 658 * Return 0 for success. Otherwise the operation failed (and, most likely, caused a fatal error). 659 */ 660 int heap_apply_summary(uint valcount, uint *summary); 661 662 /**@}*/ 663 664 /** 665 * \defgroup Serial access methods 666 * @{ 667 */ 668 669 /**@}*/ 670 671 /** 672 * \defgroup Search access methods 673 * @{ 674 */ 675 676 677 /** 678 * An array of data structures is stored in memory, beginning at start, each structure being structsize bytes. 679 * Within each struct, there is a key value keysize bytes long, starting at position keyoffset (from 680 * the start of the structure.) Search through these in order. If one is found whose key matches, return it. 681 * If numstructs are searched with no result, return nullptr. 682 * 683 * numstructs may be -1 (0xFFFFFFFF) to indicate no upper limit to the number of structures to search. 684 * The search will continue until a match is found, or (if ZeroKeyTerminates is set) a zero key. 685 * 686 * The KeyIndirect, ZeroKeyTerminates, and ReturnIndex options may be used. 687 */ 688 uint linear_search(uint key, uint keysize, uint start, uint structsize, uint numstructs, 689 uint keyoffset, uint options); 690 691 /** 692 * An array of data structures is in memory, as above. However, the structs must be stored in forward 693 * order of their keys (taking each key to be a multibyte unsigned integer.) There can be no duplicate keys. 694 * numstructs must indicate the exact length of the array; it cannot be -1. 695 * 696 * The KeyIndirect and ReturnIndex options may be used. 697 */ 698 uint binary_search(uint key, uint keysize, uint start, uint structsize, uint numstructs, 699 uint keyoffset, uint options); 700 701 /** 702 * The structures may be anywhere in memory, in any order. They are linked by a four-byte address field, 703 * which is found in each struct at position nextoffset. If this field contains zero, it indicates 704 * the end of the linked list. 705 * 706 * The KeyIndirect and ZeroKeyTerminates options may be used. 707 */ 708 uint linked_search(uint key, uint keysize, uint start, uint keyoffset, uint nextoffset, uint options); 709 710 /**@}*/ 711 712 /** 713 * \defgroup Osdepend access methods 714 * @{ 715 */ 716 glulx_malloc(uint len)717 inline void *glulx_malloc(uint len) { 718 return malloc(len); 719 } glulx_realloc(void * ptr,uint len)720 inline void *glulx_realloc(void *ptr, uint len) { 721 return realloc(ptr, len); 722 } glulx_free(void * ptr)723 inline void glulx_free(void *ptr) { 724 free(ptr); 725 } glulx_setrandom(uint32 seed)726 inline void glulx_setrandom(uint32 seed) { 727 _random.setSeed(seed); 728 } glulx_random()729 inline uint glulx_random() { 730 return _random.getRandomNumber(0xfffffff); 731 } 732 733 void glulx_sort(void *addr, int count, int size, int(*comparefunc)(const void *p1, const void *p2)); 734 735 /**@}*/ 736 737 /** 738 * \defgroup Gestalt access methods 739 * @{ 740 */ 741 742 uint do_gestalt(uint val, uint val2); 743 744 /**@}*/ 745 746 /** 747 * \defgroup Glkop access methods 748 * @{ 749 */ 750 751 /** 752 * glkop section initialization 753 */ 754 void glkopInit(); 755 756 void set_library_select_hook(void(*func)(uint)); 757 758 /** 759 * Set up the class hash tables and other startup-time stuff. 760 */ 761 bool init_dispatch(); 762 763 /** 764 * The object registration/unregistration callbacks that the library calls 765 * to keep the hash tables up to date. 766 */ 767 gidispatch_rock_t glulxe_classtable_register(void *obj, uint objclass); 768 769 gidispatch_rock_t glulxe_classtable_register_existing(void *obj, uint objclass, uint dispid); 770 771 void glulxe_classtable_unregister(void *obj, uint objclass, gidispatch_rock_t objrock); 772 773 gidispatch_rock_t glulxe_retained_register(void *array, uint len, const char *typecode); 774 void glulxe_retained_unregister(void *array, uint len, const char *typecode, gidispatch_rock_t objrock); 775 776 /** 777 * Turn a list of Glulx arguments into a list of Glk arguments, dispatch the function call, and return the result. 778 */ 779 uint perform_glk(uint funcnum, uint numargs, uint *arglist); 780 781 /** 782 * Read the prefixes of an argument string -- the "<>&+:#!" chars. 783 */ 784 const char *read_prefix(const char *cx, int *isref, int *isarray, int *passin, int *passout, 785 int *nullok, int *isretained, int *isreturn); 786 787 /** 788 * This is used by some interpreter code which has to, well, find a Glk stream given its ID. 789 */ 790 strid_t find_stream_by_id(uint objid); 791 792 /** 793 * Return the ID of a given Glk window. 794 */ 795 uint find_id_for_window(winid_t win); 796 797 /** 798 * Return the ID of a given Glk stream. 799 */ 800 uint find_id_for_stream(strid_t str); 801 802 /** 803 * Return the ID of a given Glk fileref. 804 */ 805 uint find_id_for_fileref(frefid_t fref); 806 807 /** 808 * Return the ID of a given Glk schannel. 809 */ 810 uint find_id_for_schannel(schanid_t schan); 811 812 /**@}*/ 813 814 /** 815 * \defgroup Profile access methods 816 * @{ 817 */ 818 819 void setup_profile(strid_t stream, char *filename); 820 int init_profile(); 821 void profile_set_call_counts(int flag); 822 823 #if VM_PROFILING 824 uint profile_opcount; 825 #define profile_tick() (profile_opcount++) 826 int profile_profiling_active(); 827 void profile_in(uint addr, uint stackuse, int accel); 828 void profile_out(uint stackuse); 829 void profile_fail(const char *reason); 830 void profile_quit(); 831 #else /* VM_PROFILING */ profile_tick()832 void profile_tick() {} profile_profiling_active()833 void profile_profiling_active() {} profile_in(uint addr,uint stackuse,int accel)834 void profile_in(uint addr, uint stackuse, int accel) {} profile_out(uint stackuse)835 void profile_out(uint stackuse) {} profile_fail(const char * reason)836 void profile_fail(const char *reason) {} profile_quit()837 void profile_quit() {} 838 #endif /* VM_PROFILING */ 839 840 #if VM_DEBUGGER 841 unsigned long debugger_opcount; debugger_tick()842 void debugger_tick() { debugger_opcount++ } 843 int debugger_load_info_stream(strid_t stream); 844 int debugger_load_info_chunk(strid_t stream, uint pos, uint len); 845 void debugger_track_cpu(int flag); 846 void debugger_set_start_trap(int flag); 847 void debugger_set_quit_trap(int flag); 848 void debugger_set_crash_trap(int flag); 849 void debugger_check_story_file(); 850 void debugger_setup_start_state(); 851 int debugger_ever_invoked(); 852 int debugger_cmd_handler(char *cmd); 853 void debugger_cycle_handler(int cycle); 854 void debugger_check_func_breakpoint(uint addr); 855 void debugger_block_and_debug(char *msg); 856 void debugger_handle_crash(char *msg); 857 void debugger_handle_quit(); 858 #else /* VM_DEBUGGER */ debugger_tick()859 void debugger_tick() {} debugger_check_story_file()860 void debugger_check_story_file() {} debugger_setup_start_state()861 void debugger_setup_start_state() {} debugger_check_func_breakpoint(uint addr)862 void debugger_check_func_breakpoint(uint addr) {} debugger_handle_crash(const char * msg)863 void debugger_handle_crash(const char *msg) {} 864 #endif /* VM_DEBUGGER */ 865 866 /**@}*/ 867 868 /** 869 * \defgroup Accel access methods 870 * @{ 871 */ 872 873 acceleration_func accel_find_func(uint index); 874 acceleration_func accel_get_func(uint addr); 875 void accel_set_func(uint index, uint addr); 876 void accel_set_param(uint index, uint val); 877 878 uint accel_get_param_count() const; 879 uint accel_get_param(uint index) const; 880 881 /** 882 * Iterate the entire acceleration table, calling the callback for each (non-nullptr) entry. 883 * This is used only for autosave. 884 */ 885 void accel_iterate_funcs(void(*func)(uint index, uint addr)); 886 887 /**@}*/ 888 889 /** 890 * \defgroup Float access methods 891 * @{ 892 */ 893 #ifdef FLOAT_SUPPORT 894 895 /* Uncomment this definition if your gfloat32 type is not a standard 896 IEEE-754 single-precision (32-bit) format. Normally, Glulx assumes 897 that it can reinterpret-cast IEEE-754 int values into gfloat32 898 values. If you uncomment this, Glulx switches to lengthier 899 (but safer) encoding and decoding functions. */ 900 /* #define FLOAT_NOT_NATIVE (1) */ 901 init_float()902 int init_float() { 903 return true; 904 } 905 906 /** 907 * Encode floats by a lot of annoying bit manipulation. 908 * The function is adapted from code in Python (Objects/floatobject.c) 909 */ 910 static uint encode_float(gfloat32 val); 911 912 /** 913 * Decode floats by a lot of annoying bit manipulation. 914 * The function is adapted from code in Python (Objects/floatobject.c) 915 */ 916 static gfloat32 decode_float(uint val); 917 918 /* Uncomment this definition if your powf() function does not support 919 all the corner cases specified by C99. If you uncomment this, 920 osdepend.c will provide a safer implementation of glulx_powf(). */ 921 /* #define FLOAT_COMPILE_SAFER_POWF (1) */ 922 glulx_powf(gfloat32 val1,gfloat32 val2)923 inline gfloat32 glulx_powf(gfloat32 val1, gfloat32 val2) const { 924 return powf(val1, val2); 925 } 926 927 #endif /* FLOAT_SUPPORT */ 928 /**@}*/ 929 930 /** 931 * \defgroup serial access methods 932 * @{ 933 */ 934 935 /** 936 * Set up the undo chain and anything else that needs to be set up. 937 */ 938 bool init_serial(); 939 940 /** 941 * Clean up memory when the VM shuts down. 942 */ 943 void final_serial(); 944 945 /** 946 * Add a state pointer to the undo chain. This returns 0 on success, 1 on failure. 947 */ 948 uint perform_saveundo(); 949 950 /** 951 * Pull a state pointer from the undo chain. This returns 0 on success, 1 on failure. 952 * Note that if it succeeds, the frameptr, localsbase, and valstackbase registers are invalid; 953 * they must be rebuilt from the stack. 954 */ 955 uint perform_restoreundo(); 956 957 uint perform_verify(); 958 959 /**@}*/ 960 961 /** 962 * \defgroup Strings access methods 963 * @{ 964 */ 965 966 /** 967 * Write a signed integer to the current output stream. 968 */ 969 void stream_num(int val, int inmiddle, int charnum); 970 971 /** 972 * Write a Glulx string object to the current output stream. inmiddle is zero if we are beginning 973 * a new string, or nonzero if restarting one (E0/E1/E2, as appropriate for the string type). 974 */ 975 void stream_string(uint addr, int inmiddle, int bitnum); 976 977 /** 978 * Get the current table address. 979 */ 980 uint stream_get_table(); 981 982 /** 983 * Set the current table address, and rebuild decoding cache. 984 */ 985 void stream_set_table(uint addr); 986 987 void stream_get_iosys(uint *mode, uint *rock); 988 void stream_set_iosys(uint mode, uint rock); 989 char *make_temp_string(uint addr); 990 uint32 *make_temp_ustring(uint addr); 991 void free_temp_string(char *str); 992 void free_temp_ustring(uint32 *str); 993 994 /**@}*/ 995 }; 996 997 extern Glulx *g_vm; 998 999 #define fatal_error(s) (fatal_error_handler((s), nullptr, false, 0)) 1000 #define fatal_error_2(s1, s2) (fatal_error_handler((s1), (s2), false, 0)) 1001 #define fatal_error_i(s, v) (fatal_error_handler((s), nullptr, true, (v))) 1002 #define nonfatal_warning(s) (nonfatal_warning_handler((s), nullptr, false, 0)) 1003 #define nonfatal_warning_2(s1, s2) (nonfatal_warning_handler((s1), (s2), false, 0)) 1004 #define nonfatal_warning_i(s, v) (nonfatal_warning_handler((s), nullptr, true, (v))) 1005 1006 } // End of namespace Glulx 1007 } // End of namespace Glk 1008 1009 #endif 1010