mirror of https://github.com/Washi1337/Emux.git
Moved emulator stuff out of cpu and into GameBoy class
Replaced OnPerformedStep event with hardcoded calls to whatever component to reduce EventArgs creation (GC) Added Cpu.SpeedMultiplier to dimplify (speedMode ? 2 : 1) everwhere
This commit is contained in:
parent
6565bd2933
commit
fe0d65a084
|
@ -130,7 +130,7 @@ namespace Emux.GameBoy.Audio
|
|||
|
||||
public void ChannelStep(int cycles)
|
||||
{
|
||||
double cpuSpeedFactor = Spu.Device.Cpu.SpeedFactor;
|
||||
double cpuSpeedFactor = Spu.Device.SpeedFactor;
|
||||
if (!Active || double.IsNaN(cpuSpeedFactor) || double.IsInfinity(cpuSpeedFactor) || cpuSpeedFactor < 0.5)
|
||||
return;
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ namespace Emux.GameBoy.Audio
|
|||
|
||||
public virtual void ChannelStep(int cycles)
|
||||
{
|
||||
double cpuSpeedFactor = Spu.Device.Cpu.SpeedFactor;
|
||||
double cpuSpeedFactor = Spu.Device.SpeedFactor;
|
||||
if (!Active || double.IsNaN(cpuSpeedFactor) || double.IsInfinity(cpuSpeedFactor) || cpuSpeedFactor < 0.5)
|
||||
return;
|
||||
|
||||
|
|
|
@ -47,9 +47,9 @@ namespace Emux.GameBoy.Audio
|
|||
|
||||
protected void UpdateFrequency(int cycles)
|
||||
{
|
||||
if (SweepTime > 0 && _spu.Device.Cpu.SpeedFactor > 0.5)
|
||||
if (SweepTime > 0 && _spu.Device.SpeedFactor > 0.5)
|
||||
{
|
||||
double timeDelta = (cycles / GameBoyCpu.OfficialClockFrequency) / _spu.Device.Cpu.SpeedFactor;
|
||||
double timeDelta = (cycles / GameBoyCpu.OfficialClockFrequency) / _spu.Device.SpeedFactor;
|
||||
_frequencySweepClock += timeDelta;
|
||||
|
||||
while (_frequencySweepClock >= SweepTime)
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace Emux.GameBoy.Audio
|
|||
{
|
||||
if (EnvelopeSweepCount > 0)
|
||||
{
|
||||
double timeDelta = (cycles / GameBoyCpu.OfficialClockFrequency) / _channel.Spu.Device.Cpu.SpeedFactor;
|
||||
double timeDelta = (cycles / GameBoyCpu.OfficialClockFrequency) / _channel.Spu.Device.SpeedFactor;
|
||||
_timer += timeDelta;
|
||||
|
||||
double stepInterval = EnvelopeSweepCount / 64.0;
|
||||
|
|
|
@ -127,7 +127,7 @@ namespace Emux.GameBoy.Audio
|
|||
|
||||
public void ChannelStep(int cycles)
|
||||
{
|
||||
double cpuSpeedFactor = Spu.Device.Cpu.SpeedFactor;
|
||||
double cpuSpeedFactor = Spu.Device.SpeedFactor;
|
||||
if (!Active
|
||||
|| !SoundEnabled
|
||||
|| double.IsNaN(cpuSpeedFactor)
|
||||
|
|
|
@ -16,39 +16,16 @@ namespace Emux.GameBoy.Cpu
|
|||
public const int SerialLinkIsr = 0x0058;
|
||||
public const int JoypadPressIsr = 0x0060;
|
||||
public const double OfficialClockFrequency = 4194304;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the processor has resumed execution.
|
||||
/// </summary>
|
||||
public event EventHandler Resumed;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the processor is paused by breaking the execution explicitly, or when the control flow hit a breakpoint.
|
||||
/// </summary>
|
||||
public event EventHandler Paused;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the process has completely shut down.
|
||||
/// </summary>
|
||||
public event EventHandler Terminated;
|
||||
|
||||
public event StepEventHandler PerformedStep;
|
||||
|
||||
private readonly Z80Disassembler _disassembler;
|
||||
private readonly GameBoy _device;
|
||||
private readonly ManualResetEvent _continueSignal = new ManualResetEvent(false);
|
||||
private readonly ManualResetEvent _terminateSignal = new ManualResetEvent(false);
|
||||
|
||||
private ulong _ticks;
|
||||
private bool _break = true;
|
||||
private bool _halt = false;
|
||||
private readonly ManualResetEvent _frameStartSignal = new ManualResetEvent(false);
|
||||
private readonly ManualResetEvent _breakSignal = new ManualResetEvent(false);
|
||||
|
||||
private TimeSpan _frameStartTime;
|
||||
private ulong _frameStartTickCount;
|
||||
|
||||
private readonly IDictionary<ushort, Breakpoint> _breakpoints = new Dictionary<ushort, Breakpoint>();
|
||||
|
||||
public double CyclesPerSecond;
|
||||
|
||||
private ulong _frameStartTickCount;
|
||||
private ulong _ticks;
|
||||
public bool IsBroken = true;
|
||||
public bool Halted = false;
|
||||
|
||||
public GameBoyCpu(GameBoy device, IClock clock)
|
||||
{
|
||||
|
@ -57,32 +34,12 @@ namespace Emux.GameBoy.Cpu
|
|||
|
||||
Registers = new RegisterBank();
|
||||
Alu = new GameBoyAlu(Registers);
|
||||
EnableFrameLimit = true;
|
||||
Clock = clock ?? throw new ArgumentNullException(nameof(clock));
|
||||
|
||||
Clock.Tick += ClockOnTick;
|
||||
new Thread(CpuLoop)
|
||||
{
|
||||
Name = "Z80CPULOOP",
|
||||
IsBackground = true
|
||||
}.Start();
|
||||
}
|
||||
|
||||
private void ClockOnTick(object sender, EventArgs e)
|
||||
{
|
||||
_frameStartSignal.Set();
|
||||
var time = DateTime.Now.TimeOfDay;
|
||||
var delta = time - _frameStartTime;
|
||||
CyclesPerSecond = (_ticks - _frameStartTickCount) / delta.TotalSeconds;
|
||||
FramesPerSecond = 1 / delta.TotalSeconds;
|
||||
_frameStartTime = time;
|
||||
_frameStartTickCount = _ticks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the register bank of the processor.
|
||||
/// </summary>
|
||||
public RegisterBank Registers
|
||||
/// <summary>
|
||||
/// Gets the register bank of the processor.
|
||||
/// </summary>
|
||||
public RegisterBank Registers
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
@ -104,44 +61,19 @@ namespace Emux.GameBoy.Cpu
|
|||
/// Gets a value indicating whether the processor is active.
|
||||
/// </summary>
|
||||
public bool Running
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the processor should limit the execution speed to the original GameBoy clock speed.
|
||||
/// Disable this if experiencing heavy performance losses.
|
||||
/// </summary>
|
||||
public bool EnableFrameLimit
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public double FramesPerSecond
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public double CyclesPerSecond
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public double SpeedFactor
|
||||
{
|
||||
get { return CyclesPerSecond / (OfficialClockFrequency * (DoubleSpeed ? 2 : 1)); }
|
||||
}
|
||||
|
||||
public bool DoubleSpeed
|
||||
public bool DoubleSpeed
|
||||
{
|
||||
get;
|
||||
internal set;
|
||||
}
|
||||
|
||||
public int SpeedMultiplier => DoubleSpeed ? 2 : 1;
|
||||
|
||||
public bool IsPreparingSpeedSwitch
|
||||
{
|
||||
get;
|
||||
|
@ -173,58 +105,16 @@ namespace Emux.GameBoy.Cpu
|
|||
|
||||
public void Shutdown()
|
||||
{
|
||||
Terminate();
|
||||
|
||||
}
|
||||
|
||||
private void CpuLoop()
|
||||
{
|
||||
bool enabled = true;
|
||||
while (enabled)
|
||||
{
|
||||
if (WaitHandle.WaitAny(new WaitHandle[] { _continueSignal, _terminateSignal }) == 1)
|
||||
{
|
||||
enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Running = true;
|
||||
_continueSignal.Reset();
|
||||
OnResumed();
|
||||
|
||||
int cycles = 0;
|
||||
do
|
||||
{
|
||||
cycles += CpuStep();
|
||||
if (cycles >= GameBoyGpu.FullFrameCycles * (DoubleSpeed ? 2 : 1))
|
||||
{
|
||||
_device.Spu.SpuStep(cycles / (DoubleSpeed ? 2 : 1));
|
||||
cycles -= GameBoyGpu.FullFrameCycles * (DoubleSpeed ? 2 : 1);
|
||||
if (EnableFrameLimit)
|
||||
{
|
||||
WaitHandle.WaitAny(new WaitHandle[] { _breakSignal, _frameStartSignal });
|
||||
_frameStartSignal.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
if (_breakpoints.TryGetValue(Registers.PC, out var breakpoint) && breakpoint.Condition(this))
|
||||
_break = true;
|
||||
|
||||
} while (!_break);
|
||||
|
||||
_breakSignal.Reset();
|
||||
Running = false;
|
||||
OnPaused();
|
||||
}
|
||||
}
|
||||
OnTerminated();
|
||||
}
|
||||
|
||||
private int CpuStep()
|
||||
public int PerformNextInstruction()
|
||||
{
|
||||
Registers.IMESet = false;
|
||||
|
||||
int cycles;
|
||||
if (_halt)
|
||||
if (Halted)
|
||||
{
|
||||
cycles = 4;
|
||||
}
|
||||
|
@ -255,99 +145,30 @@ namespace Emux.GameBoy.Cpu
|
|||
cycles += 12;
|
||||
}
|
||||
|
||||
_halt = false;
|
||||
Halted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update cycle dependent components.
|
||||
OnPerformedStep(new StepEventArgs(cycles / (DoubleSpeed ? 2 : 1)));
|
||||
OnPerformedStep(cycles / SpeedMultiplier);
|
||||
|
||||
_ticks = (_ticks + (ulong) cycles) & long.MaxValue;
|
||||
return cycles;
|
||||
|
||||
return cycles;
|
||||
}
|
||||
|
||||
public void Step()
|
||||
{
|
||||
Clock.Stop();
|
||||
_break = true;
|
||||
_continueSignal.Set();
|
||||
}
|
||||
public void SecondElapsed(TimeSpan delta)
|
||||
{
|
||||
CyclesPerSecond = (_ticks - _frameStartTickCount) / delta.TotalSeconds;
|
||||
_ticks = 0;
|
||||
}
|
||||
|
||||
public void Run()
|
||||
protected virtual void OnPerformedStep(int cycles)
|
||||
{
|
||||
_frameStartTime = DateTime.Now.TimeOfDay;
|
||||
Clock.Start();
|
||||
_break = false;
|
||||
_continueSignal.Set();
|
||||
}
|
||||
|
||||
public void Break()
|
||||
{
|
||||
_breakSignal.Set();
|
||||
Clock.Stop();
|
||||
_continueSignal.Reset();
|
||||
_break = true;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
Clock.Stop();
|
||||
_continueSignal.Reset();
|
||||
_terminateSignal.Set();
|
||||
}
|
||||
|
||||
public Breakpoint SetBreakpoint(ushort address)
|
||||
{
|
||||
if (!_breakpoints.TryGetValue(address, out var breakpoint))
|
||||
{
|
||||
breakpoint = new Breakpoint(address);
|
||||
_breakpoints.Add(address, breakpoint);
|
||||
}
|
||||
|
||||
return breakpoint;
|
||||
}
|
||||
|
||||
public void RemoveBreakpoint(ushort address)
|
||||
{
|
||||
_breakpoints.Remove(address);
|
||||
}
|
||||
|
||||
public IEnumerable<Breakpoint> GetBreakpoints()
|
||||
{
|
||||
return _breakpoints.Values;
|
||||
}
|
||||
|
||||
public Breakpoint GetBreakpointAtAddress(ushort address)
|
||||
{
|
||||
_breakpoints.TryGetValue(address, out var breakpoint);
|
||||
return breakpoint;
|
||||
}
|
||||
|
||||
public void ClearBreakpoints()
|
||||
{
|
||||
_breakpoints.Clear();
|
||||
}
|
||||
|
||||
protected virtual void OnResumed()
|
||||
{
|
||||
Resumed?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
protected virtual void OnPaused()
|
||||
{
|
||||
Paused?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
protected virtual void OnTerminated()
|
||||
{
|
||||
Terminated?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
protected virtual void OnPerformedStep(StepEventArgs args)
|
||||
{
|
||||
PerformedStep?.Invoke(this, args);
|
||||
}
|
||||
_device.Gpu.Step(cycles);
|
||||
_device.Timer.Step(cycles);
|
||||
}
|
||||
|
||||
private Z80Instruction ReadNextInstruction()
|
||||
{
|
||||
|
@ -423,7 +244,7 @@ namespace Emux.GameBoy.Cpu
|
|||
|
||||
internal void Halt()
|
||||
{
|
||||
_halt = true;
|
||||
Halted = true;
|
||||
}
|
||||
|
||||
internal void Stop()
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Emux.GameBoy.Audio;
|
||||
using Emux.GameBoy.Cartridge;
|
||||
using Emux.GameBoy.Cpu;
|
||||
|
@ -14,10 +16,45 @@ namespace Emux.GameBoy
|
|||
/// </summary>
|
||||
public class GameBoy
|
||||
{
|
||||
public GameBoy(ICartridge cartridge, IClock clock, bool preferGbcMode)
|
||||
private readonly ManualResetEvent _continueSignal = new ManualResetEvent(false);
|
||||
private readonly ManualResetEvent _terminateSignal = new ManualResetEvent(false);
|
||||
private readonly ManualResetEvent _frameStartSignal = new ManualResetEvent(false);
|
||||
private readonly ManualResetEvent _breakSignal = new ManualResetEvent(false);
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the processor has resumed execution.
|
||||
/// </summary>
|
||||
public event EventHandler Resumed;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the processor is paused by breaking the execution explicitly, or when the control flow hit a breakpoint.
|
||||
/// </summary>
|
||||
public event EventHandler Paused;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the process has completely shut down.
|
||||
/// </summary>
|
||||
public event EventHandler Terminated;
|
||||
|
||||
public event StepEventHandler PerformedStep;
|
||||
|
||||
private readonly IDictionary<ushort, Breakpoint> _breakpoints = new Dictionary<ushort, Breakpoint>();
|
||||
|
||||
private IClock Clock;
|
||||
|
||||
private int framesCount;
|
||||
|
||||
public double FramesPerSecond;
|
||||
public bool EnableFrameLimit;
|
||||
public TimeSpan _frameStartTime;
|
||||
|
||||
|
||||
public GameBoy(ICartridge cartridge, IClock clock, bool preferGbcMode)
|
||||
{
|
||||
GbcMode = preferGbcMode && (cartridge.GameBoyColorFlag & GameBoyColorFlag.SupportsColor) != 0;
|
||||
|
||||
Clock = clock;
|
||||
|
||||
Components = new List<IGameBoyComponent>
|
||||
{
|
||||
(Cartridge = cartridge),
|
||||
|
@ -34,9 +71,18 @@ namespace Emux.GameBoy
|
|||
|
||||
Reset();
|
||||
IsPoweredOn = true;
|
||||
}
|
||||
|
||||
public ICollection<IGameBoyComponent> Components
|
||||
Clock.Tick += nextFrame;
|
||||
new Thread(CpuLoop)
|
||||
{
|
||||
Name = "Z80CPULOOP",
|
||||
IsBackground = true
|
||||
}.Start();
|
||||
|
||||
Gpu.VBlankStarted += (_, __) => framesCount++;
|
||||
}
|
||||
|
||||
private ICollection<IGameBoyComponent> Components
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
@ -49,10 +95,10 @@ namespace Emux.GameBoy
|
|||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the central processing unit of the emulated GameBoy device.
|
||||
/// </summary>
|
||||
public GameBoyCpu Cpu
|
||||
/// <summary>
|
||||
/// Gets the central processing unit of the emulated GameBoy device.
|
||||
/// </summary>
|
||||
public GameBoyCpu Cpu
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
@ -114,14 +160,149 @@ namespace Emux.GameBoy
|
|||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the state of the GameBoy to the bootup state.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
public double SpeedFactor => Cpu.CyclesPerSecond / (GameBoyCpu.OfficialClockFrequency * Cpu.SpeedMultiplier);
|
||||
|
||||
private void nextFrame(object sender, EventArgs e)
|
||||
{
|
||||
_frameStartSignal.Set();
|
||||
|
||||
var time = DateTime.Now.TimeOfDay;
|
||||
var delta = time - _frameStartTime;
|
||||
if (delta.TotalSeconds > 1)
|
||||
{
|
||||
FramesPerSecond = framesCount / delta.TotalSeconds;
|
||||
framesCount = 0;
|
||||
Cpu.SecondElapsed(delta);
|
||||
|
||||
_frameStartTime = time;
|
||||
}
|
||||
}
|
||||
|
||||
public void Step()
|
||||
{
|
||||
Clock.Stop();
|
||||
Cpu.IsBroken = true;
|
||||
_continueSignal.Set();
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
_frameStartTime = DateTime.Now.TimeOfDay;
|
||||
Clock.Start();
|
||||
Cpu.IsBroken = false;
|
||||
_continueSignal.Set();
|
||||
}
|
||||
|
||||
public void Break()
|
||||
{
|
||||
_breakSignal.Set();
|
||||
Clock.Stop();
|
||||
_continueSignal.Reset();
|
||||
Cpu.IsBroken = true;
|
||||
}
|
||||
|
||||
private void CpuLoop()
|
||||
{
|
||||
bool enabled = true;
|
||||
while (enabled)
|
||||
{
|
||||
if (WaitHandle.WaitAny(new WaitHandle[] { _continueSignal, _terminateSignal }) == 1)
|
||||
{
|
||||
enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Cpu.Running = true;
|
||||
_continueSignal.Reset();
|
||||
OnResumed();
|
||||
|
||||
int cycles = 0;
|
||||
do
|
||||
{
|
||||
cycles += Cpu.PerformNextInstruction();
|
||||
if (cycles >= GameBoyGpu.FullFrameCycles * Cpu.SpeedMultiplier)
|
||||
{
|
||||
Spu.SpuStep(cycles / Cpu.SpeedMultiplier);
|
||||
cycles -= GameBoyGpu.FullFrameCycles * Cpu.SpeedMultiplier;
|
||||
if (EnableFrameLimit)
|
||||
{
|
||||
WaitHandle.WaitAny(new WaitHandle[] { _breakSignal, _frameStartSignal });
|
||||
_frameStartSignal.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
if (_breakpoints.TryGetValue(Cpu.Registers.PC, out var breakpoint) && breakpoint.Condition(Cpu))
|
||||
Cpu.IsBroken = true;
|
||||
|
||||
} while (!Cpu.IsBroken);
|
||||
|
||||
_breakSignal.Reset();
|
||||
Cpu.Running = false;
|
||||
OnPaused();
|
||||
}
|
||||
}
|
||||
OnTerminated();
|
||||
}
|
||||
|
||||
protected virtual void OnResumed()
|
||||
{
|
||||
Resumed?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
protected virtual void OnPaused()
|
||||
{
|
||||
Paused?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
protected virtual void OnTerminated()
|
||||
{
|
||||
Terminated?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
protected virtual void OnPerformedStep(StepEventArgs args)
|
||||
{
|
||||
PerformedStep?.Invoke(this, args);
|
||||
}
|
||||
|
||||
public Breakpoint SetBreakpoint(ushort address)
|
||||
{
|
||||
if (!_breakpoints.TryGetValue(address, out var breakpoint))
|
||||
{
|
||||
breakpoint = new Breakpoint(address);
|
||||
_breakpoints.Add(address, breakpoint);
|
||||
}
|
||||
|
||||
return breakpoint;
|
||||
}
|
||||
|
||||
public void RemoveBreakpoint(ushort address)
|
||||
{
|
||||
_breakpoints.Remove(address);
|
||||
}
|
||||
|
||||
public IEnumerable<Breakpoint> GetBreakpoints()
|
||||
{
|
||||
return _breakpoints.Values;
|
||||
}
|
||||
|
||||
public Breakpoint GetBreakpointAtAddress(ushort address)
|
||||
{
|
||||
_breakpoints.TryGetValue(address, out var breakpoint);
|
||||
return breakpoint;
|
||||
}
|
||||
|
||||
public void ClearBreakpoints()
|
||||
{
|
||||
_breakpoints.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the state of the GameBoy to the bootup state.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
foreach (var component in Components)
|
||||
component.Reset();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -129,9 +310,11 @@ namespace Emux.GameBoy
|
|||
/// </summary>
|
||||
public void Terminate()
|
||||
{
|
||||
Clock.Stop();
|
||||
|
||||
foreach (var component in Components)
|
||||
component.Shutdown();
|
||||
IsPoweredOn = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ namespace Emux.GameBoy.Graphics
|
|||
public const int ScanLineOamCycles = 80;
|
||||
public const int ScanLineVramCycles = 172;
|
||||
public const int HBlankCycles = 204;
|
||||
public const int OneLineCycles = 456;
|
||||
public const int VBlankCycles = 456 * 10;
|
||||
public const int OneLineCycles = ScanLineOamCycles + ScanLineVramCycles + HBlankCycles;
|
||||
public const int VBlankCycles = OneLineCycles * 10;
|
||||
public const int FullFrameCycles = 70224;
|
||||
|
||||
public event EventHandler HBlankStarted;
|
||||
|
@ -389,7 +389,6 @@ namespace Emux.GameBoy.Graphics
|
|||
|
||||
public void Initialize()
|
||||
{
|
||||
_device.Cpu.PerformedStep += CpuOnPerformedStep;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
|
@ -416,19 +415,14 @@ namespace Emux.GameBoy.Graphics
|
|||
|
||||
public void Shutdown()
|
||||
{
|
||||
_device.Cpu.PerformedStep -= CpuOnPerformedStep;
|
||||
}
|
||||
|
||||
private void CpuOnPerformedStep(object sender, StepEventArgs args)
|
||||
{
|
||||
GpuStep(args.Cycles);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances the execution of the graphical processor unit.
|
||||
/// </summary>
|
||||
/// <param name="cycles">The cycles the central processor unit has executed since last step.</param>
|
||||
private void GpuStep(int cycles)
|
||||
public void Step(int cycles)
|
||||
{
|
||||
if ((_lcdc & LcdControlFlags.EnableLcd) == 0)
|
||||
return;
|
||||
|
@ -468,8 +462,8 @@ namespace Emux.GameBoy.Graphics
|
|||
{
|
||||
currentMode = LcdStatusFlags.VBlankMode;
|
||||
OnVBlankStarted();
|
||||
VideoOutput.RenderFrame(_frameBuffer);
|
||||
_device.Cpu.Registers.IF |= InterruptFlags.VBlank;
|
||||
VideoOutput.RenderFrame(_frameBuffer);
|
||||
_device.Cpu.Registers.IF |= InterruptFlags.VBlank;
|
||||
if ((stat & LcdStatusFlags.VBlankModeInterrupt) == LcdStatusFlags.VBlankModeInterrupt)
|
||||
_device.Cpu.Registers.IF |= InterruptFlags.LcdStat;
|
||||
}
|
||||
|
@ -699,14 +693,14 @@ namespace Emux.GameBoy.Graphics
|
|||
private static Color GetGbcColor(byte[] paletteMemory, int paletteIndex, int colorIndex)
|
||||
{
|
||||
ushort rawValue = (ushort)(paletteMemory[paletteIndex * 8 + colorIndex * 2] | (paletteMemory[paletteIndex * 8 + colorIndex * 2 + 1] << 8));
|
||||
return new Color(
|
||||
(byte)((rawValue & 0x1F) * (0xFF / 0x1F)),
|
||||
(byte)(((rawValue >> 5) & 0x1F) * (0xFF / 0x1F)),
|
||||
(byte)(((rawValue >> 10) & 0x1F) * (0xFF / 0x1F)));
|
||||
return new Color(
|
||||
(byte)((rawValue & 0x1F) * (0xFF / 0x1F)),
|
||||
(byte)(((rawValue >> 5) & 0x1F) * (0xFF / 0x1F)),
|
||||
(byte)(((rawValue >> 10) & 0x1F) * (0xFF / 0x1F)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static int GetGreyshadeIndex(byte palette, int paletteIndex)
|
||||
|
||||
private static int GetGreyshadeIndex(byte palette, int paletteIndex)
|
||||
{
|
||||
return (palette >> (paletteIndex * 2)) & 3;
|
||||
}
|
||||
|
@ -730,10 +724,6 @@ namespace Emux.GameBoy.Graphics
|
|||
if ((flags & SpriteDataFlags.XFlip) != 0)
|
||||
actualX = 7 - actualX;
|
||||
|
||||
if (LY == 0)
|
||||
{
|
||||
|
||||
}
|
||||
int paletteIndex = (int)(flags & SpriteDataFlags.PaletteNumberMask);
|
||||
int colorIndex = GetPixelColorIndex(actualX, currentTileData);
|
||||
RenderPixel(outputX, LY, colorIndex, GetGbcColor(_bgPaletteMemory, paletteIndex, colorIndex));
|
||||
|
|
|
@ -61,7 +61,6 @@ namespace Emux.GameBoy.Timer
|
|||
|
||||
public void Initialize()
|
||||
{
|
||||
_device.Cpu.PerformedStep += CpuOnPerformedStep;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
|
@ -74,7 +73,6 @@ namespace Emux.GameBoy.Timer
|
|||
|
||||
public void Shutdown()
|
||||
{
|
||||
_device.Cpu.PerformedStep -= CpuOnPerformedStep;
|
||||
}
|
||||
|
||||
public int GetTimaFrequency()
|
||||
|
@ -97,13 +95,9 @@ namespace Emux.GameBoy.Timer
|
|||
{
|
||||
return (int)(GameBoyCpu.OfficialClockFrequency / GetTimaFrequency());
|
||||
}
|
||||
|
||||
private void CpuOnPerformedStep(object sender, StepEventArgs args)
|
||||
{
|
||||
TimerStep(args.Cycles);
|
||||
}
|
||||
|
||||
|
||||
private void TimerStep(int cycles)
|
||||
public void Step(int cycles)
|
||||
{
|
||||
_divClock += cycles;
|
||||
while (_divClock > DivCycleInterval)
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace Emux.MonoGame
|
|||
|
||||
_video = new Texture2D(GraphicsDevice, 160, 144);
|
||||
_font = Content.Load<SpriteFont>("Calibri");
|
||||
GameBoy.Cpu.Run();
|
||||
GameBoy.Run();
|
||||
}
|
||||
|
||||
protected override void Update(GameTime gameTime)
|
||||
|
@ -139,7 +139,7 @@ namespace Emux.MonoGame
|
|||
private void DrawDebugInformation(GameTime time)
|
||||
{
|
||||
_fps.Add(1 / time.ElapsedGameTime.TotalSeconds);
|
||||
_gbfps.Add(GameBoy.Cpu.FramesPerSecond);
|
||||
_gbfps.Add(GameBoy.FramesPerSecond);
|
||||
|
||||
var difference = time.TotalGameTime - _last;
|
||||
if (difference.TotalSeconds > 1)
|
||||
|
|
|
@ -43,14 +43,14 @@ namespace Emux.Gui
|
|||
{
|
||||
if (value != null)
|
||||
{
|
||||
value.Cpu.Paused -= CpuOnPaused;
|
||||
value.Cpu.Resumed -= CpuOnResumed;
|
||||
value.Paused -= CpuOnPaused;
|
||||
value.Resumed -= CpuOnResumed;
|
||||
}
|
||||
_device = value;
|
||||
if (_device != null)
|
||||
{
|
||||
_device.Cpu.Paused += CpuOnPaused;
|
||||
_device.Cpu.Resumed += CpuOnResumed;
|
||||
_device.Paused += CpuOnPaused;
|
||||
_device.Resumed += CpuOnResumed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,9 +30,9 @@ namespace Emux.Gui
|
|||
set
|
||||
{
|
||||
if (value)
|
||||
_gameBoy.Cpu.SetBreakpoint(_instruction.Offset);
|
||||
_gameBoy.SetBreakpoint(_instruction.Offset);
|
||||
else
|
||||
_gameBoy.Cpu.RemoveBreakpoint(_instruction.Offset);
|
||||
_gameBoy.RemoveBreakpoint(_instruction.Offset);
|
||||
OnPropertyChanged(nameof(IsBreakpoint));
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ namespace Emux.Gui
|
|||
{
|
||||
get
|
||||
{
|
||||
var bp = _gameBoy.Cpu.GetBreakpointAtAddress(_instruction.Offset);
|
||||
var bp = _gameBoy.GetBreakpointAtAddress(_instruction.Offset);
|
||||
if (bp == null)
|
||||
return null;
|
||||
App.Current.DeviceManager.Breakpoints.TryGetValue(_instruction.Offset, out var breakpointInfo);
|
||||
|
|
|
@ -179,14 +179,14 @@ namespace Emux.Gui
|
|||
{
|
||||
if (_currentDevice != null)
|
||||
{
|
||||
_currentDevice.Cpu.Paused -= GameBoyOnPaused;
|
||||
_currentDevice.Cpu.Resumed -= GameBoyOnResumed;
|
||||
_currentDevice.Paused -= GameBoyOnPaused;
|
||||
_currentDevice.Resumed -= GameBoyOnResumed;
|
||||
RunningOverlay.DisableOverlay();
|
||||
}
|
||||
|
||||
_currentDevice = DeviceManager.CurrentDevice;
|
||||
_currentDevice.Cpu.Paused += GameBoyOnPaused;
|
||||
_currentDevice.Cpu.Resumed += GameBoyOnResumed;
|
||||
_currentDevice.Paused += GameBoyOnPaused;
|
||||
_currentDevice.Resumed += GameBoyOnResumed;
|
||||
_currentDevice.Gpu.VideoOutput = _videoWindow;
|
||||
|
||||
_videoWindow.Device = _currentDevice;
|
||||
|
@ -252,7 +252,7 @@ namespace Emux.Gui
|
|||
|
||||
private void StepCommandOnExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
_currentDevice.Cpu.Step();
|
||||
_currentDevice.Step();
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
|
@ -273,12 +273,12 @@ namespace Emux.Gui
|
|||
|
||||
private void RunCommandOnExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
_currentDevice.Cpu.Run();
|
||||
_currentDevice.Run();
|
||||
}
|
||||
|
||||
private void BreakCommandOnExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
_currentDevice.Cpu.Break();
|
||||
_currentDevice.Break();
|
||||
}
|
||||
|
||||
private void SetBreakpointCommandOnExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
|
@ -307,7 +307,7 @@ namespace Emux.Gui
|
|||
}
|
||||
else
|
||||
{
|
||||
var bp = _currentDevice.Cpu.SetBreakpoint(address);
|
||||
var bp = _currentDevice.SetBreakpoint(address);
|
||||
DeviceManager.Breakpoints[address] = new BreakpointInfo(bp);
|
||||
}
|
||||
}
|
||||
|
@ -322,7 +322,7 @@ namespace Emux.Gui
|
|||
|
||||
private void ClearBreakpointsCommandOnExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
_currentDevice.Cpu.ClearBreakpoints();
|
||||
_currentDevice.ClearBreakpoints();
|
||||
}
|
||||
|
||||
private void KeyPadCommandOnExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
|
@ -401,7 +401,7 @@ namespace Emux.Gui
|
|||
{
|
||||
if (instruction.Breakpoint == null)
|
||||
{
|
||||
_currentDevice.Cpu.SetBreakpoint((ushort) instruction.Offset);
|
||||
_currentDevice.SetBreakpoint((ushort) instruction.Offset);
|
||||
}
|
||||
|
||||
var dialog = new BreakpointDialog(instruction.Breakpoint);
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace Emux.Gui
|
|||
lock (this)
|
||||
{
|
||||
Dispatcher.Invoke(() => Title = string.Format("Video Output ({0:0.00} %)",
|
||||
_device.Cpu.SpeedFactor * 100));
|
||||
_device.SpeedFactor * 100));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ namespace Emux.Gui
|
|||
private void VideoWindowOnKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Space)
|
||||
Device.Cpu.EnableFrameLimit = false;
|
||||
Device.EnableFrameLimit = false;
|
||||
else if (GetBindedButton(e.Key, out var button))
|
||||
Device.KeyPad.PressedButtons |= button;
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ namespace Emux.Gui
|
|||
private void VideoWindowOnKeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Space)
|
||||
Device.Cpu.EnableFrameLimit = true;
|
||||
Device.EnableFrameLimit = true;
|
||||
else if (GetBindedButton(e.Key, out var button))
|
||||
Device.KeyPad.PressedButtons &= ~button;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue