Work towards accurate bus/memory/io timings. Especially Z80 m-cycle timing.

Signed-off-by: Adrian Conlon <adrian.conlon@gmail.com>
This commit is contained in:
Adrian Conlon 2020-07-05 00:09:51 +01:00
parent cd4af67177
commit 47ecdad3e8
11 changed files with 264 additions and 250 deletions

View File

@ -34,16 +34,16 @@ namespace EightBit
protected override Register16 GetWord()
{
this.intermediate.High = this.BusRead();
this.intermediate.High = this.MemoryRead();
++this.Bus.Address.Word;
this.intermediate.Low = this.BusRead();
this.intermediate.Low = this.MemoryRead();
return this.intermediate;
}
protected override Register16 GetWordPaged(byte page, byte offset)
{
this.intermediate.High = this.BusRead(offset, page);
this.intermediate.Low = this.BusRead(++offset, page);
this.intermediate.High = this.MemoryRead(offset, page);
this.intermediate.Low = this.MemoryRead(++offset, page);
return this.intermediate;
}
@ -62,15 +62,15 @@ namespace EightBit
protected override void SetWord(Register16 value)
{
this.BusWrite(value.High);
this.MemoryWrite(value.High);
++this.Bus.Address.Word;
this.BusWrite(value.Low);
this.MemoryWrite(value.Low);
}
protected override void SetWordPaged(byte page, byte offset, Register16 value)
{
this.BusWrite(offset, page, value.High);
this.BusWrite(++offset, page, value.Low);
this.MemoryWrite(offset, page, value.High);
this.MemoryWrite(++offset, page, value.Low);
}
}
}

View File

@ -127,9 +127,9 @@ namespace EightBit
this.Jump(0);
}
protected sealed override void Push(byte value) => this.BusWrite(--this.SP.Word, value);
protected sealed override void Push(byte value) => this.MemoryWrite(--this.SP.Word, value);
protected sealed override byte Pop() => this.BusRead(this.SP.Word++);
protected sealed override byte Pop() => this.MemoryRead(this.SP.Word++);
protected sealed override Register16 GetWord()
{
@ -196,7 +196,7 @@ namespace EightBit
var offsetAddress = this.PC.Word++;
if (condition)
{
var offset = (sbyte)this.BusRead(offsetAddress);
var offset = (sbyte)this.MemoryRead(offsetAddress);
this.JumpRelative(offset);
}

View File

@ -35,16 +35,16 @@ namespace EightBit
protected override Register16 GetWord()
{
this.intermediate.Low = this.BusRead();
this.intermediate.Low = this.MemoryRead();
++this.Bus.Address.Word;
this.intermediate.High = this.BusRead();
this.intermediate.High = this.MemoryRead();
return this.intermediate;
}
protected override Register16 GetWordPaged(byte page, byte offset)
{
this.intermediate.Low = this.BusRead(offset, page);
this.intermediate.High = this.BusRead(++offset, page);
this.intermediate.Low = this.MemoryRead(offset, page);
this.intermediate.High = this.MemoryRead(++offset, page);
return this.intermediate;
}
@ -63,15 +63,15 @@ namespace EightBit
protected override void SetWord(Register16 value)
{
this.BusWrite(value.Low);
this.MemoryWrite(value.Low);
++this.Bus.Address.Word;
this.BusWrite(value.High);
this.MemoryWrite(value.High);
}
protected override void SetWordPaged(byte page, byte offset, Register16 value)
{
this.BusWrite(offset, page, value.Low);
this.BusWrite(++offset, page, value.High);
this.MemoryWrite(offset, page, value.Low);
this.MemoryWrite(++offset, page, value.High);
}
}
}

View File

@ -136,47 +136,51 @@ namespace EightBit
protected virtual void HandleINT() => this.RaiseINT();
protected void BusWrite(byte low, byte high, byte data)
protected void MemoryWrite(byte low, byte high, byte data)
{
this.Bus.Address.Low = low;
this.Bus.Address.High = high;
this.BusWrite(data);
this.MemoryWrite(data);
}
protected void BusWrite(ushort address, byte data)
protected void MemoryWrite(ushort address, byte data)
{
this.Bus.Address.Word = address;
this.BusWrite(data);
this.MemoryWrite(data);
}
protected void BusWrite(Register16 address, byte data) => this.BusWrite(address.Word, data);
protected void MemoryWrite(Register16 address, byte data) => this.MemoryWrite(address.Word, data);
protected void BusWrite(byte data)
protected void MemoryWrite(byte data)
{
this.Bus.Data = data;
this.BusWrite();
this.MemoryWrite();
}
protected virtual void MemoryWrite() => this.BusWrite();
protected virtual void BusWrite() => this.Bus.Write(); // N.B. Should be the only real call into the "Bus.Write" code.
protected byte BusRead(byte low, byte high)
protected byte MemoryRead(byte low, byte high)
{
this.Bus.Address.Low = low;
this.Bus.Address.High = high;
return this.BusRead();
return this.MemoryRead();
}
protected byte BusRead(ushort address)
protected byte MemoryRead(ushort address)
{
this.Bus.Address.Word = address;
return this.BusRead();
return this.MemoryRead();
}
protected byte BusRead(Register16 address) => this.BusRead(address.Word);
protected byte MemoryRead(Register16 address) => this.MemoryRead(address.Word);
protected virtual byte MemoryRead() => this.BusRead();
protected virtual byte BusRead() => this.Bus.Read(); // N.B. Should be the only real call into the "Bus.Read" code.
protected byte FetchByte() => this.BusRead(this.PC.Word++);
protected byte FetchByte() => this.MemoryRead(this.PC.Word++);
protected abstract Register16 GetWord();

View File

