diff options
Diffstat (limited to 'engines/glk/frotz/processor.h')
-rw-r--r-- | engines/glk/frotz/processor.h | 1584 |
1 files changed, 1584 insertions, 0 deletions
diff --git a/engines/glk/frotz/processor.h b/engines/glk/frotz/processor.h new file mode 100644 index 0000000000..b5c113def0 --- /dev/null +++ b/engines/glk/frotz/processor.h @@ -0,0 +1,1584 @@ +/* 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. + * + */ + +#ifndef GLK_FROTZ_PROCESSOR +#define GLK_FROTZ_PROCESSOR + +#include "glk/frotz/mem.h" +#include "glk/frotz/glk_interface.h" +#include "glk/frotz/frotz_types.h" +#include "common/stack.h" + +namespace Gargoyle { +namespace Frotz { + +#define TEXT_BUFFER_SIZE 200 + +#define CODE_BYTE(v) v = codeByte() +#define CODE_WORD(v) v = codeWord() +#define CODE_IDX_WORD(v,i) v = codeWordIdx(i) +#define GET_PC(v) v = getPC() +#define SET_PC(v) setPC(v) + +enum string_type { + LOW_STRING, ABBREVIATION, HIGH_STRING, EMBEDDED_STRING, VOCABULARY +}; + +class Processor; +class Quetzal; +typedef void (Processor::*Opcode)(); + +/** + * Zcode processor + */ +class Processor : public GlkInterface, public virtual Mem { + friend class Quetzal; +private: + Opcode op0_opcodes[16]; + Opcode op1_opcodes[16]; + static const char *const ERR_MESSAGES[ERR_NUM_ERRORS]; + static Opcode var_opcodes[64]; + static Opcode ext_opcodes[64]; + + int _finished; + zword zargs[8]; + int zargc; + uint _randomInterval; + uint _randomCtr; + bool first_restart; + bool script_valid; + + // Stack data + zword _stack[STACK_SIZE]; + zword *_sp; + zword *_fp; + zword _frameCount; + + // Text related fields + static zchar ZSCII_TO_LATIN1[]; + zchar *_decoded, *_encoded; + int _resolution; + int _errorCount[ERR_NUM_ERRORS]; + + // Buffer related fields + bool _locked; + zchar _prevC; + zchar _buffer[TEXT_BUFFER_SIZE]; + size_t _bufPos; + + // Stream related fields + int script_width; + strid_t sfp, rfp, pfp; + Common::FixedStack<Redirect, MAX_NESTING> _redirect; +private: + /** + * \defgroup General support methods + * @{ + */ + + /** + * Load an operand, either a variable or a constant. + */ + void load_operand(zbyte type); + + /** + * Given the operand specifier byte, load all (up to four) operands + * for a VAR or EXT opcode. + */ + void load_all_operands(zbyte specifier); + + /** + * Call a subroutine. Save PC and FP then load new PC and initialise + * new stack frame. Note that the caller may legally provide less or + * more arguments than the function actually has. The call type "ct" + * can be 0 (z_call_s), 1 (z_call_n) or 2 (direct call). + */ + void call(zword routine, int argc, zword *args, int ct); + + /** + * Return from the current subroutine and restore the previous _stack + * frame. The result may be stored (0), thrown away (1) or pushed on + * the stack (2). In the latter case a direct call has been finished + * and we must exit the interpreter loop. + */ + void ret(zword value); + + /** + * Take a jump after an instruction based on the flag, either true or + * false. The branch can be short or long; it is encoded in one or two + * bytes respectively. When bit 7 of the first byte is set, the jump + * takes place if the flag is true; otherwise it is taken if the flag + * is false. When bit 6 of the first byte is set, the branch is short; + * otherwise it is long. The offset occupies the bottom 6 bits of the + * first byte plus all the bits in the second byte for long branches. + * Uniquely, an offset of 0 means return false, and an offset of 1 is + * return true. + */ + void branch(bool flag); + + /** + * Store an operand, either as a variable or pushed on the stack. + */ + void store(zword value); + + /* + * Call the interpreter loop directly. This is necessary when + * + * - a sound effect has been finished + * - a read instruction has timed out + * - a newline countdown has hit zero + * + * The interpreter returns the result value on the stack. + */ + int direct_call(zword addr); + + /** + * Set the seed value for the random number generator. + */ + void seed_random(int value); + + /**@}*/ + + /** + * \defgroup Input support methods + * @{ + */ + + /** + * Copy the contents of the text buffer to the output streams. + */ + void flush_buffer(); + + /** + * High level output function. + */ + void print_char(zchar c); + + /** + * Print a string of ASCII characters. + */ + void print_string(const char *s); + + /** + * Print an unsigned 32bit number in decimal or hex. + */ + void print_long(uint value, int base); + + /** + * High level newline function. + */ + void new_line(); + + /** + * Returns true if the buffer is empty + */ + bool bufferEmpty() const { return !_bufPos; } + + /** + * An error has occurred. Ignore it, pass it to os_fatal or report + * it according to err_report_mode. + * @param errNum Numeric code for error (1 to ERR_NUM_ERRORS) + */ + void runtimeError(ErrorCode errNum); + + /**@}*/ + + /** + * \defgroup Input support methods + * @{ + */ + + /** + * Check if the given key is an input terminator. + */ + bool is_terminator(zchar key); + + /** + * Ask the user a question; return true if the answer is yes. + */ + bool read_yes_or_no(const char *s); + + /** + * Read a string from the current input stream. + */ + void read_string(int max, zchar *buffer); + + /** + * Ask the user to type in a number and return it. + */ + int read_number(); + + /**@}*/ + + /** + * \defgroup Memory support methods + * @{ + */ + + /** + * Called when the H_FLAGS field of the header has changed + */ + virtual void flagsChanged(zbyte value) override; + + /** + * This function does the dirty work for z_save_undo. + */ + int save_undo(); + + /** + * This function does the dirty work for z_restore_undo. + */ + int restore_undo(); + + /** + * Begin output redirection to the memory of the Z-machine. + */ + void memory_open(zword table, zword xsize, bool buffering); + + /** + * End of output redirection. + */ + void memory_close(); + + /** + * Redirect a newline to the memory of the Z-machine. + */ + void memory_new_line(); + + /** + * Redirect a string of characters to the memory of the Z-machine. + */ + void memory_word(const zchar *s); + + /**@}*/ + + /** + * \defgroup Object support methods + * @{ + */ + + /** + * Calculate the address of an object. + */ + zword object_address(zword obj); + + /** + * Return the address of the given object's name. + */ + zword object_name(zword object); + + /** + * Calculate the start address of the property list associated with an object. + */ + zword first_property(zword obj); + + /** + * Calculate the address of the next property in a property list. + */ + zword next_property(zword prop_addr); + + /** + * Unlink an object from its parent and siblings. + */ + void unlink_object(zword object); + + /**@}*/ + + /** + * \defgroup Screen support methods + * @{ + */ + + void screen_char(zchar c); + void screen_new_line(); + void screen_word(const zchar *s); + void screen_mssg_on(); + void screen_mssg_off(); + + /**@}*/ + + /** + * \defgroup Stream support methods + * @{ + */ + + /** + * Waits for the user to type an input line + */ + zchar console_read_input(int max, zchar *buf, zword timeout, bool continued); + + /** + * Waits for a keypress + */ + zchar console_read_key(zword timeout); + + /** + * Write a single character to the scrollback buffer. + * + */ + void scrollback_char(zchar c); + + /** + * Write a string to the scrollback buffer. + */ + void scrollback_word(const zchar *s); + + /** + * Send an input line to the scrollback buffer. + */ + void scrollback_write_input(const zchar *buf, zchar key); + + /** + * Remove an input line from the scrollback buffer. + */ + void scrollback_erase_input(const zchar *buf); + + /** + * Start printing a "debugging" message. + */ + void stream_mssg_on(); + + /** + * Stop printing a "debugging" message. + */ + void stream_mssg_off(); + + /** + * Send a single character to the output stream. + */ + void stream_char(zchar c); + + /** + * Send a string of characters to the output streams. + */ + void stream_word(const zchar *s); + + /** + * Send a newline to the output streams. + */ + void stream_new_line(); + + /** + * Read a single keystroke from the current input stream. + */ + zchar stream_read_key(zword timeout, zword routine, bool hot_keys); + + /** + * Read a line of input from the current input stream. + */ + zchar stream_read_input(int max, zchar *buf, zword timeout, zword routine, + bool hot_keys, bool no_scripting); + + /* + * script_open + * + * Open the transscript file. 'AMFV' makes this more complicated as it + * turns transscription on/off several times to exclude some text from + * the transscription file. This wasn't a problem for the original V4 + * interpreters which always sent transscription to the printer, but it + * means a problem to modern interpreters that offer to open a new file + * every time transscription is turned on. Our solution is to append to + * the old transscription file in V1 to V4, and to ask for a new file + * name in V5+. + * + */ + void script_open(); + + /* + * Stop transscription. + */ + void script_close(); + + /** + * Write a newline to the transscript file. + */ + void script_new_line(); + + /** + * Write a single character to the transscript file. + */ + void script_char(zchar c); + + /** + * Write a string to the transscript file. + */ + void script_word(const zchar *s); + + /** + * Send an input line to the transscript file. + */ + void script_write_input(const zchar *buf, zchar key); + + /** + * Remove an input line from the transscript file. + */ + void script_erase_input(const zchar *buf); + + /** + * Start sending a "debugging" message to the transscript file. + */ + void script_mssg_on(); + + /** + * Stop writing a "debugging" message. + */ + void script_mssg_off(); + + /** + * Open a file to record the player's input. + */ + void record_open(); + + /** + * Stop recording the player's input. + */ + void record_close(); + + /** + * Helper function for record_char. + */ + void record_code(int c, bool force_encoding); + + /** + * Write a character to the command file. + */ + void record_char(zchar c); + + /** + * Copy a keystroke to the command file. + */ + void record_write_key(zchar key); + + /** + * Copy a line of input to a command file. + */ + void record_write_input(const zchar *buf, zchar key); + + /** + * Open a file of commands for playback. + */ + void replay_open(); + + /** + * Stop playback of commands. + */ + void replay_close(); + + /* + * Helper function for replay_key and replay_line. + */ + int replay_code(); + + /** + * Read a character from the command file. + */ + zchar replay_char(); + + /** + * Read a keystroke from a command file. + */ + zchar replay_read_key(); + + /* + * Read a line of input from a command file. + */ + zchar replay_read_input(zchar *buf); + + /**@}*/ + + /** + * \defgroup Text support methods + * @{ + */ + + /** + * Map a ZSCII character into Unicode. + */ + zchar translate_from_zscii(zbyte c); + + /** + * Convert a Unicode character to ZSCII, returning 0 on failure. + */ + zbyte unicode_to_zscii(zchar c); + + /** + * Map a Unicode character onto the ZSCII alphabet. + * + */ + zbyte translate_to_zscii(zchar c); + + /** + * Return a character from one of the three character sets. + */ + zchar alphabet(int set, int index); + + /** + * Find the number of bytes used for dictionary resolution. + */ + void find_resolution(); + + /** + * Copy a ZSCII string from the memory to the global "decoded" string. + */ + void load_string(zword addr, zword length); + + /** + * Encode the Unicode text in the global "decoded" string then write + * the result to the global "encoded" array. (This is used to look up + * words in the dictionary.) Up to V3 the vocabulary resolution is + * two, from V4 it is three, and from V9 it is any number of words. + * Because each word contains three Z-characters, that makes six or + * nine Z-characters respectively. Longer words are chopped to the + * proper size, shorter words are are padded out with 5's. For word + * completion we pad with 0s and 31s, the minimum and maximum + * Z-characters. + */ + void encode_text(int padding); + + /** + * Convert _encoded text to Unicode. The _encoded text consists of 16bit + * words. Every word holds 3 Z-characters (5 bits each) plus a spare + * bit to mark the last word. The Z-characters translate to ZSCII by + * looking at the current current character set. Some select another + * character set, others refer to abbreviations. + * + * There are several different string types: + * + * LOW_STRING - from the lower 64KB (byte address) + * ABBREVIATION - from the abbreviations table (word address) + * HIGH_STRING - from the end of the memory map (packed address) + * EMBEDDED_STRING - from the instruction stream (at PC) + * VOCABULARY - from the dictionary (byte address) + * + * The last type is only used for word completion. + */ + void decode_text(string_type st, zword addr); + + /** + * Print a signed 16bit number. + */ + void print_num(zword value); + + /** + * print_object + * + * Print an object description. + * + */ + void print_object(zword object); + + /** + * Scan a dictionary searching for the given word. The first argument + * can be + * + * 0x00 - find the first word which is >= the given one + * 0x05 - find the word which exactly matches the given one + * 0x1f - find the last word which is <= the given one + * + * The return value is 0 if the search fails. + */ + zword lookup_text(int padding, zword dct); + + /** + * tokenise_text + * + * Translate a single word to a token and append it to the token + * buffer. Every token consists of the address of the dictionary + * entry, the length of the word and the offset of the word from + * the start of the text buffer. Unknown words cause empty slots + * if the flag is set (such that the text can be scanned several + * times with different dictionaries); otherwise they are zero. + * + */ + void tokenise_text(zword text, zword length, zword from, zword parse, zword dct, bool flag); + + /** + * Split an input line into words and translate the words to tokens. + */ + void tokenise_line(zword text, zword token, zword dct, bool flag); + + /** + * Scan the vocabulary to complete the last word on the input line + * (similar to "tcsh" under Unix). The return value is + * + * 2 ==> completion is impossible + * 1 ==> completion is ambiguous + * 0 ==> completion is successful + * + * The function also returns a string in its second argument. In case + * of 2, the string is empty; in case of 1, the string is the longest + * extension of the last word on the input line that is common to all + * possible completions (for instance, if the last word on the input + * is "fo" and its only possible completions are "follow" and "folly" + * then the string is "ll"); in case of 0, the string is an extension + * to the last word that results in the only possible completion. + */ + int completion(const zchar *buffer, zchar *result); + + /** + * Convert a Unicode character to lowercase. + * Taken from Zip2000 by Kevin Bracey. + */ + zchar unicode_tolower(zchar c); + + /**@}*/ +protected: + /** + * \defgroup General Opcode methods + * @{ + */ + + /* + * Load and execute an extended opcode. + */ + void __extended__(); + + /* + * Exit game because an unknown opcode has been hit. + */ + void __illegal__(); + + /* + * Store the current _stack frame for later use with z_throw. + * + * no zargs used + */ + void z_catch(); + + /** + * Go back to the given _stack frame and return the given value. + * + * zargs[0] = value to return + * zargs[1] = _stack frame + */ + void z_throw(); + + /* + * Call a subroutine and discard its result. + * + * zargs[0] = packed address of subroutine + * zargs[1] = first argument (optional) + * ... + * zargs[7] = seventh argument (optional) + */ + void z_call_n(); + + /** + * Call a subroutine and store its result. + * + * zargs[0] = packed address of subroutine + * zargs[1] = first argument (optional) + * ... + * zargs[7] = seventh argument (optional) + */ + void z_call_s(); + + /** + * Branch if subroutine was called with >= n arg's. + * + * zargs[0] = number of arguments + */ + void z_check_arg_count(); + + /** + * Jump unconditionally to the given address. + * + * zargs[0] = PC relative address + */ + void z_jump(); + + /* + * No operation. + * + * no zargs used + */ + void z_nop(); + + /* + * Stop game and exit interpreter. + * + * no zargs used + */ + void z_quit(); + + /* + * Return from a subroutine with the given value. + * + * zargs[0] = value to return + */ + void z_ret(); + + /* + * Return from a subroutine with a value popped off the stack. + * + * no zargs used + */ + void z_ret_popped(); + + /* + * Return from a subroutine with false (0). + * + * no zargs used + */ + void z_rfalse(); + + /* + * Return from a subroutine with true (1). + * + * no zargs used + */ + void z_rtrue(); + + /** + * Store a random number or set the random number seed. + * + * zargs[0] = range (positive) or seed value (negative) + */ + void z_random(); + + /** + * Load / play / stop / discard a sound effect. + * + * zargs[0] = number of bleep (1 or 2) or sample + * zargs[1] = operation to perform (samples only) + * zargs[2] = repeats and volume (play sample only) + * zargs[3] = end-of-sound routine (play sample only, optional) + * + * Note: Volumes range from 1 to 8, volume 255 is the default volume. + * Repeats are stored in the high byte, 255 is infinite loop. + * + */ + void z_sound_effect(); + + /** + * Branch if the story file is a legal copy + */ + void z_piracy(); + + /** + * Save the current Z-machine state for a future undo. + * + * no zargs used + */ + void z_save_undo(); + + /** + * Restore a Z-machine state from memory. + * + * no zargs used + */ + void z_restore_undo(); + + /**@}*/ + + /** + * \defgroup Input Opcode methods + * @{ + */ + + /** + * Add or remove a menu and branch if successful. + * + * zargs[0] = number of menu + * zargs[1] = table of menu entries or 0 to remove menu + */ + void z_make_menu(); + + /** + * Read a line of input and (in V5+) store the terminating key. + * + * zargs[0] = address of text buffer + * zargs[1] = address of token buffer + * zargs[2] = timeout in tenths of a second (optional) + * zargs[3] = packed address of routine to be called on timeout + */ + void z_read(); + + /** + * Read and store a key. + * + * zargs[0] = input device (must be 1) + * zargs[1] = timeout in tenths of a second (optional) + * zargs[2] = packed address of routine to be called on timeout + */ + void z_read_char(); + + /** + * z_read_mouse, write the current mouse status into a table. + * + * zargs[0] = address of table + */ + void z_read_mouse(); + + /**@}*/ + + /** + * \defgroup Math Opcode methods + * @{ + */ + + /** + * 16 bit addition. + * + * zargs[0] = first value + * zargs[1] = second value + */ + void z_add(); + + /** + * Bitwise AND operation. + * + * zargs[0] = first value + * zargs[1] = second value + */ + void z_and(); + + /** + * Arithmetic SHIFT operation. + * + * zargs[0] = value + * zargs[1] = #positions to shift left (positive) or right + */ + void z_art_shift(); + + /** + * Signed 16bit division. + * + * zargs[0] = first value + * zargs[1] = second value + */ + void z_div(); + + /** + * B ranch if the first value equals any of the following. + * + * zargs[0] = first value + * zargs[1] = second value (optional) + * ... + * zargs[3] = fourth value (optional) + */ + void z_je(); + + /** + * Branch if the first value is greater than the second. + * + * zargs[0] = first value + * zargs[1] = second value + */ + void z_jg(); + + /** + * Branch if the first value is less than the second. + * + * zargs[0] = first value + * zargs[1] = second value + */ + void z_jl(); + + /** + * Branch if value is zero. + * + * zargs[0] = value + */ + void z_jz(); + + /** + * Logical SHIFT operation. + * + * zargs[0] = value + * zargs[1] = #positions to shift left (positive) or right (negative) + */ + void z_log_shift(); + + /* + * Remainder after signed 16bit division. + * + * zargs[0] = first value + * zargs[1] = second value + */ + void z_mod(); + + /** + * 16 bit multiplication. + * + * zargs[0] = first value + * zargs[1] = second value + */ + void z_mul(); + + /** + * Bitwise NOT operation. + * + * zargs[0] = value + */ + void z_not(); + + /** + * Bitwise OR operation. + * + * zargs[0] = first value + * zargs[1] = second value + */ + void z_or(); + + /** + * 16 bit substraction. + * + * zargs[0] = first value + * zargs[1] = second value + */ + void z_sub(); + + /** + * Branch if all the flags of a bit mask are set in a value. + * + * zargs[0] = value to be examined + * zargs[1] = bit mask + */ + void z_test(); + + /**@}*/ + + /** + * \defgroup Object Opcode methods + * @{ + */ + + /** + * Branch if the first object is inside the second. + * + * zargs[0] = first object + * zargs[1] = second object + */ + void z_jin(); + + /** + * Store the child of an object. + * + * zargs[0] = object + */ + void z_get_child(); + + /** + * Store the number of the first or next property. + * + * zargs[0] = object + * zargs[1] = address of current property (0 gets the first property) + */ + void z_get_next_prop(); + + /** + * Store the parent of an object. + * + * zargs[0] = object + */ + void z_get_parent(); + + /** + * Store the value of an object property. + * + * zargs[0] = object + * zargs[1] = number of property to be examined + */ + void z_get_prop(); + + /** + * Store the address of an object property. + * + * zargs[0] = object + * zargs[1] = number of property to be examined + */ + void z_get_prop_addr(); + + /** + * Store the length of an object property. + * + * zargs[0] = address of property to be examined + */ + void z_get_prop_len(); + + /** + * Store the sibling of an object. + * + * zargs[0] = object + */ + void z_get_sibling(); + + /** + * Make an object the first child of another object. + * + * zargs[0] = object to be moved + * zargs[1] = destination object + */ + void z_insert_obj(); + + /** + * Set the value of an object property. + * + * zargs[0] = object + * zargs[1] = number of property to set + * zargs[2] = value to set property to + */ + void z_put_prop(); + + /** + * Unlink an object from its parent and siblings. + * + * zargs[0] = object + */ + void z_remove_obj(); + + /** + * Set an object attribute. + * + * zargs[0] = object + * zargs[1] = number of attribute to set + */ + void z_set_attr(); + + /** + * Branch if an object attribute is set. + * + * zargs[0] = object + * zargs[1] = number of attribute to test + */ + void z_test_attr(); + + /** + * Clear an object attribute. + * + * zargs[0] = object + * zargs[1] = number of attribute to be cleared + */ + void z_clear_attr(); + + /**@}*/ + + /** + * \defgroup Screen Opcode methods + * @{ + */ + + /** + * Turn text buffering on/off. + * + * zargs[0] = new text buffering flag (0 or 1) + */ + void z_buffer_mode(); + + /** + * Set the screen buffering mode. + * + * zargs[0] = mode + */ + void z_buffer_screen(); + + /** + * Erase the line starting at the cursor position. + * + * zargs[0] = 1 + #units to erase (1 clears to the end of the line) + */ + void z_erase_line(); + + /** + * Erase a window or the screen to background colour. + * + * zargs[0] = window (-3 current, -2 screen, -1 screen & unsplit) + */ + void z_erase_window(); + + /** + * Write the cursor coordinates into a table. + * + * zargs[0] = address to write information to + */ + void z_get_cursor(); + + /** + * Print ASCII text in a rectangular area. + * + * zargs[0] = address of text to be printed + * zargs[1] = width of rectangular area + * zargs[2] = height of rectangular area (optional) + * zargs[3] = number of char's to skip between lines (optional) + */ + void z_print_table(); + + /** + * Set the foreground and background colours + * to specific RGB colour values. + * + * zargs[0] = foreground colour + * zargs[1] = background colour + * zargs[2] = window (-3 is the current one, optional) + */ + void z_set_true_colour(); + + /** + * Set the foreground and background colours. + * + * zargs[0] = foreground colour + * zargs[1] = background colour + * zargs[2] = window (-3 is the current one, optional) + */ + void z_set_colour(); + + /** + * Set the font for text output and store the previous font. + * + * zargs[0] = number of font or 0 to keep current font + */ + void z_set_font(); + + /** + * Set the cursor position or turn the cursor on/off. + * + * zargs[0] = y-coordinate or -2/-1 for cursor on/off + * zargs[1] = x-coordinate + * zargs[2] = window (-3 is the current one, optional) + */ + void z_set_cursor(); + + /** + * z_set_text_style, set the style for text output. + * + * zargs[0] = style flags to set or 0 to reset text style + */ + void z_set_text_style(); + + /** + * Select the current window. + * + * zargs[0] = window to be selected (-3 is the current one) + */ + void z_set_window(); + + /** + * Display the status line for V1 to V3 games. + * + * no zargs used + */ + void pad_status_line(int column); + + /** + * Display the status line for V1 to V3 games. + * + * no zargs used + */ + void z_show_status(); + + /** + * Split the screen into an upper (1) and lower (0) window. + * + * zargs[0] = height of upper window in screen units (V6) or #lines + */ + void z_split_window(); + + /**@}*/ + + /** + * \defgroup Stream Opcode methods + * @{ + */ + + /** + * Select an input stream. + * + * zargs[0] = input stream to be selected + */ + void z_input_stream(); + + /** + * Open or close an output stream. + * + * zargs[0] = stream to open (positive) or close (negative) + * zargs[1] = address to redirect output to (stream 3 only) + * zargs[2] = width of redirected output (stream 3 only, optional) + */ + void z_output_stream(); + + /** + * Re-load dynamic area, clear the stack and set the PC. + * + * no zargs used + */ + void z_restart(); + + /** + * Save [a part of] the Z-machine state to disk. + * + * zargs[0] = address of memory area to save (optional) + * zargs[1] = number of bytes to save + * zargs[2] = address of suggested file name + */ + void z_save(); + + /** + * Restore [a part of] a Z-machine state from disk + * + * zargs[0] = address of area to restore (optional) + * zargs[1] = number of bytes to restore + * zargs[2] = address of suggested file name + */ + void z_restore(); + + /** + * Check the story file integrity. + * + * no zargs used + */ + void z_verify(); + + /**@}*/ + + /** + * \defgroup Table Opcode methods + * @{ + */ + + /** + * Copy a table or fill it with zeroes. + * + * zargs[0] = address of table + * zargs[1] = destination address or 0 for fill + * zargs[2] = size of table + * + * Note: Copying is safe even when source and destination overlap; but + * if zargs[1] is negative the table _must_ be copied forwards. + */ + void z_copy_table(); + + /** + * Store a value from a table of bytes. + * + * zargs[0] = address of table + * zargs[1] = index of table entry to store + */ + void z_loadb(); + + /** + * Store a value from a table of words. + * + * zargs[0] = address of table + * zargs[1] = index of table entry to store + */ + void z_loadw(); + + /** + * Find and store the address of a target within a table. + * + * zargs[0] = target value to be searched for + * zargs[1] = address of table + * zargs[2] = number of table entries to check value against + * zargs[3] = type of table (optional, defaults to 0x82) + * + * Note: The table is a word array if bit 7 of zargs[3] is set; otherwise + * it's a byte array. The lower bits hold the address step. + */ + void z_scan_table(); + + /** + * Write a byte into a table of bytes. + * + * zargs[0] = address of table + * zargs[1] = index of table entry + * zargs[2] = value to be written + */ + void z_storeb(); + + /** + * Write a word into a table of words. + * + * zargs[0] = address of table + * zargs[1] = index of table entry + * zargs[2] = value to be written + */ + void z_storew(); + + /**@}*/ + + /** + * \defgroup Text Opcode methods + * @{ + */ + + /** + * Test if a unicode character can be printed (bit 0) and read (bit 1). + * + * zargs[0] = Unicode + */ + void z_check_unicode(); + + /** + * Encode a ZSCII string for use in a dictionary. + * + * zargs[0] = address of text buffer + * zargs[1] = length of ASCII string + * zargs[2] = offset of ASCII string within the text buffer + * zargs[3] = address to store encoded text in + * + * This is a V5+ opcode and therefore the dictionary resolution must be + * three 16bit words. + */ + void z_encode_text(); + + /** + * Print a new line. + * + * no zargs used + * + */ + void z_new_line(); + + /** + * Print a string embedded in the instruction stream. + * + * no zargs used + */ + void z_print(); + + /** + * Print a string from the lower 64KB. + * + * zargs[0] = address of string to print + */ + void z_print_addr(); + + /** + * Print a single ZSCII character. + * + * zargs[0] = ZSCII character to be printed + */ + void z_print_char(); + + /** + * Print a formatted table. + * + * zargs[0] = address of formatted table to be printed + */ + void z_print_form(); + + /** + * Print a signed number. + * + * zargs[0] = number to print + */ + void z_print_num(); + + /** + * Print an object description. + * + * zargs[0] = number of object to be printed + */ + void z_print_obj(); + + /** + * Print the string at the given packed address. + * + * zargs[0] = packed address of string to be printed + */ + void z_print_paddr(); + + /* + * Print the string at PC, print newline then return true. + * + * no zargs used + */ + void z_print_ret(); + + /** + * Print unicode character + * + * zargs[0] = Unicode + */ + void z_print_unicode(); + + /** + * Make a lexical analysis of a ZSCII string. + * + * zargs[0] = address of string to analyze + * zargs[1] = address of token buffer + * zargs[2] = address of dictionary (optional) + * zargs[3] = set when unknown words cause empty slots (optional) + */ + void z_tokenise(); + + /**@}*/ + + /** + * \defgroup Variable Opcode methods + * @{ + */ + + /** + * Decrement a variable. + * + * zargs[0] = variable to decrement + */ + void z_dec(); + + /** + * Decrement a variable and branch if now less than value. + * + * zargs[0] = variable to decrement + * zargs[1] = value to check variable against + */ + void z_dec_chk(); + + /** + * Increment a variable. + * + * zargs[0] = variable to increment + */ + void z_inc(); + + /** + * Increment a variable and branch if now greater than value. + * + * zargs[0] = variable to increment + * zargs[1] = value to check variable against + */ + void z_inc_chk(); + + /** + * Store the value of a variable. + * + * zargs[0] = variable to store + */ + void z_load(); + + /** + * Pop a value off the game stack and discard it. + * + * no zargs used + */ + void z_pop(); + + /** + * Pop n values off the game or user stack and discard them. + * + * zargs[0] = number of values to discard + * zargs[1] = address of user stack (optional) + */ + void z_pop_stack(); + + /** + * Pop a value off... + * + * a) ...the game or a user stack and store it (V6) + * + * zargs[0] = address of user stack (optional) + * + * b) ...the game stack and write it to a variable (other than V6) + * + * zargs[0] = variable to write value to + */ + void z_pull(); + + /** + * Push a value onto the game stack. + * + * zargs[0] = value to push onto the stack + */ + void z_push(); + + /** + * Push a value onto a user stack then branch if successful. + * + * zargs[0] = value to push onto the stack + * zargs[1] = address of user stack + */ + void z_push_stack(); + + /** + * Write a value to a variable. + * + * zargs[0] = variable to be written to + * zargs[1] = value to write + */ + void z_store(); + + /**@}*/ +public: + /** + * Constructor + */ + Processor(OSystem *syst, const GargoyleGameDescription *gameDesc); + + /** + * Initialization + */ + void initialize(); + + /** + * Z-code interpreter main loop + */ + void interpret(); + + /** + * \defgroup Memory access methods + * @{ + */ + + /** + * Square brackets operator + */ + zbyte &operator[](uint addr) { return zmp[addr]; } + + /** + * Read a code byte + */ + zbyte codeByte() { return *pcp++; } + + /** + * Read a code word + */ + zword codeWord() { + zword v = READ_BE_UINT16(pcp); + pcp += 2; + return v; + } + + /** + * Return a code word at a given address + */ + zword codeWordIdx(uint addr) const { + return READ_BE_UINT16(pcp + addr); + } + + /** + * Return the current program execution offset + */ + uint getPC() const { return pcp - zmp; } + + /** + * Set the program execution offset + */ + void setPC(uint addr) { pcp = zmp + addr; } + + /**@}*/ +}; + +} // End of namespace Frotz +} // End of namespace Gargoyle + +#endif |