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:
parent
acd7892436
commit
ae126d2552
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
//}
|
||||
|
|
|
@ -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++;
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
|
||||
|
|
15
Virtu/Cpu.cs
15
Virtu/Cpu.cs
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace Jellyfish.Virtu
|
|||
{
|
||||
do
|
||||
{
|
||||
Events.RaiseEvents(Cpu.Execute());
|
||||
Events.HandleEvents(Cpu.Execute());
|
||||
}
|
||||
while (State == MachineState.Running);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 (*.*)|*.*";
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 (*.*)|*.*";
|
||||
|
|
|
@ -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) =>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) =>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue