/* * 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 */
}/* 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 */
static void decode_text(string_type st, zword addr) { // zword* ptr; long byte_addr; zword c2; zword code; zbyte c, prev_c = 0; int shift_state = 0; int shift_lock = 0; int status = 0; // ptr = NULL; /* makes compilers shut up */ byte_addr = 0; if (resolution == 0) { find_resolution(); } /* Calculate the byte address if necessary */ if (st == string_type.ABBREVIATION) { byte_addr = (long)addr << 1; } else if (st == string_type.HIGH_STRING) { if (main.h_version <= ZMachine.V3) { byte_addr = (long)addr << 1; } else if (main.h_version <= ZMachine.V5) { byte_addr = (long)addr << 2; } else if (main.h_version <= ZMachine.V7) { byte_addr = ((long)addr << 2) + ((long)main.h_strings_offset << 3); } else /* (h_version <= V8) */ { byte_addr = (long)addr << 3; } if (byte_addr >= main.story_size) { Err.runtime_error(ErrorCodes.ERR_ILL_PRINT_ADDR); } } /* Loop until a 16bit word has the highest bit set */ if (st == string_type.VOCABULARY) { ptrDt = 0; } do { int i; /* Fetch the next 16bit word */ if (st == string_type.LOW_STRING || st == string_type.VOCABULARY) { FastMem.LOW_WORD(addr, out code); addr += 2; } else if (st == string_type.HIGH_STRING || st == string_type.ABBREVIATION) { FastMem.HIGH_WORD(byte_addr, out code); byte_addr += 2; } else { FastMem.CODE_WORD(out code); } /* Read its three Z-characters */ for (i = 10; i >= 0; i -= 5) { zword abbr_addr; zword ptr_addr; zword zc; c = (zbyte)((code >> i) & 0x1f); switch (status) { case 0: /* normal operation */ if (shift_state == 2 && c == 6) { status = 2; } else if (main.h_version == ZMachine.V1 && c == 1) { Buffer.new_line(); } else if (main.h_version >= ZMachine.V2 && shift_state == 2 && c == 7) { Buffer.new_line(); } else if (c >= 6) { outchar(st, alphabet(shift_state, c - 6)); } else if (c == 0) { outchar(st, ' '); } else if (main.h_version >= ZMachine.V2 && c == 1) { status = 1; } else if (main.h_version >= ZMachine.V3 && c <= 3) { status = 1; } else { shift_state = (shift_lock + (c & 1) + 1) % 3; if (main.h_version <= ZMachine.V2 && c >= 4) { shift_lock = shift_state; } break; } shift_state = shift_lock; break; case 1: /* abbreviation */ ptr_addr = (zword)(main.h_abbreviations + 64 * (prev_c - 1) + 2 * c); FastMem.LOW_WORD(ptr_addr, out abbr_addr); decode_text(string_type.ABBREVIATION, abbr_addr); status = 0; break; case 2: /* ZSCII character - first part */ status = 3; break; case 3: /* ZSCII character - second part */ zc = (zword)((prev_c << 5) | c); c2 = translate_from_zscii((zbyte)zc); // TODO This doesn't seem right outchar(st, c2); status = 0; break; } prev_c = c; } } while (!((code & 0x8000) > 0)); if (st == string_type.VOCABULARY) { ptrDt = 0; } }/* decode_text */