mirror of
https://github.com/MoleskiCoder/EightBitNet.git
synced 2024-09-07 23:54:58 +00:00
Step can be split a little to make it easier to override.
This commit is contained in:
parent
e746f218e3
commit
c8ac0f20dc
@ -8,6 +8,15 @@ namespace EightBit
|
||||
|
||||
public abstract class Processor(Bus memory) : ClockedChip
|
||||
{
|
||||
#region Instruction execution events
|
||||
|
||||
public event EventHandler<EventArgs>? ExecutingInstruction;
|
||||
public event EventHandler<EventArgs>? ExecutedInstruction;
|
||||
protected virtual void OnExecutedInstruction() => this.ExecutedInstruction?.Invoke(this, EventArgs.Empty);
|
||||
protected virtual void OnExecutingInstruction() => this.ExecutingInstruction?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
#endregion
|
||||
|
||||
private PinLevel resetLine;
|
||||
private PinLevel intLine;
|
||||
|
||||
@ -49,7 +58,20 @@ namespace EightBit
|
||||
|
||||
public static sbyte SignExtend(int b, int x) => SignExtend(b, (byte)x);
|
||||
|
||||
public abstract int Step();
|
||||
public virtual int Step()
|
||||
{
|
||||
this.ResetCycles();
|
||||
this.OnExecutingInstruction();
|
||||
if (this.Powered)
|
||||
{
|
||||
this.PoweredStep();
|
||||
}
|
||||
|
||||
this.OnExecutedInstruction();
|
||||
return this.Cycles;
|
||||
}
|
||||
|
||||
public abstract void PoweredStep();
|
||||
|
||||
public abstract void Execute();
|
||||
|
||||
@ -186,7 +208,7 @@ namespace EightBit
|
||||
|
||||
protected virtual byte BusRead() => this.Bus.Read(); // N.B. Should be the only real call into the "Bus.Read" code.
|
||||
|
||||
protected byte FetchByte()
|
||||
protected virtual byte FetchByte()
|
||||
{
|
||||
this.Bus.Address.Assign(this.PC);
|
||||
this.PC.Word++;
|
||||
|
@ -17,10 +17,6 @@ namespace EightBit
|
||||
public Intel8080(Bus bus, InputOutput ports)
|
||||
: base(bus) => this.ports = ports;
|
||||
|
||||
public event EventHandler<EventArgs> ExecutingInstruction;
|
||||
|
||||
public event EventHandler<EventArgs> ExecutedInstruction;
|
||||
|
||||
public override Register16 AF
|
||||
{
|
||||
get
|
||||
@ -50,38 +46,26 @@ namespace EightBit
|
||||
this.Execute(x, y, z, p, q);
|
||||
}
|
||||
|
||||
public override int Step()
|
||||
public override void PoweredStep()
|
||||
{
|
||||
this.ResetCycles();
|
||||
this.OnExecutingInstruction();
|
||||
if (this.Powered)
|
||||
if (this.RESET.Lowered())
|
||||
{
|
||||
if (this.RESET.Lowered())
|
||||
{
|
||||
this.HandleRESET();
|
||||
}
|
||||
else if (this.INT.Lowered())
|
||||
{
|
||||
this.HandleINT();
|
||||
}
|
||||
else if (this.HALT.Lowered())
|
||||
{
|
||||
this.Execute(0); // NOP
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Execute(this.FetchByte());
|
||||
}
|
||||
this.HandleRESET();
|
||||
}
|
||||
else if (this.INT.Lowered())
|
||||
{
|
||||
this.HandleINT();
|
||||
}
|
||||
else if (this.HALT.Lowered())
|
||||
{
|
||||
this.Execute(0); // NOP
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Execute(this.FetchByte());
|
||||
}
|
||||
|
||||
this.OnExecutedInstruction();
|
||||
return this.Cycles;
|
||||
}
|
||||
|
||||
protected virtual void OnExecutingInstruction() => this.ExecutingInstruction?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
protected virtual void OnExecutedInstruction() => this.ExecutedInstruction?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
protected override void HandleRESET()
|
||||
{
|
||||
base.HandleRESET();
|
||||
|
@ -15,10 +15,6 @@ namespace EightBit.GameBoy
|
||||
public LR35902(Bus bus)
|
||||
: base(bus) => this.bus = bus;
|
||||
|
||||
public event EventHandler<EventArgs> ExecutingInstruction;
|
||||
|
||||
public event EventHandler<EventArgs> ExecutedInstruction;
|
||||
|
||||
public int ClockCycles => this.Cycles * 4;
|
||||
|
||||
public override Register16 AF
|
||||
@ -63,61 +59,50 @@ namespace EightBit.GameBoy
|
||||
System.Diagnostics.Debug.Assert(this.Cycles > 0, $"No timing associated with instruction (CB prefixed? {this.prefixCB}) 0x{this.OpCode:X2}");
|
||||
}
|
||||
|
||||
public override int Step()
|
||||
public override void PoweredStep()
|
||||
{
|
||||
this.OnExecutingInstruction();
|
||||
this.prefixCB = false;
|
||||
this.ResetCycles();
|
||||
if (this.Powered)
|
||||
|
||||
var interruptEnable = this.Bus.Peek(IoRegisters.BASE + IoRegisters.IE);
|
||||
var interruptFlags = this.bus.IO.Peek(IoRegisters.IF);
|
||||
|
||||
var masked = interruptEnable & interruptFlags;
|
||||
if (masked != 0)
|
||||
{
|
||||
var interruptEnable = this.Bus.Peek(IoRegisters.BASE + IoRegisters.IE);
|
||||
var interruptFlags = this.bus.IO.Peek(IoRegisters.IF);
|
||||
|
||||
var masked = interruptEnable & interruptFlags;
|
||||
if (masked != 0)
|
||||
if (this.IME)
|
||||
{
|
||||
if (this.IME)
|
||||
{
|
||||
this.bus.IO.Poke(IoRegisters.IF, 0);
|
||||
this.LowerINT();
|
||||
var index = Chip.FindFirstSet(masked);
|
||||
this.Bus.Data = (byte)(0x38 + (index << 3));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.RaiseHALT();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.RESET.Lowered())
|
||||
{
|
||||
this.HandleRESET();
|
||||
}
|
||||
else if (this.INT.Lowered())
|
||||
{
|
||||
this.HandleINT();
|
||||
}
|
||||
else if (this.HALT.Lowered())
|
||||
{
|
||||
this.Execute(0); // NOP
|
||||
this.bus.IO.Poke(IoRegisters.IF, 0);
|
||||
this.LowerINT();
|
||||
var index = Chip.FindFirstSet(masked);
|
||||
this.Bus.Data = (byte)(0x38 + (index << 3));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Execute(this.FetchByte());
|
||||
this.RaiseHALT();
|
||||
}
|
||||
|
||||
this.bus.IO.CheckTimers(this.ClockCycles);
|
||||
this.bus.IO.TransferDma();
|
||||
}
|
||||
|
||||
this.OnExecutedInstruction();
|
||||
return this.ClockCycles;
|
||||
if (this.RESET.Lowered())
|
||||
{
|
||||
this.HandleRESET();
|
||||
}
|
||||
else if (this.INT.Lowered())
|
||||
{
|
||||
this.HandleINT();
|
||||
}
|
||||
else if (this.HALT.Lowered())
|
||||
{
|
||||
this.Execute(0); // NOP
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Execute(this.FetchByte());
|
||||
}
|
||||
|
||||
this.bus.IO.CheckTimers(this.ClockCycles);
|
||||
this.bus.IO.TransferDma();
|
||||
}
|
||||
|
||||
protected virtual void OnExecutingInstruction() => this.ExecutingInstruction?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
protected virtual void OnExecutedInstruction() => this.ExecutedInstruction?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
protected override void HandleRESET()
|
||||
{
|
||||
base.HandleRESET();
|
||||
|
@ -52,14 +52,14 @@ namespace EightBit
|
||||
|
||||
case 0x42: this.Jam(); break; // *JAM
|
||||
case 0x43: this.IndexedIndirectXRead(); this.SRE(); break; // *SRE (indexed indirect X)
|
||||
case 0x44: this.ZeroPageRead(); break; // *NOP (zero page)
|
||||
//case 0x44: this.ZeroPageRead(); break; // *NOP (zero page)
|
||||
case 0x47: this.ZeroPageRead(); this.SRE(); break; // *SRE (zero page)
|
||||
case 0x4b: this.ImmediateRead(); this.ASR(); break; // *ASR (immediate)
|
||||
case 0x4f: this.AbsoluteRead(); this.SRE(); break; // *SRE (absolute)
|
||||
|
||||
case 0x52: this.Jam(); break; // *JAM
|
||||
case 0x53: this.IndirectIndexedYAddress(); this.FixupRead(); this.SRE(); break; // *SRE (indirect indexed Y)
|
||||
case 0x54: this.ZeroPageXRead(); break; // *NOP (zero page, X)
|
||||
//case 0x54: this.ZeroPageXRead(); break; // *NOP (zero page, X)
|
||||
case 0x57: this.ZeroPageXRead(); this.SRE(); break; // *SRE (zero page, X)
|
||||
case 0x5a: this.SwallowRead(); break; // *NOP (implied)
|
||||
case 0x5b: this.AbsoluteYAddress(); this.FixupRead(); this.SRE(); break; // *SRE (absolute, Y)
|
||||
@ -83,7 +83,7 @@ namespace EightBit
|
||||
case 0x7f: this.AbsoluteXAddress(); this.FixupRead(); this.RRA(); break; // *RRA (absolute, X)
|
||||
|
||||
case 0x80: this.ImmediateRead(); break; // *NOP (immediate)
|
||||
case 0x82: this.ImmediateRead(); break; // *NOP (immediate)
|
||||
//case 0x82: this.ImmediateRead(); break; // *NOP (immediate)
|
||||
case 0x83: this.IndexedIndirectXAddress(); this.MemoryWrite((byte)(this.A & this.X)); break; // *SAX (indexed indirect X)
|
||||
case 0x87: this.ZeroPageAddress(); this.MemoryWrite((byte)(this.A & this.X)); break; // *SAX (zero page)
|
||||
case 0x89: this.ImmediateRead(); break; // *NOP (immediate)
|
||||
@ -109,7 +109,7 @@ namespace EightBit
|
||||
case 0xbb: this.AbsoluteYAddress(); this.MaybeFixup(); this.LAS(); break; // *LAS (absolute, Y)
|
||||
case 0xbf: this.AbsoluteYRead(); this.A = this.X = this.Through(); break; // *LAX (absolute, Y)
|
||||
|
||||
case 0xc2: this.ImmediateRead(); break; // *NOP (immediate)
|
||||
//case 0xc2: this.ImmediateRead(); break; // *NOP (immediate)
|
||||
case 0xc3: this.IndexedIndirectXRead(); this.DCP(); break; // *DCP (indexed indirect X)
|
||||
case 0xc7: this.ZeroPageRead(); this.DCP(); break; // *DCP (zero page)
|
||||
case 0xcb: this.ImmediateRead(); this.AXS(); break; // *AXS (immediate)
|
||||
@ -117,14 +117,14 @@ namespace EightBit
|
||||
|
||||
case 0xd2: this.Jam(); break; // *JAM
|
||||
case 0xd3: this.IndirectIndexedYAddress(); this.FixupRead(); this.DCP(); break; // *DCP (indirect indexed Y)
|
||||
case 0xd4: this.ZeroPageXRead(); break; // *NOP (zero page, X)
|
||||
//case 0xd4: this.ZeroPageXRead(); break; // *NOP (zero page, X)
|
||||
case 0xd7: this.ZeroPageXRead(); this.DCP(); break; // *DCP (zero page, X)
|
||||
case 0xda: this.SwallowRead(); break; // *NOP (implied)
|
||||
case 0xdb: this.AbsoluteYAddress(); this.FixupRead(); this.DCP(); break; // *DCP (absolute, Y)
|
||||
case 0xdc: this.AbsoluteXAddress(); this.MaybeFixupRead(); break; // *NOP (absolute, X)
|
||||
case 0xdf: this.AbsoluteXAddress(); this.FixupRead(); this.DCP(); break; // *DCP (absolute, X)
|
||||
|
||||
case 0xe2: this.ImmediateRead(); break; // *NOP (immediate)
|
||||
//case 0xe2: this.ImmediateRead(); break; // *NOP (immediate)
|
||||
case 0xe3: this.IndexedIndirectXRead(); this.ISB(); break; // *ISB (indexed indirect X)
|
||||
case 0xe7: this.ZeroPageRead(); this.ISB(); break; // *ISB (zero page)
|
||||
case 0xeb: this.ImmediateRead(); this.SBC(); break; // *SBC (immediate)
|
||||
@ -132,7 +132,7 @@ namespace EightBit
|
||||
|
||||
case 0xf2: this.Jam(); break; // *JAM
|
||||
case 0xf3: this.IndirectIndexedYAddress(); this.FixupRead(); this.ISB(); break; // *ISB (indirect indexed Y)
|
||||
case 0xf4: this.ZeroPageXRead(); break; // *NOP (zero page, X)
|
||||
//case 0xf4: this.ZeroPageXRead(); break; // *NOP (zero page, X)
|
||||
case 0xf7: this.ZeroPageXRead(); this.ISB(); break; // *ISB (zero page, X)
|
||||
case 0xfa: this.SwallowRead(); break; // *NOP (implied)
|
||||
case 0xfb: this.AbsoluteYAddress(); this.FixupRead(); this.ISB(); break; // *ISB (absolute, Y)
|
||||
|
@ -6,15 +6,6 @@ namespace EightBit
|
||||
{
|
||||
public abstract class M6502Core(Bus bus) : LittleEndianProcessor(bus)
|
||||
{
|
||||
#region Instruction execution events
|
||||
|
||||
public event EventHandler<EventArgs>? ExecutingInstruction;
|
||||
public event EventHandler<EventArgs>? ExecutedInstruction;
|
||||
protected virtual void OnExecutedInstruction() => this.ExecutedInstruction?.Invoke(this, EventArgs.Empty);
|
||||
protected virtual void OnExecutingInstruction() => this.ExecutingInstruction?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Pin controls
|
||||
|
||||
#region NMI pin
|
||||
@ -403,6 +394,7 @@ namespace EightBit
|
||||
|
||||
case 0x40: this.SwallowRead(); this.RTI(); break; // RTI (implied)
|
||||
case 0x41: this.IndexedIndirectXRead(); this.EorR(); break; // EOR (indexed indirect X)
|
||||
case 0x44: this.ZeroPageRead(); break; // *NOP (zero page)
|
||||
case 0x45: this.ZeroPageRead(); this.EorR(); break; // EOR (zero page)
|
||||
case 0x46: this.ZeroPageRead(); this.ModifyWrite(this.LSR()); break; // LSR (zero page)
|
||||
case 0x48: this.SwallowRead(); this.Push(this.A); break; // PHA (implied)
|
||||
@ -414,6 +406,7 @@ namespace EightBit
|
||||
|
||||
case 0x50: this.BranchNot(this.Overflow); break; // BVC (relative)
|
||||
case 0x51: this.IndirectIndexedYRead(); this.EorR(); break; // EOR (indirect indexed Y)
|
||||
case 0x54: this.ZeroPageXRead(); break; // *NOP (zero page, X)
|
||||
case 0x55: this.ZeroPageXRead(); this.EorR(); break; // EOR (zero page, X)
|
||||
case 0x56: this.ZeroPageXRead(); this.ModifyWrite(this.LSR()); break; // LSR (zero page, X)
|
||||
case 0x58: this.SwallowRead(); this.ResetFlag(StatusBits.IF); break; // CLI (implied)
|
||||
@ -441,7 +434,8 @@ namespace EightBit
|
||||
case 0x7d: this.AbsoluteXRead(); this.ADC(); break; // ADC (absolute, X)
|
||||
case 0x7e: this.AbsoluteXAddress(); this.FixupRead(); this.ModifyWrite(this.ROR()); break; // ROR (absolute, X)
|
||||
|
||||
case 0x81: this.IndexedIndirectXAddress(); this.MemoryWrite(A); break; // STA (indexed indirect X)
|
||||
case 0x81: this.IndexedIndirectXAddress(); this.MemoryWrite(this.A); break; // STA (indexed indirect X)
|
||||
case 0x82: this.ImmediateRead(); break; // *NOP (immediate)
|
||||
case 0x84: this.ZeroPageAddress(); this.MemoryWrite(this.Y); break; // STY (zero page)
|
||||
case 0x85: this.ZeroPageAddress(); this.MemoryWrite(this.A); break; // STA (zero page)
|
||||
case 0x86: this.ZeroPageAddress(); this.MemoryWrite(this.X); break; // STX (zero page)
|
||||
@ -488,6 +482,7 @@ namespace EightBit
|
||||
|
||||
case 0xc0: this.ImmediateRead(); this.CMP(this.Y); break; // CPY (immediate)
|
||||
case 0xc1: this.IndexedIndirectXRead(); this.CMP(this.A); break; // CMP (indexed indirect X)
|
||||
case 0xc2: this.ImmediateRead(); break; // *NOP (immediate)
|
||||
case 0xc4: this.ZeroPageRead(); this.CMP(this.Y); break; // CPY (zero page)
|
||||
case 0xc5: this.ZeroPageRead(); this.CMP(this.A); break; // CMP (zero page)
|
||||
case 0xc6: this.ZeroPageRead(); this.ModifyWrite(this.DEC()); break; // DEC (zero page)
|
||||
@ -500,6 +495,7 @@ namespace EightBit
|
||||
|
||||
case 0xd0: this.BranchNot(this.Zero); break; // BNE (relative)
|
||||
case 0xd1: this.IndirectIndexedYRead(); this.CMP(this.A); break; // CMP (indirect indexed Y)
|
||||
case 0xd4: this.ZeroPageXRead(); break; // *NOP (zero page, X)
|
||||
case 0xd5: this.ZeroPageXRead(); this.CMP(this.A); break; // CMP (zero page, X)
|
||||
case 0xd6: this.ZeroPageXRead(); this.ModifyWrite(this.DEC()); break; // DEC (zero page, X)
|
||||
case 0xd8: this.SwallowRead(); this.ResetFlag(StatusBits.DF); break; // CLD (implied)
|
||||
@ -509,6 +505,7 @@ namespace EightBit
|
||||
|
||||
case 0xe0: this.ImmediateRead(); this.CMP(this.X); break; // CPX (immediate)
|
||||
case 0xe1: this.IndexedIndirectXRead(); this.SBC(); break; // SBC (indexed indirect X)
|
||||
case 0xe2: this.ImmediateRead(); break; // *NOP (immediate)
|
||||
case 0xe4: this.ZeroPageRead(); this.CMP(this.X); break; // CPX (zero page)
|
||||
case 0xe5: this.ZeroPageRead(); this.SBC(); break; // SBC (zero page)
|
||||
case 0xe6: this.ZeroPageRead(); this.ModifyWrite(INC()); break; // INC (zero page)
|
||||
@ -521,6 +518,7 @@ namespace EightBit
|
||||
|
||||
case 0xf0: this.Branch(this.Zero); break; // BEQ (relative)
|
||||
case 0xf1: this.IndirectIndexedYRead(); this.SBC(); break; // SBC (indirect indexed Y)
|
||||
case 0xf4: this.ZeroPageXRead(); break; // *NOP (zero page, X)
|
||||
case 0xf5: this.ZeroPageXRead(); this.SBC(); break; // SBC (zero page, X)
|
||||
case 0xf6: this.ZeroPageXRead(); this.ModifyWrite(this.INC()); break; // INC (zero page, X)
|
||||
case 0xf8: this.SwallowRead(); this.SetFlag(StatusBits.DF); break; // SED (implied)
|
||||
@ -532,42 +530,34 @@ namespace EightBit
|
||||
return cycles != this.Cycles;
|
||||
}
|
||||
|
||||
public override int Step()
|
||||
public override void PoweredStep()
|
||||
{
|
||||
this.ResetCycles();
|
||||
this.OnExecutingInstruction();
|
||||
if (this.Powered)
|
||||
this.Tick();
|
||||
if (this.SO.Lowered())
|
||||
{
|
||||
this.Tick();
|
||||
if (this.SO.Lowered())
|
||||
{
|
||||
this.HandleSO();
|
||||
}
|
||||
|
||||
if (this.RDY.Raised())
|
||||
{
|
||||
this.FetchInstruction();
|
||||
if (this.RESET.Lowered())
|
||||
{
|
||||
this.HandleRESET();
|
||||
}
|
||||
else if (this.NMI.Lowered())
|
||||
{
|
||||
this.HandleNMI();
|
||||
}
|
||||
else if (this.INT.Lowered() && (this.InterruptMasked == 0))
|
||||
{
|
||||
this.HandleINT();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Execute();
|
||||
}
|
||||
}
|
||||
this.HandleSO();
|
||||
}
|
||||
|
||||
this.OnExecutedInstruction();
|
||||
return this.Cycles;
|
||||
if (this.RDY.Raised())
|
||||
{
|
||||
this.FetchInstruction();
|
||||
if (this.RESET.Lowered())
|
||||
{
|
||||
this.HandleRESET();
|
||||
}
|
||||
else if (this.NMI.Lowered())
|
||||
{
|
||||
this.HandleNMI();
|
||||
}
|
||||
else if (this.INT.Lowered() && (this.InterruptMasked == 0))
|
||||
{
|
||||
this.HandleINT();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FetchInstruction()
|
||||
|
133
M6502/W65C02.cs
133
M6502/W65C02.cs
@ -6,6 +6,9 @@ namespace EightBit
|
||||
{
|
||||
public class W65C02(Bus bus) : M6502Core(bus)
|
||||
{
|
||||
private bool _stopped = false;
|
||||
private bool _waiting = false;
|
||||
|
||||
#region Interrupts
|
||||
|
||||
protected override void Interrupt(byte vector, InterruptSource source, InterruptType type)
|
||||
@ -25,7 +28,125 @@ namespace EightBit
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
var cycles = this.Cycles;
|
||||
switch (this.OpCode)
|
||||
{
|
||||
case 0x02: this.SwallowFetch(); break; // *NOP
|
||||
case 0x03: break; // null
|
||||
case 0x04: break; // TSB zp
|
||||
case 0x07: break; // RMB0 zp
|
||||
case 0x0b: break; // null
|
||||
case 0x0c: break; // TSB a
|
||||
case 0x0f: break; // BBR0 r
|
||||
|
||||
case 0x12: this.ZeroPageIndirectAddress(); this.OrR(); break; // ORA (zp),y
|
||||
case 0x13: break; // null
|
||||
case 0x14: break; // TRB zp
|
||||
case 0x17: break; // RMB1 zp
|
||||
case 0x1a: this.SwallowRead(); this.A = this.INC(this.A); break; // INC A
|
||||
case 0x1b: break; // null
|
||||
case 0x1c: break; // TRB a
|
||||
case 0x1f: break; // BBR1 r
|
||||
|
||||
case 0x22: this.SwallowFetch(); break; // *NOP
|
||||
case 0x23: break; // null
|
||||
case 0x27: break; // RMB2 zp
|
||||
case 0x2b: break; // null
|
||||
case 0x2f: break; // BBR2 r
|
||||
|
||||
case 0x32: this.ZeroPageIndirectRead(); this.AndR(); break; // AND (zp)
|
||||
case 0x33: break; // null
|
||||
case 0x34: break; // BIT zp,x
|
||||
case 0x37: break; // RMB3 zp
|
||||
case 0x3a: this.SwallowRead(); this.A = this.DEC(this.A); break; // DEC A
|
||||
case 0x3b: break; // null
|
||||
case 0x3c: break; // BIT a,x
|
||||
case 0x3f: break; // BBR3 r
|
||||
|
||||
case 0x42: this.SwallowFetch(); break; // *NOP
|
||||
case 0x43: break; // null
|
||||
case 0x47: break; // RMB4 zp
|
||||
case 0x4b: break; // null
|
||||
case 0x4f: break; // BBR4 r
|
||||
|
||||
case 0x52: this.ZeroPageIndirectRead(); this.EorR(); break; // EOR (zp)
|
||||
case 0x53: break; // null
|
||||
case 0x57: break; // RMB5 zp
|
||||
case 0x5a: this.SwallowRead(); this.Push(this.Y); break; // PHY s
|
||||
case 0x5b: break; // null
|
||||
case 0x5c: break; // null
|
||||
case 0x5f: break; // BBR5 r
|
||||
|
||||
case 0x62: this.SwallowFetch(); break; // *NOP
|
||||
case 0x63: break; // null
|
||||
case 0x64: this.ZeroPageAddress(); this.MemoryWrite(0); break; // STZ zp
|
||||
case 0x67: break; // RMB6 zp
|
||||
case 0x6b: break; // null
|
||||
case 0x6f: break; // BBR6 r
|
||||
|
||||
case 0x72: this.ZeroPageIndirectRead(); this.ADC(); break; // ADC (zp)
|
||||
case 0x73: break; // null
|
||||
case 0x74: this.ZeroPageXAddress(); this.MemoryWrite(0); break; // STZ zp,x
|
||||
case 0x77: break; // RMB7 zp
|
||||
case 0x7a: this.SwallowRead(); this.SwallowPop(); this.Y = this.Through(this.Pop()); break; // PLY s
|
||||
case 0x7b: break; // null
|
||||
case 0x7c: break; // JMP (a,x)
|
||||
case 0x7f: break; // BBR7 r
|
||||
|
||||
case 0x80: break; // BRA r
|
||||
case 0x83: break; // null
|
||||
case 0x87: break; // SMB0 zp
|
||||
case 0x89: break; // BIT # (TBC)
|
||||
case 0x8b: break; // null
|
||||
case 0x8f: break; // BBS0 r
|
||||
|
||||
case 0x92: ZeroPageIndirectAddress(); this.MemoryWrite(this.A); break; // STA (zp)
|
||||
case 0x93: break; // null
|
||||
case 0x97: break; // SMB1 zp
|
||||
case 0x9b: break; // null
|
||||
case 0x9c: this.AbsoluteAddress(); this.MemoryWrite(0); break; // STZ a
|
||||
case 0x9e: this.AbsoluteXAddress(); this.MemoryWrite(0); break; // STZ a,x
|
||||
case 0x9f: break; // BBS1 r
|
||||
|
||||
case 0xa3: break; // null
|
||||
case 0xa7: break; // SMB2 zp
|
||||
case 0xab: break; // null
|
||||
case 0xaf: break; // BBS2 r
|
||||
|
||||
case 0xb2: ZeroPageIndirectRead(); this.A = this.Through(); break; // LDA (zp)
|
||||
case 0xb3: break; // null
|
||||
case 0xb7: break; // SMB3 zp
|
||||
case 0xbb: break; // null
|
||||
case 0xbf: break; // BBS3 r
|
||||
|
||||
case 0xc3: break; // null
|
||||
case 0xc7: break; // SMB4 zp
|
||||
case 0xcb: this.SwallowRead(); this._waiting = true; break; // WAI i
|
||||
case 0xcf: break; // BBS4 r
|
||||
|
||||
case 0xd2: this.ZeroPageIndirectRead(); this.CMP(this.A); break; // CMP (zp)
|
||||
case 0xd3: break; // null
|
||||
case 0xd7: break; // SMB5 zp
|
||||
case 0xda: this.SwallowRead(); this.Push(this.X); break; // PHX s
|
||||
case 0xdb: this.SwallowRead(); this._stopped = true; break; // STP i
|
||||
case 0xdc: break; // null
|
||||
case 0xdf: break; // BBS5 r
|
||||
|
||||
case 0xe3: break; // null
|
||||
case 0xe7: break; // SMB6 zp
|
||||
case 0xeb: break; // null
|
||||
case 0xef: break; // BBS6 r
|
||||
|
||||
case 0xf2: this.ZeroPageIndirectRead(); this.SBC(); break; // SBC (zp)
|
||||
case 0xf3: break; // null
|
||||
case 0xf7: break; // SMB7 zp
|
||||
case 0xfa: this.SwallowRead(); this.SwallowPop(); this.X = this.Through(this.Pop()); break; // PLX s
|
||||
case 0xfb: break; // null
|
||||
case 0xfc: break; // null
|
||||
case 0xff: break; // BBS7 r
|
||||
}
|
||||
|
||||
return cycles != this.Cycles;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -91,6 +212,16 @@ namespace EightBit
|
||||
|
||||
#endregion
|
||||
|
||||
#region Address and read
|
||||
|
||||
private void ZeroPageIndirectRead()
|
||||
{
|
||||
this.ZeroPageIndirectAddress();
|
||||
this.MemoryRead();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -50,10 +50,6 @@ namespace EightBit
|
||||
{
|
||||
}
|
||||
|
||||
public event EventHandler<EventArgs> ExecutingInstruction;
|
||||
|
||||
public event EventHandler<EventArgs> ExecutedInstruction;
|
||||
|
||||
public event EventHandler<EventArgs> RaisingNMI;
|
||||
|
||||
public event EventHandler<EventArgs> RaisedNMI;
|
||||
@ -174,41 +170,33 @@ namespace EightBit
|
||||
this.RaiseHALT();
|
||||
}
|
||||
|
||||
public override int Step()
|
||||
public override void PoweredStep()
|
||||
{
|
||||
this.ResetCycles();
|
||||
this.OnExecutingInstruction();
|
||||
if (this.Powered)
|
||||
this.prefix10 = this.prefix11 = false;
|
||||
if (this.Halted)
|
||||
{
|
||||
this.prefix10 = this.prefix11 = false;
|
||||
if (this.Halted)
|
||||
{
|
||||
this.HandleHALT();
|
||||
}
|
||||
else if (this.RESET.Lowered())
|
||||
{
|
||||
this.HandleRESET();
|
||||
}
|
||||
else if (this.NMI.Lowered())
|
||||
{
|
||||
this.HandleNMI();
|
||||
}
|
||||
else if (this.FIRQ.Lowered() && (this.FastInterruptMasked == 0))
|
||||
{
|
||||
this.HandleFIRQ();
|
||||
}
|
||||
else if (this.INT.Lowered() && (this.InterruptMasked == 0))
|
||||
{
|
||||
this.HandleINT();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Execute(this.FetchByte());
|
||||
}
|
||||
this.HandleHALT();
|
||||
}
|
||||
else if (this.RESET.Lowered())
|
||||
{
|
||||
this.HandleRESET();
|
||||
}
|
||||
else if (this.NMI.Lowered())
|
||||
{
|
||||
this.HandleNMI();
|
||||
}
|
||||
else if (this.FIRQ.Lowered() && (this.FastInterruptMasked == 0))
|
||||
{
|
||||
this.HandleFIRQ();
|
||||
}
|
||||
else if (this.INT.Lowered() && (this.InterruptMasked == 0))
|
||||
{
|
||||
this.HandleINT();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Execute(this.FetchByte());
|
||||
}
|
||||
|
||||
this.OnExecutedInstruction();
|
||||
return this.Cycles;
|
||||
}
|
||||
|
||||
public override void Execute()
|
||||
@ -490,10 +478,6 @@ namespace EightBit
|
||||
|
||||
private void OnLoweredRW() => this.LoweredRW?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
private void OnExecutingInstruction() => this.ExecutingInstruction?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
private void OnExecutedInstruction() => this.ExecutedInstruction?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
private void Push(Register16 stack, byte value) => this.MemoryWrite(--stack.Word, value);
|
||||
|
||||
private void PushS(byte value) => this.Push(this.S, value);
|
||||
|
100
Z80/Z80.cs
100
Z80/Z80.cs
@ -42,10 +42,6 @@ namespace EightBit
|
||||
private sbyte displacement = 0;
|
||||
private bool displaced = false;
|
||||
|
||||
public event EventHandler<EventArgs>? ExecutingInstruction;
|
||||
|
||||
public event EventHandler<EventArgs>? ExecutedInstruction;
|
||||
|
||||
public event EventHandler<EventArgs>? RaisingNMI;
|
||||
|
||||
public event EventHandler<EventArgs>? RaisedNMI;
|
||||
@ -340,63 +336,55 @@ namespace EightBit
|
||||
}
|
||||
}
|
||||
|
||||
public override int Step()
|
||||
public override void PoweredStep()
|
||||
{
|
||||
this.ResetCycles();
|
||||
this.OnExecutingInstruction();
|
||||
if (this.Powered)
|
||||
this.displaced = this.prefixCB = this.prefixDD = this.prefixED = this.prefixFD = false;
|
||||
var handled = false;
|
||||
if (this.RESET.Lowered())
|
||||
{
|
||||
this.displaced = this.prefixCB = this.prefixDD = this.prefixED = this.prefixFD = false;
|
||||
var handled = false;
|
||||
if (this.RESET.Lowered())
|
||||
this.HandleRESET();
|
||||
handled = true;
|
||||
}
|
||||
else if (this.NMI.Lowered())
|
||||
{
|
||||
this.HandleNMI();
|
||||
handled = true;
|
||||
}
|
||||
else if (this.INT.Lowered())
|
||||
{
|
||||
this.RaiseINT();
|
||||
this.RaiseHALT();
|
||||
if (this.IFF1)
|
||||
{
|
||||
this.HandleRESET();
|
||||
this.HandleINT();
|
||||
handled = true;
|
||||
}
|
||||
else if (this.NMI.Lowered())
|
||||
{
|
||||
this.HandleNMI();
|
||||
handled = true;
|
||||
}
|
||||
else if (this.INT.Lowered())
|
||||
{
|
||||
this.RaiseINT();
|
||||
this.RaiseHALT();
|
||||
if (this.IFF1)
|
||||
{
|
||||
this.HandleINT();
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
else if (this.HALT.Lowered())
|
||||
{
|
||||
// ** From the Z80 CPU User Manual
|
||||
// When a software HALT instruction is executed, the CPU executes NOPs until an interrupt
|
||||
// is received(either a nonmaskable or a maskable interrupt while the interrupt flip-flop is
|
||||
// enabled). The two interrupt lines are sampled with the rising clock edge during each T4
|
||||
// state as depicted in Figure 11.If a nonmaskable interrupt is received or a maskable interrupt
|
||||
// is received and the interrupt enable flip-flop is set, then the HALT state is exited on
|
||||
// the next rising clock edge.The following cycle is an interrupt acknowledge cycle corresponding
|
||||
// to the type of interrupt that was received.If both are received at this time, then
|
||||
// the nonmaskable interrupt is acknowledged because it is the highest priority.The purpose
|
||||
// of executing NOP instructions while in the HALT state is to keep the memory refresh signals
|
||||
// active.Each cycle in the HALT state is a normal M1(fetch) cycle except that the data
|
||||
// received from the memory is ignored and an NOP instruction is forced internally to the
|
||||
// CPU.The HALT acknowledge signal is active during this time indicating that the processor
|
||||
// is in the HALT state.
|
||||
_ = this.ReadInitialOpCode();
|
||||
this.Execute(0); // NOP
|
||||
handled = true;
|
||||
}
|
||||
|
||||
if (!handled)
|
||||
{
|
||||
this.Execute(this.FetchInitialOpCode());
|
||||
}
|
||||
}
|
||||
else if (this.HALT.Lowered())
|
||||
{
|
||||
// ** From the Z80 CPU User Manual
|
||||
// When a software HALT instruction is executed, the CPU executes NOPs until an interrupt
|
||||
// is received(either a nonmaskable or a maskable interrupt while the interrupt flip-flop is
|
||||
// enabled). The two interrupt lines are sampled with the rising clock edge during each T4
|
||||
// state as depicted in Figure 11.If a nonmaskable interrupt is received or a maskable interrupt
|
||||
// is received and the interrupt enable flip-flop is set, then the HALT state is exited on
|
||||
// the next rising clock edge.The following cycle is an interrupt acknowledge cycle corresponding
|
||||
// to the type of interrupt that was received.If both are received at this time, then
|
||||
// the nonmaskable interrupt is acknowledged because it is the highest priority.The purpose
|
||||
// of executing NOP instructions while in the HALT state is to keep the memory refresh signals
|
||||
// active.Each cycle in the HALT state is a normal M1(fetch) cycle except that the data
|
||||
// received from the memory is ignored and an NOP instruction is forced internally to the
|
||||
// CPU.The HALT acknowledge signal is active during this time indicating that the processor
|
||||
// is in the HALT state.
|
||||
_ = this.ReadInitialOpCode();
|
||||
this.Execute(0); // NOP
|
||||
handled = true;
|
||||
}
|
||||
|
||||
this.OnExecutedInstruction();
|
||||
return this.Cycles;
|
||||
if (!handled)
|
||||
{
|
||||
this.Execute(this.FetchInitialOpCode());
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRaisedPOWER()
|
||||
@ -423,10 +411,6 @@ namespace EightBit
|
||||
base.OnRaisedPOWER();
|
||||
}
|
||||
|
||||
protected virtual void OnExecutingInstruction() => this.ExecutingInstruction?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
protected virtual void OnExecutedInstruction() => this.ExecutedInstruction?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
protected virtual void OnRaisingNMI() => this.RaisingNMI?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
protected virtual void OnRaisedNMI() => this.RaisedNMI?.Invoke(this, EventArgs.Empty);
|
||||
|
Loading…
Reference in New Issue
Block a user