void storew (zword addr, zword value) { storeb ((zword) (addr + 0), hi (value)); storeb ((zword) (addr + 1), lo (value)); }/* storew */
/* * z_copy_table, 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 (void) { zword addr; zword size = zargs[2]; zbyte value; int i; if (zargs[1] == 0) /* zero table */ for (i = 0; i < size; i++) storeb ((zword) (zargs[0] + i), 0); else if ((short) size < 0 || zargs[0] > zargs[1]) /* copy forwards */ for (i = 0; i < (((short) size < 0) ? - (short) size : size); i++) { addr = zargs[0] + i; LOW_BYTE (addr, value) storeb ((zword) (zargs[1] + i), value); } else /* copy backwards */ for (i = size - 1; i >= 0; i--) { addr = zargs[0] + i; LOW_BYTE (addr, value) storeb ((zword) (zargs[1] + i), value); } }/* z_copy_table */
void Mem::restart_header(void) { zword screen_x_size; zword screen_y_size; zbyte font_x_size; zbyte font_y_size; int i; SET_BYTE(H_CONFIG, h_config); SET_WORD(H_FLAGS, h_flags); if (h_version >= V4) { SET_BYTE(H_INTERPRETER_NUMBER, h_interpreter_number); SET_BYTE(H_INTERPRETER_VERSION, h_interpreter_version); SET_BYTE(H_SCREEN_ROWS, h_screen_rows); SET_BYTE(H_SCREEN_COLS, h_screen_cols); } // It's less trouble to use font size 1x1 for V5 games, especially because of // a bug in the unreleased German version of "Zork 1" if (h_version != V6) { screen_x_size = (zword)h_screen_cols; screen_y_size = (zword)h_screen_rows; font_x_size = 1; font_y_size = 1; } else { screen_x_size = h_screen_width; screen_y_size = h_screen_height; font_x_size = h_font_width; font_y_size = h_font_height; } if (h_version >= V5) { SET_WORD(H_SCREEN_WIDTH, screen_x_size); SET_WORD(H_SCREEN_HEIGHT, screen_y_size); SET_BYTE(H_FONT_HEIGHT, font_y_size); SET_BYTE(H_FONT_WIDTH, font_x_size); SET_BYTE(H_DEFAULT_BACKGROUND, h_default_background); SET_BYTE(H_DEFAULT_FOREGROUND, h_default_foreground); } if (h_version == V6) for (i = 0; i < 8; i++) storeb((zword)(H_USER_NAME + i), h_user_name[i]); SET_BYTE(H_STANDARD_HIGH, h_standard_high); SET_BYTE(H_STANDARD_LOW, h_standard_low); set_header_extension(HX_FLAGS, hx_flags); set_header_extension(HX_FORE_COLOUR, hx_fore_colour); set_header_extension(HX_BACK_COLOUR, hx_back_colour); }
void memory_new_line (void) { zword size; zword addr; redirect[depth].total += redirect[depth].width; redirect[depth].width = 0; addr = redirect[depth].table; LOW_WORD (addr, size) addr += 2; if (redirect[depth].xsize != 0xffff) { redirect[depth].table = addr + size; size = 0; } else storeb ((zword) (addr + (size++)), 13); storew (redirect[depth].table, size); }/* memory_new_line */
void memory_word (const zword *s) { zword size; zword addr; zword c; if (h_version == V6) { int width = os_string_width (s); if (redirect[depth].xsize != 0xffff) if (redirect[depth].width + width > redirect[depth].xsize) { if (*s == ' ' || *s == ZC_INDENT || *s == ZC_GAP) width = os_string_width (++s); memory_new_line (); } redirect[depth].width += width; } addr = redirect[depth].table; LOW_WORD (addr, size) addr += 2; while ((c = *s++) != 0) storeb ((zword) (addr + (size++)), translate_to_zscii (c)); storew (redirect[depth].table, size); }/* memory_word */
void Mem::storew(zword addr, zword value) { storeb((zword)(addr + 0), hi(value)); storeb((zword)(addr + 1), lo(value)); }
void Processor::z_read() { zchar buffer[INPUT_BUFFER_SIZE]; zword addr; zchar key; zbyte max, size; zbyte c; int i; // Supply default arguments if (zargc < 3) zargs[2] = 0; // Get maximum input size addr = zargs[0]; LOW_BYTE(addr, max); if (h_version <= V4) max--; if (max >= INPUT_BUFFER_SIZE) max = INPUT_BUFFER_SIZE - 1; // Get initial input size if (h_version >= V5) { addr++; LOW_BYTE(addr, size); } else { size = 0; } // Copy initial input to local buffer for (i = 0; i < size; i++) { addr++; LOW_BYTE(addr, c); buffer[i] = translate_from_zscii(c); } buffer[i] = 0; // Draw status line for V1 to V3 games if (h_version <= V3) z_show_status(); // Read input from current input stream key = stream_read_input( max, buffer, // buffer and size zargs[2], // timeout value zargs[3], // timeout routine false, // enable hot keys h_version == V6 // no script in V6 ); if (key == ZC_BAD) return; // Perform save_undo for V1 to V4 games if (h_version <= V4) save_undo(); // Copy local buffer back to dynamic memory for (i = 0; buffer[i] != 0; i++) { if (key == ZC_RETURN) { buffer[i] = unicode_tolower (buffer[i]); } storeb((zword)(zargs[0] + ((h_version <= V4) ? 1 : 2) + i), translate_to_zscii(buffer[i])); } // Add null character (V1-V4) or write input length into 2nd byte if (h_version <= V4) storeb((zword)(zargs[0] + 1 + i), 0); else storeb((zword)(zargs[0] + 1), i); // Tokenise line if a token buffer is present if (key == ZC_RETURN && zargs[1] != 0) tokenise_line (zargs[0], zargs[1], 0, false); // Store key if (h_version >= V5) store(translate_to_zscii(key)); }
void NewCpu::Step() { if (_stealCycles > 0) { _stealCycles--; } else if (_dmaCycles > 0) { if (_dmaCycles % 2 == 0) { _value = loadb(_dmaAddr++); } else { storeb(0x2004, _value); } _dmaCycles--; if (_dmaCycles == 0) { _dmaAddr = 0; EndInstr(); } } else if (_cycle == 0) { if (_wantNmi) { _type = InstrType::NMI; _wantNmi = false; _cycle = 1; } else if (_wantIrq && !_regs.GetFlag(Flag::IRQ)) { _type = InstrType::IRQ; _wantIrq = false; _cycle = 1; } else { #if defined(TRACE) Trace(); #endif _op = LoadBBumpPC(); Decode(); _cycle = 1; } } else { switch (_type) { case InstrType::BRK: switch (_cycle) { case 1: LoadBBumpPC(); _cycle++; break; case 2: PushB(_regs.PC.B.H); _cycle++; break; case 3: PushB(_regs.PC.B.L); _cycle++; break; case 4: PushB(_regs.P | (u8)Flag::Break | (u8)Flag::Unused); _cycle++; break; case 5: _regs.PC.B.L = loadb(IRQ_VECTOR); _cycle++; break; case 6: _regs.PC.B.H = loadb(IRQ_VECTOR + 1); _regs.SetFlag(Flag::IRQ, true); EndInstr(); break; } break; case InstrType::NMI: switch (_cycle) { case 1: _cycle++; break; case 2: PushB(_regs.PC.B.H); _cycle++; break; case 3: PushB(_regs.PC.B.L); _cycle++; break; case 4: PushB(_regs.P); _cycle++; break; case 5: _regs.PC.B.L = loadb(NMI_VECTOR); _cycle++; break; case 6: _regs.PC.B.H = loadb(NMI_VECTOR + 1); EndInstr(); break; } break; case InstrType::IRQ: switch (_cycle) { case 1: _cycle++; break; case 2: PushB(_regs.PC.B.H); _cycle++; break; case 3: PushB(_regs.PC.B.L); _cycle++; break; case 4: PushB(_regs.P); _cycle++; break; case 5: _regs.PC.B.L = loadb(IRQ_VECTOR); _cycle++; break; case 6: _regs.PC.B.H = loadb(IRQ_VECTOR + 1); _regs.SetFlag(Flag::IRQ, true); EndInstr(); break; } break; case InstrType::RTI: switch (_cycle) { case 1: loadb(_regs.PC.W); _cycle++; break; case 2: _regs.SP++; _cycle++; break; case 3: _regs.P = loadb(0x100 | _regs.SP++); _cycle++; break; case 4: _regs.PC.B.L = loadb(0x100 | _regs.SP++); _cycle++; break; case 5: _regs.PC.B.H = loadb(0x100 | _regs.SP); EndInstr(); break; } break; case InstrType::RTS: switch (_cycle) { case 1: loadb(_regs.PC.W); _cycle++; break; case 2: _regs.SP++; _cycle++; break; case 3: _regs.PC.B.L = loadb(0x100 | _regs.SP++); _cycle++; break; case 4: _regs.PC.B.H = loadb(0x100 | _regs.SP); _cycle++; break; case 5: _regs.PC.W++; EndInstr(); break; } break; case InstrType::PHAorPHP: switch (_cycle) { case 1: loadb(_regs.PC.W); _cycle++; break; case 2: if (_pIdxReg == &_regs.P) { PushB(*_pIdxReg | (u8)Flag::Break | (u8)Flag::Unused); } else { PushB(*_pIdxReg); } EndInstr(); break; } break; case InstrType::PLAorPLP: switch (_cycle) { case 1: loadb(_regs.PC.W); _cycle++; break; case 2: _regs.SP++; _cycle++; break; case 3: *_pIdxReg = loadb(0x100 | _regs.SP); if (_pIdxReg == &_regs.A) { _regs.SetZN(_regs.A); } EndInstr(); break; } break; case InstrType::JSR: switch (_cycle) { case 1: _value = LoadBBumpPC(); _cycle++; break; case 2: _cycle++; break; case 3: PushB(_regs.PC.B.H); _cycle++; break; case 4: PushB(_regs.PC.B.L); _cycle++; break; case 5: _regs.PC.B.H = loadb(_regs.PC.W); _regs.PC.B.L = _value; EndInstr(); break; } break; case InstrType::Implied: loadb(_regs.PC.W); // throwaway read (*this.*_action)(); EndInstr(); break; case InstrType::Accumulator: loadb(_regs.PC.W); _value = _regs.A; (*this.*_action)(); _regs.A = _value; EndInstr(); break; case InstrType::Immediate: _value = LoadBBumpPC(); (*this.*_action)(); EndInstr(); break; case InstrType::AbsoluteJmp: switch (_cycle) { case 1: _value = LoadBBumpPC(); _cycle++; break; case 2: _regs.PC.B.H = LoadBBumpPC(); _regs.PC.B.L = _value; EndInstr(); break; } break; case InstrType::AbsoluteRead: switch (_cycle) { case 1: _addr.B.L = LoadBBumpPC(); _cycle++; break; case 2: _addr.B.H = LoadBBumpPC(); _cycle++; break; case 3: _value = loadb(_addr.W); (*this.*_action)(); EndInstr(); break; } break; case InstrType::AbsoluteRMW: switch (_cycle) { case 1: _addr.B.L = LoadBBumpPC(); _cycle++; break; case 2: _addr.B.H = LoadBBumpPC(); _cycle++; break; case 3: _value = loadb(_addr.W); _cycle++; break; case 4: storeb(_addr.W, _value); (*this.*_action)(); _cycle++; break; case 5: storeb(_addr.W, _value); EndInstr(); break; } break; case InstrType::AbsoluteWrite: switch (_cycle) { case 1: _addr.B.L = LoadBBumpPC(); _cycle++; break; case 2: _addr.B.H = LoadBBumpPC(); _cycle++; break; case 3: (*this.*_action)(); EndInstr(); break; } break; case InstrType::ZPRead: switch (_cycle) { case 1: _addr.W = (u16)LoadBBumpPC(); _cycle++; break; case 2: _value = loadb(_addr.W); (*this.*_action)(); EndInstr(); break; } break; case InstrType::ZPRMW: switch (_cycle) { case 1: _addr.W = (u16)LoadBBumpPC(); _cycle++; break; case 2: _value = loadb(_addr.W); _cycle++; break; case 3: storeb(_addr.W, _value); (*this.*_action)(); _cycle++; break; case 4: storeb(_addr.W, _value); EndInstr(); break; } break; case InstrType::ZPWRite: switch (_cycle) { case 1: _addr.W = (u16)LoadBBumpPC(); _cycle++; break; case 2: (*this.*_action)(); EndInstr(); break; } break; case InstrType::ZPIndexedRead: switch (_cycle) { case 1: _addr.W = (u16)LoadBBumpPC(); _cycle++; break; case 2: loadb(_addr.W); _addr.B.L = (u8)(_addr.B.L + *_pIdxReg); _cycle++; break; case 3: _value = loadb(_addr.W); (*this.*_action)(); EndInstr(); break; } break; case InstrType::ZPIndexedRMW: switch (_cycle) { case 1: _addr.W = (u16)LoadBBumpPC(); _cycle++; break; case 2: loadb(_addr.W); _addr.B.L = (u8)(_addr.B.L + _regs.X); _cycle++; break; case 3: _value = loadb(_addr.W); _cycle++; break; case 4: storeb(_addr.W, _value); (*this.*_action)(); _cycle++; break; case 5: storeb(_addr.W, _value); EndInstr(); break; } break; case InstrType::ZPIndexedWrite: switch (_cycle) { case 1: _addr.W = (u16)LoadBBumpPC(); _cycle++; break; case 2: loadb(_addr.W); _addr.B.L = (u8)(_addr.B.L + *_pIdxReg); _cycle++; break; case 3: (*this.*_action)(); EndInstr(); break; } break; case InstrType::AbsoluteIndexedRead: switch (_cycle) { case 1: _addr.B.L = LoadBBumpPC(); _cycle++; break; case 2: _addr.B.H = LoadBBumpPC(); Pair newAddr; newAddr.W = (u16)_addr.B.L + (u16)*_pIdxReg; _addr.B.L = newAddr.B.L; _pageCross = newAddr.B.H != 0; _cycle++; break; case 3: _value = loadb(_addr.W); if (_pageCross) { _addr.B.H++; _cycle++; } else { (*this.*_action)(); EndInstr(); } break; case 4: _value = loadb(_addr.W); (*this.*_action)(); EndInstr(); break; } break; case InstrType::AbsoluteIndexedRMW: switch (_cycle) { case 1: _addr.B.L = LoadBBumpPC(); _cycle++; break; case 2: _addr.B.H = LoadBBumpPC(); Pair newAddr; newAddr.W = (u16)_addr.B.L + (u16)_regs.X; _addr.B.L = newAddr.B.L; _pageCross = newAddr.B.H != 0; _cycle++; break; case 3: loadb(_addr.W); if (_pageCross) { _addr.B.H++; } _cycle++; break; case 4: _value = loadb(_addr.W); _cycle++; break; case 5: storeb(_addr.W, _value); (*this.*_action)(); _cycle++; break; case 6: storeb(_addr.W, _value); EndInstr(); break; } break; case InstrType::AbsoluteIndexedWrite: switch (_cycle) { case 1: _addr.B.L = LoadBBumpPC(); _cycle++; break; case 2: _addr.B.H = LoadBBumpPC(); Pair newAddr; newAddr.W = (u16)_addr.B.L + (u16)*_pIdxReg; _addr.B.L = newAddr.B.L; _pageCross = newAddr.B.H != 0; _cycle++; break; case 3: loadb(_addr.W); if (_pageCross) { _addr.B.H++; } _cycle++; break; case 4: (*this.*_action)(); EndInstr(); break; } break; case InstrType::Relative: switch (_cycle) { case 1: _value = LoadBBumpPC(); _cycle++; break; case 2: { u8 op = loadb(_regs.PC.W); (*this.*_action)(); if (_doBranch) { Pair newPC; newPC.W = (u16)((i32)(i16)_regs.PC.W + (i32)(i8)_value); _regs.PC.B.L = newPC.B.L; _pageCross = newPC.B.H != _regs.PC.B.H; _value = newPC.B.H; _cycle++; } else { EndInstr(); #if defined(TRACE) Trace(); #endif _op = op; _regs.PC.W++; Decode(); _cycle = 1; } } break; case 3: { u8 op = loadb(_regs.PC.W); if (_pageCross) { _regs.PC.B.H = _value; _cycle++; } else { EndInstr(); #if defined(TRACE) Trace(); #endif _op = op; _regs.PC.W++; Decode(); _cycle = 1; } } break; case 4: { #if defined(TRACE) Trace(); #endif _op = LoadBBumpPC(); Decode(); _cycle = 1; } break; } break; case InstrType::IndexedIndirectRead: switch (_cycle) { case 1: _value = LoadBBumpPC(); _cycle++; break; case 2: loadb(_value); _value += _regs.X; _cycle++; break; case 3: _addr.B.L = loadb(_value); _cycle++; break; case 4: _addr.B.H = loadb((u8)(_value + 1)); _cycle++; break; case 5: _value = loadb(_addr.W); (*this.*_action)(); EndInstr(); break; } break; case InstrType::IndexedIndirectRMW: switch (_cycle) { case 1: _value = LoadBBumpPC(); _cycle++; break; case 2: loadb(_value); _value += _regs.X; _cycle++; break; case 3: _addr.B.L = loadb(_value); _cycle++; break; case 4: _addr.B.H = loadb((u8)(_value + 1)); _cycle++; break; case 5: _value = loadb(_addr.W); _cycle++; break; case 6: storeb(_addr.W, _value); (*this.*_action)(); _cycle++; break; case 7: storeb(_addr.W, _value); EndInstr(); break; } break; case InstrType::IndexedIndirectWrite: switch (_cycle) { case 1: _value = LoadBBumpPC(); _cycle++; break; case 2: loadb(_value); _value += _regs.X; _cycle++; break; case 3: _addr.B.L = loadb(_value); _cycle++; break; case 4: _addr.B.H = loadb((u8)(_value + 1)); _cycle++; break; case 5: (*this.*_action)(); EndInstr(); break; } break; case InstrType::IndirectIndexedRead: switch (_cycle) { case 1: _value = LoadBBumpPC(); _cycle++; break; case 2: _addr.B.L = loadb(_value); _cycle++; break; case 3: _addr.B.H = loadb((u8)(_value + 1)); Pair newAddr; newAddr.W = (u16)_addr.B.L + (u16)_regs.Y; _addr.B.L = newAddr.B.L; _pageCross = newAddr.B.H != 0; _cycle++; break; case 4: _value = loadb(_addr.W); if (_pageCross) { _addr.B.H++; _cycle++; } else { (*this.*_action)(); EndInstr(); } break; case 5: _value = loadb(_addr.W); (*this.*_action)(); EndInstr(); break; } break; case InstrType::IndirectIndexedRMW: __debugbreak(); break; case InstrType::IndirectIndexedWrite: switch (_cycle) { case 1: _value = LoadBBumpPC(); _cycle++; break; case 2: _addr.B.L = loadb(_value); _cycle++; break; case 3: _addr.B.H = loadb((u8)(_value + 1)); Pair newAddr; newAddr.W = (u16)_addr.B.L + (u16)_regs.Y; _addr.B.L = newAddr.B.L; _pageCross = newAddr.B.H != 0; _cycle++; break; case 4: loadb(_addr.W); if (_pageCross) { _addr.B.H++; } _cycle++; break; case 5: (*this.*_action)(); EndInstr(); break; } break; case InstrType::AbsoluteIndirectJmp: switch (_cycle) { case 1: _addr.B.L = LoadBBumpPC(); _cycle++; break; case 2: _addr.B.H = LoadBBumpPC(); _cycle++; break; case 3: _value = loadb(_addr.W); _cycle++; break; case 4: _addr.B.L = u8(_addr.B.L + 1); _regs.PC.B.L = _value; _regs.PC.B.H = loadb(_addr.W); EndInstr(); break; } break; default: __debugbreak(); } } }