示例#1
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 */
示例#2
0
        }/* direct_call */

        /*
         * __extended__
         *
         * Load and execute an extended opcode.
         *
         */

        static void __extended__()
        {
            zbyte opcode;
            zbyte specifier;

            FastMem.CODE_BYTE(out opcode);
            FastMem.CODE_BYTE(out specifier);

            load_all_operands(specifier);

            if (opcode < 0x1e)                  /* extended opcodes from 0x1e on */
            // ext_opcodes[opcode] ();		/* are reserved for future spec' */
            {
                private_invoke(ext_opcodes[opcode], "Extended", opcode, opcode);
            }
        }/* __extended__ */
示例#3
0
        }/* ret */

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

        internal static void branch(bool flag)
        {
            long  pc;
            zword offset;
            zbyte specifier;
            zbyte off1;
            zbyte off2;

            FastMem.CODE_BYTE(out specifier);

            off1 = (zbyte)(specifier & 0x3f);

            if (!flag)
            {
                specifier ^= 0x80;
            }

            if ((specifier & 0x40) == 0)
            {                          // if (!(specifier & 0x40)) {		/* it's a long branch */
                if ((off1 & 0x20) > 0) /* propagate sign bit */
                {
                    off1 |= 0xc0;
                }

                FastMem.CODE_BYTE(out off2);

                offset = (zword)((off1 << 8) | off2);
            }
            else
            {
                offset = off1;          /* it's a short branch */
            }
            if ((specifier & 0x80) > 0)
            {
                if (offset > 1)
                {               /* normal branch */
                    FastMem.GET_PC(out pc);
                    pc += (short)offset - 2;
                    FastMem.SET_PC(pc);
                }
                else
                {
                    ret(offset);                /* special case, return 0 or 1 */
                }
            }
        }/* branch */
示例#4
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 */
示例#5
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 */
示例#6
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 */