Exemple #1
0
        }/* reset_memory */

        /*
         * storeb
         *
         * Write a byte value to the dynamic Z-machine memory.
         *
         */

        internal static void storeb(zword addr, zbyte value)
        {
            if (addr >= main.h_dynamic_size)
            {
                Err.runtime_error(ErrorCodes.ERR_STORE_RANGE);
            }

            if (addr == ZMachine.H_FLAGS + 1)
            {   /* flags register is modified */
                main.h_flags &= (zword)(~(ZMachine.SCRIPTING_FLAG | ZMachine.FIXED_FONT_FLAG));
                main.h_flags |= (zword)(value & (ZMachine.SCRIPTING_FLAG | ZMachine.FIXED_FONT_FLAG));

                if ((value & ZMachine.SCRIPTING_FLAG) > 0)
                {
                    if (!main.ostream_script)
                    {
                        Files.script_open();
                    }
                }
                else
                {
                    if (main.ostream_script)
                    {
                        Files.script_close();
                    }
                }

                Screen.refresh_text_style();
            }

            SET_BYTE(addr, value);

            DebugState.Output("storeb: {0} -> {1}", addr, value);
        }/* storeb */
Exemple #2
0
        }/* load_all_operands */

        /*
         * interpret
         *
         * Z-code interpreter main loop
         *
         */

        internal static void interpret()
        {
            do
            {
                zbyte opcode;

                FastMem.CODE_BYTE(out opcode);

                DebugState.Output("CODE: {0} -> {1:X}", FastMem.pcp - 1, opcode);

                if (main.abort_game_loop == true)
                {
                    main.abort_game_loop = false;
                    return;
                }

                zargc = 0;
                if (opcode < 0x80)
                {                       /* 2OP opcodes */
                    load_operand((zbyte)((opcode & 0x40) > 0 ? 2 : 1));
                    load_operand((zbyte)((opcode & 0x20) > 0 ? 2 : 1));

                    private_invoke(var_opcodes[opcode & 0x1f], "2OP", (opcode & 0x1f), opcode);
                }
                else if (opcode < 0xb0)
                {               /* 1OP opcodes */
                    load_operand((zbyte)(opcode >> 4));

                    private_invoke(op1_opcodes[opcode & 0x0f], "1OP", (opcode & 0x0f), opcode);
                }
                else if (opcode < 0xc0)
                {               /* 0OP opcodes */
                    private_invoke(op0_opcodes[opcode - 0xb0], "0OP", (opcode - 0xb0), opcode);
                }
                else
                {                               /* VAR opcodes */
                    zbyte specifier1;
                    zbyte specifier2;

                    if (opcode == 0xec || opcode == 0xfa)
                    {                                      /* opcodes 0xec */
                        FastMem.CODE_BYTE(out specifier1); /* and 0xfa are */
                        FastMem.CODE_BYTE(out specifier2); /* call opcodes */
                        load_all_operands(specifier1);     /* with up to 8 */
                        load_all_operands(specifier2);     /* arguments    */
                    }
                    else
                    {
                        FastMem.CODE_BYTE(out specifier1);
                        load_all_operands(specifier1);
                    }

                    private_invoke(var_opcodes[opcode - 0xc0], "VAR", (opcode - 0xc0), opcode);
                }

                os_.tick();
            } while (finished == 0);

            finished--;
        }/* interpret */
Exemple #3
0
        internal static void SET_WORD(long addr, zword v)
        {
            ZMData[addr]     = HI(v);
            ZMData[addr + 1] = LO(v);

            DebugState.Output("ZMP: {0} -> {1}", addr, v);
        }
Exemple #4
0
 private static void private_invoke(zinstruction instruction, string array, int index, int opcode)
 {
     DebugState.last_call_made = instruction.Method.Name + ":" + opcode;
     DebugState.Output(false, "Invoking: {0:X} -> {1} -> {2}", opcode, instruction.Method.Name, invokeCount);
     instruction.DynamicInvoke();
     invokeCount++;
 }
