diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs | 17 | ||||
-rw-r--r-- | src/Noddybox.Emulation/Clock.cs | 163 | ||||
-rw-r--r-- | src/Noddybox.Emulation/ClockEventArgs.cs | 67 |
3 files changed, 195 insertions, 52 deletions
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
{
/// <summary>
- /// Provides a basic clock implementation that is geared towards the VBL.
+ /// Provides a clock implementation that is geared towards a raster display.
/// </summary>
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<ClockEventArgs> handler, ClockEventArgs.ClockEventType eventType)
+ {
+ if (handler != null)
+ {
+ handler(this, new ClockEventArgs(eventType));
+ }
+ }
+
+ #endregion
+
+ #region Events
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public EventHandler<ClockEventArgs> EndPreFrame;
+
+ /// <summary>
+ /// The end of a raster line has been reached.
+ /// </summary>
+ public EventHandler<ClockEventArgs> EndOfLine;
+
+ /// <summary>
+ /// The last raster line has been drawn and the VBL is starting.
+ /// </summary>
+ public EventHandler<ClockEventArgs> StartOfVBL;
+
+ /// <summary>
+ /// The VBL has completed.
+ /// </summary>
+ public EventHandler<ClockEventArgs> EndOfVBL;
#endregion
#region Public properties
/// <summary>
- /// Returns true if the frame has finished.
+ /// Returns true if VBL is happening.
/// </summary>
- public bool FrameDone
+ public bool VBL
{
get
{
- return frameCount > perFrame;
+ return line > noLines;
}
}
/// <summary>
- /// 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.
/// </summary>
- public uint RasterLine
+ public int RasterLine
{
get
{
- return frameCount / perLine;
+ return line;
}
}
/// <summary>
- /// Gets the ticks this frame so far.
+ /// Gets the total number of cycles per frame.
/// </summary>
- public uint Ticks
- {
- get {return frameCount;}
- }
+ public ulong TotalCyclesPerFrame {get; private set;}
#endregion
#region Public members
/// <summary>
- /// Starts a new frame.
- /// </summary>
- public void StartFrame()
- {
- if (FrameDone)
- {
- frameCount -= perFrame;
- }
- }
-
- /// <summary>
/// Adds a number of ticks to the clock.
/// </summary>
/// <param name="ticks">The ticks to add.</param>
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);
+ }
+ }
}
/// <summary>
@@ -94,7 +166,8 @@ namespace Noddybox.Emulation /// </summary>
public void Reset()
{
- frameCount = 0;
+ line = -1;
+ cycles = noLines;
}
#endregion
@@ -104,28 +177,20 @@ namespace Noddybox.Emulation /// <summary>
/// Defines a clock.
/// </summary>
- /// <param name="ticksPerSecond">The number of ticks per second.</param>
- /// <param name="framesPerSecond">The number of frames per second.</param>
- public Clock(uint ticksPerSecond, uint framesPerSecond)
+ /// <param name="cyclesPerLine">The number of cycles per line.</param>
+ /// <param name="cyclesPerVbl">Cycles taken for the VBL at the end of the frame.</param>
+ /// <param name="cyclesPreFrame">Cycles before the first line is drawn.</param>
+ /// <param name="noLines">The number of raster lines before the VBL.</param>
+ 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;
- /// <summary>
- /// Defines a clock.
- /// </summary>
- /// <param name="ticksPerSecond">The number of ticks per second.</param>
- /// <param name="framesPerSecond">The number of frames per second.</param>
- /// <param name="ticksPerLine">The number of clock ticks per raster line.</param>
- 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 <http://www.gnu.org/licenses/>.
+//
+// Copyright (c) 2012 Ian Cowburn
+//
+using System;
+
+namespace Noddybox.Emulation
+{
+ /// <summary>
+ /// Provides arguments for an event from the clock.
+ /// </summary>
+ public class ClockEventArgs : EventArgs
+ {
+ /// <summary>
+ /// The event type.
+ /// </summary>
+ public enum ClockEventType
+ {
+ /// <summary>
+ /// The pre-frame has ended.
+ /// </summary>
+ EndPreFrame,
+
+ /// <summary>
+ /// We've completed a raster line.
+ /// </summary>
+ EndLine,
+
+ /// <summary>
+ /// We've completed the last raster line and are starting VBL.
+ /// </summary>
+ StartVBL,
+
+ /// <summary>
+ /// We've finished VBL.
+ /// </summary>
+ EndVBL
+ }
+
+ /// <summary>
+ /// The type of event raised.
+ /// </summary>
+ public ClockEventType EventType {get; set;}
+
+ /// <summary>
+ /// Constructor.
+ /// </summary>
+ /// <param name="eventType">The event type.</param>
+ public ClockEventArgs(ClockEventType eventType)
+ {
+ EventType = eventType;
+ }
+ }
+}
|