From 23d93cc1fe3cec97ef4c3fc5ec3cc84afe360f4e Mon Sep 17 00:00:00 2001 From: scrimpeh Date: Mon, 6 Jul 2015 21:15:48 +0200 Subject: [PATCH] Apple II - Add Input Callbacks, Change definition of a lag frame --- .../AppleII/AppleII.IInputPollable.cs | 2 +- .../Computers/AppleII/AppleII.cs | 3 + ExternalCoreProjects/Virtu/Cpu.cs | 292 +++++++++--------- ExternalCoreProjects/Virtu/Memory.cs | 19 +- References/Virtu.dll | Bin 173056 -> 173056 bytes 5 files changed, 168 insertions(+), 148 deletions(-) diff --git a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IInputPollable.cs b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IInputPollable.cs index 19c29a7f16..f160aff77c 100644 --- a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IInputPollable.cs +++ b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.IInputPollable.cs @@ -12,6 +12,6 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII private set { _machine.Lagged = value; } } - public IInputCallbackSystem InputCallbacks { [FeatureNotImplemented]get; private set; } + public IInputCallbackSystem InputCallbacks { get; private set; } } } diff --git a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs index b0cae8af74..21b57a5d99 100644 --- a/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs +++ b/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.cs @@ -34,6 +34,7 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII Tracer = new TraceBuffer(); MemoryCallbacks = new MemoryCallbackSystem(); + InputCallbacks = new InputCallbackSystem(); _disk1 = rom; RomSet.Add(rom); @@ -58,6 +59,8 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII _machine.Memory.WriteCallback = MemoryCallbacks.CallWrites; _machine.Memory.ExecuteCallback = MemoryCallbacks.CallExecutes; + _machine.Memory.InputCallback = InputCallbacks.Call; + InitSaveStates(); SetupMemoryDomains(); PutSettings(settings ?? new Settings()); diff --git a/ExternalCoreProjects/Virtu/Cpu.cs b/ExternalCoreProjects/Virtu/Cpu.cs index 712730a488..71ea78caf3 100644 --- a/ExternalCoreProjects/Virtu/Cpu.cs +++ b/ExternalCoreProjects/Virtu/Cpu.cs @@ -199,163 +199,163 @@ namespace Jellyfish.Virtu if (pc <= 0xFFFD) //sanity check to make sure we don't read from outside address space. { - switch (_memory.Read(pc)) + switch (_memory.Peek(pc)) { - case 0x0C: return string.Format("NOP (${0:X4})", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x0D: return string.Format("ORA ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x0E: return string.Format("ASL ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x19: return string.Format("ORA ${0:X4},Y *", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x1D: return string.Format("ORA ${0:X4},X *", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x1E: return string.Format("ASL ${0:X4},X", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x20: return string.Format("JSR ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x2C: return string.Format("BIT ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x2D: return string.Format("AND ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x2E: return string.Format("ROL ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x39: return string.Format("AND ${0:X4},Y *", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x3D: return string.Format("AND ${0:X4},X *", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x3E: return string.Format("ROL ${0:X4},X", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x4C: return string.Format("JMP ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x4D: return string.Format("EOR ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x4E: return string.Format("LSR ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x59: return string.Format("EOR ${0:X4},Y *", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x5D: return string.Format("EOR ${0:X4},X *", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x5E: return string.Format("LSR ${0:X4},X", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x6C: return string.Format("JMP (${0:X4})", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x6D: return string.Format("ADC ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x6E: return string.Format("ROR ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x79: return string.Format("ADC ${0:X4},Y *", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x7D: return string.Format("ADC ${0:X4},X *", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x7E: return string.Format("ROR ${0:X4},X", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x8C: return string.Format("STY ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x8D: return string.Format("STA ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x8E: return string.Format("STX ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x99: return string.Format("STA ${0:X4},Y", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0x9D: return string.Format("STA ${0:X4},X", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xAC: return string.Format("LDY ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xAD: return string.Format("LDA ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xAE: return string.Format("LDX ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xB9: return string.Format("LDA ${0:X4},Y *", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xBC: return string.Format("LDY ${0:X4},X *", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xBD: return string.Format("LDA ${0:X4},X *", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xBE: return string.Format("LDX ${0:X4},Y *", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xCC: return string.Format("CPY ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xCD: return string.Format("CMP ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xCE: return string.Format("DEC ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xD9: return string.Format("CMP ${0:X4},Y *", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xDD: return string.Format("CMP ${0:X4},X *", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xDE: return string.Format("DEC ${0:X4},X", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xEC: return string.Format("CPX ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xED: return string.Format("SBC ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xEE: return string.Format("INC ${0:X4}", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xF9: return string.Format("SBC ${0:X4},Y *", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xFD: return string.Format("SBC ${0:X4},X *", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); - case 0xFE: return string.Format("INC ${0:X4},X", _memory.Read(pc + 1) | _memory.Read(pc + 2) << 8); + case 0x0C: return string.Format("NOP (${0:X4})", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x0D: return string.Format("ORA ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x0E: return string.Format("ASL ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x19: return string.Format("ORA ${0:X4},Y *", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x1D: return string.Format("ORA ${0:X4},X *", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x1E: return string.Format("ASL ${0:X4},X", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x20: return string.Format("JSR ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x2C: return string.Format("BIT ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x2D: return string.Format("AND ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x2E: return string.Format("ROL ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x39: return string.Format("AND ${0:X4},Y *", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x3D: return string.Format("AND ${0:X4},X *", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x3E: return string.Format("ROL ${0:X4},X", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x4C: return string.Format("JMP ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x4D: return string.Format("EOR ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x4E: return string.Format("LSR ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x59: return string.Format("EOR ${0:X4},Y *", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x5D: return string.Format("EOR ${0:X4},X *", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x5E: return string.Format("LSR ${0:X4},X", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x6C: return string.Format("JMP (${0:X4})", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x6D: return string.Format("ADC ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x6E: return string.Format("ROR ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x79: return string.Format("ADC ${0:X4},Y *", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x7D: return string.Format("ADC ${0:X4},X *", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x7E: return string.Format("ROR ${0:X4},X", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x8C: return string.Format("STY ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x8D: return string.Format("STA ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x8E: return string.Format("STX ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x99: return string.Format("STA ${0:X4},Y", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0x9D: return string.Format("STA ${0:X4},X", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xAC: return string.Format("LDY ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xAD: return string.Format("LDA ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xAE: return string.Format("LDX ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xB9: return string.Format("LDA ${0:X4},Y *", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xBC: return string.Format("LDY ${0:X4},X *", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xBD: return string.Format("LDA ${0:X4},X *", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xBE: return string.Format("LDX ${0:X4},Y *", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xCC: return string.Format("CPY ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xCD: return string.Format("CMP ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xCE: return string.Format("DEC ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xD9: return string.Format("CMP ${0:X4},Y *", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xDD: return string.Format("CMP ${0:X4},X *", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xDE: return string.Format("DEC ${0:X4},X", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xEC: return string.Format("CPX ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xED: return string.Format("SBC ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xEE: return string.Format("INC ${0:X4}", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xF9: return string.Format("SBC ${0:X4},Y *", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xFD: return string.Format("SBC ${0:X4},X *", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); + case 0xFE: return string.Format("INC ${0:X4},X", _memory.Peek(pc + 1) | _memory.Peek(pc + 2) << 8); } } if (pc <= 0xFFFE) //read two-byte opcodes here { - switch (_memory.Read(pc)) + switch (_memory.Peek(pc)) { - case 0x01: return string.Format("ORA (${0:X2},X)", _memory.Read(++pc)); - case 0x04: return string.Format("NOP ${0:X2}", _memory.Read(++pc)); - case 0x05: return string.Format("ORA ${0:X2}", _memory.Read(++pc)); - case 0x06: return string.Format("ASL ${0:X2}", _memory.Read(++pc)); - case 0x09: return string.Format("ORA #${0:X2}", _memory.Read(++pc)); - case 0x10: return string.Format("BPL ${0:X4}", pc + 2 + (sbyte)_memory.Read(pc + 1)); - case 0x11: return string.Format("ORA (${0:X2}),Y *", _memory.Read(++pc)); - case 0x14: return string.Format("NOP ${0:X2},X", _memory.Read(++pc)); - case 0x15: return string.Format("ORA ${0:X2},X", _memory.Read(++pc)); - case 0x16: return string.Format("ASL ${0:X2},X", _memory.Read(++pc)); - case 0x1C: return string.Format("NOP (${0:X2},X)", _memory.Read(++pc)); - case 0x21: return string.Format("AND (${0:X2},X)", _memory.Read(++pc)); - case 0x24: return string.Format("BIT ${0:X2}", _memory.Read(++pc)); - case 0x25: return string.Format("AND ${0:X2}", _memory.Read(++pc)); - case 0x26: return string.Format("ROL ${0:X2}", _memory.Read(++pc)); - case 0x29: return string.Format("AND #${0:X2}", _memory.Read(++pc)); - case 0x30: return string.Format("BMI ${0:X4}", pc + 2 + (sbyte)_memory.Read(pc + 1)); - case 0x31: return string.Format("AND (${0:X2}),Y *", _memory.Read(++pc)); - case 0x34: return string.Format("NOP ${0:X2},X", _memory.Read(++pc)); - case 0x35: return string.Format("AND ${0:X2},X", _memory.Read(++pc)); - case 0x36: return string.Format("ROL ${0:X2},X", _memory.Read(++pc)); - case 0x3C: return string.Format("NOP (${0:X2},X)", _memory.Read(++pc)); - case 0x41: return string.Format("EOR (${0:X2},X)", _memory.Read(++pc)); - case 0x44: return string.Format("NOP ${0:X2}", _memory.Read(++pc)); - case 0x45: return string.Format("EOR ${0:X2}", _memory.Read(++pc)); - case 0x46: return string.Format("LSR ${0:X2}", _memory.Read(++pc)); - case 0x49: return string.Format("EOR #${0:X2}", _memory.Read(++pc)); - case 0x50: return string.Format("BVC ${0:X4}", pc + 2 + (sbyte)_memory.Read(pc + 1)); - case 0x51: return string.Format("EOR (${0:X2}),Y *", _memory.Read(++pc)); - case 0x54: return string.Format("NOP ${0:X2},X", _memory.Read(++pc)); - case 0x55: return string.Format("EOR ${0:X2},X", _memory.Read(++pc)); - case 0x56: return string.Format("LSR ${0:X2},X", _memory.Read(++pc)); - case 0x5C: return string.Format("NOP (${0:X2},X)", _memory.Read(++pc)); - case 0x61: return string.Format("ADC (${0:X2},X)", _memory.Read(++pc)); - case 0x64: return string.Format("NOP ${0:X2}", _memory.Read(++pc)); - case 0x65: return string.Format("ADC ${0:X2}", _memory.Read(++pc)); - case 0x66: return string.Format("ROR ${0:X2}", _memory.Read(++pc)); - case 0x69: return string.Format("ADC #${0:X2}", _memory.Read(++pc)); - case 0x70: return string.Format("BVS ${0:X4}", pc + 2 + (sbyte)_memory.Read(pc + 1)); - case 0x71: return string.Format("ADC (${0:X2}),Y *", _memory.Read(++pc)); - case 0x74: return string.Format("NOP ${0:X2},X", _memory.Read(++pc)); - case 0x75: return string.Format("ADC ${0:X2},X", _memory.Read(++pc)); - case 0x76: return string.Format("ROR ${0:X2},X", _memory.Read(++pc)); - case 0x7C: return string.Format("NOP (${0:X2},X)", _memory.Read(++pc)); - case 0x80: return string.Format("NOP #${0:X2}", _memory.Read(++pc)); - case 0x81: return string.Format("STA (${0:X2},X)", _memory.Read(++pc)); - case 0x82: return string.Format("NOP #${0:X2}", _memory.Read(++pc)); - case 0x84: return string.Format("STY ${0:X2}", _memory.Read(++pc)); - case 0x85: return string.Format("STA ${0:X2}", _memory.Read(++pc)); - case 0x86: return string.Format("STX ${0:X2}", _memory.Read(++pc)); - case 0x89: return string.Format("NOP #${0:X2}", _memory.Read(++pc)); - case 0x90: return string.Format("BCC ${0:X4}", pc + 2 + (sbyte)_memory.Read(pc + 1)); - case 0x91: return string.Format("STA (${0:X2}),Y", _memory.Read(++pc)); - case 0x94: return string.Format("STY ${0:X2},X", _memory.Read(++pc)); - case 0x95: return string.Format("STA ${0:X2},X", _memory.Read(++pc)); - case 0x96: return string.Format("STX ${0:X2},Y", _memory.Read(++pc)); - case 0xA0: return string.Format("LDY #${0:X2}", _memory.Read(++pc)); - case 0xA1: return string.Format("LDA (${0:X2},X)", _memory.Read(++pc)); - case 0xA2: return string.Format("LDX #${0:X2}", _memory.Read(++pc)); - case 0xA4: return string.Format("LDY ${0:X2}", _memory.Read(++pc)); - case 0xA5: return string.Format("LDA ${0:X2}", _memory.Read(++pc)); - case 0xA6: return string.Format("LDX ${0:X2}", _memory.Read(++pc)); - case 0xA9: return string.Format("LDA #${0:X2}", _memory.Read(++pc)); - case 0xB0: return string.Format("BCS ${0:X4}", pc + 2 + (sbyte)_memory.Read(pc + 1)); - case 0xB1: return string.Format("LDA (${0:X2}),Y *", _memory.Read(++pc)); - case 0xB4: return string.Format("LDY ${0:X2},X", _memory.Read(++pc)); - case 0xB5: return string.Format("LDA ${0:X2},X", _memory.Read(++pc)); - case 0xB6: return string.Format("LDX ${0:X2},Y", _memory.Read(++pc)); - case 0xC0: return string.Format("CPY #${0:X2}", _memory.Read(++pc)); - case 0xC1: return string.Format("CMP (${0:X2},X)", _memory.Read(++pc)); - case 0xC2: return string.Format("NOP #${0:X2}", _memory.Read(++pc)); - case 0xC4: return string.Format("CPY ${0:X2}", _memory.Read(++pc)); - case 0xC5: return string.Format("CMP ${0:X2}", _memory.Read(++pc)); - case 0xC6: return string.Format("DEC ${0:X2}", _memory.Read(++pc)); - case 0xC9: return string.Format("CMP #${0:X2}", _memory.Read(++pc)); - case 0xD0: return string.Format("BNE ${0:X4}", pc + 2 + (sbyte)_memory.Read(pc + 1)); - case 0xD1: return string.Format("CMP (${0:X2}),Y *", _memory.Read(++pc)); - case 0xD4: return string.Format("NOP ${0:X2},X", _memory.Read(++pc)); - case 0xD5: return string.Format("CMP ${0:X2},X", _memory.Read(++pc)); - case 0xD6: return string.Format("DEC ${0:X2},X", _memory.Read(++pc)); - case 0xDC: return string.Format("NOP (${0:X2},X)", _memory.Read(++pc)); - case 0xE0: return string.Format("CPX #${0:X2}", _memory.Read(++pc)); - case 0xE1: return string.Format("SBC (${0:X2},X)", _memory.Read(++pc)); - case 0xE2: return string.Format("NOP #${0:X2}", _memory.Read(++pc)); - case 0xE4: return string.Format("CPX ${0:X2}", _memory.Read(++pc)); - case 0xE5: return string.Format("SBC ${0:X2}", _memory.Read(++pc)); - case 0xE6: return string.Format("INC ${0:X2}", _memory.Read(++pc)); - case 0xE9: return string.Format("SBC #${0:X2}", _memory.Read(++pc)); - case 0xF0: return string.Format("BEQ ${0:X4}", pc + 2 + (sbyte)_memory.Read(pc + 1)); - case 0xF1: return string.Format("SBC (${0:X2}),Y *", _memory.Read(++pc)); - case 0xF4: return string.Format("NOP ${0:X2},X", _memory.Read(++pc)); - case 0xF5: return string.Format("SBC ${0:X2},X", _memory.Read(++pc)); - case 0xF6: return string.Format("INC ${0:X2},X", _memory.Read(++pc)); - case 0xFC: return string.Format("NOP (${0:X2},X)", _memory.Read(++pc)); + case 0x01: return string.Format("ORA (${0:X2},X)", _memory.Peek(++pc)); + case 0x04: return string.Format("NOP ${0:X2}", _memory.Peek(++pc)); + case 0x05: return string.Format("ORA ${0:X2}", _memory.Peek(++pc)); + case 0x06: return string.Format("ASL ${0:X2}", _memory.Peek(++pc)); + case 0x09: return string.Format("ORA #${0:X2}", _memory.Peek(++pc)); + case 0x10: return string.Format("BPL ${0:X4}", pc + 2 + (sbyte)_memory.Peek(pc + 1)); + case 0x11: return string.Format("ORA (${0:X2}),Y *", _memory.Peek(++pc)); + case 0x14: return string.Format("NOP ${0:X2},X", _memory.Peek(++pc)); + case 0x15: return string.Format("ORA ${0:X2},X", _memory.Peek(++pc)); + case 0x16: return string.Format("ASL ${0:X2},X", _memory.Peek(++pc)); + case 0x1C: return string.Format("NOP (${0:X2},X)", _memory.Peek(++pc)); + case 0x21: return string.Format("AND (${0:X2},X)", _memory.Peek(++pc)); + case 0x24: return string.Format("BIT ${0:X2}", _memory.Peek(++pc)); + case 0x25: return string.Format("AND ${0:X2}", _memory.Peek(++pc)); + case 0x26: return string.Format("ROL ${0:X2}", _memory.Peek(++pc)); + case 0x29: return string.Format("AND #${0:X2}", _memory.Peek(++pc)); + case 0x30: return string.Format("BMI ${0:X4}", pc + 2 + (sbyte)_memory.Peek(pc + 1)); + case 0x31: return string.Format("AND (${0:X2}),Y *", _memory.Peek(++pc)); + case 0x34: return string.Format("NOP ${0:X2},X", _memory.Peek(++pc)); + case 0x35: return string.Format("AND ${0:X2},X", _memory.Peek(++pc)); + case 0x36: return string.Format("ROL ${0:X2},X", _memory.Peek(++pc)); + case 0x3C: return string.Format("NOP (${0:X2},X)", _memory.Peek(++pc)); + case 0x41: return string.Format("EOR (${0:X2},X)", _memory.Peek(++pc)); + case 0x44: return string.Format("NOP ${0:X2}", _memory.Peek(++pc)); + case 0x45: return string.Format("EOR ${0:X2}", _memory.Peek(++pc)); + case 0x46: return string.Format("LSR ${0:X2}", _memory.Peek(++pc)); + case 0x49: return string.Format("EOR #${0:X2}", _memory.Peek(++pc)); + case 0x50: return string.Format("BVC ${0:X4}", pc + 2 + (sbyte)_memory.Peek(pc + 1)); + case 0x51: return string.Format("EOR (${0:X2}),Y *", _memory.Peek(++pc)); + case 0x54: return string.Format("NOP ${0:X2},X", _memory.Peek(++pc)); + case 0x55: return string.Format("EOR ${0:X2},X", _memory.Peek(++pc)); + case 0x56: return string.Format("LSR ${0:X2},X", _memory.Peek(++pc)); + case 0x5C: return string.Format("NOP (${0:X2},X)", _memory.Peek(++pc)); + case 0x61: return string.Format("ADC (${0:X2},X)", _memory.Peek(++pc)); + case 0x64: return string.Format("NOP ${0:X2}", _memory.Peek(++pc)); + case 0x65: return string.Format("ADC ${0:X2}", _memory.Peek(++pc)); + case 0x66: return string.Format("ROR ${0:X2}", _memory.Peek(++pc)); + case 0x69: return string.Format("ADC #${0:X2}", _memory.Peek(++pc)); + case 0x70: return string.Format("BVS ${0:X4}", pc + 2 + (sbyte)_memory.Peek(pc + 1)); + case 0x71: return string.Format("ADC (${0:X2}),Y *", _memory.Peek(++pc)); + case 0x74: return string.Format("NOP ${0:X2},X", _memory.Peek(++pc)); + case 0x75: return string.Format("ADC ${0:X2},X", _memory.Peek(++pc)); + case 0x76: return string.Format("ROR ${0:X2},X", _memory.Peek(++pc)); + case 0x7C: return string.Format("NOP (${0:X2},X)", _memory.Peek(++pc)); + case 0x80: return string.Format("NOP #${0:X2}", _memory.Peek(++pc)); + case 0x81: return string.Format("STA (${0:X2},X)", _memory.Peek(++pc)); + case 0x82: return string.Format("NOP #${0:X2}", _memory.Peek(++pc)); + case 0x84: return string.Format("STY ${0:X2}", _memory.Peek(++pc)); + case 0x85: return string.Format("STA ${0:X2}", _memory.Peek(++pc)); + case 0x86: return string.Format("STX ${0:X2}", _memory.Peek(++pc)); + case 0x89: return string.Format("NOP #${0:X2}", _memory.Peek(++pc)); + case 0x90: return string.Format("BCC ${0:X4}", pc + 2 + (sbyte)_memory.Peek(pc + 1)); + case 0x91: return string.Format("STA (${0:X2}),Y", _memory.Peek(++pc)); + case 0x94: return string.Format("STY ${0:X2},X", _memory.Peek(++pc)); + case 0x95: return string.Format("STA ${0:X2},X", _memory.Peek(++pc)); + case 0x96: return string.Format("STX ${0:X2},Y", _memory.Peek(++pc)); + case 0xA0: return string.Format("LDY #${0:X2}", _memory.Peek(++pc)); + case 0xA1: return string.Format("LDA (${0:X2},X)", _memory.Peek(++pc)); + case 0xA2: return string.Format("LDX #${0:X2}", _memory.Peek(++pc)); + case 0xA4: return string.Format("LDY ${0:X2}", _memory.Peek(++pc)); + case 0xA5: return string.Format("LDA ${0:X2}", _memory.Peek(++pc)); + case 0xA6: return string.Format("LDX ${0:X2}", _memory.Peek(++pc)); + case 0xA9: return string.Format("LDA #${0:X2}", _memory.Peek(++pc)); + case 0xB0: return string.Format("BCS ${0:X4}", pc + 2 + (sbyte)_memory.Peek(pc + 1)); + case 0xB1: return string.Format("LDA (${0:X2}),Y *", _memory.Peek(++pc)); + case 0xB4: return string.Format("LDY ${0:X2},X", _memory.Peek(++pc)); + case 0xB5: return string.Format("LDA ${0:X2},X", _memory.Peek(++pc)); + case 0xB6: return string.Format("LDX ${0:X2},Y", _memory.Peek(++pc)); + case 0xC0: return string.Format("CPY #${0:X2}", _memory.Peek(++pc)); + case 0xC1: return string.Format("CMP (${0:X2},X)", _memory.Peek(++pc)); + case 0xC2: return string.Format("NOP #${0:X2}", _memory.Peek(++pc)); + case 0xC4: return string.Format("CPY ${0:X2}", _memory.Peek(++pc)); + case 0xC5: return string.Format("CMP ${0:X2}", _memory.Peek(++pc)); + case 0xC6: return string.Format("DEC ${0:X2}", _memory.Peek(++pc)); + case 0xC9: return string.Format("CMP #${0:X2}", _memory.Peek(++pc)); + case 0xD0: return string.Format("BNE ${0:X4}", pc + 2 + (sbyte)_memory.Peek(pc + 1)); + case 0xD1: return string.Format("CMP (${0:X2}),Y *", _memory.Peek(++pc)); + case 0xD4: return string.Format("NOP ${0:X2},X", _memory.Peek(++pc)); + case 0xD5: return string.Format("CMP ${0:X2},X", _memory.Peek(++pc)); + case 0xD6: return string.Format("DEC ${0:X2},X", _memory.Peek(++pc)); + case 0xDC: return string.Format("NOP (${0:X2},X)", _memory.Peek(++pc)); + case 0xE0: return string.Format("CPX #${0:X2}", _memory.Peek(++pc)); + case 0xE1: return string.Format("SBC (${0:X2},X)", _memory.Peek(++pc)); + case 0xE2: return string.Format("NOP #${0:X2}", _memory.Peek(++pc)); + case 0xE4: return string.Format("CPX ${0:X2}", _memory.Peek(++pc)); + case 0xE5: return string.Format("SBC ${0:X2}", _memory.Peek(++pc)); + case 0xE6: return string.Format("INC ${0:X2}", _memory.Peek(++pc)); + case 0xE9: return string.Format("SBC #${0:X2}", _memory.Peek(++pc)); + case 0xF0: return string.Format("BEQ ${0:X4}", pc + 2 + (sbyte)_memory.Peek(pc + 1)); + case 0xF1: return string.Format("SBC (${0:X2}),Y *", _memory.Peek(++pc)); + case 0xF4: return string.Format("NOP ${0:X2},X", _memory.Peek(++pc)); + case 0xF5: return string.Format("SBC ${0:X2},X", _memory.Peek(++pc)); + case 0xF6: return string.Format("INC ${0:X2},X", _memory.Peek(++pc)); + case 0xFC: return string.Format("NOP (${0:X2},X)", _memory.Peek(++pc)); } } if (pc <= 0xFFFF) //read one-byte opcodes here { - switch (_memory.Read(pc)) + switch (_memory.Peek(pc)) { case 0x00: return "BRK"; case 0x08: return "PHP"; diff --git a/ExternalCoreProjects/Virtu/Memory.cs b/ExternalCoreProjects/Virtu/Memory.cs index 1465aac15c..13a299c799 100644 --- a/ExternalCoreProjects/Virtu/Memory.cs +++ b/ExternalCoreProjects/Virtu/Memory.cs @@ -5,6 +5,7 @@ using System.Globalization; using System.IO; using Jellyfish.Library; using Jellyfish.Virtu.Services; +using Newtonsoft.Json; namespace Jellyfish.Virtu { @@ -291,7 +292,15 @@ namespace Jellyfish.Virtu private int ReadIoRegionC0C0(int address) { - Machine.Lagged = false; + if ((0xC000 <= address && address <= 0xC00F) || (0xC061 <= address && address <= 0xC067) || (0xC069 <= address && address <= 0xC06F)) + { + Machine.Lagged = false; + if (InputCallback != null) + { + InputCallback(); + } + } + switch (address) { case 0xC000: @@ -2130,10 +2139,18 @@ namespace Jellyfish.Virtu private Action _writeIoRegionC8CF; private Action _writeRomRegionD0FF; + [JsonIgnore] public Action ReadCallback; + + [JsonIgnore] public Action WriteCallback; + + [JsonIgnore] public Action ExecuteCallback; + [JsonIgnore] + public Action InputCallback; + private Keyboard _keyboard; private GamePort _gamePort; private Cassette _cassette; diff --git a/References/Virtu.dll b/References/Virtu.dll index d4d121b9d9a0512230d4fd53d8a59ba11ce8d36b..bcea43dda8bab8f1e135109d3704691ea9e1ec26 100644 GIT binary patch delta 23743 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 delta 23821 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 Rw^9786Q%uk4_W>L|8HlmsQ&-}