Exemple #5
0
        }/* call */

        /*
         * ret
         *
         * 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.
         *
         */

        internal static void ret(zword value)
        {
            long pc;
            int  ct;

            if (main.sp > main.fp)
            {
                Err.runtime_error(ErrorCodes.ERR_STK_UNDF);
            }

            main.sp = main.fp;

            DebugState.Output("Removing Frame: {0}", main.frame_count);

            ct = main.stack[main.sp++] >> (main.option_save_quetzal == true ? 12 : 8);
            main.frame_count--;
            main.fp = 1 + main.stack[main.sp++];              // fp = stack + 1 + *sp++;
            pc      = main.stack[main.sp++];
            pc      = (main.stack[main.sp++] << 9) | (int)pc; // TODO Really don't trust casting PC to int

            FastMem.SET_PC(pc);

            /* Handle resulting value */

            if (ct == 0)
            {
                store(value);
            }
            if (ct == 2)
            {
                main.stack[--main.sp] = value;
            }

            /* Stop main loop for direct calls */

            if (ct == 2)
            {
                finished++;
            }
        }/* ret */
Exemple #6
0
        /*
         * load_operand
         *
         * Load an operand, either a variable or a constant.
         *
         */

        static void load_operand(zbyte type)
        {
            zword value;

            if ((type & 2) > 0)
            {                   /* variable */
                zbyte variable;

                FastMem.CODE_BYTE(out variable);

                if (variable == 0)
                {
                    value = main.stack[main.sp++];
                }
                else if (variable < 16)
                {
                    value = main.stack[main.fp - variable];
                }
                else
                {
                    zword addr = (zword)(main.h_globals + 2 * (variable - 16)); // TODO Make sure this logic
                    FastMem.LOW_WORD(addr, out value);
                }
            }
            else if ((type & 1) > 0)
            {           /* small constant */
                zbyte bvalue;

                FastMem.CODE_BYTE(out bvalue);
                value = bvalue;
            }
            else
            {
                FastMem.CODE_WORD(out value);           /* large constant */
            }
            zargs[zargc++] = value;

            DebugState.Output("  Storing operand: {0} -> {1}", zargc - 1, value);
        }/* load_operand */
Exemple #7
0
        }/* branch */

        /*
         * store
         *
         * Store an operand, either as a variable or pushed on the stack.
         *
         */

        internal static void store(zword value)
        {
            zbyte variable;

            FastMem.CODE_BYTE(out variable);

            if (variable == 0)
            {
                main.stack[--main.sp] = value; // *--sp = value;
                DebugState.Output("  Storing {0} on stack at {1}", value, main.sp);
            }
            else if (variable < 16)
            {
                main.stack[main.fp - variable] = value;  // *(fp - variable) = value;
                DebugState.Output("  Storing {0} on stack as Variable {1} at {2}", value, variable, main.sp);
            }
            else
            {
                zword addr = (zword)(main.h_globals + 2 * (variable - 16));
                FastMem.SET_WORD(addr, value);
                DebugState.Output("  Storing {0} at {1}", value, addr);
            }
        }/* store */
Exemple #8
0
        }/* interpret */

        /*
         * call
         *
         * 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).
         *
         */

        internal static void call(zword routine, int argc, int args_offset, int ct)
        {
            long  pc;
            zword value;
            zbyte count;
            int   i;

            if (main.sp < 4)//if (sp - stack < 4)
            {
                Err.runtime_error(ErrorCodes.ERR_STK_OVF);
            }

            FastMem.GET_PC(out pc);

            main.stack[--main.sp] = (zword)(pc >> 9);
            main.stack[--main.sp] = (zword)(pc & 0x1ff);
            main.stack[--main.sp] = (zword)(main.fp - 1); // *--sp = (zword) (fp - stack - 1);
            main.stack[--main.sp] = (zword)(argc | (ct << (main.option_save_quetzal == true ? 12 : 8)));

            main.fp = main.sp;
            main.frame_count++;

            DebugState.Output("Added Frame: {0} -> {1}:{2}:{3}:{4}",
                              main.frame_count,
                              main.stack[main.sp + 0],
                              main.stack[main.sp + 1],
                              main.stack[main.sp + 2],
                              main.stack[main.sp + 3]);

            /* Calculate byte address of routine */

            if (main.h_version <= ZMachine.V3)
            {
                pc = (long)routine << 1;
            }
            else if (main.h_version <= ZMachine.V5)
            {
                pc = (long)routine << 2;
            }
            else if (main.h_version <= ZMachine.V7)
            {
                pc = ((long)routine << 2) + ((long)main.h_functions_offset << 3);
            }
            else /* (h_version <= V8) */
            {
                pc = (long)routine << 3;
            }

            if (pc >= main.story_size)
            {
                Err.runtime_error(ErrorCodes.ERR_ILL_CALL_ADDR);
            }

            FastMem.SET_PC(pc);

            /* Initialise local variables */

            FastMem.CODE_BYTE(out count);

            if (count > 15)
            {
                Err.runtime_error(ErrorCodes.ERR_CALL_NON_RTN);
            }
            if (main.sp < count)
            {
                Err.runtime_error(ErrorCodes.ERR_STK_OVF);
            }

            if (main.option_save_quetzal == true)
            {
                main.stack[main.fp] |= (zword)(count << 8);     /* Save local var count for Quetzal. */
            }
            value = 0;

            for (i = 0; i < count; i++)
            {
                if (main.h_version <= ZMachine.V4)              /* V1 to V4 games provide default */
                {
                    FastMem.CODE_WORD(out value);               /* values for all local variables */
                }
                main.stack[--main.sp] = (zword)((argc-- > 0) ? zargs[args_offset + i] : value);
                //*--sp = (zword) ((argc-- > 0) ? args[i] : value);
            }

            /* Start main loop for direct calls */

            if (ct == 2)
            {
                interpret();
            }
        }/* call */
