summaryrefslogtreecommitdiff
path: root/src/Noddybox.Emulation.EightBit.Z80
diff options
context:
space:
mode:
Diffstat (limited to 'src/Noddybox.Emulation.EightBit.Z80')
-rw-r--r--src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs104
-rw-r--r--src/Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs2
-rw-r--r--src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeByte.cs2
-rw-r--r--src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeCB.cs2
-rw-r--r--src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeED.cs399
-rw-r--r--src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeShiftedCB.cs2
-rw-r--r--src/Noddybox.Emulation.EightBit.Z80/Z80CpuEventArgs.cs87
-rw-r--r--src/Noddybox.Emulation.EightBit.Z80/Z80Flags.cs83
8 files changed, 661 insertions, 20 deletions
diff --git a/src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs b/src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs
index 78f0bfa..f937ea9 100644
--- a/src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs
+++ b/src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs
@@ -11,7 +11,7 @@
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
-// along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+// along with Noddybox.Emulation. If not, see <http://www.gnu.org/licenses/>.
//
// Copyright (c) 2012 Ian Cowburn
//
@@ -26,20 +26,11 @@ namespace Noddybox.Emulation.EightBit.Z80
{
#region Private types
- [Flags]
- private enum Z80Flags
+ private enum EventType
{
- None = 0x00,
- Carry = 0x01,
- Neg = 0x02,
- PV = 0x04,
- Hidden3 = 0x08,
- HalfCarry = 0x10,
- Hidden5 = 0x20,
- Zero = 0x40,
- Sign = 0x80,
- Hidden = Hidden3 | Hidden5
- };
+ HALT,
+ EDHook
+ }
#endregion
@@ -295,5 +286,90 @@ namespace Noddybox.Emulation.EightBit.Z80
}
#endregion
+
+ #region Events
+
+ /// <summary>
+ /// The CPU has been halted.
+ /// </summary>
+ public event EventHandler<Z80CpuEventArgs> HaltEvent;
+
+ /// <summary>
+ /// A no-operation ED opcode has been executed. Useful for placing
+ /// hooks into the Z80 code.
+ /// </summary>
+ public event EventHandler<Z80CpuEventArgs> EDNopEvent;
+
+ /// <summary>
+ /// Called to raise <see cref="HaltEvent"/>
+ /// </summary>
+ /// <param name="e">The event arguments.</param>
+ protected void OnHaltEvent(Z80CpuEventArgs e)
+ {
+ EventHandler<Z80CpuEventArgs> handler = HaltEvent;
+
+ if (handler != null)
+ {
+ handler(this, e);
+ }
+ }
+
+ /// <summary>
+ /// Called to raise <see cref="EDNopEvent"/>
+ /// </summary>
+ /// <param name="e">The event arguments.</param>
+ protected void OnEDNopEvent(Z80CpuEventArgs e)
+ {
+ EventHandler<Z80CpuEventArgs> handler = EDNopEvent;
+
+ if (handler != null)
+ {
+ handler(this, e);
+ }
+ }
+
+ private void TriggerEvent(EventType type, byte opcode)
+ {
+ Z80CpuEventArgs e = new Z80CpuEventArgs
+ {
+ Opcode = opcode,
+ A = this.A,
+ F = this.F,
+ BC = this.BC,
+ DE = this.DE,
+ HL = this.HL,
+ SP = this.SP,
+ PC = this.PC,
+ AF_ = this.AF_,
+ BC_ = this.BC_,
+ DE_ = this.DE_,
+ HL_ = this.HL_
+ };
+
+ switch(type)
+ {
+ case EventType.HALT:
+ OnHaltEvent(e);
+ break;
+
+ case EventType.EDHook:
+ OnEDNopEvent(e);
+ break;
+ }
+
+ A = e.A;
+ F = e.F;
+ BC = e.BC;
+ DE = e.DE;
+ HL = e.HL;
+ SP = e.SP;
+ PC = e.PC;
+ AF_ = e.AF_;
+ BC_ = e.BC_;
+ DE_ = e.DE_;
+ HL_ = e.HL_;
+ }
+
+ #endregion
}
}
diff --git a/src/Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs
index 47f4d28..389ba41 100644
--- a/src/Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs
+++ b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs
@@ -11,7 +11,7 @@
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
-// along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+// along with Noddybox.Emulation. If not, see <http://www.gnu.org/licenses/>.
//
// Copyright (c) 2012 Ian Cowburn
//
diff --git a/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeByte.cs b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeByte.cs
index e03a3f3..f0256ba 100644
--- a/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeByte.cs
+++ b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeByte.cs
@@ -11,7 +11,7 @@
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
-// along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+// along with Noddybox.Emulation. If not, see <http://www.gnu.org/licenses/>.
//
// Copyright (c) 2012 Ian Cowburn
//
diff --git a/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeCB.cs b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeCB.cs
index fc17936..5abf167 100644
--- a/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeCB.cs
+++ b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeCB.cs
@@ -11,7 +11,7 @@
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
-// along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+// along with Noddybox.Emulation. If not, see <http://www.gnu.org/licenses/>.
//
// Copyright (c) 2012 Ian Cowburn
//
diff --git a/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeED.cs b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeED.cs
index d06ee3d..a6037f6 100644
--- a/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeED.cs
+++ b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeED.cs
@@ -11,7 +11,7 @@
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
-// along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+// along with Noddybox.Emulation. If not, see <http://www.gnu.org/licenses/>.
//
// Copyright (c) 2012 Ian Cowburn
//
@@ -29,6 +29,7 @@ namespace Noddybox.Emulation.EightBit.Z80
{
ushort addr;
byte b;
+ Register16 tmp = new Register16(0);
switch(opcode)
{
@@ -135,7 +136,401 @@ namespace Noddybox.Emulation.EightBit.Z80
device.Write(BC.reg, DE.high);
break;
- default:
+ case 0x52: // SBC HL,DE
+ clock.Add(15);
+ SBC(ref HL.reg, DE.reg);
+ break;
+
+ case 0x53: // LD (nnnn),DE
+ clock.Add(20);
+ addr = FetchWord();
+ memory.Write(addr++, DE.low);
+ memory.Write(addr, DE.high);
+ break;
+
+ case 0x54: // NEG
+ clock.Add(8);
+ b = A;
+ A = 0;
+ SUB8(b);
+ break;
+
+ case 0x55: // RETN
+ clock.Add(14);
+ IFF1 = IFF2;
+ PC = POP();
+ break;
+
+ case 0x56: // IM 1
+ clock.Add(8);
+ IM = 1;
+ break;
+
+ case 0x57: // LD A,I
+ clock.Add(9);
+ A = (byte)I;
+ break;
+
+ case 0x58: // IN E,(C)
+ clock.Add(12);
+ DE.low = device.Read(BC.reg);
+ F = Z80Flags.Carry | PSZtable[BC.low] | H35table[BC.low];
+ break;
+
+ case 0x59: // OUT (C),E
+ clock.Add(12);
+ device.Write(BC.reg, DE.low);
+ break;
+
+ case 0x5a: // ADC HL, DE
+ clock.Add(15);
+ ADC16(ref HL.reg, DE.reg);
+ break;
+
+ case 0x5b: // LD DE,(nnnn)
+ clock.Add(20);
+ addr = FetchWord();
+ DE.low = memory.Read(addr++);
+ DE.high = memory.Read(addr);
+ break;
+
+ case 0x5c: // NEG
+ clock.Add(8);
+ b = A;
+ A = 0;
+ SUB8(b);
+ break;
+
+ case 0x5d: // RETN
+ clock.Add(14);
+ IFF1 = IFF2;
+ PC = POP();
+ break;
+
+ case 0x5e: // IM 2
+ clock.Add(8);
+ IM = 2;
+ break;
+
+ case 0x5f: // LD A,R
+ clock.Add(9);
+ A = R;
+ break;
+
+ case 0x60: // IN H,(C)
+ clock.Add(12);
+ HL.high = device.Read(BC.reg);
+ F = Z80Flags.Carry | PSZtable[DE.high] | H35table[DE.high];
+ break;
+
+ case 0x61: // OUT (C),H
+ clock.Add(12);
+ device.Write(BC.reg, HL.high);
+ break;
+
+ case 0x62: // SBC HL,HL
+ clock.Add(15);
+ SBC(ref HL.reg, HL.reg);
+ break;
+
+ case 0x63: // LD (nnnn),HL
+ clock.Add(20);
+ addr = FetchWord();
+ memory.Write(addr++, HL.low);
+ memory.Write(addr, HL.high);
+ break;
+
+ case 0x64: // NEG
+ clock.Add(8);
+ b = A;
+ A = 0;
+ SUB8(b);
+ break;
+
+ case 0x65: // RETN
+ clock.Add(14);
+ IFF1 = IFF2;
+ PC = POP();
+ break;
+
+ case 0x66: // IM 0
+ clock.Add(8);
+ IM = 0;
+ break;
+
+ case 0x67: // RRD
+ clock.Add(18);
+ b = memory.Read(HL.reg);
+ memory.Write(HL.reg, (byte)((b >> 4)|(A << 4)));
+ A = (byte)((A & 0xf0) | (b & 0x0f));
+ F = Z80Flags.Carry | PSZtable[A] | H35table[A];
+ break;
+
+ case 0x68: // IN L,(C)
+ clock.Add(12);
+ HL.low = device.Read(BC.reg);
+ F = Z80Flags.Carry | PSZtable[BC.low] | H35table[BC.low];
+ break;
+
+ case 0x69: // OUT (C),L
+ clock.Add(12);
+ device.Write(BC.reg, HL.low);
+ break;
+
+ case 0x6a: // ADC HL, HL
+ clock.Add(15);
+ ADC16(ref HL.reg, HL.reg);
+ break;
+
+ case 0x6b: // LD HL,(nnnn)
+ clock.Add(20);
+ addr = FetchWord();
+ HL.low = memory.Read(addr++);
+ HL.high = memory.Read(addr);
+ break;
+
+ case 0x6c: // NEG
+ clock.Add(8);
+ b = A;
+ A = 0;
+ SUB8(b);
+ break;
+
+ case 0x6d: // RETN
+ clock.Add(14);
+ IFF1 = IFF2;
+ PC = POP();
+ break;
+
+ case 0x6e: // IM 0/1
+ clock.Add(8);
+ IM = 0;
+ break;
+
+ case 0x6f: // RLD
+ clock.Add(18);
+ b = memory.Read(HL.reg);
+ memory.Write(HL.reg, (byte)((b << 4)|(A & 0x0f)));
+ A = (byte)((A & 0xf0) | (b >> 4));
+ F = Z80Flags.Carry | PSZtable[A] | H35table[A];
+ break;
+
+ case 0x70: // IN (C)
+ clock.Add(12);
+ b = device.Read(BC.reg);
+ F = Z80Flags.Carry | PSZtable[b] | H35table[b];
+ break;
+
+ case 0x71: // OUT (C)
+ clock.Add(12);
+ device.Write(BC.reg, 0);
+ break;
+
+ case 0x72: // SBC HL,SP
+ clock.Add(15);
+ SBC(ref HL.reg, SP);
+ break;
+
+ case 0x73: // LD (nnnn),SP
+ clock.Add(20);
+ addr = FetchWord();
+ memory.Write(addr++, (byte)(SP & 0xff));
+ memory.Write(addr, (byte)(SP >> 8));
+ break;
+
+ case 0x74: // NEG
+ clock.Add(8);
+ b = A;
+ A = 0;
+ SUB8(b);
+ break;
+
+ case 0x75: // RETN
+ clock.Add(14);
+ IFF1 = IFF2;
+ PC = POP();
+ break;
+
+ case 0x76: // IM 1
+ clock.Add(8);
+ IM = 1;
+ break;
+
+ case 0x77: // NOP
+ clock.Add(18);
+ TriggerEvent(EventType.EDHook, opcode);
+ break;
+
+ case 0x78: // IN A,(C)
+ clock.Add(12);
+ A = device.Read(BC.reg);
+ F = Z80Flags.Carry | PSZtable[BC.low] | H35table[BC.low];
+ break;
+
+ case 0x79: // OUT (C),A
+ clock.Add(12);
+ device.Write(BC.reg, A);
+ break;
+
+ case 0x7a: // ADC HL, SP
+ clock.Add(15);
+ ADC16(ref HL.reg, SP);
+ break;
+
+ case 0x7b: // LD SP,(nnnn)
+ clock.Add(20);
+ addr = FetchWord();
+ tmp.low = memory.Read(addr++);
+ tmp.high = memory.Read(addr);
+ SP = tmp.reg;
+ break;
+
+ case 0x7c: // NEG
+ clock.Add(8);
+ b = A;
+ A = 0;
+ SUB8(b);
+ break;
+
+ case 0x7d: // RETN
+ clock.Add(14);
+ IFF1 = IFF2;
+ PC = POP();
+ break;
+
+ case 0x7e: // IM 2
+ clock.Add(8);
+ IM = 2;
+ break;
+
+ case 0x7f: // NOP
+ clock.Add(8);
+ TriggerEvent(EventType.EDHook, opcode);
+ break;
+
+ case 0xa0: // LDI
+ clock.Add(16);
+ LDI();
+ break;
+
+ case 0xa1: // CPI
+ clock.Add(16);
+ CPI();
+ break;
+
+ case 0xa2: // INI
+ clock.Add(16);
+ INI();
+ break;
+
+ case 0xa3: // OUTI
+ clock.Add(16);
+ OUTI();
+ break;
+
+ case 0xa8: // LDD
+ clock.Add(16);
+ LDD();
+ break;
+
+ case 0xa9: // CPD
+ clock.Add(16);
+ CPD();
+ break;
+
+ case 0xaa: // IND
+ clock.Add(16);
+ IND();
+ break;
+
+ case 0xab: // OUTD
+ clock.Add(16);
+ OUTD();
+ break;
+
+ case 0xb0: // LDIR
+ clock.Add(16);
+ LDI();
+ if (BC.reg > 0)
+ {
+ clock.Add(5);
+ PC -= 2;
+ }
+ break;
+
+ case 0xb1: // CPIR
+ clock.Add(16);
+ CPI();
+ if (BC.reg > 0 && (F & Z80Flags.Zero) == Z80Flags.None)
+ {
+ clock.Add(5);
+ PC -= 2;
+ }
+ break;
+
+ case 0xb2: // INIR
+ clock.Add(16);
+ INI();
+ if (BC.reg > 0)
+ {
+ clock.Add(5);
+ PC -= 2;
+ }
+ break;
+
+ case 0xb3: // OTIR
+ clock.Add(16);
+ OUTI();
+ if (BC.reg > 0)
+ {
+ clock.Add(5);
+ PC -= 2;
+ }
+ break;
+
+ case 0xb8: // LDDR
+ clock.Add(16);
+ LDD();
+ if (BC.reg > 0)
+ {
+ clock.Add(5);
+ PC -= 2;
+ }
+ break;
+
+ case 0xb9: // CPDR
+ clock.Add(16);
+ CPD();
+ if (BC.reg > 0 && (F & Z80Flags.Zero) == Z80Flags.None)
+ {
+ clock.Add(5);
+ PC -= 2;
+ }
+ break;
+
+ case 0xba: // INDR
+ clock.Add(16);
+ IND();
+ if (BC.reg > 0)
+ {
+ clock.Add(5);
+ PC -= 2;
+ }
+ break;
+
+ case 0xbb: // OTDR
+ clock.Add(16);
+ OUTD();
+ if (BC.reg > 0)
+ {
+ clock.Add(5);
+ PC -= 2;
+ }
+ break;
+
+ default: // NOP
+ clock.Add(8);
+ TriggerEvent(EventType.EDHook, opcode);
break;
}
}
diff --git a/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeShiftedCB.cs b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeShiftedCB.cs
index 80ce41d..4545fbc 100644
--- a/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeShiftedCB.cs
+++ b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeShiftedCB.cs
@@ -11,7 +11,7 @@
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
-// along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+// along with Noddybox.Emulation. If not, see <http://www.gnu.org/licenses/>.
//
// Copyright (c) 2012 Ian Cowburn
//
diff --git a/src/Noddybox.Emulation.EightBit.Z80/Z80CpuEventArgs.cs b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuEventArgs.cs
new file mode 100644
index 0000000..fb0173a
--- /dev/null
+++ b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuEventArgs.cs
@@ -0,0 +1,87 @@
+// This file is part of the Noddybox.Emulation C# suite.
+//
+// Noddybox.Emulation is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Noddybox.Emulation is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Noddybox.Emulation. If not, see <http://www.gnu.org/licenses/>.
+//
+// Copyright (c) 2012 Ian Cowburn
+//
+using System;
+
+namespace Noddybox.Emulation.EightBit.Z80
+{
+ /// <summary>
+ /// Represents events from the Z80.
+ /// </summary>
+ public class Z80CpuEventArgs : EventArgs
+ {
+ /// <summary>
+ /// The opcode that was executed to trigger the event.
+ /// </summary>
+ public byte Opcode {get; set;}
+
+ /// <summary>
+ /// The current state of the accumulator.
+ /// </summary>
+ public byte A {get; set;}
+
+ /// <summary>
+ /// The current state of the flag register.
+ /// </summary>
+ public Z80Flags F {get; set;}
+
+ /// <summary>
+ /// The current state of the BC register pair.
+ /// </summary>
+ public Register16 BC {get; set;}
+
+ /// <summary>
+ /// The current state of the DE register pair.
+ /// </summary>
+ public Register16 DE {get; set;}
+
+ /// <summary>
+ /// The current state of the HL register pair.
+ /// </summary>
+ public Register16 HL {get; set;}
+
+ /// <summary>
+ /// The current state of the stack pointer.
+ /// </summary>
+ public ushort SP {get; set;}
+
+ /// <summary>
+ /// The current state of the program counter.
+ /// </summary>
+ public ushort PC {get; set;}
+
+ /// <summary>
+ /// The alternate AF' register.
+ /// </summary>
+ public Register16 AF_ {get; set;}
+
+ /// <summary>
+ /// The alternate BC' register.
+ /// </summary>
+ public Register16 BC_ {get; set;}
+
+ /// <summary>
+ /// The alternate DE' register.
+ /// </summary>
+ public Register16 DE_ {get; set;}
+
+ /// <summary>
+ /// The alternate HL' register.
+ /// </summary>
+ public Register16 HL_ {get; set;}
+ }
+}
diff --git a/src/Noddybox.Emulation.EightBit.Z80/Z80Flags.cs b/src/Noddybox.Emulation.EightBit.Z80/Z80Flags.cs
new file mode 100644
index 0000000..edcd5f5
--- /dev/null
+++ b/src/Noddybox.Emulation.EightBit.Z80/Z80Flags.cs
@@ -0,0 +1,83 @@
+// This file is part of the Noddybox.Emulation C# suite.
+//
+// Noddybox.Emulation is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Noddybox.Emulation is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Noddybox.Emulation. If not, see <http://www.gnu.org/licenses/>.
+//
+// Copyright (c) 2012 Ian Cowburn
+//
+using System;
+
+namespace Noddybox.Emulation.EightBit.Z80
+{
+ /// <summary>
+ /// Defines the bits in the Z80 flag register.
+ /// </summary>
+ [Flags]
+ public enum Z80Flags
+ {
+ /// <summary>
+ /// No flags set.
+ /// </summary>
+ None = 0x00,
+
+ /// <summary>
+ /// The carry flag.
+ /// </summary>
+ Carry = 0x01,
+
+ /// <summary>
+ /// The negative flag.
+ /// </summary>
+ Neg = 0x02,
+
+ /// <summary>
+ /// The parity/overflow flag.
+ /// </summary>
+ PV = 0x04,
+
+ /// <summary>
+ /// A hidden flag. Undocumented by Zilog, but affected by most operations.
+ /// </summary>
+ Hidden3 = 0x08,
+
+ /// <summary>
+ /// The half-carry flag.
+ /// </summary>
+ HalfCarry = 0x10,
+
+ /// <summary>
+ /// A hidden flag. Undocumented by Zilog, but affected by most operations.
+ /// </summary>
+ Hidden5 = 0x20,
+
+ /// <summary>
+ /// The zero flag.
+ /// </summary>
+ Zero = 0x40,
+
+ /// <summary>
+ /// The sign flag.
+ /// </summary>
+ Sign = 0x80,
+
+ /// <summary>
+ /// A bitmask for all the hidden registers.
+ /// </summary>
+ Hidden = Hidden3 | Hidden5,
+
+ /// <summary>
+ /// All bits set.
+ /// </summary>
+ All = 0xff
+ };
+}