Cosmetic changes.

Implemented video scanner and floating bus.

--HG--
extra : convert_revision : svn%3Affd33b8c-2492-42e0-bdc5-587b920b7d6d/trunk%4035682
This commit is contained in:
Sean Fausett 2009-12-13 05:53:53 +00:00
parent acd7892436
commit ae126d2552
23 changed files with 150 additions and 160 deletions

View File

@ -9,42 +9,18 @@ namespace Jellyfish.Library
public sealed partial class DirectSound
{
[Flags]
private enum BufferCapabilities
{
PrimaryBuffer = 0x00000001,
CtrlPositionNotify = 0x00000100,
StickyFocus = 0x00004000,
GlobalFocus = 0x00008000
}
private enum BufferCapabilities { PrimaryBuffer = 0x00000001, CtrlPositionNotify = 0x00000100, StickyFocus = 0x00004000, GlobalFocus = 0x00008000 }
[Flags]
private enum BufferLock
{
None = 0x00000000,
FromWriteCursor = 0x00000001,
EntireBuffer = 0x00000002
}
private enum BufferLock { None = 0x00000000, FromWriteCursor = 0x00000001, EntireBuffer = 0x00000002 }
[Flags]
private enum BufferPlay
{
Looping = 0x00000001
}
private enum BufferPlay { Looping = 0x00000001 }
[Flags]
private enum BufferStatus
{
Playing = 0x00000001,
BufferLost = 0x00000002,
Looping = 0x00000004,
Terminated = 0x00000020
}
private enum BufferStatus { Playing = 0x00000001, BufferLost = 0x00000002, Looping = 0x00000004, Terminated = 0x00000020 }
private enum CooperativeLevel
{
Normal = 1,
Priority = 2
}
private enum CooperativeLevel { Normal = 1, Priority = 2 }
[StructLayout(LayoutKind.Sequential)]
private sealed class BufferDescription

View File

@ -10,16 +10,16 @@ namespace Jellyfish.Library
{
Name = name;
UnhandledException += Application_UnhandledException;
//AppDomain.CurrentDomain.UnhandledException += AppDomain_UnhandledException;
UnhandledException += OnApplicationUnhandledException;
//AppDomain.CurrentDomain.UnhandledException += OnAppDomainUnhandledException;
}
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
private void OnApplicationUnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
MessageBox.Show(GetExceptionMessage(e.ExceptionObject), GetExceptionCaption("Application Exception", false), MessageBoxButton.OK);
}
//private void AppDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
//private void OnAppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
//{
// MessageBox.Show(GetExceptionMessage(e.ExceptionObject as Exception), GetExceptionCaption("AppDomain Exception", e.IsTerminating), MessageBoxButton.OK);
//}

View File

@ -11,10 +11,10 @@ namespace Jellyfish.Library
{
InitializeComponent();
CompositionTarget.Rendering += CompositionTarget_Rendering;
CompositionTarget.Rendering += OnCompositionTargetRendering;
}
private void CompositionTarget_Rendering(object sender, EventArgs e)
private void OnCompositionTargetRendering(object sender, EventArgs e)
{
_frameCount++;

View File

@ -14,18 +14,18 @@ namespace Jellyfish.Library
{
Name = name;
DispatcherUnhandledException += Application_DispatcherUnhandledException;
AppDomain.CurrentDomain.UnhandledException += AppDomain_UnhandledException;
DispatcherUnhandledException += OnApplicationDispatcherUnhandledException;
AppDomain.CurrentDomain.UnhandledException += OnAppDomainUnhandledException;
}
private void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
private void OnApplicationDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
MessageBox.Show(GetExceptionMessage(e.Exception), GetExceptionCaption("Application Dispatcher Exception", true));
Shutdown();
e.Handled = true;
}
private void AppDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
private void OnAppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
MessageBox.Show(GetExceptionMessage(e.ExceptionObject as Exception), GetExceptionCaption("AppDomain Exception", e.IsTerminating));
}

View File

@ -11,10 +11,10 @@ namespace Jellyfish.Library
{
InitializeComponent();
CompositionTarget.Rendering += CompositionTarget_Rendering;
CompositionTarget.Rendering += OnCompositionTargetRendering;
}
private void CompositionTarget_Rendering(object sender, EventArgs e)
private void OnCompositionTargetRendering(object sender, EventArgs e)
{
_frameCount++;

View File

@ -10,8 +10,6 @@ namespace Jellyfish.Virtu
public Cpu(Machine machine) :
base(machine)
{
_updateEvent = UpdateEvent; // cache delegate; avoids garbage
ExecuteOpcode65N02 = new Action[OpcodeCount]
{
Execute65X02Brk00, Execute65X02Ora01, Execute65N02Nop02, Execute65N02Nop03,
@ -157,7 +155,7 @@ namespace Jellyfish.Virtu
UpdateSettings();
Machine.Events.AddEvent(CyclesPerUpdate, _updateEvent);
Machine.Video.VSync += OnVideoVSync;
}
public override void Reset()
@ -3212,21 +3210,20 @@ namespace Jellyfish.Virtu
}
#endregion
private void UpdateEvent()
private void OnVideoVSync(object sender, EventArgs e)
{
UpdateSettings();
if (Machine.Settings.Cpu.IsThrottled)
{
long elapsedTime = DateTime.UtcNow.Ticks - _lastTime;
if (elapsedTime < TicksPerVSync)
long ticksPerVSync = Machine.Video.TicksPerVSync;
if (elapsedTime < ticksPerVSync)
{
Thread.Sleep(TimeSpan.FromTicks(TicksPerVSync - elapsedTime).Milliseconds);
Thread.Sleep(TimeSpan.FromTicks(ticksPerVSync - elapsedTime).Milliseconds);
}
_lastTime = DateTime.UtcNow.Ticks;
}
Machine.Events.AddEvent(CyclesPerUpdate, _updateEvent);
}
private void UpdateSettings()
@ -3245,8 +3242,6 @@ namespace Jellyfish.Virtu
public int Opcode { get; private set; }
public long Cycles { get; private set; }
private Action _updateEvent;
private Memory _memory;
private Action[] _executeOpcode;

View File

@ -4,11 +4,6 @@ namespace Jellyfish.Virtu
{
public partial class Cpu
{
private const int CyclesPerUpdate = 17030;
private const int CyclesPerVSync = 17030;
private const int CyclesPerSecond = 1022730;
private static readonly long TicksPerVSync = TimeSpan.FromSeconds((double)CyclesPerVSync / CyclesPerSecond).Ticks;
private const int OpcodeCount = 256;
private readonly Action[] ExecuteOpcode65N02;

View File

@ -96,19 +96,6 @@
</Member>
</Members>
</Type>
<Type Name="Video">
<Members>
<Member Name="#ReadFloatingBus()">
<Messages>
<Message TypeName="MarkMembersAsStatic" Category="Microsoft.Performance" CheckId="CA1822" Created="2009-12-11 09:07:49Z" FixCategory="DependsOnFix">
<Issue>
<Item>'Video.ReadFloatingBus()'</Item>
</Issue>
</Message>
</Messages>
</Member>
</Members>
</Type>
</Types>
</Namespace>
</Namespaces>
@ -153,19 +140,6 @@
</Member>
</Members>
</Type>
<Type Name="Video">
<Members>
<Member Name="#ReadFloatingBus()">
<Messages>
<Message TypeName="MarkMembersAsStatic" Category="Microsoft.Performance" CheckId="CA1822" Created="2009-04-13 00:02:55Z" FixCategory="DependsOnFix">
<Issue>
<Item>'Video.ReadFloatingBus()'</Item>
</Issue>
</Message>
</Messages>
</Member>
</Members>
</Type>
</Types>
</Namespace>
</Namespaces>
@ -180,9 +154,6 @@
<Rule TypeName="DoNotRaiseReservedExceptionTypes" Category="Microsoft.Usage" CheckId="CA2201">
<Resolution Name="TooGeneric">{0} creates an exception of type {1}, an exception type that is not sufficiently specific and should never be raised by user code. If this exception instance might be thrown, use a different exception type.</Resolution>
</Rule>
<Rule TypeName="MarkMembersAsStatic" Category="Microsoft.Performance" CheckId="CA1822">
<Resolution Name="Default">The 'this' parameter (or 'Me' in Visual Basic) of {0} is never used. Mark the member as static (or Shared in Visual Basic) or use 'this'/'Me' in the method body or at least one property accessor, if appropriate.</Resolution>
</Rule>
<Rule TypeName="RemoveUnusedLocals" Category="Microsoft.Performance" CheckId="CA1804">
<Resolution Name="Default">{0} declares a variable, {1}, of type {2}, which is never used or is only assigned to. Use this variable or remove it.</Resolution>
</Rule>

View File

@ -10,7 +10,6 @@ namespace Jellyfish.Virtu
public Keyboard(Machine machine) :
base(machine)
{
_pollEvent = PollEvent; // cache delegate; avoids garbage
}
public override void Initialize()
@ -19,8 +18,7 @@ namespace Jellyfish.Virtu
_gamePortService = Machine.Services.GetService<GamePortService>();
_keyboardService.AsciiKeyDown += (sender, e) => Latch = e.AsciiKey;
Machine.Events.AddEvent(CyclesPerPoll, _pollEvent);
Machine.Video.VSync += OnVideoVSync;
}
[SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
@ -123,7 +121,7 @@ namespace Jellyfish.Virtu
Strobe = false;
}
private void PollEvent()
private void OnVideoVSync(object sender, EventArgs e)
{
if (_keyboardService.IsResetKeyDown)
{
@ -145,8 +143,6 @@ namespace Jellyfish.Virtu
Machine.Video.ToggleMonochrome();
_keyboardService.WaitForKeyUp();
}
Machine.Events.AddEvent(CyclesPerPoll, _pollEvent);
}
public bool IsAnyKeyDown { get { return _keyboardService.IsAnyKeyDown; } }
@ -154,10 +150,6 @@ namespace Jellyfish.Virtu
private int Latch { get { return _latch; } set { _latch = value; Strobe = true; } }
private const int CyclesPerPoll = 17030;
private Action _pollEvent;
private KeyboardService _keyboardService;
private GamePortService _gamePortService;

View File

@ -83,7 +83,7 @@ namespace Jellyfish.Virtu
{
do
{
Events.RaiseEvents(Cpu.Execute());
Events.HandleEvents(Cpu.Execute());
}
while (State == MachineState.Running);

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
namespace Jellyfish.Virtu
@ -78,8 +77,7 @@ namespace Jellyfish.Virtu
return 0;
}
[SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate")]
public void RaiseEvents(int delta)
public void HandleEvents(int delta)
{
LinkedListNode<MachineEvent> node = _used.First;
node.Value.Delta -= delta;

View File

@ -38,7 +38,7 @@ namespace Jellyfish.Virtu.Settings
};
Video = new VideoSettings
{
IsFullScreen = false, IsMonochrome = false, ScannerType = 0,
IsFullScreen = false, IsMonochrome = false, ScannerModes = ScannerModes.None,
Color = new ColorSettings
{
Black = 0x000000,
@ -172,8 +172,8 @@ namespace Jellyfish.Virtu.Settings
Video = new VideoSettings
{
IsFullScreen = (bool)video.Attribute("IsFullScreen"),
IsMonochrome = (bool)video.Attribute("IsMonochrome"),
ScannerType = (int)video.Attribute("ScannerType"),
IsMonochrome = (bool)video.Attribute("IsMonochrome"),
ScannerModes = (ScannerModes)Enum.Parse(typeof(ScannerModes), (string)video.Attribute("ScannerModes"), true),
Color = new ColorSettings
{
Black = (uint)color.Attribute("Black"),
@ -269,7 +269,7 @@ namespace Jellyfish.Virtu.Settings
new XElement(ns + "Video",
new XAttribute("IsFullScreen", Video.IsFullScreen),
new XAttribute("IsMonochrome", Video.IsMonochrome),
new XAttribute("ScannerType", Video.ScannerType),
new XAttribute("ScannerModes", Video.ScannerModes),
new XElement(ns + "Color",
new XAttribute("Black", Video.Color.Black),
new XAttribute("DarkBlue", Video.Color.DarkBlue),
@ -377,11 +377,14 @@ namespace Jellyfish.Virtu.Settings
public uint Monochrome { get; set; }
}
[Flags]
public enum ScannerModes { None = 0x0, AppleII = 0x1, Pal = 0x2 } // defaults to AppleIIe, Ntsc
public sealed class VideoSettings
{
public bool IsFullScreen { get; set; }
public bool IsMonochrome { get; set; }
public int ScannerType { get; set; }
public ScannerModes ScannerModes { get; set; }
public ColorSettings Color { get; set; }
};
}

View File

@ -1,5 +1,4 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
namespace Jellyfish.Virtu.Services
@ -31,8 +30,7 @@ namespace Jellyfish.Virtu.Services
public abstract bool IsKeyDown(int key);
[SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate")]
protected void RaiseAsciiKeyDown(int asciiKey)
protected void OnAsciiKeyDown(int asciiKey)
{
EventHandler<AsciiKeyEventArgs> handler = AsciiKeyDown;
if (handler != null)

View File

@ -26,11 +26,11 @@ namespace Jellyfish.Virtu
_machine.Services.AddService(typeof(VideoService), _videoService);
Loaded += (sender, e) => _machine.Start();
CompositionTarget.Rendering += CompositionTarget_Rendering;
CompositionTarget.Rendering += OnCompositionTargetRendering;
Application.Current.Exit += (sender, e) => _machine.Stop();
_disk1Button.Click += (sender, e) => DiskButton_Click(0);
_disk2Button.Click += (sender, e) => DiskButton_Click(1);
_disk1Button.Click += (sender, e) => OnDiskButtonClick(0);
_disk2Button.Click += (sender, e) => OnDiskButtonClick(1);
}
public void Dispose()
@ -43,14 +43,14 @@ namespace Jellyfish.Virtu
_videoService.Dispose();
}
private void CompositionTarget_Rendering(object sender, EventArgs e)
private void OnCompositionTargetRendering(object sender, EventArgs e)
{
_keyboardService.Update();
_gamePortService.Update();
_videoService.Update();
}
private void DiskButton_Click(int drive)
private void OnDiskButtonClick(int drive)
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*";

View File

@ -19,9 +19,9 @@ namespace Jellyfish.Virtu.Services
_page = page;
_page.KeyDown += Page_KeyDown;
_page.KeyUp += Page_KeyUp;
_page.LostFocus += Page_LostFocus;
_page.KeyDown += OnPageKeyDown;
_page.KeyUp += OnPageKeyUp;
_page.LostFocus += OnPageLostFocus;
}
public override bool IsKeyDown(int key)
@ -62,7 +62,7 @@ namespace Jellyfish.Virtu.Services
return _states[(int)key];
}
private void Page_KeyDown(object sender, KeyEventArgs e)
private void OnPageKeyDown(object sender, KeyEventArgs e)
{
_states[(int)e.Key] = true;
IsAnyKeyDown = true;
@ -70,19 +70,19 @@ namespace Jellyfish.Virtu.Services
int asciiKey = GetAsciiKey(e.Key, e.PlatformKeyCode);
if (asciiKey >= 0)
{
RaiseAsciiKeyDown(asciiKey);
OnAsciiKeyDown(asciiKey);
e.Handled = true;
}
}
private void Page_KeyUp(object sender, KeyEventArgs e)
private void OnPageKeyUp(object sender, KeyEventArgs e)
{
_capsLock ^= (e.Key == Key.CapsLock); // SL is missing caps lock support; try to track manually
_states[(int)e.Key] = false;
_updateAnyKeyDown = true;
}
private void Page_LostFocus(object sender, RoutedEventArgs e) // reset keyboard state on lost focus; can't access keyboard state on got focus
private void OnPageLostFocus(object sender, RoutedEventArgs e) // reset keyboard state on lost focus; can't access keyboard state on got focus
{
IsAnyKeyDown = false;
foreach (Key key in KeyValues)

View File

@ -29,9 +29,9 @@ namespace Jellyfish.Virtu
UpdateSettings();
IsVBlank = true;
Machine.Events.AddEvent((CyclesPerVBlank / 2), _leaveVBlankEvent);
Machine.Events.AddEvent(CyclesPerVSync, _resetVSyncEvent);
Machine.Events.AddEvent(CyclesPerFlash, _inverseTextEvent);
Machine.Events.AddEvent(_cyclesPerVBlankPreset, _leaveVBlankEvent); // align flush events with scanner; assumes vcount preset at start of frame [3-15, 3-16]
Machine.Events.AddEvent(_cyclesPerVSync, _resetVSyncEvent);
Machine.Events.AddEvent(_cyclesPerFlash, _inverseTextEvent);
}
public override void Reset()
@ -92,8 +92,29 @@ namespace Jellyfish.Virtu
public int ReadFloatingBus()
{
// TODO
return 0x00;
// derive scanner counters from current cycles into frame; assumes hcount and vcount preset at start of frame [3-13, 3-15, 3-16]
int cycles = _cyclesPerVSync - Machine.Events.FindEvent(_resetVSyncEvent);
int hClock = cycles % CyclesPerHSync;
int hCount = (hClock != 0) ? HCountPreset + hClock - 1 : 0;
int vLine = cycles / CyclesPerHSync;
int vCount = _vCountPreset + vLine;
// derive scanner address [5-8]
int address = ((vCount << 4) & 0x0380) | ((0x0068 + (hCount & 0x0038) + (((vCount >> 1) & 0x0060) | ((vCount >> 3) & 0x0018))) & 0x0078) | (hCount & 0x0007);
if (_memory.IsHires && !(_memory.IsMixed && ((vCount & 0xA0) == 0xA0))) // hires but not actively mixed [5-13, 5-19]
{
address |= (_memory.IsVideoPage2 ? 0x4000 : 0x2000) | ((vCount << 10) & 0x1C00);
}
else
{
address |= _memory.IsVideoPage2 ? 0x0800 : 0x0400;
if (((_scannerModes & ScannerModes.AppleII) != 0) && (hCount < HCountLeaveHBlank))
{
address |= 0x1000;
}
}
return _memory.Read(address);
}
public void SetCharSet()
@ -641,7 +662,7 @@ namespace Jellyfish.Virtu
#region Flush Methods
private void FlushRowMode0(int y)
{
int address = (!_memory.IsVideoPage2 ? 0x0400 : 0x0800) + AddressOffset[y];
int address = (_memory.IsVideoPage2 ? 0x0800 : 0x0400) + AddressOffset[y];
for (int x = 0; x < CellColumns; x++)
{
if (_isCellDirty[CellColumns * y + x])
@ -654,7 +675,7 @@ namespace Jellyfish.Virtu
private void FlushRowMode1(int y)
{
int address = (!_memory.IsVideoPage2 ? 0x0400 : 0x0800) + AddressOffset[y];
int address = (_memory.IsVideoPage2 ? 0x0800 : 0x0400) + AddressOffset[y];
for (int x = 0; x < CellColumns; x++)
{
if (_isCellDirty[CellColumns * y + x])
@ -667,7 +688,7 @@ namespace Jellyfish.Virtu
private void FlushRowMode2(int y)
{
int address = (!_memory.IsVideoPage2 ? 0x0400 : 0x0800) + AddressOffset[y];
int address = (_memory.IsVideoPage2 ? 0x0800 : 0x0400) + AddressOffset[y];
for (int x = 0; x < 2 * CellColumns; x += 2)
{
if (_isCellDirty[CellColumns * y + x / 2])
@ -705,7 +726,7 @@ namespace Jellyfish.Virtu
private void FlushRowMode5(int y)
{
int address = !_memory.IsVideoPage2 ? 0x2000 : 0x4000;
int address = _memory.IsVideoPage2 ? 0x4000 : 0x2000;
for (int i = 0; i < CellHeight; i++, y++)
{
for (int x = 0; x < CellColumns; x++)
@ -745,7 +766,7 @@ namespace Jellyfish.Virtu
private void FlushRowMode8(int y)
{
int address = (!_memory.IsVideoPage2 ? 0x0400 : 0x0800) + AddressOffset[y];
int address = (_memory.IsVideoPage2 ? 0x0800 : 0x0400) + AddressOffset[y];
for (int x = 0; x < CellColumns; x++)
{
if (_isCellDirty[CellColumns * y + x])
@ -758,7 +779,7 @@ namespace Jellyfish.Virtu
private void FlushRowMode9(int y)
{
int address = (!_memory.IsVideoPage2 ? 0x0400 : 0x0800) + AddressOffset[y];
int address = (_memory.IsVideoPage2 ? 0x0800 : 0x0400) + AddressOffset[y];
for (int x = 0; x < 2 * CellColumns; x += 2)
{
if (_isCellDirty[CellColumns * y + x / 2])
@ -796,7 +817,7 @@ namespace Jellyfish.Virtu
private void FlushRowModeC(int y)
{
int address = !_memory.IsVideoPage2 ? 0x2000 : 0x4000;
int address = _memory.IsVideoPage2 ? 0x4000 : 0x2000;
for (int i = 0; i < CellHeight; i++, y++)
{
for (int x = 0; x < CellColumns; x++)
@ -812,7 +833,7 @@ namespace Jellyfish.Virtu
private void FlushRowModeD(int y)
{
int address = !_memory.IsVideoPage2 ? 0x2000 : 0x4000;
int address = _memory.IsVideoPage2 ? 0x4000 : 0x2000;
for (int i = 0; i < CellHeight; i++, y++)
{
for (int x = 0; x < CellColumns; x++)
@ -854,7 +875,7 @@ namespace Jellyfish.Virtu
private void FlushRowEvent()
{
int y = (CyclesPerVSync - (CyclesPerVBlank / 2) - Machine.Events.FindEvent(_resetVSyncEvent)) / CyclesPerHSync;
int y = (_cyclesPerVSync - _cyclesPerVBlankPreset - Machine.Events.FindEvent(_resetVSyncEvent)) / CyclesPerHSync;
FlushRowMode[_memory.VideoMode](y - CellHeight); // in arrears
@ -866,7 +887,7 @@ namespace Jellyfish.Virtu
{
IsVBlank = true;
Machine.Events.AddEvent(CyclesPerVBlank, _leaveVBlankEvent);
Machine.Events.AddEvent(_cyclesPerVBlank, _leaveVBlankEvent);
}
}
@ -886,7 +907,7 @@ namespace Jellyfish.Virtu
DirtyScreenText();
Machine.Events.AddEvent(CyclesPerFlash, _inverseTextEvent);
Machine.Events.AddEvent(_cyclesPerFlash, _inverseTextEvent);
}
private void LeaveVBlankEvent()
@ -900,7 +921,13 @@ namespace Jellyfish.Virtu
{
UpdateSettings();
Machine.Events.AddEvent(CyclesPerVSync, _resetVSyncEvent);
EventHandler handler = VSync;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
Machine.Events.AddEvent(_cyclesPerVSync, _resetVSyncEvent);
}
private void SetPixel(int x, int y, int color)
@ -949,6 +976,23 @@ namespace Jellyfish.Virtu
_colorPalette[ColorDHiresE] = settings.Color.Yellow;
_colorPalette[ColorDHiresF] = settings.Color.White;
_scannerModes = settings.ScannerModes;
if ((_scannerModes & ScannerModes.Pal) != 0)
{
_vCountPreset = VCountPresetPal;
_vLineLeaveVBlank = VLineLeaveVBlankPal;
}
else
{
_vCountPreset = VCountPresetNtsc;
_vLineLeaveVBlank = VLineLeaveVBlankNtsc;
}
_cyclesPerVBlank = (_vLineLeaveVBlank - VLineEnterVBlank) * CyclesPerHSync;
_cyclesPerVBlankPreset = (_vLineLeaveVBlank - VLineTriggerPreset) * CyclesPerHSync; // cycles during vblank after vcount preset [3-15, 3-16]
_cyclesPerVSync = _vLineLeaveVBlank * CyclesPerHSync;
_cyclesPerFlash = VSyncsPerFlash * _cyclesPerVSync;
if (_videoService.IsFullScreen != settings.IsFullScreen)
{
_videoService.ToggleFullScreen();
@ -956,6 +1000,9 @@ namespace Jellyfish.Virtu
}
public bool IsVBlank { get; private set; }
public long TicksPerVSync { get { return TimeSpan.FromSeconds((double)_cyclesPerVSync / CyclesPerSecond).Ticks; } }
public event EventHandler VSync;
private Action _flushRowEvent;
private Action _inverseTextEvent;
@ -969,5 +1016,12 @@ namespace Jellyfish.Virtu
private uint[] _colorPalette = new uint[ColorPaletteCount];
private bool[] _isCellDirty = new bool[Height * CellColumns + 1]; // includes sentinel
private bool _isTextInversed;
private int _cyclesPerVBlank;
private int _cyclesPerVBlankPreset;
private int _cyclesPerVSync;
private int _cyclesPerFlash;
private int _vCountPreset;
private int _vLineLeaveVBlank;
private ScannerModes _scannerModes;
}
}

View File

@ -1596,9 +1596,17 @@ namespace Jellyfish.Virtu
private const int CyclesPerHBlank = 25;
private const int CyclesPerHSync = 65;
private const int CyclesPerFlush = 8 * CyclesPerHSync;
private const int CyclesPerVBlank = 70 * CyclesPerHSync;
private const int CyclesPerVSync = 262 * CyclesPerHSync;
private const int CyclesPerFlash = 16 * CyclesPerVSync;
private const int CyclesPerSecond = 1022730;
private const int HCountPreset = 0x40; // hcount preset after hcount overflows -> HPE' low [3-13]
private const int HCountLeaveHBlank = 0x58; // hcount when leaving hblank [3-15]
private const int VCountPresetNtsc = 0xFA; // vcount preset after vcount overflows (NTSC) [3-13]
private const int VCountPresetPal = 0xC8; // vcount preset after vcount overflows (PAL) [3-17]
private const int VLineEnterVBlank = 192; // vline when entering vblank (NTSC & PAL) [3-17]
private const int VLineTriggerPreset = 256; // vline when vcount overflows and presets (NTSC & PAL) [3-15, 3-16]
private const int VLineLeaveVBlankNtsc = 262; // vline when leaving vblank (NTSC) [3-13]
private const int VLineLeaveVBlankPal = 312; // vline when leaving vblank (PAL) [3-17]
private const int VSyncsPerFlash = 16; // flash count using vcount overflow [3-17]
public const int ModeCount = 16;
@ -1622,7 +1630,7 @@ namespace Jellyfish.Virtu
private readonly Action<int>[] FlushRowMode;
private const int Width = 560;
private const int Height = 192;
private const int Height = VLineEnterVBlank;
private const int TextHeight = 8;
private const int TextRows = Height / TextHeight;

View File

@ -26,11 +26,11 @@ namespace Jellyfish.Virtu
_machine.Services.AddService(typeof(VideoService), _videoService);
Loaded += (sender, e) => _machine.Start();
CompositionTarget.Rendering += CompositionTarget_Rendering;
CompositionTarget.Rendering += OnCompositionTargetRendering;
Application.Current.Exit += (sender, e) => _machine.Stop();
_disk1Button.Click += (sender, e) => DiskButton_Click(0);
_disk2Button.Click += (sender, e) => DiskButton_Click(1);
_disk1Button.Click += (sender, e) => OnDiskButtonClick(0);
_disk2Button.Click += (sender, e) => OnDiskButtonClick(1);
}
public void Dispose()
@ -43,14 +43,14 @@ namespace Jellyfish.Virtu
_videoService.Dispose();
}
private void CompositionTarget_Rendering(object sender, EventArgs e)
private void OnCompositionTargetRendering(object sender, EventArgs e)
{
_keyboardService.Update();
_gamePortService.Update();
_videoService.Update();
}
private void DiskButton_Click(int drive)
private void OnDiskButtonClick(int drive)
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = "Disk Files (*.dsk;*.nib)|*.dsk;*.nib|All Files (*.*)|*.*";

View File

@ -18,7 +18,7 @@ namespace Jellyfish.Virtu.Services
_window = window;
_window.SourceInitialized += (sender, e) => _directSound.Start(_window.GetHandle());
_directSound.Update += DirectSound_Update;
_directSound.Update += OnDirectSoundUpdate;
_window.Closed += (sender, e) => _directSound.Stop();
}
@ -32,7 +32,7 @@ namespace Jellyfish.Virtu.Services
base.Dispose(disposing);
}
private void DirectSound_Update(object sender, DirectSoundUpdateEventArgs e)
private void OnDirectSoundUpdate(object sender, DirectSoundUpdateEventArgs e)
{
IntPtr buffer = e.Buffer;
Update(e.BufferSize, (source, count) =>

View File

@ -18,8 +18,8 @@ namespace Jellyfish.Virtu.Services
_window = window;
_window.KeyDown += Window_KeyDown;
_window.KeyUp += Window_KeyUp;
_window.KeyDown += OnWindowKeyDown;
_window.KeyUp += OnWindowKeyUp;
_window.GotKeyboardFocus += (sender, e) => _updateAnyKeyDown = true;
}
@ -61,7 +61,7 @@ namespace Jellyfish.Virtu.Services
return _states[(int)key];
}
private void Window_KeyDown(object sender, KeyEventArgs e)
private void OnWindowKeyDown(object sender, KeyEventArgs e)
{
_states[(int)((e.Key == Key.System) ? e.SystemKey : e.Key)] = true;
IsAnyKeyDown = true;
@ -69,12 +69,12 @@ namespace Jellyfish.Virtu.Services
int asciiKey = GetAsciiKey(e.Key, e.KeyboardDevice);
if (asciiKey >= 0)
{
RaiseAsciiKeyDown(asciiKey);
OnAsciiKeyDown(asciiKey);
e.Handled = true;
}
}
private void Window_KeyUp(object sender, KeyEventArgs e)
private void OnWindowKeyUp(object sender, KeyEventArgs e)
{
_states[(int)((e.Key == Key.System) ? e.SystemKey : e.Key)] = false;
_updateAnyKeyDown = true;

View File

@ -18,7 +18,7 @@ namespace Jellyfish.Virtu.Services
_game = game;
_directSound.Start(_game.Window.Handle);
_directSound.Update += DirectSound_Update;
_directSound.Update += OnDirectSoundUpdate;
_game.Exiting += (sender, e) => _directSound.Stop();
}
@ -30,7 +30,7 @@ namespace Jellyfish.Virtu.Services
}
}
private void DirectSound_Update(object sender, DirectSoundUpdateEventArgs e)
private void OnDirectSoundUpdate(object sender, DirectSoundUpdateEventArgs e)
{
IntPtr buffer = e.Buffer;
Update(e.BufferSize, (source, count) =>

View File

@ -48,7 +48,7 @@ namespace Jellyfish.Virtu.Services
#endif
if (asciiKey >= 0)
{
RaiseAsciiKeyDown(asciiKey);
OnAsciiKeyDown(asciiKey);
}
}
}
@ -73,7 +73,7 @@ namespace Jellyfish.Virtu.Services
#endif
if (asciiKey >= 0)
{
RaiseAsciiKeyDown(asciiKey);
OnAsciiKeyDown(asciiKey);
}
}
}

View File

@ -18,8 +18,8 @@ namespace Jellyfish.Virtu.Services
_game = game;
_game.GraphicsDeviceManager.PreparingDeviceSettings += GraphicsDeviceManager_PreparingDeviceSettings;
_game.GraphicsDeviceService.DeviceCreated += GraphicsDeviceService_DeviceCreated;
_game.GraphicsDeviceManager.PreparingDeviceSettings += OnGraphicsDeviceManagerPreparingDeviceSettings;
_game.GraphicsDeviceService.DeviceCreated += OnGraphicsDeviceServiceDeviceCreated;
_game.GraphicsDeviceService.DeviceReset += (sender, e) => SetTexturePosition();
}
@ -68,7 +68,7 @@ namespace Jellyfish.Virtu.Services
}
}
private void GraphicsDeviceManager_PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
private void OnGraphicsDeviceManagerPreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
{
DisplayMode displayMode = e.GraphicsDeviceInformation.Adapter.CurrentDisplayMode;
PresentationParameters presentationParameters = e.GraphicsDeviceInformation.PresentationParameters;
@ -83,7 +83,7 @@ namespace Jellyfish.Virtu.Services
}
}
private void GraphicsDeviceService_DeviceCreated(object sender, EventArgs e)
private void OnGraphicsDeviceServiceDeviceCreated(object sender, EventArgs e)
{
_graphicsDevice = _game.GraphicsDevice;
_spriteBatch = new SpriteBatch(_graphicsDevice);