Exemple #9
0
        }/* restart_header */

        /*
         * init_memory
         *
         * Allocate memory and load the story file.
         *
         */

        internal static void init_memory()
        {
            long  size;
            zword addr;
            zword n;
            int   i, j;

            // TODO Abstract this part
            /* Open story file */
            // story_fp = new System.IO.FileStream(main.story_name, System.IO.FileMode.Open, System.IO.FileAccess.Read);
            story_fp = os_.path_open(main.story_data);
            if (story_fp == null)
            {
                os_.fatal("Cannot open story file");
            }
            init_fp_pos = story_fp.Position;

            storyData = new byte[story_fp.Length];
            story_fp.Read(storyData, 0, storyData.Length);
            story_fp.Position = 0;

            DebugState.Output("Starting story: {0}", main.story_name);

            /* Allocate memory for story header */

            ZMData = new byte[64];
            Frotz.Other.ZMath.clearArray(ZMData);

            /* Load header into memory */
            if (story_fp.Read(ZMData, 0, 64) != 64)
            {
                os_.fatal("Story file read error");
            }

            /* Copy header fields to global variables */
            LOW_BYTE(ZMachine.H_VERSION, out main.h_version);

            if (main.h_version < ZMachine.V1 || main.h_version > ZMachine.V8)
            {
                os_.fatal("Unknown Z-code version");
            }

            LOW_BYTE(ZMachine.H_CONFIG, out main.h_config);
            if (main.h_version == ZMachine.V3 && ((main.h_config & ZMachine.CONFIG_BYTE_SWAPPED) != 0))
            {
                os_.fatal("Byte swapped story file");
            }

            LOW_WORD(ZMachine.H_RELEASE, out main.h_release);
            LOW_WORD(ZMachine.H_RESIDENT_SIZE, out main.h_resident_size);
            LOW_WORD(ZMachine.H_START_PC, out main.h_start_pc);
            LOW_WORD(ZMachine.H_DICTIONARY, out main.h_dictionary);
            LOW_WORD(ZMachine.H_OBJECTS, out main.h_objects);
            LOW_WORD(ZMachine.H_GLOBALS, out main.h_globals);
            LOW_WORD(ZMachine.H_DYNAMIC_SIZE, out main.h_dynamic_size);
            LOW_WORD(ZMachine.H_FLAGS, out main.h_flags);

            for (i = 0, addr = ZMachine.H_SERIAL; i < 6; i++, addr++)
            {
                LOW_BYTE(addr, out main.h_serial[i]);
            }
            // TODO serial might need to be a char

            /* Auto-detect buggy story files that need special fixes */

            main.story_id = Story.UNKNOWN;

            for (i = 0; records[i].story_id != Story.UNKNOWN; i++)
            {
                if (main.h_release == records[i].release)
                {
                    for (j = 0; j < 6; j++)
                    {
                        if (main.h_serial[j] != records[i].serial[j])
                        {
                            goto no_match;
                        }
                    }

                    main.story_id = records[i].story_id;
                }

                no_match :; /* null statement */
            }

            LOW_WORD(ZMachine.H_ABBREVIATIONS, out main.h_abbreviations);
            LOW_WORD(ZMachine.H_FILE_SIZE, out main.h_file_size);

            /* Calculate story file size in bytes */
            if (main.h_file_size != 0)
            {
                main.story_size = 2 * main.h_file_size;

                if (main.h_version >= ZMachine.V4)
                {
                    main.story_size *= 2;
                }

                if (main.h_version >= ZMachine.V6)
                {
                    main.story_size *= 2;
                }

                if (main.story_id == Story.AMFV && main.h_release == 47)
                {
                    main.story_size = 2 * main.h_file_size;
                }
                else if (main.story_size > 0)
                {/* os_path_open() set the size */
                }
                else
                {/* some old games lack the file size entry */
                    main.story_size   = story_fp.Length - init_fp_pos;
                    story_fp.Position = init_fp_pos + 64;
                }

                LOW_WORD(ZMachine.H_CHECKSUM, out main.h_checksum);
                LOW_WORD(ZMachine.H_ALPHABET, out main.h_alphabet);
                LOW_WORD(ZMachine.H_FUNCTIONS_OFFSET, out main.h_functions_offset);
                LOW_WORD(ZMachine.H_STRINGS_OFFSET, out main.h_strings_offset);
                LOW_WORD(ZMachine.H_TERMINATING_KEYS, out main.h_terminating_keys);
                LOW_WORD(ZMachine.H_EXTENSION_TABLE, out main.h_extension_table);

                /* Zork Zero beta and Macintosh versions don't have the graphics flag set */

                if (main.story_id == Story.ZORK_ZERO)
                {
                    if (main.h_release == 96 || main.h_release == 153 ||
                        main.h_release == 242 || main.h_release == 296)
                    {
                        main.h_flags |= ZMachine.GRAPHICS_FLAG;
                    }
                }

                /* Adjust opcode tables */

                if (main.h_version <= ZMachine.V4)
                {
                    Process.op0_opcodes[0x09] = new Process.zinstruction(Variable.z_pop);
                    Process.op0_opcodes[0x0f] = new Process.zinstruction(Math.z_not);
                }
                else
                {
                    Process.op0_opcodes[0x09] = new Process.zinstruction(Process.z_catch);
                    Process.op0_opcodes[0x0f] = new Process.zinstruction(Process.z_call_n);
                }

                /* Allocate memory for story data */

                byte[] temp = new byte[ZMData.Length];
                Frotz.Other.ZMath.clearArray(temp);

                System.Array.Copy(ZMData, temp, ZMData.Length);

                ZMData = new byte[main.story_size];
                Frotz.Other.ZMath.clearArray(ZMData);
                System.Array.Copy(temp, ZMData, temp.Length);

                /* Load story file in chunks of 32KB */

                n = 0x8000;

                for (size = 64; size < main.story_size; size += n)
                {
                    if (main.story_size - size < 0x8000)
                    {
                        n = (ushort)(main.story_size - size);
                    }
                    SET_PC(size);

                    int read = story_fp.Read(ZMData, (int)pcp, n);

                    if (read != n)
                    {
                        os_.fatal("Story file read error");
                    }
                }

                // Take a moment to calculate the checksum of the story file in case verify is called
                ZMData_checksum = 0;
                for (int k = 64; k < ZMData.Length; k++)
                {
                    ZMData_checksum += ZMData[k];
                }
            }

            DebugState.Output("Story Size: {0}", main.story_size);

            first_restart = true;

            /* Read header extension table */

            main.hx_table_size    = get_header_extension(ZMachine.HX_TABLE_SIZE);
            main.hx_unicode_table = get_header_extension(ZMachine.HX_UNICODE_TABLE);
            main.hx_flags         = get_header_extension(ZMachine.HX_FLAGS);
        }/* init_memory */
Exemple #10
0
 internal static void SET_BYTE(long addr, byte v)
 {
     ZMData[addr] = v;
     DebugState.Output("ZMP: {0} -> {1}", addr, v);
 }