diff options
Diffstat (limited to 'src/Noddybox.Emulation/Clock.cs')
-rw-r--r-- | src/Noddybox.Emulation/Clock.cs | 163 |
1 files changed, 114 insertions, 49 deletions
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
|