diff options
| author | Ian C <ianc@noddybox.co.uk> | 2012-10-01 20:54:16 +0000 | 
|---|---|---|
| committer | Ian C <ianc@noddybox.co.uk> | 2012-10-01 20:54:16 +0000 | 
| commit | 0d6c2c21d4423fad32a5877dae0ac26d7c20fe9e (patch) | |
| tree | c21bb1ad0d2618d70a874c435d8acd939ae89ad1 | |
| parent | 68d1358a25617e30c18722ba441b9a37424a64d2 (diff) | |
Last check-in before we abandon a "real" ULA emulation and just cheat!
| -rw-r--r-- | WPZX81/WPZX81/SplashScreenImage.jpg | bin | 93849 -> 97272 bytes | |||
| -rw-r--r-- | WPZX81/WPZX81/ZX81/Emulation.cs | 129 | 
2 files changed, 114 insertions, 15 deletions
| diff --git a/WPZX81/WPZX81/SplashScreenImage.jpg b/WPZX81/WPZX81/SplashScreenImage.jpgBinary files differ index 33ebf76..a13be9d 100644 --- a/WPZX81/WPZX81/SplashScreenImage.jpg +++ b/WPZX81/WPZX81/SplashScreenImage.jpg diff --git a/WPZX81/WPZX81/ZX81/Emulation.cs b/WPZX81/WPZX81/ZX81/Emulation.cs index 5c3e01e..f7a851a 100644 --- a/WPZX81/WPZX81/ZX81/Emulation.cs +++ b/WPZX81/WPZX81/ZX81/Emulation.cs @@ -33,6 +33,61 @@ namespace WPZX81.ZX81      {
          #region Private data
 +        private class Display
 +        {
 +            private ushort[] screen;
 +            private int x;
 +            private int y;
 +            private int w;
 +            private int h;
 +
 +            public Display(int w, int h)
 +            {
 +                this.screen = new ushort[w * h];
 +                this.w = w;
 +                this.h = h;
 +                this.x = 0;
 +                this.y = 0;
 +            }
 +
 +            public ushort[] Screen {get {return screen;}}
 +
 +            private int count;
 +            private int invalid;
 +
 +            public void Reset()
 +            {
 +                Debug.WriteLine("Display: {0} writes done ({1} invalid).  Ended up at {2},{3} out of {4}, {5}", count, invalid, x, y, w, h);
 +                count = 0;
 +                invalid = 0;
 +
 +                x = 0;
 +                y = 0;
 +
 +                this.screen = new ushort[w * h];
 +            }
 +
 +            public void Write(ushort v)
 +            {
 +                if (x < w)
 +                {
 +                    screen[x++ + y * w] = v;
 +                }
 +                else
 +                {
 +                    invalid++;
 +                }
 +
 +                count++;
 +            }
 +
 +            public void NextLine()
 +            {
 +                x = 0;
 +                y = (y + 1) % h;
 +            }
 +        }
 +
          private Clock       clock;
          private byte[]      mem;
          private int         vsync;
 @@ -43,6 +98,8 @@ namespace WPZX81.ZX81          private int         rambot;
          private int         ramtop;
          private byte[]      matrix;
 +        private int         lastR6;
 +        private Display     display;
          // Some system variables
          //
 @@ -186,7 +243,6 @@ namespace WPZX81.ZX81              }
          }
 -
          private bool OperationCallback(ICpu sender)
          {
              // During VSYNC, keep resetting the clock
 @@ -213,21 +269,31 @@ namespace WPZX81.ZX81              // Maskable interupts are tied to bit 6 of the refresh register.
              //
 -            if ((Z80.Refresh | 0x20) == 0)
 +            if ((Z80.Refresh & 0x40) == 0) // && lastR6 == 0x20)
              {
                  Z80.MaskableInterrupt(0xff);
 +                display.NextLine();
 +                lineCounter = (lineCounter + 1) % 8;
              }
 -            // The frame finishes when VSYNC is triggered (ie. HYSNC is off).  Note we wait until we've had a good few opcodes with VSYNC happening.
 +            // Record last bit 6 of the refresh register
 +            //
 +            lastR6 = Z80.Refresh & 0x20;
 +
 +            // The frame finishes when VSYNC is triggered (ie. HYSNC is off).
 +            // Note we wait until we've had a good few opcodes with VSYNC happening as some hi-res routines trigger short blasts of VSYNC.
              //
 -            if (vsync > 10 && !vsyncNoted)
 +            if (vsync > 20 && !vsyncNoted)
              {
 +                display.Reset();
                  vsyncNoted = true;
 -                return true;
 +                return false;
              }
              else
              {
 -                return false;
 +                // Make sure we're not in a state where good operations aren't happening
 +                //
 +                return (Z80.ExecutedInstructions < 65000);
              }
          }
 @@ -260,7 +326,7 @@ namespace WPZX81.ZX81          /// This array must have <see cref="Width"/> times <see cref="Height"/>
          /// elements.
          /// </summary>
 -        public ushort[] Screen {get; private set;}
 +        public ushort[] Screen {get {return display.Screen;}}
          #endregion
 @@ -271,8 +337,10 @@ namespace WPZX81.ZX81          /// </summary>
          public void Run()
          {
 -            vsyncNoted = false;
 +            display.Reset();
 +            Z80.ExecutedInstructions = 0;
              Z80.Run(OperationCallback);
 +            Debug.WriteLine("Executed instructions {0}", Z80.ExecutedInstructions);
          }
          /// <summary>
 @@ -301,11 +369,13 @@ namespace WPZX81.ZX81              hsync = false;
              vsyncNoted = false;
              nmiGenerator = false;
 +            lastR6 = 0;
 +            lineCounter = 0;
              rambot = Settings.StaticRamAt0x2000 ? 0x2000 : 0x4000;
              ramtop = Settings.RamPack ? 0x8000 : 0x4400;
 -            new Random().NextBytes(mem);
 +            mem.Initialize();
              for(int f = 0 ; f < 8; f++)
              {
 @@ -340,7 +410,7 @@ namespace WPZX81.ZX81          {
              matrix = new byte[8];
              mem = new byte[0x10000];
 -            Screen = new ushort[Width * Height];
 +            display = new Display(Width, Height);
              clock = new Clock(16000, 50, 1, 50);
              Z80 = new Z80Cpu();
              Z80.Initialise(this, this, clock);
 @@ -354,20 +424,47 @@ namespace WPZX81.ZX81          byte IMemory.Read(ushort address)
          {
 -            // Reads above 0x8000 are grabbed by the ULA to generate the display.
 +            // Reads above 0x8000 are grabbed by the ULA to generate the display.  We only do this if the hysnc generator is enabled.
              //
 -            if (address >= 0x8000)
 +            if (address >= 0x8000 && hsync)
              {
                  byte b = mem[address & 0x7fff];
 -                // Opcodes with bit 6 are still passed to the CPU
 +                // Opcodes with bit 6 are still passed to the CPU.
                  //
                  if ((b & 0x20) == 0x20)
                  {
 +                    for(int pixel = 0; pixel < 8; pixel++)
 +                    {
 +                        display.Write(0xffff);
 +                    }
 +
                      return b;
                  }
                  else
                  {
 +                    int inv = (b & 0x80);
 +                    b |= 0x3f;
 +
 +                    int bitmap = mem[(int)Z80.InterruptVector << 8 | (int)b << 3 | lineCounter];
 +
 +                    if (inv != 0)
 +                    {
 +                        bitmap = ~bitmap;
 +                    }
 +
 +                    for(int pixel = 7; pixel >= 0; pixel--)
 +                    {
 +                        if ((bitmap & (1 << pixel)) == 0)
 +                        {
 +                            display.Write(0xffff);
 +                        }
 +                        else
 +                        {
 +                            display.Write(0);
 +                        }
 +                    }
 +
                      // Return NOP
                      //
                      return 0;
 @@ -375,7 +472,7 @@ namespace WPZX81.ZX81              }
              else
              {
 -                return mem[address & 0x7fff];
 +                return mem[address];
              }
          }
 @@ -407,7 +504,8 @@ namespace WPZX81.ZX81                      // Rather than just a boolean, we not how many opcode VSYNC has been active.  This stops us getting
                      // confused by IN A,(FE) / OUT (FF),A pairs used to reset the ULA LINECTR.
                      //
 -                    vsync = 0;
 +                    vsync = 1;
 +                    vsyncNoted = false;
                      if (!nmiGenerator)
                      {
 @@ -470,6 +568,7 @@ namespace WPZX81.ZX81                  //
                  case 0xfe:
                      nmiGenerator = true;
 +                    clock.CycleCount = 0;
                      break;
                  // The ZX81 sends an OUT FF,A after the VSYNC to start HYSNC generation,
 | 
