using Core.Cpu; using Core.Io; using Core.Memory; using System; using System.IO; using System.Collections.Generic; namespace Core { public class SmsMachine { public Z80 Cpu { get; private set; } public SmsMemoryBus MemoryBus { get; private set; } public SmsIoBus IoBus { get; private set; } public Core.Video.SmsVdp VideoProcessor { get; private set; } public ushort? Breakpoint { get; set; } = null; // NTSC SMS T-States per frame public const int TStatesPerFrame = 59736; public SmsMachine() { MemoryBus = new SmsMemoryBus(); VideoProcessor = new Core.Video.SmsVdp(); IoBus = new SmsIoBus { VideoProcessor = this.VideoProcessor }; Cpu = new Z80(MemoryBus, IoBus); } public void LoadCartridge(byte[] romData) { MemoryBus.LoadCartridge(romData); Reset(); } public void Reset() { MemoryBus.CleanRAMData(); Cpu.Reset(); } public void RunFrame() { int tStatesThisFrame = 0; while (tStatesThisFrame < 59736) // Standard NTSC frame time { // 1. Run one CPU instruction int cycles = Cpu.Step(); tStatesThisFrame += cycles; // 2. Tell the VDP to catch up VideoProcessor.Update(cycles); // 3. Check if the VDP is begging for attention! if (VideoProcessor.InterruptPending && Cpu.IFF1) { int intCycles = Cpu.RequestInterrupt(); tStatesThisFrame += intCycles; VideoProcessor.Update(intCycles); // Keep VDP perfectly in sync } // 4. THE RESTORED BREAKPOINT TRAP if (Breakpoint.HasValue && Cpu.PC == Breakpoint.Value) { break; // Instantly abort the frame so the debugger can take over! } } } } }