summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--WPZX81/WPZX81/ZX81/Emulation.cs231
1 files changed, 34 insertions, 197 deletions
diff --git a/WPZX81/WPZX81/ZX81/Emulation.cs b/WPZX81/WPZX81/ZX81/Emulation.cs
index f7a851a..fdc0ef7 100644
--- a/WPZX81/WPZX81/ZX81/Emulation.cs
+++ b/WPZX81/WPZX81/ZX81/Emulation.cs
@@ -33,62 +33,8 @@ 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 ushort[] screen;
private byte[] mem;
private int vsync;
private bool hsync;
@@ -99,7 +45,6 @@ namespace WPZX81.ZX81
private int ramtop;
private byte[] matrix;
private int lastR6;
- private Display display;
// Some system variables
//
@@ -133,6 +78,11 @@ namespace WPZX81.ZX81
0xc3, 0x07, 0x02, /* JP $0207 */
};
+ private byte[] retPatch = new byte[]
+ {
+ 0xc9 /* ret */
+ };
+
private byte[] fastPatch = new byte[]
{
0xed, ED_WAITKEY, /* (START KEY WAIT) */
@@ -206,6 +156,8 @@ namespace WPZX81.ZX81
{
Patch(0x2fc, savePatch);
Patch(0x347, loadPatch);
+ Patch(0x2bc, retPatch);
+
// Patch(0x4ca, fastPatch);
// Patch(0x2bb, keyboardPatch);
// Patch(0xf3a, pausePatch);
@@ -243,58 +195,17 @@ namespace WPZX81.ZX81
}
}
- private bool OperationCallback(ICpu sender)
+ private void GenerateScreen()
{
- // During VSYNC, keep resetting the clock
- //
- if (vsync > 0)
- {
- vsync++;
- clock.CycleCount = 0;
- }
- else
+ ushort p = PeekWord(D_FILE);
+
+ for(int y = 0; y < 24; y++)
{
- // If we're out of VSYNC, see if we need to generate an interrupt
- //
- if (clock.CycleCount >= 224)
+ for(int x = 0; x < 32; x++)
{
- clock.CycleCount -= 224;
-
- if (nmiGenerator)
- {
- Z80.NonMaskableInterrupt(0xff);
- }
+ p++;
}
}
-
- // Maskable interupts are tied to bit 6 of the refresh register.
- //
- if ((Z80.Refresh & 0x40) == 0) // && lastR6 == 0x20)
- {
- Z80.MaskableInterrupt(0xff);
- display.NextLine();
- lineCounter = (lineCounter + 1) % 8;
- }
-
- // 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 > 20 && !vsyncNoted)
- {
- display.Reset();
- vsyncNoted = true;
- return false;
- }
- else
- {
- // Make sure we're not in a state where good operations aren't happening
- //
- return (Z80.ExecutedInstructions < 65000);
- }
}
#endregion
@@ -326,7 +237,7 @@ namespace WPZX81.ZX81
/// This array must have <see cref="Width"/> times <see cref="Height"/>
/// elements.
/// </summary>
- public ushort[] Screen {get {return display.Screen;}}
+ public ushort[] Screen {get {return screen;}}
#endregion
@@ -337,10 +248,18 @@ namespace WPZX81.ZX81
/// </summary>
public void Run()
{
- display.Reset();
- Z80.ExecutedInstructions = 0;
- Z80.Run(OperationCallback);
- Debug.WriteLine("Executed instructions {0}", Z80.ExecutedInstructions);
+ // Check FAST flag
+ //
+ if ((mem[CDFLAG] & 0x80) == 0)
+ {
+ Z80.Run();
+ Z80.Run();
+ Z80.Run();
+ }
+
+ Z80.Run();
+
+ GenerateScreen();
}
/// <summary>
@@ -375,7 +294,10 @@ namespace WPZX81.ZX81
rambot = Settings.StaticRamAt0x2000 ? 0x2000 : 0x4000;
ramtop = Settings.RamPack ? 0x8000 : 0x4400;
- mem.Initialize();
+ for(int f = 0 ; f < mem.Length; f++)
+ {
+ mem[f] = 0;
+ }
for(int f = 0 ; f < 8; f++)
{
@@ -410,8 +332,8 @@ namespace WPZX81.ZX81
{
matrix = new byte[8];
mem = new byte[0x10000];
- display = new Display(Width, Height);
- clock = new Clock(16000, 50, 1, 50);
+ screen = new ushort[Width * Height];
+ clock = new Clock(0, 16000, 1, 0);
Z80 = new Z80Cpu();
Z80.Initialise(this, this, clock);
Z80.EDNopEvent += EDCallback;
@@ -424,56 +346,7 @@ namespace WPZX81.ZX81
byte IMemory.Read(ushort address)
{
- // 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 && hsync)
- {
- byte b = mem[address & 0x7fff];
-
- // 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;
- }
- }
- else
- {
- return mem[address];
- }
+ return mem[address & 0x7fff];
}
void IMemory.Write(ushort address, byte value)
@@ -499,19 +372,6 @@ namespace WPZX81.ZX81
// ULA
//
case 0xfe:
-
- // Once the ULA is read the vsync video level is triggered and the HYSNC switched off if NMI generation is off.
- // 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 = 1;
- vsyncNoted = false;
-
- if (!nmiGenerator)
- {
- hsync = false;
- }
-
switch(device&0xff00)
{
case 0xfe00:
@@ -558,29 +418,6 @@ namespace WPZX81.ZX81
{
switch(device & 0xff)
{
- // Turns off the NMI generator
- //
- case 0xfd:
- nmiGenerator = false;
- break;
-
- // Turns on the NMI generator
- //
- case 0xfe:
- nmiGenerator = true;
- clock.CycleCount = 0;
- break;
-
- // The ZX81 sends an OUT FF,A after the VSYNC to start HYSNC generation,
- // which puts the ULA back to 'white' output and releases the reset on the
- // ULA LINECTR.
- //
- case 0xff:
- vsync = 0;
- hsync = true;
- lineCounter = 0;
- break;
-
default:
break;
}