using Core.Cpu; using Core.Io; using Core.Memory; using Core.Video; using Core.Audio; 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 SmsVdp VideoProcessor { get; private set; } public SmsApu AudioProcessor { get; private set; } public ushort? Breakpoint { get; set; } = null; private int _tStateCarryover = 0; // NTSC SMS T-States per frame public const int TStatesPerFrame = 59736; //NTSC //public const int TStatesPerFrame = 49780; //PAL public SmsMachine() { MemoryBus = new SmsMemoryBus(); VideoProcessor = new SmsVdp(); AudioProcessor = new SmsApu(); IoBus = new SmsIoBus { VideoProcessor = this.VideoProcessor, AudioProcessor = this.AudioProcessor }; Cpu = new Z80(MemoryBus, IoBus); } public void LoadCartridge(byte[] romData) { MemoryBus.LoadCartridge(romData); Reset(); } public void Reset() { MemoryBus.CleanRAMData(); VideoProcessor.Reset(); Cpu.Reset(); _tStateCarryover = 0; } public void RunFrame() { int tStatesThisFrame = _tStateCarryover; while (tStatesThisFrame < TStatesPerFrame) // 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); AudioProcessor.Update(cycles); // 3. Check if the VDP is begging for attention! //if (VideoProcessor.InterruptPending && Cpu.IFF1) if (VideoProcessor.InterruptPending) { int intCycles = Cpu.RequestInterrupt(); if (intCycles > 0) { tStatesThisFrame += intCycles; VideoProcessor.Update(intCycles); AudioProcessor.Update(intCycles); } } // 4. THE RESTORED BREAKPOINT TRAP if (Breakpoint.HasValue && Cpu.PC == Breakpoint.Value) { break; // Instantly abort the frame so the debugger can take over! } } } public void SaveState(string filePath) { using (var fs = new System.IO.FileStream(filePath, System.IO.FileMode.Create)) using (var bw = new System.IO.BinaryWriter(fs)) { Cpu.SaveState(bw); MemoryBus.SaveState(bw); VideoProcessor.SaveState(bw); AudioProcessor.SaveState(bw); } } public void LoadState(string filePath) { if (!System.IO.File.Exists(filePath)) return; using (var fs = new System.IO.FileStream(filePath, System.IO.FileMode.Open)) using (var br = new System.IO.BinaryReader(fs)) { Cpu.LoadState(br); MemoryBus.LoadState(br); VideoProcessor.LoadState(br); AudioProcessor.LoadState(br); } } } }