@ -4,9 +4,8 @@
namespace Fuse
{
using System;
using System.Diagnostics;
using EightBit;
[DebuggerDisplay("Cycles = {Cycles}, Specifier = {Specifier}, Address = {Address}, Value = {Value}")]
public class TestEvent
{
private int cycles;
@ -23,6 +22,9 @@ namespace Fuse
this.Value = value;
}
public TestEvent(int cycles, string specifier, ushort address)
: this(cycles, specifier, address, (byte)Mask.Eight) => this.ContentionEvent = true;
public int Cycles => this.cycles;
public string Specifier { get; private set; }
@ -31,6 +33,8 @@ namespace Fuse
public byte Value { get; private set; } = (byte)EightBit.Mask.Eight;
private bool ContentionEvent { get; set; } = false;
public bool TryParse(Lines lines)
{
if (lines == null)
@ -47,6 +51,17 @@ namespace Fuse
return returned;
}
public override string ToString()
{
var possible = $"Cycles = {this.Cycles}, Specifier = {this.Specifier}, Address = {this.Address:X4}";
if (!this.ContentionEvent)
{
possible += $", Value = {this.Value:X2}";
}
return possible;
}
private bool TryParseLine(string line)
{
var split = line.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);

View File

@ -156,7 +156,7 @@ namespace EightBit
case 5:
return this.L;
case 6:
return this.BusRead(this.HL.Word);
return this.MemoryRead(this.HL.Word);
case 7:
return this.A;
default:
@ -187,7 +187,7 @@ namespace EightBit
this.L = value;
break;
case 6:
this.BusWrite(this.HL.Word, value);
this.MemoryWrite(this.HL.Word, value);
break;
case 7:
this.A = value;
@ -270,11 +270,11 @@ namespace EightBit
switch (p)
{
case 0: // LD (BC),A
this.BusWrite(this.BC, this.A);
this.MemoryWrite(this.BC, this.A);
this.Tick(7);
break;
case 1: // LD (DE),A
this.BusWrite(this.DE, this.A);
this.MemoryWrite(this.DE, this.A);
this.Tick(7);
break;
case 2: // LD (nn),HL
@ -284,7 +284,7 @@ namespace EightBit
break;
case 3: // LD (nn),A
this.Bus.Address.Word = this.FetchWord().Word;
this.BusWrite(this.A);
this.MemoryWrite(this.A);
this.Tick(13);
break;
default:
@ -296,11 +296,11 @@ namespace EightBit
switch (p)
{
case 0: // LD A,(BC)
this.A = this.BusRead(this.BC);
this.A = this.MemoryRead(this.BC);
this.Tick(7);
break;
case 1: // LD A,(DE)
this.A = this.BusRead(this.DE);
this.A = this.MemoryRead(this.DE);
this.Tick(7);
break;
case 2: // LD HL,(nn)
@ -310,7 +310,7 @@ namespace EightBit
break;
case 3: // LD A,(nn)
this.Bus.Address.Word = this.FetchWord().Word;
this.A = this.BusRead();
this.A = this.MemoryRead();
this.Tick(13);
break;
default:
@ -811,13 +811,13 @@ namespace EightBit
private void XHTL(Register16 exchange)
{
this.MEMPTR.Low = this.BusRead(this.SP.Word);
this.MEMPTR.Low = this.MemoryRead(this.SP.Word);
++this.Bus.Address.Word;
this.MEMPTR.High = this.BusRead();
this.BusWrite(exchange.High);
this.MEMPTR.High = this.MemoryRead();
this.MemoryWrite(exchange.High);
exchange.High = this.MEMPTR.High;
--this.Bus.Address.Word;
this.BusWrite(exchange.Low);
this.MemoryWrite(exchange.Low);
exchange.Low = this.MEMPTR.Low;
}

View File

@ -181,7 +181,7 @@ namespace EightBit.GameBoy
case 5:
return this.L;
case 6:
return this.BusRead(this.HL.Word);
return this.MemoryRead(this.HL.Word);
case 7:
return this.A;
default:
@ -212,7 +212,7 @@ namespace EightBit.GameBoy
this.L = value;
break;
case 6:
this.BusWrite(this.HL.Word, value);
this.MemoryWrite(this.HL.Word, value);
break;
case 7:
this.A = value;
@ -408,22 +408,22 @@ namespace EightBit.GameBoy
switch (p)
{
case 0: // LD (BC),A
this.BusWrite(this.BC, this.A);
this.MemoryWrite(this.BC, this.A);
this.Tick(2);
break;
case 1: // LD (DE),A
this.BusWrite(this.DE, this.A);
this.MemoryWrite(this.DE, this.A);
this.Tick(2);
break;
case 2: // GB: LDI (HL),A
this.BusWrite(this.HL.Word++, this.A);
this.MemoryWrite(this.HL.Word++, this.A);
this.Tick(2);
break;
case 3: // GB: LDD (HL),A
this.BusWrite(this.HL.Word--, this.A);
this.MemoryWrite(this.HL.Word--, this.A);
this.Tick(2);
break;
@ -437,22 +437,22 @@ namespace EightBit.GameBoy
switch (p)
{
case 0: // LD A,(BC)
this.A = this.BusRead(this.BC);
this.A = this.MemoryRead(this.BC);
this.Tick(2);
break;
case 1: // LD A,(DE)
this.A = this.BusRead(this.DE);
this.A = this.MemoryRead(this.DE);
this.Tick(2);
break;
case 2: // GB: LDI A,(HL)
this.A = this.BusRead(this.HL.Word++);
this.A = this.MemoryRead(this.HL.Word++);
this.Tick(2);
break;
case 3: // GB: LDD A,(HL)
this.A = this.BusRead(this.HL.Word--);
this.A = this.MemoryRead(this.HL.Word--);
this.Tick(2);
break;
@ -625,7 +625,7 @@ namespace EightBit.GameBoy
break;
case 4: // GB: LD (FF00 + n),A
this.BusWrite((ushort)(IoRegisters.BASE + this.FetchByte()), this.A);
this.MemoryWrite((ushort)(IoRegisters.BASE + this.FetchByte()), this.A);
this.Tick(3);
break;
@ -645,7 +645,7 @@ namespace EightBit.GameBoy
break;
case 6: // GB: LD A,(FF00 + n)
this.A = this.BusRead((ushort)(IoRegisters.BASE + this.FetchByte()));
this.A = this.MemoryRead((ushort)(IoRegisters.BASE + this.FetchByte()));
this.Tick(3);
break;
@ -721,21 +721,21 @@ namespace EightBit.GameBoy
this.Tick(3);
break;
case 4: // GB: LD (FF00 + C),A
this.BusWrite((ushort)(IoRegisters.BASE + this.C), this.A);
this.MemoryWrite((ushort)(IoRegisters.BASE + this.C), this.A);
this.Tick(2);
break;
case 5: // GB: LD (nn),A
this.Bus.Address.Word = this.MEMPTR.Word = this.FetchWord().Word;
this.BusWrite(this.A);
this.MemoryWrite(this.A);
this.Tick(4);
break;
case 6: // GB: LD A,(FF00 + C)
this.A = this.BusRead((ushort)(IoRegisters.BASE + this.C));
this.A = this.MemoryRead((ushort)(IoRegisters.BASE + this.C));
this.Tick(2);
break;
case 7: // GB: LD A,(nn)
this.Bus.Address.Word = this.MEMPTR.Word = this.FetchWord().Word;
this.A = this.BusRead();
this.A = this.MemoryRead();
this.Tick(4);
break;
default:

View File

@ -198,15 +198,15 @@ namespace EightBit
case 0x03: this.SLO(this.AM_IndexedIndirectX()); break; // *SLO (indexed indirect X)
case 0x04: this.AM_ZeroPage(); break; // *NOP (zero page)
case 0x05: this.A = this.OrR(this.A, this.AM_ZeroPage()); break; // ORA (zero page)
case 0x06: this.BusReadModifyWrite(this.ASL(this.AM_ZeroPage())); break; // ASL (zero page)
case 0x06: this.ReadModifyWrite(this.ASL(this.AM_ZeroPage())); break; // ASL (zero page)
case 0x07: this.SLO(this.AM_ZeroPage()); break; // *SLO (zero page)
case 0x08: this.BusRead(); this.PHP(); break; // PHP (implied)
case 0x08: this.MemoryRead(); this.PHP(); break; // PHP (implied)
case 0x09: this.A = this.OrR(this.A, this.AM_Immediate()); break; // ORA (immediate)
case 0x0a: this.BusRead(); this.A = this.ASL(this.A); break; // ASL A (implied)
case 0x0a: this.MemoryRead(); this.A = this.ASL(this.A); break; // ASL A (implied)
case 0x0b: this.ANC(this.AM_Immediate()); break; // *ANC (immediate)
case 0x0c: this.AM_Absolute(); break; // *NOP (absolute)
case 0x0d: this.A = this.OrR(this.A, this.AM_Absolute()); break; // ORA (absolute)
case 0x0e: this.BusReadModifyWrite(this.ASL(this.AM_Absolute())); break; // ASL (absolute)
case 0x0e: this.ReadModifyWrite(this.ASL(this.AM_Absolute())); break; // ASL (absolute)
case 0x0f: this.SLO(this.AM_Absolute()); break; // *SLO (absolute)
case 0x10: this.Branch(this.Negative == 0); break; // BPL (relative)
@ -215,15 +215,15 @@ namespace EightBit
case 0x13: this.SLO(this.AM_IndirectIndexedY()); break; // *SLO (indirect indexed Y)
case 0x14: this.AM_ZeroPageX(); break; // *NOP (zero page, X)
case 0x15: this.A = this.OrR(this.A, this.AM_ZeroPageX()); break; // ORA (zero page, X)
case 0x16: this.BusReadModifyWrite(this.ASL(this.AM_ZeroPageX())); break; // ASL (zero page, X)
case 0x16: this.ReadModifyWrite(this.ASL(this.AM_ZeroPageX())); break; // ASL (zero page, X)
case 0x17: this.SLO(this.AM_ZeroPageX()); break; // *SLO (zero page, X)
case 0x18: this.BusRead(); this.P = ClearBit(this.P, StatusBits.CF); break; // CLC (implied)
case 0x18: this.MemoryRead(); this.P = ClearBit(this.P, StatusBits.CF); break; // CLC (implied)
case 0x19: this.A = this.OrR(this.A, this.AM_AbsoluteY()); break; // ORA (absolute, Y)
case 0x1a: this.BusRead(); break; // *NOP (implied)
case 0x1a: this.MemoryRead(); break; // *NOP (implied)
case 0x1b: this.SLO(this.AM_AbsoluteY()); break; // *SLO (absolute, Y)
case 0x1c: this.AM_AbsoluteX(); break; // *NOP (absolute, X)
case 0x1d: this.A = this.OrR(this.A, this.AM_AbsoluteX()); break; // ORA (absolute, X)
case 0x1e: this.BusReadModifyWrite(this.ASL(this.AM_AbsoluteX(PageCrossingBehavior.AlwaysReadTwice))); break; // ASL (absolute, X)
case 0x1e: this.ReadModifyWrite(this.ASL(this.AM_AbsoluteX(PageCrossingBehavior.AlwaysReadTwice))); break; // ASL (absolute, X)
case 0x1f: this.SLO(this.AM_AbsoluteX()); break; // *SLO (absolute, X)
case 0x20: this.JSR(); break; // JSR (absolute)
@ -232,15 +232,15 @@ namespace EightBit
case 0x23: this.RLA(this.AM_IndexedIndirectX()); break; // *RLA (indexed indirect X)
case 0x24: this.BIT(this.A, this.AM_ZeroPage()); break; // BIT (zero page)
case 0x25: this.A = this.AndR(this.A, this.AM_ZeroPage()); break; // AND (zero page)
case 0x26: this.BusReadModifyWrite(this.ROL(this.AM_ZeroPage())); break; // ROL (zero page)
case 0x26: this.ReadModifyWrite(this.ROL(this.AM_ZeroPage())); break; // ROL (zero page)
case 0x27: this.RLA(this.AM_ZeroPage()); break; // *RLA (zero page)
case 0x28: this.BusRead(); this.BusRead(this.S, 1); this.PLP(); break; // PLP (implied)
case 0x28: this.MemoryRead(); this.MemoryRead(this.S, 1); this.PLP(); break; // PLP (implied)
case 0x29: this.A = this.AndR(this.A, this.AM_Immediate()); break; // AND (immediate)
case 0x2a: this.BusRead(); this.A = this.ROL(this.A); break; // ROL A (implied)
case 0x2a: this.MemoryRead(); this.A = this.ROL(this.A); break; // ROL A (implied)
case 0x2b: this.ANC(this.AM_Immediate()); break; // *ANC (immediate)
case 0x2c: this.BIT(this.A, this.AM_Absolute()); break; // BIT (absolute)
case 0x2d: this.A = this.AndR(this.A, this.AM_Absolute()); break; // AND (absolute)
case 0x2e: this.BusReadModifyWrite(this.ROL(this.AM_Absolute())); break; // ROL (absolute)
case 0x2e: this.ReadModifyWrite(this.ROL(this.AM_Absolute())); break; // ROL (absolute)
case 0x2f: this.RLA(this.AM_Absolute()); break; // *RLA (absolute)
case 0x30: this.Branch(this.Negative); break; // BMI (relative)
@ -249,32 +249,32 @@ namespace EightBit
case 0x33: this.RLA(this.AM_IndirectIndexedY()); break; // *RLA (indirect indexed Y)
case 0x34: this.AM_ZeroPageX(); break; // *NOP (zero page, X)
case 0x35: this.A = this.AndR(this.A, this.AM_ZeroPageX()); break; // AND (zero page, X)
case 0x36: this.BusReadModifyWrite(this.ROL(this.AM_ZeroPageX())); break; // ROL (zero page, X)
case 0x36: this.ReadModifyWrite(this.ROL(this.AM_ZeroPageX())); break; // ROL (zero page, X)
case 0x37: this.RLA(this.AM_ZeroPageX()); break; // *RLA (zero page, X)
case 0x38: this.BusRead(); this.P = SetBit(this.P, StatusBits.CF); break; // SEC (implied)
case 0x38: this.MemoryRead(); this.P = SetBit(this.P, StatusBits.CF); break; // SEC (implied)
case 0x39: this.A = this.AndR(this.A, this.AM_AbsoluteY()); break; // AND (absolute, Y)
case 0x3a: this.BusRead(); break; // *NOP (implied)
case 0x3a: this.MemoryRead(); break; // *NOP (implied)
case 0x3b: this.RLA(this.AM_AbsoluteY()); break; // *RLA (absolute, Y)
case 0x3c: this.AM_AbsoluteX(); break; // *NOP (absolute, X)
case 0x3d: this.A = this.AndR(this.A, this.AM_AbsoluteX()); break; // AND (absolute, X)
case 0x3e: this.BusReadModifyWrite(this.ROL(this.AM_AbsoluteX(PageCrossingBehavior.AlwaysReadTwice))); break; // ROL (absolute, X)
case 0x3e: this.ReadModifyWrite(this.ROL(this.AM_AbsoluteX(PageCrossingBehavior.AlwaysReadTwice))); break; // ROL (absolute, X)
case 0x3f: this.RLA(this.AM_AbsoluteX()); break; // *RLA (absolute, X)
case 0x40: this.BusRead(); this.RTI(); break; // RTI (implied)
case 0x40: this.MemoryRead(); this.RTI(); break; // RTI (implied)
case 0x41: this.A = this.EorR(this.A, this.AM_IndexedIndirectX()); break; // EOR (indexed indirect X)
case 0x42: break;
case 0x43: this.SRE(this.AM_IndexedIndirectX()); break; // *SRE (indexed indirect X)
case 0x44: this.AM_ZeroPage(); break; // *NOP (zero page)
case 0x45: this.A = this.EorR(this.A, this.AM_ZeroPage()); break; // EOR (zero page)
case 0x46: this.BusReadModifyWrite(this.LSR(this.AM_ZeroPage())); break; // LSR (zero page)
case 0x46: this.ReadModifyWrite(this.LSR(this.AM_ZeroPage())); break; // LSR (zero page)
case 0x47: this.SRE(this.AM_ZeroPage()); break; // *SRE (zero page)
case 0x48: this.BusRead(); this.Push(this.A); break; // PHA (implied)
case 0x48: this.MemoryRead(); this.Push(this.A); break; // PHA (implied)
case 0x49: this.A = this.EorR(this.A, this.AM_Immediate()); break; // EOR (immediate)
case 0x4a: this.BusRead(); this.A = this.LSR(this.A); break; // LSR A (implied)
case 0x4a: this.MemoryRead(); this.A = this.LSR(this.A); break; // LSR A (implied)
case 0x4b: this.ASR(this.AM_Immediate()); break; // *ASR (immediate)
case 0x4c: this.Jump(this.Address_Absolute().Word); break; // JMP (absolute)
case 0x4d: this.A = this.EorR(this.A, this.AM_Absolute()); break; // EOR (absolute)
case 0x4e: this.BusReadModifyWrite(this.LSR(this.AM_Absolute())); break; // LSR (absolute)
case 0x4e: this.ReadModifyWrite(this.LSR(this.AM_Absolute())); break; // LSR (absolute)
case 0x4f: this.SRE(this.AM_Absolute()); break; // *SRE (absolute)
case 0x50: this.Branch(this.Overflow == 0); break; // BVC (relative)
@ -283,32 +283,32 @@ namespace EightBit
case 0x53: this.SRE(this.AM_IndirectIndexedY()); break; // *SRE (indirect indexed Y)
case 0x54: this.AM_ZeroPageX(); break; // *NOP (zero page, X)
case 0x55: this.A = this.EorR(this.A, this.AM_ZeroPageX()); break; // EOR (zero page, X)
case 0x56: this.BusReadModifyWrite(this.LSR(this.AM_ZeroPageX())); break; // LSR (zero page, X)
case 0x56: this.ReadModifyWrite(this.LSR(this.AM_ZeroPageX())); break; // LSR (zero page, X)
case 0x57: this.SRE(this.AM_ZeroPageX()); break; // *SRE (zero page, X)
case 0x58: this.BusRead(); this.P = ClearBit(this.P, StatusBits.IF); break; // CLI (implied)
case 0x58: this.MemoryRead(); this.P = ClearBit(this.P, StatusBits.IF); break; // CLI (implied)
case 0x59: this.A = this.EorR(this.A, this.AM_AbsoluteY()); break; // EOR (absolute, Y)
case 0x5a: this.BusRead(); break; // *NOP (implied)
case 0x5a: this.MemoryRead(); break; // *NOP (implied)
case 0x5b: this.SRE(this.AM_AbsoluteY()); break; // *SRE (absolute, Y)
case 0x5c: this.AM_AbsoluteX(); break; // *NOP (absolute, X)
case 0x5d: this.A = this.EorR(this.A, this.AM_AbsoluteX()); break; // EOR (absolute, X)
case 0x5e: this.BusReadModifyWrite(this.LSR(this.AM_AbsoluteX(PageCrossingBehavior.AlwaysReadTwice))); break; // LSR (absolute, X)
case 0x5e: this.ReadModifyWrite(this.LSR(this.AM_AbsoluteX(PageCrossingBehavior.AlwaysReadTwice))); break; // LSR (absolute, X)
case 0x5f: this.SRE(this.AM_AbsoluteX()); break; // *SRE (absolute, X)
case 0x60: this.BusRead(); this.RTS(); break; // RTS (implied)
case 0x60: this.MemoryRead(); this.RTS(); break; // RTS (implied)
case 0x61: this.A = this.ADC(this.A, this.AM_IndexedIndirectX()); break; // ADC (indexed indirect X)
case 0x62: break;
case 0x63: this.RRA(this.AM_IndexedIndirectX()); break; // *RRA (indexed indirect X)
case 0x64: this.AM_ZeroPage(); break; // *NOP (zero page)
case 0x65: this.A = this.ADC(this.A, this.AM_ZeroPage()); break; // ADC (zero page)
case 0x66: this.BusReadModifyWrite(this.ROR(this.AM_ZeroPage())); break; // ROR (zero page)
case 0x66: this.ReadModifyWrite(this.ROR(this.AM_ZeroPage())); break; // ROR (zero page)
case 0x67: this.RRA(this.AM_ZeroPage()); break; // *RRA (zero page)
case 0x68: this.BusRead(); this.BusRead(this.S, 1); this.A = this.Through(this.Pop()); break; // PLA (implied)
case 0x68: this.MemoryRead(); this.MemoryRead(this.S, 1); this.A = this.Through(this.Pop()); break; // PLA (implied)
case 0x69: this.A = this.ADC(this.A, this.AM_Immediate()); break; // ADC (immediate)
case 0x6a: this.BusRead(); this.A = this.ROR(this.A); break; // ROR A (implied)
case 0x6a: this.MemoryRead(); this.A = this.ROR(this.A); break; // ROR A (implied)
case 0x6b: this.ARR(this.AM_Immediate()); break; // *ARR (immediate)
case 0x6c: this.Jump(this.Address_Indirect().Word); break; // JMP (indirect)
case 0x6d: this.A = this.ADC(this.A, this.AM_Absolute()); break; // ADC (absolute)
case 0x6e: this.BusReadModifyWrite(this.ROR(this.AM_Absolute())); break; // ROR (absolute)
case 0x6e: this.ReadModifyWrite(this.ROR(this.AM_Absolute())); break; // ROR (absolute)
case 0x6f: this.RRA(this.AM_Absolute()); break; // *RRA (absolute)
case 0x70: this.Branch(this.Overflow); break; // BVS (relative)
@ -317,45 +317,45 @@ namespace EightBit
case 0x73: this.RRA(this.AM_IndirectIndexedY()); break; // *RRA (indirect indexed Y)
case 0x74: this.AM_ZeroPageX(); break; // *NOP (zero page, X)
case 0x75: this.A = this.ADC(this.A, this.AM_ZeroPageX()); break; // ADC (zero page, X)
case 0x76: this.BusReadModifyWrite(this.ROR(this.AM_ZeroPageX())); break; // ROR (zero page, X)
case 0x76: this.ReadModifyWrite(this.ROR(this.AM_ZeroPageX())); break; // ROR (zero page, X)
case 0x77: this.RRA(this.AM_ZeroPageX()); break; // *RRA (zero page, X)
case 0x78: this.BusRead(); this.P = SetBit(this.P, StatusBits.IF); break; // SEI (implied)
case 0x78: this.MemoryRead(); this.P = SetBit(this.P, StatusBits.IF); break; // SEI (implied)
case 0x79: this.A = this.ADC(this.A, this.AM_AbsoluteY()); break; // ADC (absolute, Y)
case 0x7a: this.BusRead(); break; // *NOP (implied)
case 0x7a: this.MemoryRead(); break; // *NOP (implied)
case 0x7b: this.RRA(this.AM_AbsoluteY()); break; // *RRA (absolute, Y)
case 0x7c: this.AM_AbsoluteX(); break; // *NOP (absolute, X)
case 0x7d: this.A = this.ADC(this.A, this.AM_AbsoluteX()); break; // ADC (absolute, X)
case 0x7e: this.BusReadModifyWrite(this.ROR(this.AM_AbsoluteX(PageCrossingBehavior.AlwaysReadTwice))); break; // ROR (absolute, X)
case 0x7e: this.ReadModifyWrite(this.ROR(this.AM_AbsoluteX(PageCrossingBehavior.AlwaysReadTwice))); break; // ROR (absolute, X)
case 0x7f: this.RRA(this.AM_AbsoluteX()); break; // *RRA (absolute, X)
case 0x80: this.AM_Immediate(); break; // *NOP (immediate)
case 0x81: this.BusWrite(this.Address_IndexedIndirectX(), this.A); break; // STA (indexed indirect X)
case 0x81: this.MemoryWrite(this.Address_IndexedIndirectX(), this.A); break; // STA (indexed indirect X)
case 0x82: this.AM_Immediate(); break; // *NOP (immediate)
case 0x83: this.BusWrite(this.Address_IndexedIndirectX(), (byte)(this.A & this.X)); break; // *SAX (indexed indirect X)
case 0x84: this.BusWrite(this.Address_ZeroPage(), this.Y); break; // STY (zero page)
case 0x85: this.BusWrite(this.Address_ZeroPage(), this.A); break; // STA (zero page)
case 0x86: this.BusWrite(this.Address_ZeroPage(), this.X); break; // STX (zero page)
case 0x87: this.BusWrite(this.Address_ZeroPage(), (byte)(this.A & this.X)); break; // *SAX (zero page)
case 0x88: this.BusRead(); this.Y = this.DEC(this.Y); break; // DEY (implied)
case 0x83: this.MemoryWrite(this.Address_IndexedIndirectX(), (byte)(this.A & this.X)); break; // *SAX (indexed indirect X)
case 0x84: this.MemoryWrite(this.Address_ZeroPage(), this.Y); break; // STY (zero page)
case 0x85: this.MemoryWrite(this.Address_ZeroPage(), this.A); break; // STA (zero page)
case 0x86: this.MemoryWrite(this.Address_ZeroPage(), this.X); break; // STX (zero page)
case 0x87: this.MemoryWrite(this.Address_ZeroPage(), (byte)(this.A & this.X)); break; // *SAX (zero page)
case 0x88: this.MemoryRead(); this.Y = this.DEC(this.Y); break; // DEY (implied)
case 0x89: this.AM_Immediate(); break; // *NOP (immediate)
case 0x8a: this.BusRead(); this.A = this.Through(this.X); break; // TXA (implied)
case 0x8a: this.MemoryRead(); this.A = this.Through(this.X); break; // TXA (implied)
case 0x8b: break;
case 0x8c: this.BusWrite(this.Address_Absolute(), this.Y); break; // STY (absolute)
case 0x8d: this.BusWrite(this.Address_Absolute(), this.A); break; // STA (absolute)
case 0x8e: this.BusWrite(this.Address_Absolute(), this.X); break; // STX (absolute)
case 0x8f: this.BusWrite(this.Address_Absolute(), (byte)(this.A & this.X)); break; // *SAX (absolute)
case 0x8c: this.MemoryWrite(this.Address_Absolute(), this.Y); break; // STY (absolute)
case 0x8d: this.MemoryWrite(this.Address_Absolute(), this.A); break; // STA (absolute)
case 0x8e: this.MemoryWrite(this.Address_Absolute(), this.X); break; // STX (absolute)
case 0x8f: this.MemoryWrite(this.Address_Absolute(), (byte)(this.A & this.X)); break; // *SAX (absolute)
case 0x90: this.Branch(this.Carry == 0); break; // BCC (relative)
case 0x91: this.AM_IndirectIndexedY(); this.BusWrite(this.A); break; // STA (indirect indexed Y)
case 0x91: this.AM_IndirectIndexedY(); this.MemoryWrite(this.A); break; // STA (indirect indexed Y)
case 0x92: break;
case 0x93: break;
case 0x94: this.BusWrite(this.Address_ZeroPageX(), this.Y); break; // STY (zero page, X)
case 0x95: this.BusWrite(this.Address_ZeroPageX(), this.A); break; // STA (zero page, X)
case 0x96: this.BusWrite(this.Address_ZeroPageY(), this.X); break; // STX (zero page, Y)
case 0x97: this.BusWrite(this.Address_ZeroPageY(), (byte)(this.A & this.X)); break; // *SAX (zero page, Y)
case 0x98: this.BusRead(); this.A = this.Through(this.Y); break; // TYA (implied)
case 0x94: this.MemoryWrite(this.Address_ZeroPageX(), this.Y); break; // STY (zero page, X)
case 0x95: this.MemoryWrite(this.Address_ZeroPageX(), this.A); break; // STA (zero page, X)
case 0x96: this.MemoryWrite(this.Address_ZeroPageY(), this.X); break; // STX (zero page, Y)
case 0x97: this.MemoryWrite(this.Address_ZeroPageY(), (byte)(this.A & this.X)); break; // *SAX (zero page, Y)
case 0x98: this.MemoryRead(); this.A = this.Through(this.Y); break; // TYA (implied)
case 0x99: this.STA_AbsoluteY(); break; // STA (absolute, Y)
case 0x9a: this.BusRead(); this.S = this.X; break; // TXS (implied)
case 0x9a: this.MemoryRead(); this.S = this.X; break; // TXS (implied)
case 0x9b: break;
case 0x9c: break;
case 0x9d: this.STA_AbsoluteX(); break; // STA (absolute, X)
@ -370,9 +370,9 @@ namespace EightBit
case 0xa5: this.A = this.Through(this.AM_ZeroPage()); break; // LDA (zero page)
case 0xa6: this.X = this.Through(this.AM_ZeroPage()); break; // LDX (zero page)
case 0xa7: this.A = this.X = this.Through(this.AM_ZeroPage()); break; // *LAX (zero page)
case 0xa8: this.BusRead(); this.Y = this.Through(this.A); break; // TAY (implied)
case 0xa8: this.MemoryRead(); this.Y = this.Through(this.A); break; // TAY (implied)
case 0xa9: this.A = this.Through(this.AM_Immediate()); break; // LDA (immediate)
case 0xaa: this.BusRead(); this.X = this.Through(this.A); break; // TAX (implied)
case 0xaa: this.MemoryRead(); this.X = this.Through(this.A); break; // TAX (implied)
case 0xab: this.A = this.X = this.Through(this.AM_Immediate()); break; // *ATX (immediate)
case 0xac: this.Y = this.Through(this.AM_Absolute()); break; // LDY (absolute)
case 0xad: this.A = this.Through(this.AM_Absolute()); break; // LDA (absolute)
@ -387,9 +387,9 @@ namespace EightBit
case 0xb5: this.A = this.Through(this.AM_ZeroPageX()); break; // LDA (zero page, X)
case 0xb6: this.X = this.Through(this.AM_ZeroPageY()); break; // LDX (zero page, Y)
case 0xb7: this.A = this.X = this.Through(this.AM_ZeroPageY()); break; // *LAX (zero page, Y)
case 0xb8: this.BusRead(); this.P = ClearBit(this.P, StatusBits.VF); break; // CLV (implied)
case 0xb8: this.MemoryRead(); this.P = ClearBit(this.P, StatusBits.VF); break; // CLV (implied)
case 0xb9: this.A = this.Through(this.AM_AbsoluteY()); break; // LDA (absolute, Y)
case 0xba: this.BusRead(); this.X = this.Through(this.S); break; // TSX (implied)
case 0xba: this.MemoryRead(); this.X = this.Through(this.S); break; // TSX (implied)
case 0xbb: break;
case 0xbc: this.Y = this.Through(this.AM_AbsoluteX()); break; // LDY (absolute, X)
case 0xbd: this.A = this.Through(this.AM_AbsoluteX()); break; // LDA (absolute, X)
@ -402,15 +402,15 @@ namespace EightBit
case 0xc3: this.DCP(this.AM_IndexedIndirectX()); break; // *DCP (indexed indirect X)
case 0xc4: this.CMP(this.Y, this.AM_ZeroPage()); break; // CPY (zero page)
case 0xc5: this.CMP(this.A, this.AM_ZeroPage()); break; // CMP (zero page)
case 0xc6: this.BusReadModifyWrite(this.DEC(this.AM_ZeroPage())); break; // DEC (zero page)
case 0xc6: this.ReadModifyWrite(this.DEC(this.AM_ZeroPage())); break; // DEC (zero page)
case 0xc7: this.DCP(this.AM_ZeroPage()); break; // *DCP (zero page)
case 0xc8: this.BusRead(); this.Y = this.INC(this.Y); break; // INY (implied)
case 0xc8: this.MemoryRead(); this.Y = this.INC(this.Y); break; // INY (implied)
case 0xc9: this.CMP(this.A, this.AM_Immediate()); break; // CMP (immediate)
case 0xca: this.BusRead(); this.X = this.DEC(this.X); break; // DEX (implied)
case 0xca: this.MemoryRead(); this.X = this.DEC(this.X); break; // DEX (implied)
case 0xcb: this.AXS(this.AM_Immediate()); break; // *AXS (immediate)
case 0xcc: this.CMP(this.Y, this.AM_Absolute()); break; // CPY (absolute)
case 0xcd: this.CMP(this.A, this.AM_Absolute()); break; // CMP (absolute)
case 0xce: this.BusReadModifyWrite(this.DEC(this.AM_Absolute())); break; // DEC (absolute)
case 0xce: this.ReadModifyWrite(this.DEC(this.AM_Absolute())); break; // DEC (absolute)
case 0xcf: this.DCP(this.AM_Absolute()); break; // *DCP (absolute)
case 0xd0: this.Branch(this.Zero == 0); break; // BNE (relative)
@ -419,15 +419,15 @@ namespace EightBit
case 0xd3: this.DCP(this.AM_IndirectIndexedY()); break; // *DCP (indirect indexed Y)
case 0xd4: this.AM_ZeroPageX(); break; // *NOP (zero page, X)
case 0xd5: this.CMP(this.A, this.AM_ZeroPageX()); break; // CMP (zero page, X)
case 0xd6: this.BusReadModifyWrite(this.DEC(this.AM_ZeroPageX())); break; // DEC (zero page, X)
case 0xd6: this.ReadModifyWrite(this.DEC(this.AM_ZeroPageX())); break; // DEC (zero page, X)
case 0xd7: this.DCP(this.AM_ZeroPageX()); break; // *DCP (zero page, X)
case 0xd8: this.BusRead(); this.P = ClearBit(this.P, StatusBits.DF); break; // CLD (implied)
case 0xd8: this.MemoryRead(); this.P = ClearBit(this.P, StatusBits.DF); break; // CLD (implied)
case 0xd9: this.CMP(this.A, this.AM_AbsoluteY()); break; // CMP (absolute, Y)
case 0xda: this.BusRead(); break; // *NOP (implied)
case 0xda: this.MemoryRead(); break; // *NOP (implied)
case 0xdb: this.DCP(this.AM_AbsoluteY()); break; // *DCP (absolute, Y)
case 0xdc: this.AM_AbsoluteX(); break; // *NOP (absolute, X)
case 0xdd: this.CMP(this.A, this.AM_AbsoluteX()); break; // CMP (absolute, X)
case 0xde: this.BusReadModifyWrite(this.DEC(this.AM_AbsoluteX(PageCrossingBehavior.AlwaysReadTwice))); break; // DEC (absolute, X)
case 0xde: this.ReadModifyWrite(this.DEC(this.AM_AbsoluteX(PageCrossingBehavior.AlwaysReadTwice))); break; // DEC (absolute, X)
case 0xdf: this.DCP(this.AM_AbsoluteX()); break; // *DCP (absolute, X)
case 0xe0: this.CMP(this.X, this.AM_Immediate()); break; // CPX (immediate)
@ -436,15 +436,15 @@ namespace EightBit
case 0xe3: this.ISB(this.AM_IndexedIndirectX()); break; // *ISB (indexed indirect X)
case 0xe4: this.CMP(this.X, this.AM_ZeroPage()); break; // CPX (zero page)
case 0xe5: this.A = this.SBC(this.A, this.AM_ZeroPage()); break; // SBC (zero page)
case 0xe6: this.BusReadModifyWrite(this.INC(this.AM_ZeroPage())); break; // INC (zero page)
case 0xe6: this.ReadModifyWrite(this.INC(this.AM_ZeroPage())); break; // INC (zero page)
case 0xe7: this.ISB(this.AM_ZeroPage()); break; // *ISB (zero page)
case 0xe8: this.BusRead(); this.X = this.INC(this.X); break; // INX (implied)
case 0xe8: this.MemoryRead(); this.X = this.INC(this.X); break; // INX (implied)
case 0xe9: this.A = this.SBC(this.A, this.AM_Immediate()); break; // SBC (immediate)
case 0xea: this.BusRead(); break; // NOP (implied)
case 0xea: this.MemoryRead(); break; // NOP (implied)
case 0xeb: this.A = this.SBC(this.A, this.AM_Immediate()); break; // *SBC (immediate)
case 0xec: this.CMP(this.X, this.AM_Absolute()); break; // CPX (absolute)
case 0xed: this.A = this.SBC(this.A, this.AM_Absolute()); break; // SBC (absolute)
case 0xee: this.BusReadModifyWrite(this.INC(this.AM_Absolute())); break; // *ISB (absolute)
case 0xee: this.ReadModifyWrite(this.INC(this.AM_Absolute())); break; // *ISB (absolute)
case 0xf0: this.Branch(this.Zero); break; // BEQ (relative)
case 0xf1: this.A = this.SBC(this.A, this.AM_IndirectIndexedY()); break; // SBC (indirect indexed Y)
@ -452,15 +452,15 @@ namespace EightBit
case 0xf3: this.ISB(this.AM_IndirectIndexedY()); break; // *ISB (indirect indexed Y)
case 0xf4: this.AM_ZeroPageX(); break; // *NOP (zero page, X)
case 0xf5: this.A = this.SBC(this.A, this.AM_ZeroPageX()); break; // SBC (zero page, X)
case 0xf6: this.BusReadModifyWrite(this.INC(this.AM_ZeroPageX())); break; // INC (zero page, X)
case 0xf6: this.ReadModifyWrite(this.INC(this.AM_ZeroPageX())); break; // INC (zero page, X)
case 0xf7: this.ISB(this.AM_ZeroPageX()); break; // *ISB (zero page, X)
case 0xf8: this.BusRead(); this.P = SetBit(this.P, StatusBits.DF); break; // SED (implied)
case 0xf8: this.MemoryRead(); this.P = SetBit(this.P, StatusBits.DF); break; // SED (implied)
case 0xf9: this.A = this.SBC(this.A, this.AM_AbsoluteY()); break; // SBC (absolute, Y)
case 0xfa: this.BusRead(); break; // *NOP (implied)
case 0xfa: this.MemoryRead(); break; // *NOP (implied)
case 0xfb: this.ISB(this.AM_AbsoluteY()); break; // *ISB (absolute, Y)
case 0xfc: this.AM_AbsoluteX(); break; // *NOP (absolute, X)
case 0xfd: this.A = this.SBC(this.A, this.AM_AbsoluteX()); break; // SBC (absolute, X)
case 0xfe: this.BusReadModifyWrite(this.INC(this.AM_AbsoluteX(PageCrossingBehavior.AlwaysReadTwice))); break; // INC (absolute, X)
case 0xfe: this.ReadModifyWrite(this.INC(this.AM_AbsoluteX(PageCrossingBehavior.AlwaysReadTwice))); break; // INC (absolute, X)
case 0xff: this.ISB(this.AM_AbsoluteX()); break; // *ISB (absolute, X)
}
@ -561,9 +561,9 @@ namespace EightBit
base.OnRaisedPOWER();
}
protected override byte Pop() => this.BusRead(++this.S, 1);
protected override byte Pop() => this.MemoryRead(++this.S, 1);
protected override void Push(byte value) => this.BusWrite(this.S--, 1, value);
protected override void Push(byte value) => this.MemoryWrite(this.S--, 1, value);
protected virtual void RaiseSYNC()
{
@ -678,14 +678,14 @@ namespace EightBit
private byte Address_ZeroPageX()
{
var address = this.Address_ZeroPage();
this.BusRead(address);
this.MemoryRead(address);
return Chip.LowByte(address + this.X);
}
private byte Address_ZeroPageY()
{
var address = this.Address_ZeroPage();
this.BusRead(address);
this.MemoryRead(address);
return Chip.LowByte(address + this.Y);
}
@ -724,17 +724,17 @@ namespace EightBit
private byte AM_Immediate() => this.FetchByte();
private byte AM_Absolute() => this.BusRead(this.Address_Absolute());
private byte AM_Absolute() => this.MemoryRead(this.Address_Absolute());
private byte AM_ZeroPage() => this.BusRead(this.Address_ZeroPage());
private byte AM_ZeroPage() => this.MemoryRead(this.Address_ZeroPage());
private byte AM_AbsoluteX(PageCrossingBehavior behaviour = PageCrossingBehavior.MaybeReadTwice)
{
var address = this.Address_AbsoluteX();
var possible = this.BusRead(address.Low, this.crossedPage);
var possible = this.MemoryRead(address.Low, this.crossedPage);
if ((behaviour == PageCrossingBehavior.AlwaysReadTwice) || (this.crossedPage != address.High))
{
possible = this.BusRead(address.Word);
possible = this.MemoryRead(address.Word);
}
return possible;
@ -743,28 +743,28 @@ namespace EightBit
private byte AM_AbsoluteY()
{
var address = this.Address_AbsoluteY();
var possible = this.BusRead(address.Low, this.crossedPage);
var possible = this.MemoryRead(address.Low, this.crossedPage);
if (this.crossedPage != address.High)
{
possible = this.BusRead(address.Word);
possible = this.MemoryRead(address.Word);
}
return possible;
}
private byte AM_ZeroPageX() => this.BusRead(this.Address_ZeroPageX());
private byte AM_ZeroPageX() => this.MemoryRead(this.Address_ZeroPageX());
private byte AM_ZeroPageY() => this.BusRead(this.Address_ZeroPageY());
private byte AM_ZeroPageY() => this.MemoryRead(this.Address_ZeroPageY());
private byte AM_IndexedIndirectX() => this.BusRead(this.Address_IndexedIndirectX());
private byte AM_IndexedIndirectX() => this.MemoryRead(this.Address_IndexedIndirectX());
private byte AM_IndirectIndexedY()
{
var address = this.Address_IndirectIndexedY();
var possible = this.BusRead(address.Low, this.crossedPage);
var possible = this.MemoryRead(address.Low, this.crossedPage);
if (this.crossedPage != address.High)
{
possible = this.BusRead(address);
possible = this.MemoryRead(address);
}
return possible;
@ -787,12 +787,12 @@ namespace EightBit
var destination = this.Address_relative_byte();
if (condition)
{
this.BusRead();
this.MemoryRead();
var page = this.PC.High;
this.Jump(destination);
if (this.PC.High != page)
{
this.BusRead(this.PC.Low, page);
this.MemoryRead(this.PC.Low, page);
}
}
}
@ -805,11 +805,11 @@ namespace EightBit
return data;
}
private void BusReadModifyWrite(byte data)
private void ReadModifyWrite(byte data)
{
// The read will have already taken place...
this.BusWrite();
this.BusWrite(data);
this.MemoryWrite();
this.MemoryWrite(data);
}
private byte SBC(byte operand, byte data)
@ -925,7 +925,7 @@ namespace EightBit
private void JSR()
{
var low = this.FetchByte();
this.BusRead(this.S, 1); // dummy read
this.MemoryRead(this.S, 1); // dummy read
this.PushWord(this.PC);
var high = this.FetchByte();
this.PC.Low = low;
@ -962,14 +962,14 @@ namespace EightBit
private void RTI()
{
this.BusRead(this.S, 1); // dummy read
this.MemoryRead(this.S, 1); // dummy read
this.PLP();
this.Return();
}
private void RTS()
{
this.BusRead(this.S, 1); // dummy read
this.MemoryRead(this.S, 1); // dummy read
this.Return();
this.FetchByte();
}
@ -1002,52 +1002,52 @@ namespace EightBit
private void DCP(byte value)
{
this.BusReadModifyWrite(this.DEC(value));
this.ReadModifyWrite(this.DEC(value));
this.CMP(this.A, this.Bus.Data);
}
private void ISB(byte value)
{
this.BusReadModifyWrite(this.INC(value));
this.ReadModifyWrite(this.INC(value));
this.A = this.SBC(this.A, this.Bus.Data);
}
private void RLA(byte value)
{
this.BusReadModifyWrite(this.ROL(value));
this.ReadModifyWrite(this.ROL(value));
this.A = this.AndR(this.A, this.Bus.Data);
}
private void RRA(byte value)
{
this.BusReadModifyWrite(this.ROR(value));
this.ReadModifyWrite(this.ROR(value));
this.A = this.ADC(this.A, this.Bus.Data);
}
private void SLO(byte value)
{
this.BusReadModifyWrite(this.ASL(value));
this.ReadModifyWrite(this.ASL(value));
this.A = this.OrR(this.A, this.Bus.Data);
}
private void SRE(byte value)
{
this.BusReadModifyWrite(this.LSR(value));
this.ReadModifyWrite(this.LSR(value));
this.A = this.EorR(this.A, this.Bus.Data);
}
private void STA_AbsoluteX()
{
var address = this.Address_AbsoluteX();
this.BusRead(address.Low, this.crossedPage);
this.BusWrite(address, this.A);
this.MemoryRead(address.Low, this.crossedPage);
this.MemoryWrite(address, this.A);
}
private void STA_AbsoluteY()
{
var address = this.Address_AbsoluteY();
this.BusRead(address.Low, this.crossedPage);
this.BusWrite(address, this.A);
this.MemoryRead(address.Low, this.crossedPage);
this.MemoryWrite(address, this.A);
}
}
}

View File

@ -496,7 +496,7 @@ namespace EightBit
private void OnExecutedInstruction() => this.ExecutedInstruction?.Invoke(this, EventArgs.Empty);
private void Push(Register16 stack, byte value) => this.BusWrite(--stack.Word, value);
private void Push(Register16 stack, byte value) => this.MemoryWrite(--stack.Word, value);
private void PushS(byte value) => this.Push(this.S, value);
@ -506,7 +506,7 @@ namespace EightBit
this.Push(stack, value.High);
}
private byte Pop(Register16 stack) => this.BusRead(stack.Word++);
private byte Pop(Register16 stack) => this.MemoryRead(stack.Word++);
private byte PopS() => this.Pop(this.S);
@ -636,11 +636,11 @@ namespace EightBit
private byte AM_immediate_byte() => this.FetchByte();
private byte AM_direct_byte() => this.BusRead(this.Address_direct());
private byte AM_direct_byte() => this.MemoryRead(this.Address_direct());
private byte AM_indexed_byte() => this.BusRead(this.Address_indexed());
private byte AM_indexed_byte() => this.MemoryRead(this.Address_indexed());
private byte AM_extended_byte() => this.BusRead(this.Address_extended());
private byte AM_extended_byte() => this.MemoryRead(this.Address_extended());
private Register16 AM_immediate_word() => this.FetchWord();
@ -884,18 +884,18 @@ namespace EightBit
case 0x1c: this.Tick(3); this.CC &= this.AM_immediate_byte(); break; // AND (ANDCC immediate)
// ASL/LSL
case 0x08: this.Tick(6); this.BusWrite(this.ASL(this.AM_direct_byte())); break; // ASL (direct)
case 0x08: this.Tick(6); this.MemoryWrite(this.ASL(this.AM_direct_byte())); break; // ASL (direct)
case 0x48: this.Tick(2); this.A = this.ASL(this.A); break; // ASL (ASLA inherent)
case 0x58: this.Tick(2); this.B = this.ASL(this.B); break; // ASL (ASLB inherent)
case 0x68: this.Tick(6); this.BusWrite(this.ASL(this.AM_indexed_byte())); break; // ASL (indexed)
case 0x78: this.Tick(7); this.BusWrite(this.ASL(this.AM_extended_byte())); break; // ASL (extended)
case 0x68: this.Tick(6); this.MemoryWrite(this.ASL(this.AM_indexed_byte())); break; // ASL (indexed)
case 0x78: this.Tick(7); this.MemoryWrite(this.ASL(this.AM_extended_byte())); break; // ASL (extended)
// ASR
case 0x07: this.Tick(6); this.BusWrite(this.ASR(this.AM_direct_byte())); break; // ASR (direct)
case 0x07: this.Tick(6); this.MemoryWrite(this.ASR(this.AM_direct_byte())); break; // ASR (direct)
case 0x47: this.Tick(2); this.A = this.ASR(this.A); break; // ASR (ASRA inherent)
case 0x57: this.Tick(2); this.B = this.ASR(this.B); break; // ASR (ASRB inherent)
case 0x67: this.Tick(6); this.BusWrite(this.ASR(this.AM_indexed_byte())); break; // ASR (indexed)
case 0x77: this.Tick(7); this.BusWrite(this.ASR(this.AM_extended_byte())); break; // ASR (extended)
case 0x67: this.Tick(6); this.MemoryWrite(this.ASR(this.AM_indexed_byte())); break; // ASR (indexed)
case 0x77: this.Tick(7); this.MemoryWrite(this.ASR(this.AM_extended_byte())); break; // ASR (extended)
// BIT
case 0x85: this.Tick(2); this.BIT(this.A, this.AM_immediate_byte()); break; // BIT (BITA immediate)
@ -909,11 +909,11 @@ namespace EightBit
case 0xf5: this.Tick(5); this.BIT(this.B, this.AM_extended_byte()); break; // BIT (BITB extended)
// CLR
case 0x0f: this.Tick(6); this.BusWrite(this.Address_direct(), this.CLR()); break; // CLR (direct)
case 0x0f: this.Tick(6); this.MemoryWrite(this.Address_direct(), this.CLR()); break; // CLR (direct)
case 0x4f: this.Tick(2); this.A = this.CLR(); break; // CLR (CLRA implied)
case 0x5f: this.Tick(2); this.B = this.CLR(); break; // CLR (CLRB implied)
case 0x6f: this.Tick(6); this.BusWrite(this.Address_indexed(), this.CLR()); break; // CLR (indexed)
case 0x7f: this.Tick(7); this.BusWrite(this.Address_extended(), this.CLR()); break; // CLR (extended)
case 0x6f: this.Tick(6); this.MemoryWrite(this.Address_indexed(), this.CLR()); break; // CLR (indexed)
case 0x7f: this.Tick(7); this.MemoryWrite(this.Address_extended(), this.CLR()); break; // CLR (extended)
// CMP
@ -936,11 +936,11 @@ namespace EightBit
case 0xbc: this.Tick(7); this.CMP(this.X, this.AM_extended_word()); break; // CMP (CMPX, extended)
// COM
case 0x03: this.Tick(6); this.BusWrite(this.COM(this.AM_direct_byte())); break; // COM (direct)
case 0x03: this.Tick(6); this.MemoryWrite(this.COM(this.AM_direct_byte())); break; // COM (direct)
case 0x43: this.Tick(2); this.A = this.COM(this.A); break; // COM (COMA inherent)
case 0x53: this.Tick(2); this.B = this.COM(this.B); break; // COM (COMB inherent)
case 0x63: this.Tick(6); this.BusWrite(this.COM(this.AM_indexed_byte())); break; // COM (indexed)
case 0x73: this.Tick(7); this.BusWrite(this.COM(this.AM_extended_byte())); break; // COM (extended)
case 0x63: this.Tick(6); this.MemoryWrite(this.COM(this.AM_indexed_byte())); break; // COM (indexed)
case 0x73: this.Tick(7); this.MemoryWrite(this.COM(this.AM_extended_byte())); break; // COM (extended)
// CWAI
case 0x3c: this.Tick(11); this.CWAI(this.AM_direct_byte()); break; // CWAI (direct)
@ -949,11 +949,11 @@ namespace EightBit
case 0x19: this.Tick(2); this.A = this.DA(this.A); break; // DAA (inherent)
// DEC
case 0x0a: this.Tick(6); this.BusWrite(this.DEC(this.AM_direct_byte())); break; // DEC (direct)
case 0x0a: this.Tick(6); this.MemoryWrite(this.DEC(this.AM_direct_byte())); break; // DEC (direct)
case 0x4a: this.Tick(2); this.A = this.DEC(this.A); break; // DEC (DECA inherent)
case 0x5a: this.Tick(2); this.B = this.DEC(this.B); break; // DEC (DECB inherent)
case 0x6a: this.Tick(6); this.BusWrite(this.DEC(this.AM_indexed_byte())); break; // DEC (indexed)
case 0x7a: this.Tick(7); this.BusWrite(this.DEC(this.AM_extended_byte())); break; // DEC (extended)
case 0x6a: this.Tick(6); this.MemoryWrite(this.DEC(this.AM_indexed_byte())); break; // DEC (indexed)
case 0x7a: this.Tick(7); this.MemoryWrite(this.DEC(this.AM_extended_byte())); break; // DEC (extended)
// EOR
@ -973,11 +973,11 @@ namespace EightBit
case 0x1e: this.Tick(8); this.EXG(this.AM_immediate_byte()); break; // EXG (R1,R2 immediate)
// INC
case 0x0c: this.Tick(6); this.BusWrite(this.INC(this.AM_direct_byte())); break; // INC (direct)
case 0x0c: this.Tick(6); this.MemoryWrite(this.INC(this.AM_direct_byte())); break; // INC (direct)
case 0x4c: this.Tick(2); this.A = this.INC(this.A); break; // INC (INCA inherent)
case 0x5c: this.Tick(2); this.B = this.INC(this.B); break; // INC (INCB inherent)
case 0x6c: this.Tick(6); this.BusWrite(this.INC(this.AM_indexed_byte())); break; // INC (indexed)
case 0x7c: this.Tick(7); this.BusWrite(this.INC(this.AM_extended_byte())); break; // INC (extended)
case 0x6c: this.Tick(6); this.MemoryWrite(this.INC(this.AM_indexed_byte())); break; // INC (indexed)
case 0x7c: this.Tick(7); this.MemoryWrite(this.INC(this.AM_extended_byte())); break; // INC (extended)
// JMP
case 0x0e: this.Tick(6); this.Jump(this.Address_direct()); break; // JMP (direct)
@ -1028,21 +1028,21 @@ namespace EightBit
case 0x33: this.Tick(4); this.U.Word = this.Address_indexed().Word; break; // LEA (LEAU indexed)
// LSR
case 0x04: this.Tick(6); this.BusWrite(this.LSR(this.AM_direct_byte())); break; // LSR (direct)
case 0x04: this.Tick(6); this.MemoryWrite(this.LSR(this.AM_direct_byte())); break; // LSR (direct)
case 0x44: this.Tick(2); this.A = this.LSR(this.A); break; // LSR (LSRA inherent)
case 0x54: this.Tick(2); this.B = this.LSR(this.B); break; // LSR (LSRB inherent)
case 0x64: this.Tick(6); this.BusWrite(this.LSR(this.AM_indexed_byte())); break; // LSR (indexed)
case 0x74: this.Tick(7); this.BusWrite(this.LSR(this.AM_extended_byte())); break; // LSR (extended)
case 0x64: this.Tick(6); this.MemoryWrite(this.LSR(this.AM_indexed_byte())); break; // LSR (indexed)
case 0x74: this.Tick(7); this.MemoryWrite(this.LSR(this.AM_extended_byte())); break; // LSR (extended)
// MUL
case 0x3d: this.Tick(11); this.D.Word = this.MUL(this.A, this.B).Word; break; // MUL (inherent)
// NEG
case 0x00: this.Tick(6); this.BusWrite(this.NEG(this.AM_direct_byte())); break; // NEG (direct)
case 0x00: this.Tick(6); this.MemoryWrite(this.NEG(this.AM_direct_byte())); break; // NEG (direct)
case 0x40: this.Tick(2); this.A = this.NEG(this.A); break; // NEG (NEGA, inherent)
case 0x50: this.Tick(2); this.B = this.NEG(this.B); break; // NEG (NEGB, inherent)
case 0x60: this.Tick(6); this.BusWrite(this.NEG(this.AM_indexed_byte())); break; // NEG (indexed)
case 0x70: this.Tick(7); this.BusWrite(this.NEG(this.AM_extended_byte())); break; // NEG (extended)
case 0x60: this.Tick(6); this.MemoryWrite(this.NEG(this.AM_indexed_byte())); break; // NEG (indexed)
case 0x70: this.Tick(7); this.MemoryWrite(this.NEG(this.AM_extended_byte())); break; // NEG (extended)
// NOP
case 0x12: this.Tick(2); break; // NOP (inherent)
@ -1073,18 +1073,18 @@ namespace EightBit
case 0x37: this.Tick(5); this.PUL(this.U, this.AM_immediate_byte()); break; // PUL (PULU immediate)
// ROL
case 0x09: this.Tick(6); this.BusWrite(this.ROL(this.AM_direct_byte())); break; // ROL (direct)
case 0x09: this.Tick(6); this.MemoryWrite(this.ROL(this.AM_direct_byte())); break; // ROL (direct)
case 0x49: this.Tick(2); this.A = this.ROL(this.A); break; // ROL (ROLA inherent)
case 0x59: this.Tick(2); this.B = this.ROL(this.B); break; // ROL (ROLB inherent)
case 0x69: this.Tick(6); this.BusWrite(this.ROL(this.AM_indexed_byte())); break; // ROL (indexed)
case 0x79: this.Tick(7); this.BusWrite(this.ROL(this.AM_extended_byte())); break; // ROL (extended)
case 0x69: this.Tick(6); this.MemoryWrite(this.ROL(this.AM_indexed_byte())); break; // ROL (indexed)
case 0x79: this.Tick(7); this.MemoryWrite(this.ROL(this.AM_extended_byte())); break; // ROL (extended)
// ROR
case 0x06: this.Tick(6); this.BusWrite(this.ROR(this.AM_direct_byte())); break; // ROR (direct)
case 0x06: this.Tick(6); this.MemoryWrite(this.ROR(this.AM_direct_byte())); break; // ROR (direct)
case 0x46: this.Tick(2); this.A = this.ROR(this.A); break; // ROR (RORA inherent)
case 0x56: this.Tick(2); this.B = this.ROR(this.B); break; // ROR (RORB inherent)
case 0x66: this.Tick(6); this.BusWrite(this.ROR(this.AM_indexed_byte())); break; // ROR (indexed)
case 0x76: this.Tick(7); this.BusWrite(this.ROR(this.AM_extended_byte())); break; // ROR (extended)
case 0x66: this.Tick(6); this.MemoryWrite(this.ROR(this.AM_indexed_byte())); break; // ROR (indexed)
case 0x76: this.Tick(7); this.MemoryWrite(this.ROR(this.AM_extended_byte())); break; // ROR (extended)
// RTI
case 0x3B: this.Tick(6); this.RTI(); break; // RTI (inherent)
@ -1112,14 +1112,14 @@ namespace EightBit
// ST
// STA
case 0x97: this.Tick(4); this.BusWrite(this.Address_direct(), this.ST(this.A)); break; // ST (STA direct)
case 0xa7: this.Tick(4); this.BusWrite(this.Address_indexed(), this.ST(this.A)); break; // ST (STA indexed)
case 0xb7: this.Tick(5); this.BusWrite(this.Address_extended(), this.ST(this.A)); break; // ST (STA extended)
case 0x97: this.Tick(4); this.MemoryWrite(this.Address_direct(), this.ST(this.A)); break; // ST (STA direct)
case 0xa7: this.Tick(4); this.MemoryWrite(this.Address_indexed(), this.ST(this.A)); break; // ST (STA indexed)
case 0xb7: this.Tick(5); this.MemoryWrite(this.Address_extended(), this.ST(this.A)); break; // ST (STA extended)
// STB
case 0xd7: this.Tick(4); this.BusWrite(this.Address_direct(), this.ST(this.B)); break; // ST (STB direct)
case 0xe7: this.Tick(4); this.BusWrite(this.Address_indexed(), this.ST(this.B)); break; // ST (STB indexed)
case 0xf7: this.Tick(5); this.BusWrite(this.Address_extended(), this.ST(this.B)); break; // ST (STB extended)
case 0xd7: this.Tick(4); this.MemoryWrite(this.Address_direct(), this.ST(this.B)); break; // ST (STB direct)
case 0xe7: this.Tick(4); this.MemoryWrite(this.Address_indexed(), this.ST(this.B)); break; // ST (STB indexed)
case 0xf7: this.Tick(5); this.MemoryWrite(this.Address_extended(), this.ST(this.B)); break; // ST (STB extended)
// STD
case 0xdd: this.Tick(5); this.SetWord(this.Address_direct(), this.ST(this.D)); break; // ST (STD direct)

View File

@ -4,6 +4,7 @@
namespace Fuse
{
using System;
using System.Collections.Generic;
public enum Register
@ -38,8 +39,8 @@ namespace Fuse
public TestRunner(Test<RegisterState> test, Result<RegisterState> result)
{
this.cpu = new EightBit.Z80(this, this.ports);
this.test = test;
this.result = result;
this.test = test ?? throw new ArgumentNullException(nameof(test));
this.result = result ?? throw new ArgumentNullException(nameof(result));
foreach (var e in result.Events.Container)
{
@ -438,20 +439,14 @@ namespace Fuse
{
foreach (var e in events)
{
var output = $" Event issue {ToString(e)}";
System.Console.Error.WriteLine(output);
DumpEvent(e);
}
}
private static string ToString(TestEvent e)
private static void DumpEvent(TestEvent e)
{
var output = $"Cycles = {e.Cycles}, Specifier = {e.Specifier}, Address = {e.Address:X4}";
if (!e.Specifier.EndsWith("C", System.StringComparison.Ordinal))
{
output += $", Value={e.Value:X2}";
}
return output;
var output = $" Event issue {e}";
System.Console.Error.WriteLine(output);
}
private void CheckMemory()

View File

@ -493,22 +493,22 @@ namespace EightBit
protected virtual void OnRaisedWR() => this.RaisedWR?.Invoke(this, EventArgs.Empty);
protected override void BusWrite()
protected override void MemoryWrite()
{
this.Tick(3);
this.LowerMREQ();
this.LowerWR();
base.BusWrite();
base.MemoryWrite();
this.RaiseWR();
this.RaiseMREQ();
}
protected override byte BusRead()
protected override byte MemoryRead()
{
this.Tick(3);
this.LowerMREQ();
this.LowerRD();
var returned = base.BusRead();
var returned = base.MemoryRead();
this.RaiseRD();
this.RaiseMREQ();
return returned;
@ -659,7 +659,7 @@ namespace EightBit
3 => this.E,
4 => this.HL2().High,
5 => this.HL2().Low,
6 => this.BusRead(this.displaced ? this.DisplacedAddress : this.HL.Word),
6 => this.MemoryRead(this.displaced ? this.DisplacedAddress : this.HL.Word),
7 => this.A,
_ => throw new ArgumentOutOfRangeException(nameof(r)),
};
@ -687,7 +687,7 @@ namespace EightBit
this.HL2().Low = value;
break;
case 6:
this.BusWrite(this.displaced ? this.DisplacedAddress : this.HL.Word, value);
this.MemoryWrite(this.displaced ? this.DisplacedAddress : this.HL.Word, value);
break;
case 7:
this.A = value;
@ -720,7 +720,7 @@ namespace EightBit
this.L = value;
break;
case 6:
this.BusWrite(this.HL, value);
this.MemoryWrite(this.HL, value);
break;
case 7:
this.A = value;
@ -740,7 +740,7 @@ namespace EightBit
if (this.displaced)
{
this.Tick(2);
operand = this.BusRead(this.DisplacedAddress);
operand = this.MemoryRead(this.DisplacedAddress);
}
else
{
@ -784,7 +784,7 @@ namespace EightBit
this.Tick();
if (this.displaced)
{
this.BusWrite(operand);
this.MemoryWrite(operand);
if (!memoryZ)
{
this.R2(z, operand);
@ -1120,13 +1120,13 @@ namespace EightBit
this.MEMPTR.Word = this.Bus.Address.Word = this.BC.Word;
++this.MEMPTR.Word;
this.MEMPTR.High = this.Bus.Data = this.A;
this.BusWrite();
this.MemoryWrite();
break;
case 1: // LD (DE),A
this.MEMPTR.Word = this.Bus.Address.Word = this.DE.Word;
++this.MEMPTR.Word;
this.MEMPTR.High = this.Bus.Data = this.A;
this.BusWrite();
this.MemoryWrite();
break;
case 2: // LD (nn),HL
this.Bus.Address.Word = this.FetchWord().Word;
@ -1136,7 +1136,7 @@ namespace EightBit
this.MEMPTR.Word = this.Bus.Address.Word = this.FetchWord().Word;
++this.MEMPTR.Word;
this.MEMPTR.High = this.Bus.Data = this.A;
this.BusWrite();
this.MemoryWrite();
break;
default:
throw new NotSupportedException("Invalid operation mode");
@ -1149,12 +1149,12 @@ namespace EightBit
case 0: // LD A,(BC)
this.MEMPTR.Word = this.Bus.Address.Word = this.BC.Word;
++this.MEMPTR.Word;
this.A = this.BusRead();
this.A = this.MemoryRead();
break;
case 1: // LD A,(DE)
this.MEMPTR.Word = this.Bus.Address.Word = this.DE.Word;
++this.MEMPTR.Word;
this.A = this.BusRead();
this.A = this.MemoryRead();
break;
case 2: // LD HL,(nn)
this.Bus.Address.Word = this.FetchWord().Word;
@ -1163,7 +1163,7 @@ namespace EightBit
case 3: // LD A,(nn)
this.MEMPTR.Word = this.Bus.Address.Word = this.FetchWord().Word;
++this.MEMPTR.Word;
this.A = this.BusRead();
this.A = this.MemoryRead();
break;
default:
throw new NotSupportedException("Invalid operation mode");
@ -1596,7 +1596,7 @@ namespace EightBit
{
this.Tick();
this.LowerM1();
var returned = this.BusRead(this.PC.Word);
var returned = this.MemoryRead(this.PC.Word);
this.RaiseM1();
this.Bus.Address.Low = this.REFRESH;
this.Bus.Address.High = this.IV;
@ -1929,20 +1929,20 @@ namespace EightBit
private void XHTL(Register16 exchange)
{
this.MEMPTR.Low = this.BusRead(this.SP.Word);
this.MEMPTR.Low = this.MemoryRead(this.SP.Word);
++this.Bus.Address.Word;
this.MEMPTR.High = this.BusRead();
this.MEMPTR.High = this.MemoryRead();
this.Tick();
this.BusWrite(exchange.High);
this.MemoryWrite(exchange.High);
exchange.High = this.MEMPTR.High;
--this.Bus.Address.Word;
this.BusWrite(exchange.Low);
this.MemoryWrite(exchange.Low);
exchange.Low = this.MEMPTR.Low;
}
private void BlockCompare(ushort source, ushort counter)
{
var value = this.BusRead(source);
var value = this.MemoryRead(source);
var result = (byte)(this.A - value);
this.F = SetBit(this.F, StatusBits.PF, counter);
@ -1983,8 +1983,8 @@ namespace EightBit
private void BlockLoad(ushort source, ushort destination, ushort counter)
{
var value = this.BusRead(source);
this.BusWrite(destination, value);
var value = this.MemoryRead(source);
this.MemoryWrite(destination, value);
var xy = this.A + value;
this.F = SetBit(this.F, StatusBits.XF, xy & (int)Bits.Bit3);
this.F = SetBit(this.F, StatusBits.YF, xy & (int)Bits.Bit1);
@ -2014,7 +2014,7 @@ namespace EightBit
this.Tick();
var value = this.ReadPort();
this.Tick(3);
this.BusWrite(destination, value);
this.MemoryWrite(destination, value);
source.High = this.Decrement(source.High);
this.F = SetBit(this.F, StatusBits.NF);
}
@ -2046,7 +2046,7 @@ namespace EightBit
private void BlockOut(ushort source, Register16 destination)
{
this.Tick();
var value = this.BusRead(source);
var value = this.MemoryRead(source);
destination.High = this.Decrement(destination.High);
this.Bus.Address.Word = destination.Word;
this.WritePort();
@ -2100,9 +2100,9 @@ namespace EightBit
{
this.MEMPTR.Word = this.Bus.Address.Word = this.HL.Word;
++this.MEMPTR.Word;
var memory = this.BusRead();
var memory = this.MemoryRead();
this.Tick(4);
this.BusWrite((byte)(PromoteNibble(this.A) | HighNibble(memory)));
this.MemoryWrite((byte)(PromoteNibble(this.A) | HighNibble(memory)));
this.A = (byte)(HigherNibble(this.A) | LowerNibble(memory));
this.F = AdjustSZPXY(this.F, this.A);
this.F = ClearBit(this.F, StatusBits.NF | StatusBits.HC);
@ -2112,9 +2112,9 @@ namespace EightBit
{
this.MEMPTR.Word = this.Bus.Address.Word = this.HL.Word;
++this.MEMPTR.Word;
var memory = this.BusRead();
var memory = this.MemoryRead();
this.Tick(4);
this.BusWrite((byte)(PromoteNibble(memory) | LowNibble(this.A)));
this.MemoryWrite((byte)(PromoteNibble(memory) | LowNibble(this.A)));
this.A = (byte)(HigherNibble(this.A) | HighNibble(memory));
this.F = AdjustSZPXY(this.F, this.A);
this.F = ClearBit(this.F, StatusBits.NF | StatusBits.HC);