using System; using System.IO; using BizHawk.Common; namespace BizHawk.Emulation.Cores.Components.M6502 { public sealed partial class MOS6502X { public MOS6502X() { InitOpcodeHandlers(); Reset(); } public bool BCD_Enabled = true; public bool debug = false; public bool throw_unhandled; public void Reset() { A = 0; X = 0; Y = 0; P = 0; S = 0; PC = 0; TotalExecutedCycles = 0; mi = 0; opcode = 256; iflag_pending = true; RDY = true; } public void NESSoftReset() { opcode = VOP_RESET; mi = 0; iflag_pending = true; FlagI = true; } public string State(bool disassemble = true) { int notused; string a = string.Format("{0:X4} {1:X2} {2} ", PC, PeekMemory(PC), disassemble ? Disassemble(PC, out notused) : "---").PadRight(30); string b = string.Format("A:{0:X2} X:{1:X2} Y:{2:X2} P:{3:X2} SP:{4:X2} Cy:{5}", A, X, Y, P, S, TotalExecutedCycles); string val = a + b + " "; if (FlagN) val = val + "N"; if (FlagV) val = val + "V"; if (FlagT) val = val + "T"; if (FlagB) val = val + "B"; if (FlagD) val = val + "D"; if (FlagI) val = val + "I"; if (FlagZ) val = val + "Z"; if (FlagC) val = val + "C"; return val; } public bool AtStart { get { return opcode == VOP_Fetch1 || Microcode[opcode][mi] >= Uop.End; } } public string TraceState() { // only disassemble when we're at the beginning of an opcode return State(AtStart); } public const ushort NMIVector = 0xFFFA; public const ushort ResetVector = 0xFFFC; public const ushort BRKVector = 0xFFFE; public const ushort IRQVector = 0xFFFE; enum ExceptionType { BRK, NMI, IRQ } // ==== CPU State ==== public byte A; public byte X; public byte Y; public byte P; public ushort PC; public byte S; public bool IRQ; public bool NMI; public bool RDY; public void SyncState(Serializer ser) { ser.BeginSection("MOS6502X"); ser.Sync("A", ref A); ser.Sync("X", ref X); ser.Sync("Y", ref Y); ser.Sync("P", ref P); ser.Sync("PC", ref PC); ser.Sync("S", ref S); ser.Sync("NMI", ref NMI); ser.Sync("IRQ", ref IRQ); ser.Sync("RDY", ref RDY); ser.Sync("TotalExecutedCycles", ref TotalExecutedCycles); ser.Sync("opcode", ref opcode); ser.Sync("opcode2", ref opcode2); ser.Sync("opcode3", ref opcode3); ser.Sync("ea", ref ea); ser.Sync("alu_temp", ref alu_temp); ser.Sync("mi", ref mi); ser.Sync("iflag_pending", ref iflag_pending); ser.Sync("interrupt_pending", ref interrupt_pending); ser.Sync("branch_irq_hack", ref branch_irq_hack); ser.Sync("rdy_freeze", ref rdy_freeze); ser.EndSection(); } public void SaveStateBinary(BinaryWriter writer) { SyncState(Serializer.CreateBinaryWriter(writer)); } public void LoadStateBinary(BinaryReader reader) { SyncState(Serializer.CreateBinaryReader(reader)); } // ==== End State ==== /// Carry Flag public bool FlagC { get { return (P & 0x01) != 0; } private set { P = (byte)((P & ~0x01) | (value ? 0x01 : 0x00)); } } /// Zero Flag public bool FlagZ { get { return (P & 0x02) != 0; } private set { P = (byte)((P & ~0x02) | (value ? 0x02 : 0x00)); } } /// Interrupt Disable Flag public bool FlagI { get { return (P & 0x04) != 0; } set { P = (byte)((P & ~0x04) | (value ? 0x04 : 0x00)); } } /// Decimal Mode Flag public bool FlagD { get { return (P & 0x08) != 0; } private set { P = (byte)((P & ~0x08) | (value ? 0x08 : 0x00)); } } /// Break Flag public bool FlagB { get { return (P & 0x10) != 0; } private set { P = (byte)((P & ~0x10) | (value ? 0x10 : 0x00)); } } /// T... Flag public bool FlagT { get { return (P & 0x20) != 0; } private set { P = (byte)((P & ~0x20) | (value ? 0x20 : 0x00)); } } /// Overflow Flag public bool FlagV { get { return (P & 0x40) != 0; } private set { P = (byte)((P & ~0x40) | (value ? 0x40 : 0x00)); } } /// Negative Flag public bool FlagN { get { return (P & 0x80) != 0; } private set { P = (byte)((P & ~0x80) | (value ? 0x80 : 0x00)); } } public int TotalExecutedCycles; public Func ReadMemory; public Func DummyReadMemory; public Func PeekMemory; public Action WriteMemory; //this only calls when the first byte of an instruction is fetched. public Action OnExecFetch; public void SetCallbacks ( Func ReadMemory, Func DummyReadMemory, Func PeekMemory, Action WriteMemory ) { this.ReadMemory = ReadMemory; this.DummyReadMemory = DummyReadMemory; this.PeekMemory = PeekMemory; this.WriteMemory = WriteMemory; } public ushort ReadWord(ushort address) { byte l = ReadMemory(address); byte h = ReadMemory(++address); return (ushort)((h << 8) | l); } public ushort PeekWord(ushort address) { byte l = PeekMemory(address); byte h = PeekMemory(++address); return (ushort)((h << 8) | l); } private void WriteWord(ushort address, ushort value) { byte l = (byte)(value & 0xFF); byte h = (byte)(value >> 8); WriteMemory(address, l); WriteMemory(++address, h); } private ushort ReadWordPageWrap(ushort address) { ushort highAddress = (ushort)((address & 0xFF00) + ((address + 1) & 0xFF)); return (ushort)(ReadMemory(address) | (ReadMemory(highAddress) << 8)); } private static readonly byte[] TableNZ = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }; } }