109 lines
3.5 KiB
C#
109 lines
3.5 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
} |