From 026d8b1797dc90f989615c4366fcdf714928f14c Mon Sep 17 00:00:00 2001 From: Ian C Date: Mon, 9 Apr 2012 22:59:56 +0000 Subject: Updated clock. --- src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs | 17 ++- src/Noddybox.Emulation/Clock.cs | 163 ++++++++++++++++++-------- src/Noddybox.Emulation/ClockEventArgs.cs | 67 +++++++++++ 3 files changed, 195 insertions(+), 52 deletions(-) create mode 100644 src/Noddybox.Emulation/ClockEventArgs.cs (limited to 'src') diff --git a/src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs b/src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs index 06433dc..d575476 100644 --- a/src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs +++ b/src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs @@ -183,6 +183,13 @@ namespace Noddybox.Emulation.EightBit.Z80 } } + private bool VBL {get; set;} + + private void VBLHandler(object sender, ClockEventArgs e) + { + VBL = true; + } + #endregion #region ICpu Members @@ -193,6 +200,8 @@ namespace Noddybox.Emulation.EightBit.Z80 this.device = device; this.clock = clock; + this.clock.EndOfVBL += VBLHandler; + Reset(); } @@ -238,7 +247,9 @@ namespace Noddybox.Emulation.EightBit.Z80 public void Run() { - while(!clock.FrameDone) + VBL = false; + + while(!VBL) { Step(); } @@ -570,8 +581,8 @@ namespace Noddybox.Emulation.EightBit.Z80 private void TriggerEvent(EventType type, byte opcode) { Z80CpuEventArgs e = new Z80CpuEventArgs - { - Opcode = opcode, + { + Opcode = opcode }; switch(type) diff --git a/src/Noddybox.Emulation/Clock.cs b/src/Noddybox.Emulation/Clock.cs index c4c5245..7fcd0fb 100644 --- a/src/Noddybox.Emulation/Clock.cs +++ b/src/Noddybox.Emulation/Clock.cs @@ -20,73 +20,145 @@ using System; namespace Noddybox.Emulation { /// - /// Provides a basic clock implementation that is geared towards the VBL. + /// Provides a clock implementation that is geared towards a raster display. /// public class Clock { #region Private fields - private uint perSecond; - private uint perFrame; - private uint perLine; - private uint frameCount; + private uint cyclesPreFrame; + private uint cyclesPerLine; + private uint noLines; + private uint cyclesPerVbl; + + private int line; + private uint cycles; + + #endregion + + #region Private Members + + private void CallEvent(EventHandler handler, ClockEventArgs.ClockEventType eventType) + { + if (handler != null) + { + handler(this, new ClockEventArgs(eventType)); + } + } + + #endregion + + #region Events + + /// + /// The cycles for the pre-first raster line have completed. + /// This event will not fire of the pre-frame cycle count is set to zero. + /// + public EventHandler EndPreFrame; + + /// + /// The end of a raster line has been reached. + /// + public EventHandler EndOfLine; + + /// + /// The last raster line has been drawn and the VBL is starting. + /// + public EventHandler StartOfVBL; + + /// + /// The VBL has completed. + /// + public EventHandler EndOfVBL; #endregion #region Public properties /// - /// Returns true if the frame has finished. + /// Returns true if VBL is happening. /// - public bool FrameDone + public bool VBL { get { - return frameCount > perFrame; + return line > noLines; } } /// - /// Returns the current raster line. + /// Returns the current raster line (zero based), number of lines if VBL is happening or -1 if the pre-frame is happening. /// - public uint RasterLine + public int RasterLine { get { - return frameCount / perLine; + return line; } } /// - /// Gets the ticks this frame so far. + /// Gets the total number of cycles per frame. /// - public uint Ticks - { - get {return frameCount;} - } + public ulong TotalCyclesPerFrame {get; private set;} #endregion #region Public members - /// - /// Starts a new frame. - /// - public void StartFrame() - { - if (FrameDone) - { - frameCount -= perFrame; - } - } - /// /// Adds a number of ticks to the clock. /// /// The ticks to add. public void Add(uint ticks) { - frameCount += ticks; + cycles += ticks; + + // Check pre-frame end + // + if (line == -1 && cycles >= cyclesPreFrame) + { + if (cyclesPreFrame > 0 && EndPreFrame != null) + { + CallEvent(EndPreFrame, ClockEventArgs.ClockEventType.EndPreFrame); + } + + line = 0; + cycles -= cyclesPreFrame; + } + + // Check line end and VBL start. + // + if (line < noLines && cycles >= cyclesPerLine) + { + if (EndOfLine != null) + { + CallEvent(EndOfLine, ClockEventArgs.ClockEventType.EndLine); + } + + cycles -= cyclesPerLine; + + if (++line == noLines) + { + if (StartOfVBL != null) + { + CallEvent(StartOfVBL, ClockEventArgs.ClockEventType.StartVBL); + } + } + } + + // Check end of VBL + // + if (line == noLines && cycles >= cyclesPerVbl) + { + line = 0; + cycles -= cyclesPerVbl; + + if (EndOfVBL != null) + { + CallEvent(EndOfVBL, ClockEventArgs.ClockEventType.EndVBL); + } + } } /// @@ -94,7 +166,8 @@ namespace Noddybox.Emulation /// public void Reset() { - frameCount = 0; + line = -1; + cycles = noLines; } #endregion @@ -104,28 +177,20 @@ namespace Noddybox.Emulation /// /// Defines a clock. /// - /// The number of ticks per second. - /// The number of frames per second. - public Clock(uint ticksPerSecond, uint framesPerSecond) + /// The number of cycles per line. + /// Cycles taken for the VBL at the end of the frame. + /// Cycles before the first line is drawn. + /// The number of raster lines before the VBL. + public Clock(uint cyclesPreFrame, uint cyclesPerLine, uint noLines, uint cyclesPerVbl) { - this.perSecond = ticksPerSecond; - this.perFrame = ticksPerSecond / framesPerSecond; - this.perLine = 1; - this.frameCount = 0; - } + this.cyclesPreFrame = cyclesPreFrame; + this.cyclesPerLine = cyclesPerLine; + this.noLines = noLines; + this.cyclesPerVbl = cyclesPerVbl; - /// - /// Defines a clock. - /// - /// The number of ticks per second. - /// The number of frames per second. - /// The number of clock ticks per raster line. - public Clock(uint ticksPerSecond, uint framesPerSecond, uint ticksPerLine) - { - this.perSecond = ticksPerSecond; - this.perFrame = ticksPerSecond / framesPerSecond; - this.perLine = ticksPerLine; - this.frameCount = 0; + TotalCyclesPerFrame = cyclesPreFrame + (cyclesPerLine * noLines) + cyclesPerVbl; + + Reset(); } #endregion diff --git a/src/Noddybox.Emulation/ClockEventArgs.cs b/src/Noddybox.Emulation/ClockEventArgs.cs new file mode 100644 index 0000000..38bc6fb --- /dev/null +++ b/src/Noddybox.Emulation/ClockEventArgs.cs @@ -0,0 +1,67 @@ +// This file is part of the Noddybox.Emulation C# suite. +// +// Noddybox.Emulation is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Noddybox.Emulation is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Noddybox.Emulation. If not, see . +// +// Copyright (c) 2012 Ian Cowburn +// +using System; + +namespace Noddybox.Emulation +{ + /// + /// Provides arguments for an event from the clock. + /// + public class ClockEventArgs : EventArgs + { + /// + /// The event type. + /// + public enum ClockEventType + { + /// + /// The pre-frame has ended. + /// + EndPreFrame, + + /// + /// We've completed a raster line. + /// + EndLine, + + /// + /// We've completed the last raster line and are starting VBL. + /// + StartVBL, + + /// + /// We've finished VBL. + /// + EndVBL + } + + /// + /// The type of event raised. + /// + public ClockEventType EventType {get; set;} + + /// + /// Constructor. + /// + /// The event type. + public ClockEventArgs(ClockEventType eventType) + { + EventType = eventType; + } + } +} -- cgit v1.2.3