diff options
-rw-r--r-- | WPZX81/WPZX81/App.xaml.cs | 1 | ||||
-rw-r--r-- | WPZX81/WPZX81/GamePage.xaml.cs | 21 | ||||
-rw-r--r-- | WPZX81/WPZX81/Resources/Strings.Designer.cs | 9 | ||||
-rw-r--r-- | WPZX81/WPZX81/Resources/Strings.resx | 3 | ||||
-rw-r--r-- | WPZX81/WPZX81/Resources/zx81.rom | bin | 0 -> 8192 bytes | |||
-rw-r--r-- | WPZX81/WPZX81/Settings.cs | 35 | ||||
-rw-r--r-- | WPZX81/WPZX81/SettingsPage.xaml | 9 | ||||
-rw-r--r-- | WPZX81/WPZX81/SettingsPage.xaml.cs | 12 | ||||
-rw-r--r-- | WPZX81/WPZX81/Shared.cs | 2 | ||||
-rw-r--r-- | WPZX81/WPZX81/WPZX81.csproj | 1 | ||||
-rw-r--r-- | WPZX81/WPZX81/ZX81/Emulation.cs | 218 |
11 files changed, 280 insertions, 31 deletions
diff --git a/WPZX81/WPZX81/App.xaml.cs b/WPZX81/WPZX81/App.xaml.cs index 0167d21..b16ca7b 100644 --- a/WPZX81/WPZX81/App.xaml.cs +++ b/WPZX81/WPZX81/App.xaml.cs @@ -83,6 +83,7 @@ namespace WPZX81 // This code will not execute when the application is reactivated
private void Application_Launching(object sender, LaunchingEventArgs e)
{
+ Shared.ZX81 = new ZX81.Emulation();
}
// Code to execute when the application is activated (brought to foreground)
diff --git a/WPZX81/WPZX81/GamePage.xaml.cs b/WPZX81/WPZX81/GamePage.xaml.cs index 36d97d0..2741945 100644 --- a/WPZX81/WPZX81/GamePage.xaml.cs +++ b/WPZX81/WPZX81/GamePage.xaml.cs @@ -30,35 +30,23 @@ namespace WPZX81 // Create a timer for this page
timer = new GameTimer();
- timer.UpdateInterval = TimeSpan.FromTicks(333333);
+ timer.UpdateInterval = TimeSpan.FromMilliseconds(40); // Updates at 25 fps
timer.Update += OnUpdate;
timer.Draw += OnDraw;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
- // Set the sharing mode of the graphics device to turn on XNA rendering
SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true);
-
- // Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(SharedGraphicsDeviceManager.Current.GraphicsDevice);
-
- // TODO: use this.content to load your game content here
-
- // Start the timer
timer.Start();
-
base.OnNavigatedTo(e);
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
- // Stop the timer
timer.Stop();
-
- // Set the sharing mode of the graphics device to turn off XNA rendering
SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false);
-
base.OnNavigatedFrom(e);
}
@@ -68,7 +56,7 @@ namespace WPZX81 /// </summary>
private void OnUpdate(object sender, GameTimerEventArgs e)
{
- // TODO: Add your update logic here
+ Shared.ZX81.Run();
}
/// <summary>
@@ -76,9 +64,8 @@ namespace WPZX81 /// </summary>
private void OnDraw(object sender, GameTimerEventArgs e)
{
- SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.CornflowerBlue);
-
- // TODO: Add your drawing code here
+ SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.Black);
+ Shared.ZX81.UpdateDisplay(spriteBatch);
}
}
}
\ No newline at end of file diff --git a/WPZX81/WPZX81/Resources/Strings.Designer.cs b/WPZX81/WPZX81/Resources/Strings.Designer.cs index ba9ae34..a6bb352 100644 --- a/WPZX81/WPZX81/Resources/Strings.Designer.cs +++ b/WPZX81/WPZX81/Resources/Strings.Designer.cs @@ -182,6 +182,15 @@ namespace WPZX81.Resources { }
/// <summary>
+ /// Looks up a localized string similar to 16K RAM Pack Inserted.
+ /// </summary>
+ public static string RamPackText {
+ get {
+ return ResourceManager.GetString("RamPackText", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to URL for remote location of .P files.
/// </summary>
public static string RemoteURLForPFileText {
diff --git a/WPZX81/WPZX81/Resources/Strings.resx b/WPZX81/WPZX81/Resources/Strings.resx index 0f583b1..c892b78 100644 --- a/WPZX81/WPZX81/Resources/Strings.resx +++ b/WPZX81/WPZX81/Resources/Strings.resx @@ -208,4 +208,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY <data name="StickyShiftKeyText" xml:space="preserve">
<value>Sticky Shift Key</value>
</data>
+ <data name="RamPackText" xml:space="preserve">
+ <value>16K RAM Pack Inserted</value>
+ </data>
</root>
\ No newline at end of file diff --git a/WPZX81/WPZX81/Resources/zx81.rom b/WPZX81/WPZX81/Resources/zx81.rom Binary files differnew file mode 100644 index 0000000..557ddcb --- /dev/null +++ b/WPZX81/WPZX81/Resources/zx81.rom diff --git a/WPZX81/WPZX81/Settings.cs b/WPZX81/WPZX81/Settings.cs index 93616fe..7243bc3 100644 --- a/WPZX81/WPZX81/Settings.cs +++ b/WPZX81/WPZX81/Settings.cs @@ -41,10 +41,45 @@ namespace WPZX81 }
+ /// <summary>
+ /// Get/set static RAM at 0x2000 setting.
+ /// </summary>
+ public static bool StaticRamAt0x2000
+ {
+ get {return staticRamAt0x2000;}
+ set
+ {
+ if (staticRamAt0x2000 != value)
+ {
+ staticRamAt0x2000 = value;
+ Save("StaticRamAt0x2000", staticRamAt0x2000);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Get/set 16K RAM pack setting.
+ /// </summary>
+ public static bool RamPack
+ {
+ get {return ramPack;}
+ set
+ {
+ if (ramPack != value)
+ {
+ ramPack = value;
+ Save("RamPack", staticRamAt0x2000);
+ }
+ }
+ }
+
+
#region Private code
private static bool stickyShift = Load("StickyShift", false);
private static string pFileUrl = Load("PFileUrl", "http://enter-a-url.here/");
+ private static bool staticRamAt0x2000 = Load("StaticRamAt0x2000", false);
+ private static bool ramPack = Load("RamPack", true);
private static T Load<T>(string name, T defaultValue)
{
diff --git a/WPZX81/WPZX81/SettingsPage.xaml b/WPZX81/WPZX81/SettingsPage.xaml index 6c925e1..4243415 100644 --- a/WPZX81/WPZX81/SettingsPage.xaml +++ b/WPZX81/WPZX81/SettingsPage.xaml @@ -42,15 +42,22 @@ <RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
+ <RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding RemoteURLForPFileText, Source={StaticResource Strings}}"
Grid.Row="0" />
<TextBox Text="{Binding PFileUrlSetting, Mode=TwoWay}"
Grid.Row="1" />
+ <CheckBox IsChecked="{Binding RamPackSetting, Mode=TwoWay}"
+ Content="{Binding RamPackText, Source={StaticResource Strings}}"
+ Grid.Row="2" />
<CheckBox IsChecked="{Binding StickyShiftSetting, Mode=TwoWay}"
Content="{Binding StickyShiftKeyText, Source={StaticResource Strings}}"
- Grid.Row="2" />
+ Grid.Row="3" />
+ <CheckBox IsChecked="{Binding StaticRamAt0x2000Setting, Mode=TwoWay}"
+ Content="{Binding StaticRamAt0x2000Text, Source={StaticResource Strings}}"
+ Grid.Row="4" />
</Grid>
</Grid>
diff --git a/WPZX81/WPZX81/SettingsPage.xaml.cs b/WPZX81/WPZX81/SettingsPage.xaml.cs index d6d5019..5bf0c94 100644 --- a/WPZX81/WPZX81/SettingsPage.xaml.cs +++ b/WPZX81/WPZX81/SettingsPage.xaml.cs @@ -32,5 +32,17 @@ namespace WPZX81 get {return Settings.StickyShift;}
set {Settings.StickyShift = value;}
}
+
+ public bool StaticRamAt0x2000Setting
+ {
+ get {return Settings.StaticRamAt0x2000;}
+ set {Settings.StaticRamAt0x2000 = value;}
+ }
+
+ public bool RamPackSetting
+ {
+ get {return Settings.RamPack;}
+ set {Settings.RamPack = value;}
+ }
}
}
\ No newline at end of file diff --git a/WPZX81/WPZX81/Shared.cs b/WPZX81/WPZX81/Shared.cs index 38382b2..04f4588 100644 --- a/WPZX81/WPZX81/Shared.cs +++ b/WPZX81/WPZX81/Shared.cs @@ -10,7 +10,7 @@ using System.Windows.Media.Animation; using System.Windows.Shapes;
using WPZX81.ZX81;
-namespace wpspec
+namespace WPZX81
{
/// <summary>
/// Contains shared objects between the Silverlight and XNA domains
diff --git a/WPZX81/WPZX81/WPZX81.csproj b/WPZX81/WPZX81/WPZX81.csproj index 1fd98bd..8e80b73 100644 --- a/WPZX81/WPZX81/WPZX81.csproj +++ b/WPZX81/WPZX81/WPZX81.csproj @@ -114,6 +114,7 @@ <ItemGroup>
<None Include="Properties\AppManifest.xml" />
<None Include="Properties\WMAppManifest.xml" />
+ <Content Include="Resources\zx81.rom" />
</ItemGroup>
<ItemGroup>
<Content Include="ApplicationIcon.png">
diff --git a/WPZX81/WPZX81/ZX81/Emulation.cs b/WPZX81/WPZX81/ZX81/Emulation.cs index 663b297..9620052 100644 --- a/WPZX81/WPZX81/ZX81/Emulation.cs +++ b/WPZX81/WPZX81/ZX81/Emulation.cs @@ -2,6 +2,8 @@ using Noddybox.Emulation;
using Noddybox.Emulation.EightBit;
using Noddybox.Emulation.EightBit.Z80;
+using Microsoft.Xna.Framework.Graphics;
+using System.Windows.Resources;
namespace WPZX81.ZX81
{
@@ -12,26 +14,152 @@ namespace WPZX81.ZX81 {
#region Private data
- private readonly Clock clock;
- private readonly byte[] mem;
- private readonly Z80Cpu z80;
+ private Clock clock;
+ private byte[] mem;
+ private Z80Cpu z80;
+ private bool fast;
+ private int lastI;
+ private int rambot;
+ private int ramtop;
+
+ // Some system variables
+ //
+ private const int E_LINE = 16404;
+ private const int LASTK1 = 16421;
+ private const int LASTK2 = 16422;
+ private const int MARGIN = 16424;
+ private const int FRAMES = 16436;
+ private const int CDFLAG = 16443;
+
+ // ED Hooks
+ //
+ private const int ED_SAVE = 0xf0;
+ private const int ED_LOAD = 0xf1;
+ private const int ED_WAITKEY = 0xf2;
+ private const int ED_ENDWAITKEY = 0xf3;
+ private const int ED_PAUSE = 0xf4;
+
+ // ROM patches
+ //
+ private byte[] savePatch = new byte[]
+ {
+ 0xed, ED_SAVE, /* (SAVE) */
+ 0xc3, 0x07, 0x02, /* JP $0207 */
+ };
+
+ private byte[] loadPatch = new byte[]
+ {
+ 0xed, ED_LOAD, /* (LOAD) */
+ 0xc3, 0x07, 0x02, /* JP $0207 */
+ };
+
+ private byte[] fastPatch = new byte[]
+ {
+ 0xed, ED_WAITKEY, /* (START KEY WAIT) */
+ 0xcb,0x46, /* L: bit 0,(hl) */
+ 0x28,0xfc, /* jr z,L */
+ 0xed, ED_ENDWAITKEY, /* (END KEY WAIT) */
+ 0x00, /* nop */
+ };
+
+ private byte[] keyboardPatch = new byte[]
+ {
+ 0x2a,0x25,0x40, /* ld hl,(LASTK) */
+ 0xc9, /* ret */
+ };
+
+ private byte[] pausePatch = new byte[]
+ {
+ 0xed, ED_PAUSE, /* (PAUSE) */
+ 0x00, /* nop */
+ };
#endregion
#region Private methods
+ /// <summary>
+ /// Loads the font from the ZX81 according to the I register.
+ /// </summary>
+ private void LoadFont()
+ {
+ }
+
+
+ private void Patch(ushort address, byte[] patch)
+ {
+ foreach (byte b in patch)
+ {
+ mem[address++] = b;
+ }
+ }
+
+ /// <summary>
+ /// Patch the ROM to make life easier.
+ /// </summary>
+ private void PatchROM()
+ {
+ Patch(0x2fc, savePatch);
+ Patch(0x347, loadPatch);
+ Patch(0x4ca, fastPatch);
+ Patch(0x2bb, keyboardPatch);
+ Patch(0xf3a, pausePatch);
+
+ // Trust me, we have a ZX81... Honestly.
+ //
+ mem[0x21c]=0x00;
+ mem[0x21d]=0x00;
+
+ // Remove HALTs as we don't do NMI and the NMI generator properly
+ //
+ mem[0x0079]=0;
+ mem[0x02ec]=0;
+ }
+
+ /// <summary>
+ /// Handles ED hooks.
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
+ private void EDCallback(object sender, Z80CpuEventArgs e)
+ {
+ switch (e.Opcode)
+ {
+ case ED_SAVE:
+ break;
+
+ case ED_LOAD:
+ break;
+
+ case ED_WAITKEY:
+ break;
+
+ case ED_ENDWAITKEY:
+ break;
+
+ case ED_PAUSE:
+ break;
+
+ default:
+ break;
+ }
+ }
+
#endregion
#region IMemory Members
byte IMemory.Read(ushort address)
{
- throw new NotImplementedException();
+ return mem[address];
}
void IMemory.Write(ushort address, byte value)
{
- throw new NotImplementedException();
+ if (address >= rambot && address <= ramtop)
+ {
+ mem[address] = value;
+ }
}
#endregion
@@ -40,31 +168,97 @@ namespace WPZX81.ZX81 byte IDevice.Read(ushort device)
{
- throw new NotImplementedException();
+ return 0;
}
void IDevice.Write(ushort device, byte value)
{
- throw new NotImplementedException();
}
#endregion
#region Public methods
+ /// <summary>
+ /// Run the emulation for a frame.
+ /// </summary>
+ public void Run()
+ {
+ if (fast)
+ {
+ clock.StartFrame();
+ z80.Run();
+ clock.StartFrame();
+ z80.Run();
+ clock.StartFrame();
+ z80.Run();
+ clock.StartFrame();
+ }
+
+ z80.Run();
+ z80.MaskableInterrupt(0);
+ }
+
+ /// <summary>
+ /// Updates the display.
+ /// </summary>
+ /// <param name="batch">The sprite batch to use for updates.</param>
+ public void UpdateDisplay(SpriteBatch batch)
+ {
+ // Check if character pointer has updated
+ //
+ if (z80.InterruptVector != lastI)
+ {
+ LoadFont();
+ }
+ }
+
+
+ /// <summary>
+ /// Reset the ZX81.
+ /// </summary>
+ public void Reset()
+ {
+ lastI = -1;
+ fast = true;
+
+ rambot = Settings.StaticRamAt0x2000 ? 0x2000 : 0x4000;
+ ramtop = Settings.RamPack ? 0x8000 : 0x4400;
+
+ mem.Initialize();
+
+ Uri uri = new Uri("Resources/zx81.rom", UriKind.Relative);
+ StreamResourceInfo file = App.GetResourceStream(uri);
+
+ file.Stream.Read(mem, 0, 0x2000);
+ file.Stream.Close();
+
+ if (!Settings.StaticRamAt0x2000)
+ {
+ for(int f = 0; f < 0x2000; f++)
+ {
+ mem[0x2000 + f] = mem[f];
+ }
+ }
+
+ PatchROM();
+
+ clock.Reset();
+ z80.Reset();
+ }
+
#endregion
#region Constructors
public Emulation()
{
- mem = new byte[0x10000];
+ mem = new byte[0x8000];
+ clock = new Clock(16000 * 2, 50);
z80 = new Z80Cpu();
- clock = new Clock(10000, 50);
-
- WPZX81.Resources.Strings s = new Resources.Strings();
-
z80.Initialise(this, this, clock);
+ z80.EDNopEvent += EDCallback;
+ Reset();
}
#endregion
|