From 027d795cccddede3e08bd6df0807aaf6c4c8f45c Mon Sep 17 00:00:00 2001 From: Ian C Date: Fri, 9 Mar 2012 23:01:42 +0000 Subject: Updates following Z80 bug fixes. --- wpspec/wpspec/App.xaml.cs | 1 + wpspec/wpspec/GamePage.xaml.cs | 29 +++-- wpspec/wpspec/Spectrum/Emulation.cs | 235 ++++++++++++++++++++++++++++++++++-- wpspec/wpspec/wpspec.csproj | 1 + 4 files changed, 250 insertions(+), 16 deletions(-) diff --git a/wpspec/wpspec/App.xaml.cs b/wpspec/wpspec/App.xaml.cs index 7c27124..8b490e8 100644 --- a/wpspec/wpspec/App.xaml.cs +++ b/wpspec/wpspec/App.xaml.cs @@ -83,6 +83,7 @@ namespace wpspec // This code will not execute when the application is reactivated private void Application_Launching(object sender, LaunchingEventArgs e) { + Shared.Spectrum = new Spectrum.Emulation(); } // Code to execute when the application is activated (brought to foreground) diff --git a/wpspec/wpspec/GamePage.xaml.cs b/wpspec/wpspec/GamePage.xaml.cs index 4d8ff1a..f85977b 100644 --- a/wpspec/wpspec/GamePage.xaml.cs +++ b/wpspec/wpspec/GamePage.xaml.cs @@ -13,6 +13,7 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using wpspec.Spectrum; +using System.Diagnostics; namespace wpspec { @@ -23,7 +24,6 @@ namespace wpspec private ContentManager contentManager; private GameTimer timer; private SpriteBatch spriteBatch; - private Emulation spectrum; #endregion @@ -46,10 +46,6 @@ namespace wpspec timer.UpdateInterval = TimeSpan.FromMilliseconds(20); timer.Update += OnUpdate; timer.Draw += OnDraw; - - // Create the emulation - // - spectrum = new Emulation(); } #endregion @@ -66,8 +62,6 @@ namespace wpspec // spriteBatch = new SpriteBatch(SharedGraphicsDeviceManager.Current.GraphicsDevice); - // TODO: use this.content to load your game content here - // Start the timer // timer.Start(); @@ -97,6 +91,9 @@ namespace wpspec /// private void OnUpdate(object sender, GameTimerEventArgs e) { + // TODO: Softkeyboard + + Shared.Spectrum.Run(); } /// @@ -105,6 +102,24 @@ namespace wpspec private void OnDraw(object sender, GameTimerEventArgs e) { SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.Black); + + DateTime now = DateTime.Now; + + using (Texture2D screen = + new Texture2D + (SharedGraphicsDeviceManager.Current.GraphicsDevice, + Shared.Spectrum.Width, + Shared.Spectrum.Height, + false, SurfaceFormat.Color)) + { + Shared.Spectrum.Update(); + screen.SetData(Shared.Spectrum.Screen); + + spriteBatch.Begin(); + spriteBatch.Draw(screen, Vector2.Zero, Color.White); + spriteBatch.End(); + Debug.WriteLine("Render - {0} msec", (DateTime.Now - now).TotalMilliseconds); + } } #endregion diff --git a/wpspec/wpspec/Spectrum/Emulation.cs b/wpspec/wpspec/Spectrum/Emulation.cs index 58fdb83..0e4a286 100644 --- a/wpspec/wpspec/Spectrum/Emulation.cs +++ b/wpspec/wpspec/Spectrum/Emulation.cs @@ -1,19 +1,13 @@ using System; -using System.Net; using System.Windows; -using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows.Ink; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Windows.Shapes; using Noddybox.Emulation; using Noddybox.Emulation.EightBit; using Noddybox.Emulation.EightBit.Z80; using System.Reflection; using System.Windows.Resources; using System.IO; +using Microsoft.Xna.Framework; +using System.Diagnostics; namespace wpspec.Spectrum { @@ -30,15 +24,53 @@ namespace wpspec.Spectrum private byte[] tape; + private readonly byte[] matrix = new byte[9]; + + private readonly int[] screen = new int[192]; + + private readonly uint[] colours = new uint[16] + { + new Color(0x00, 0x00, 0x00).PackedValue, // BLACK + new Color(0x00, 0x00, 0xe6).PackedValue, // BLUE + new Color(0xe6, 0x00, 0x00).PackedValue, // RED + new Color(0xe6, 0x00, 0xe6).PackedValue, // MAGENTA + new Color(0x00, 0xe6, 0x00).PackedValue, // GREEN + new Color(0x00, 0xe6, 0xe6).PackedValue, // CYAN + new Color(0xe6, 0xe6, 0x00).PackedValue, // YELLOW + new Color(0xe6, 0xe6, 0xe6).PackedValue, // WHITE + new Color(0x00, 0x00, 0x00).PackedValue, // BLACK (BRIGHT) + new Color(0x00, 0x00, 0xff).PackedValue, // BLUE (BRIGHT) + new Color(0xff, 0x00, 0x00).PackedValue, // RED (BRIGHT) + new Color(0xff, 0x00, 0xff).PackedValue, // MAGENTA (BRIGHT) + new Color(0x00, 0xff, 0x00).PackedValue, // GREEN (BRIGHT) + new Color(0x00, 0xff, 0xff).PackedValue, // CYAN (BRIGHT) + new Color(0xff, 0xff, 0x00).PackedValue, // YELLOW (BRIGHT) + new Color(0xff, 0xff, 0xff).PackedValue // WHITE (BRIGHT) + }; + + private bool flash; + + private int flashCounter; + #endregion #region IMemory Members + /// + /// Read from Spectrum memory. + /// + /// The address to read. + /// The byte at the address. byte IMemory.Read(ushort address) { return mem[address]; } + /// + /// Write to Spectrum memory. ROM writes are ignored. + /// + /// The address to write to. + /// The byte to write to the address. void IMemory.Write(ushort address, byte value) { if (address >= 0x4000) @@ -51,11 +83,61 @@ namespace wpspec.Spectrum #region IDevice Members + /// + /// Read from attached Spectrum devices. + /// + /// The address of the device. + /// The byte returned by the device. byte IDevice.Read(ushort device) { - return 0; + Register16 addr = new Register16(device); + byte b = 0xff; + + switch(addr.low) + { + // Kempston joystick + // + case 0x1f: + b = matrix[8]; + break; + + // Fuller joystick + // + case 0x7f: + b = matrix[8]; + break; + + // ULA + // + default: + if ((addr.low & 1) == 0) + { + int m = 0; + int r = 1; + + while(r < 256) + { + if ((addr.high & r) == 0) + { + b &= matrix[m]; + } + + r *= 2; + m++; + } + } + + break; + } + + return b; } + /// + /// Write to an attached Spectrum device. + /// + /// The address of the device. + /// The byte to send to the device. void IDevice.Write(ushort device, byte value) { // Do nothing @@ -64,6 +146,23 @@ namespace wpspec.Spectrum #endregion #region Public Members + + /// + /// Get the width of the emulated screen in pixels. + /// + public int Width {get {return 256;}} + + /// + /// Get the height of the emulated screen in pixels. + /// + public int Height {get {return 192;}} + + /// + /// Get the emulated screen contents as packed RGBA values. + /// This array must have times + /// elements. + /// + public uint[] Screen {get; private set;} /// /// Get/set the tape file to load. @@ -79,9 +178,99 @@ namespace wpspec.Spectrum /// public void Reset() { + // Initialise the Spectrum + // + for(int f = 0; f < 8; f++) + { + matrix[f] = 0x1f; + } + + matrix[8] = 0; + + // Initialise the Z80 + // z80.Reset(); } + /// + /// Run the emulation for a frame. + /// + public void Run() + { + clock.StartFrame(); + DateTime now = DateTime.Now; + z80.Run(); + z80.MaskableInterrupt(0); + Debug.WriteLine("Exec - {0} msec", (DateTime.Now - now).TotalMilliseconds); + } + + /// + /// Update the emulation display. + /// + public void Update() + { + uint[] scr = Screen; + int addr; + int attr; + int ink; + int paper; + int t; + int p = 0; + byte b; + + DateTime now = DateTime.Now; + for(int y = 0; y < 192; y++) + { + addr = screen[y]; + + for(int x = 0; x < 32; x++) + { + attr = mem[0x5800 + x + y / 8 * 32]; + ink = attr & 0x07; + paper = (attr & 0x38) >> 3; + + if ((attr & 0x40) == 0x40) + { + ink += 8; + paper += 8; + } + + if ((attr & 0x80) == 0x80 && flash) + { + t = ink; + ink = paper; + paper = t; + } + + b = mem[addr + x]; + + for(int r = 128; r > 0; r /= 2) + { + if ((b & r) == r) + { + scr[p++] = colours[ink]; + } + else + { + scr[p++] = colours[paper]; + } + } + } + } + + for(int f = 0; f < 192; f++) + { + scr[f] = colours[(flashCounter + f) % 16]; + } + + if (++flashCounter == 16) + { + flashCounter = 0; + flash = !flash; + } + Debug.WriteLine("Draw - {0} msec", (DateTime.Now - now).TotalMilliseconds); + } + #endregion #region Constructors @@ -100,9 +289,37 @@ namespace wpspec.Spectrum file.Stream.Close(); + // Set up screen and accelerators + // + Screen = new uint[Width * Height]; + + int c = 0; + int r = 0; + + for(int f = 0; f < 192; f++) + { + screen[f] = 0x4000 + (c * 8 * 32) + (r * 32); + + c++; + + if ((c % 8) == 0) + { + if (++r == 8) + { + r = 0; + } + else + { + c -= 8; + } + } + } + // Initialise the CPU // z80.Initialise(this, this, clock); + + Reset(); } #endregion diff --git a/wpspec/wpspec/wpspec.csproj b/wpspec/wpspec/wpspec.csproj index 8b4dc6f..633c10c 100644 --- a/wpspec/wpspec/wpspec.csproj +++ b/wpspec/wpspec/wpspec.csproj @@ -97,6 +97,7 @@ SettingsPage.xaml + -- cgit v1.2.3