From 647083a1f53bbec58e5058616b84f706b0402911 Mon Sep 17 00:00:00 2001 From: Ian C Date: Mon, 2 Jan 2012 23:37:51 +0000 Subject: Added some opcodes and removed unnecessary using statements. --- src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs | 17 +- .../Z80CpuBaseOpcodes.cs | 305 +++++++++++++-- .../Z80CpuDecodeByte.cs | 407 +++++++++++++++++++++ src/Noddybox.Emulation.EightBit/Binary.cs | 9 - src/Noddybox.Emulation.EightBit/ICpu.cs | 9 - src/Noddybox.Emulation.EightBit/IDevice.cs | 9 - src/Noddybox.Emulation.EightBit/IMemory.cs | 9 - src/Noddybox.Emulation/Clock.cs | 9 - 8 files changed, 697 insertions(+), 77 deletions(-) create mode 100644 src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeByte.cs (limited to 'src') diff --git a/src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs b/src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs index 5c40854..0717ef5 100644 --- a/src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs +++ b/src/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs @@ -2,15 +2,6 @@ // Copyright (c) 2012 Ian Cowburn // using System; -using System.Net; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows.Ink; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Windows.Shapes; namespace Noddybox.Emulation.EightBit.Z80 { @@ -32,7 +23,8 @@ namespace Noddybox.Emulation.EightBit.Z80 HalfCarry = 0x10, Hidden5 = 0x20, Zero = 0x40, - Sign = 0x80 + Sign = 0x80, + Hidden = Hidden3 | Hidden5 }; #endregion @@ -46,7 +38,7 @@ namespace Noddybox.Emulation.EightBit.Z80 private Z80Flags[] Ptable = new Z80Flags[512]; private Z80Flags[] Stable = new Z80Flags[512]; private Z80Flags[] Ztable = new Z80Flags[512]; - private Z80Flags[] H35table = new Z80Flags[256]; + private Z80Flags[] H35table = new Z80Flags[512]; // Machine accessors // @@ -81,6 +73,7 @@ namespace Noddybox.Emulation.EightBit.Z80 private bool IFF2; private int IM; private bool HALT; + private int shift; #endregion @@ -120,6 +113,7 @@ namespace Noddybox.Emulation.EightBit.Z80 I = 0; R = 0; HALT = false; + shift = 0; } public void Step() @@ -216,6 +210,7 @@ namespace Noddybox.Emulation.EightBit.Z80 Ztable[f+256] = Ztable[f] | Z80Flags.Carry; SZtable[f+256] = SZtable[f] | Z80Flags.Carry; PSZtable[f+256] = PSZtable[f] | Z80Flags.Carry; + H35table[f+256] = h3 | h5; } Reset(); diff --git a/src/Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs index 40b31ca..378fd05 100644 --- a/src/Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs +++ b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs @@ -2,20 +2,58 @@ // Copyright (c) 2012 Ian Cowburn // using System; -using System.Net; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows.Ink; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Windows.Shapes; namespace Noddybox.Emulation.EightBit.Z80 { public partial class Z80Cpu { + #region Fetch and helper operations + + /// + /// Fetch the next word from the PC. + /// + /// The word. + ushort FetchWord() + { + Register16 r = new Register16(0); + + r.low = memory.Read(PC++); + r.high = memory.Read(PC++); + + return r.reg; + } + + /// + /// Swap two 16-bit registers. + /// + /// The first register. + /// The second register. + void Swap(ref Register16 a, ref Register16 b) + { + Register16 t = a; + a = b; + b = t; + } + + /// + /// Fetch the offset if the current opcode is shifted. + /// + /// The offset, or zero if the current opcode is not shifted. + sbyte Offset() + { + if (shift == 0xdd || shift == 0xfd) + { + byte b = memory.Read(PC++); + return (sbyte)b; + } + else + { + return 0; + } + } + + #endregion + #region Status register helpers /// @@ -69,7 +107,7 @@ namespace Noddybox.Emulation.EightBit.Z80 /// Add an 8-bit value to the accumulator without carry. /// /// The vakue. - private void Add8(byte b) + private void ADD8(byte b) { int w = A + b; @@ -92,7 +130,7 @@ namespace Noddybox.Emulation.EightBit.Z80 /// Add an 8-bit value to the accumulator with carry. /// /// The vakue. - private void Adc8(byte b) + private void ADC8(byte b) { int w = A + b + (int)(F & Z80Flags.Carry); @@ -115,7 +153,7 @@ namespace Noddybox.Emulation.EightBit.Z80 /// Subtract an 8-bit value from the accumulator without carry. /// /// The vakue. - private void Sub8(byte b) + private void SUB8(byte b) { int w = A - b; @@ -143,7 +181,7 @@ namespace Noddybox.Emulation.EightBit.Z80 /// Compare an 8-bit value with the accumulator. /// /// The vakue. - private void Cmp8(byte b) + private void CMP8(byte b) { int w = A - b; @@ -169,7 +207,7 @@ namespace Noddybox.Emulation.EightBit.Z80 /// Subtract an 8-bit value from the accumulator with carry. /// /// The vakue. - private void Sbc8(byte b) + private void SBC8(byte b) { int w = A - b - (int)(F & Z80Flags.Carry); @@ -197,7 +235,7 @@ namespace Noddybox.Emulation.EightBit.Z80 /// Add a 16-bit value to a register without carry. /// /// The vakue. - private void Add16(ref ushort reg, ushort b) + private void ADD16(ref ushort reg, ushort b) { int w = reg + b; @@ -222,7 +260,7 @@ namespace Noddybox.Emulation.EightBit.Z80 /// Add a 16-bit value to a register with carry. /// /// The vakue. - private void Adc16(ref ushort reg, ushort b) + private void ADC16(ref ushort reg, ushort b) { int w = reg + b + (int)(F & Z80Flags.Carry); @@ -263,7 +301,7 @@ namespace Noddybox.Emulation.EightBit.Z80 /// Subtract a 16-bit value from a register with carry. /// /// The vakue. - private void Sbc16(ref ushort reg, ushort b) + private void SBC(ref ushort reg, ushort b) { int w = reg - b - (int)(F & Z80Flags.Carry); @@ -304,7 +342,7 @@ namespace Noddybox.Emulation.EightBit.Z80 /// Increment an 8-bit register. /// /// The register to increment. - void Inc8(ref byte reg) + void INC8(ref byte reg) { reg++; @@ -325,7 +363,7 @@ namespace Noddybox.Emulation.EightBit.Z80 /// Decrement an 8-bit register. /// /// The register to decrement. - void Dec8(ref byte reg) + void DEC8(ref byte reg) { reg--; @@ -342,6 +380,44 @@ namespace Noddybox.Emulation.EightBit.Z80 } } + /// + /// Decimally adjust the accumulator. A bugger of an opcode. + /// Based on info from http://www.worldofspectrum.org/faq/reference/z80reference.htm + /// + void DAA() + { + byte add = 0; + Z80Flags carry = Z80Flags.None; + Z80Flags nf = F & Z80Flags.Neg; + byte acc = A; + + if (acc>0x99 || (F & Z80Flags.Carry) == Z80Flags.Carry) + { + add |= 0x60; + carry = Z80Flags.Carry; + } + + if ((acc & 0xf) > 0x9 || (F & Z80Flags.HalfCarry) == Z80Flags.HalfCarry) + { + add|=0x06; + } + + if (nf == Z80Flags.Neg) + { + A -= add; + } + else + { + A += add; + } + + F = PSZtable[A] + | carry + | nf | + ((Z80Flags)(acc ^ A) & Z80Flags.HalfCarry) + | H35table[A]; + } + #endregion #region ALU rotate and shift operations @@ -679,8 +755,7 @@ namespace Noddybox.Emulation.EightBit.Z80 } /// - /// Reset the PC to an address - /// register equals the passed check value. + /// Reset the PC to an address. /// /// The address. private void RST(ushort addr) @@ -691,5 +766,193 @@ namespace Noddybox.Emulation.EightBit.Z80 } #endregion + + #region Block operations + + /// + /// LDI instruction. + /// + private void LDI() + { + byte b = memory.Read(HL.reg); + memory.Write(DE.reg, b); + DE.reg++; + HL.reg++; + BC.reg--; + + if (BC.reg != 0) + { + ClearFlag(Z80Flags.HalfCarry | Z80Flags.Neg); + SetFlag(Z80Flags.PV); + } + else + { + ClearFlag(Z80Flags.HalfCarry | Z80Flags.Neg | Z80Flags.PV); + } + + F |= H35table[A + b]; + } + + /// + /// LDD instruction. + /// + private void LDD() + { + byte b = memory.Read(HL.reg); + memory.Write(DE.reg, b); + DE.reg--; + HL.reg--; + BC.reg--; + + if (BC.reg != 0) + { + ClearFlag(Z80Flags.HalfCarry | Z80Flags.Neg); + SetFlag(Z80Flags.PV); + } + else + { + ClearFlag(Z80Flags.HalfCarry | Z80Flags.Neg | Z80Flags.PV); + } + + F |= H35table[A + b]; + } + + /// + /// CPI instruction. + /// + private void CPI() + { + Z80Flags c = F & Z80Flags.Carry; + byte b = memory.Read(HL.reg); + + CMP8(b); + F |= c; + + HL.reg++; + BC.reg--; + + if (BC.reg != 0) + { + SetFlag(Z80Flags.PV); + } + else + { + ClearFlag(Z80Flags.PV); + } + } + + /// + /// CPD instruction. + /// + private void CPD() + { + Z80Flags c = F & Z80Flags.Carry; + byte b = memory.Read(HL.reg); + + CMP8(b); + F |= c; + + HL.reg--; + BC.reg--; + + if (BC.reg != 0) + { + SetFlag(Z80Flags.PV); + } + else + { + ClearFlag(Z80Flags.PV); + } + } + + /// + /// INI instruction. + /// + private void INI() + { + int w; + byte b = device.Read(BC.reg); + memory.Write(HL.reg, b); + + BC.high--; + HL.reg++; + + F = SZtable[BC.high] | H35table[BC.high]; + + w = BC.low + b; + + if ((w & 0x80) == 0x80) + { + SetFlag(Z80Flags.Neg); + } + + if ((w & 0x100) == 0x100) + { + SetFlag(Z80Flags.Carry | Z80Flags.HalfCarry); + } + else + { + ClearFlag(Z80Flags.Carry | Z80Flags.HalfCarry); + } + } + + /// + /// IND instruction. + /// + private void IND() + { + int w; + byte b = device.Read(BC.reg); + memory.Write(HL.reg, b); + + BC.high--; + HL.reg--; + + F = SZtable[BC.high] | H35table[BC.high]; + + w = BC.low + b; + + if ((w & 0x80) == 0x80) + { + SetFlag(Z80Flags.Neg); + } + + if ((w & 0x100) == 0x100) + { + SetFlag(Z80Flags.Carry | Z80Flags.HalfCarry); + } + else + { + ClearFlag(Z80Flags.Carry | Z80Flags.HalfCarry); + } + } + + /// + /// OUTI instruction. + /// + private void OUTI() + { + device.Write(BC.reg, memory.Read(HL.reg)); + + HL.reg++; + BC.high--; + + F = SZtable[BC.high] | H35table[BC.high]; + } + + /// + /// OUTD instruction. + /// + private void OUTD() + { + device.Write(BC.reg, memory.Read(HL.reg)); + + HL.reg--; + BC.high--; + + F = SZtable[BC.high] | H35table[BC.high] | Z80Flags.Neg; + } + + #endregion } } diff --git a/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeByte.cs b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeByte.cs new file mode 100644 index 0000000..4a747e1 --- /dev/null +++ b/src/Noddybox.Emulation.EightBit.Z80/Z80CpuDecodeByte.cs @@ -0,0 +1,407 @@ +// +// Copyright (c) 2012 Ian Cowburn +// +using System; + +namespace Noddybox.Emulation.EightBit.Z80 +{ + public partial class Z80Cpu + { + /// + /// Decode and execute an opcode. + /// + /// The opcode. + private void Decode(byte opcode) + { + // Check for shifted opcodes + // + switch(shift) + { + case 0xdd: + Decode(opcode, ref IX); + break; + + case 0xfd: + Decode(opcode, ref IY); + break; + + default: + Decode(opcode, ref HL); + break; + } + } + + /// + /// Decode and execute an opcode. + /// + /// The opcode. + /// The register to use for HL register operations. + private void Decode(byte opcode, ref Register16 hl) + { + ushort addr; + byte b; + + switch(opcode) + { + case 0x00: // NOP + clock.Add(4); + break; + + case 0x01: // LD BC, nnnn + clock.Add(10); + BC.reg = FetchWord(); + break; + + case 0x02: // LD (BC), A + clock.Add(7); + memory.Write(BC.reg, A); + break; + + case 0x03: // INC BC + clock.Add(6); + BC.reg++; + break; + + case 0x04: // INC B + clock.Add(4); + INC8(ref BC.high); + break; + + case 0x05: // DEC B + clock.Add(4); + DEC8(ref BC.high); + break; + + case 0x06: // LD B,n + clock.Add(7); + BC.high = memory.Read(PC++); + break; + + case 0x07: // RLCA + clock.Add(4); + RLCA(); + break; + + case 0x08: // EX AF, AF' + clock.Add(4); + Register16 t = AF_; + AF_.high = A; + AF_.low = (byte)F; + A = t.high; + F = (Z80Flags)t.low; + break; + + case 0x09: // ADD HL, BC + clock.Add(11); + ADD16(ref hl.reg, BC.reg); + break; + + case 0x0a: // LD A,(BC) + clock.Add(7); + A = memory.Read(BC.reg); + break; + + case 0x0b: // DEC BC + clock.Add(6); + BC.reg--; + break; + + case 0x0c: // INC C + clock.Add(4); + INC8(ref BC.low); + break; + + case 0x0d: // DEC C + clock.Add(4); + DEC8(ref BC.low); + break; + + case 0x0e: // LD C,n + clock.Add(7); + BC.low = memory.Read(PC++); + break; + + case 0x0f: // RRCA + clock.Add(4); + RRCA(); + break; + + case 0x10: // DJNZ + if (--BC.high == 0) + { + clock.Add(13); + JR(); + } + else + { + clock.Add(8); + PC++; + } + break; + + case 0x11: // LD DE, nnnn + clock.Add(10); + DE.reg = FetchWord(); + break; + + case 0x12: // LD (DE), A + clock.Add(7); + memory.Write(DE.reg, A); + break; + + case 0x13: // INC DE + clock.Add(6); + DE.reg++; + break; + + case 0x14: // INC D + clock.Add(4); + INC8(ref DE.high); + break; + + case 0x15: // DEC D + clock.Add(4); + DEC8(ref DE.high); + break; + + case 0x16: // LD D,n + clock.Add(7); + DE.high = memory.Read(PC++); + break; + + case 0x17: // RLA + clock.Add(4); + RLA(); + break; + + case 0x18: // JR + clock.Add(12); + JR(); + break; + + case 0x19: // ADD HL, DE + clock.Add(11); + ADD16(ref hl.reg, DE.reg); + break; + + case 0x1a: // LD A,(DE) + clock.Add(7); + A = memory.Read(DE.reg); + break; + + case 0x1b: // DEC DE + clock.Add(6); + DE.reg--; + break; + + case 0x1c: // INC E + clock.Add(4); + INC8(ref DE.low); + break; + + case 0x1d: // DEC E + clock.Add(4); + DEC8(ref DE.low); + break; + + case 0x1e: // LD E,n + clock.Add(7); + DE.low = memory.Read(PC++); + break; + + case 0x1f: // RRA + clock.Add(4); + RRA(); + break; + + case 0x20: // JR NZ, r + JR_COND(Z80Flags.Zero, Z80Flags.None); + break; + + case 0x21: // LD HL, nnnn + clock.Add(10); + hl.reg = FetchWord(); + break; + + case 0x22: // LD (nnnn), HL + clock.Add(16); + addr = FetchWord(); + memory.Write(addr, hl.low); + memory.Write((ushort)(addr + 1), hl.high); + break; + + case 0x23: // INC HL + clock.Add(6); + hl.reg++; + break; + + case 0x24: // INC H + clock.Add(4); + INC8(ref hl.high); + break; + + case 0x25: // DEC H + clock.Add(4); + DEC8(ref hl.high); + break; + + case 0x26: // LD H,n + clock.Add(7); + hl.high = memory.Read(PC++); + break; + + case 0x27: // DAA + clock.Add(4); + DAA(); + break; + + case 0x28: // JR Z,d + JR_COND(Z80Flags.Zero, Z80Flags.Zero); + break; + + case 0x29: // ADD HL, HL + clock.Add(11); + ADD16(ref hl.reg, hl.reg); + break; + + case 0x2a: // LD HL,(nnnnn) + clock.Add(7); + addr = FetchWord(); + hl.low = memory.Read(addr); + hl.high = memory.Read((ushort)(addr + 1)); + break; + + case 0x2b: // DEC HL + clock.Add(6); + hl.reg--; + break; + + case 0x2c: // INC L + clock.Add(4); + INC8(ref hl.low); + break; + + case 0x2d: // DEC L + clock.Add(4); + DEC8(ref hl.low); + break; + + case 0x2e: // LD L,n + clock.Add(7); + hl.low = memory.Read(PC++); + break; + + case 0x2f: // CPL + clock.Add(4); + A ^= 0xff; + ClearFlag(Z80Flags.Hidden); + SetFlag(Z80Flags.HalfCarry | Z80Flags.Neg | H35table[A]); + break; + + case 0x30: // JR NC, r + JR_COND(Z80Flags.Carry, Z80Flags.None); + break; + + case 0x31: // LD SP, nnnn + clock.Add(10); + SP = FetchWord(); + break; + + case 0x32: // LD (nnnn), A + clock.Add(13); + addr = FetchWord(); + memory.Write(addr, A); + break; + + case 0x33: // INC SP + clock.Add(6); + SP++; + break; + + case 0x34: // INC (HL) + clock.Add(11); + addr = (ushort)(hl.reg + Offset()); + b = memory.Read(addr); + INC8(ref b); + memory.Write(addr, b); + break; + + case 0x35: // DEC (HL) + clock.Add(11); + addr = (ushort)(hl.reg + Offset()); + b = memory.Read(addr); + DEC8(ref b); + memory.Write(addr, b); + break; + + case 0x36: // LD (HL),n + clock.Add(10); + addr = (ushort)(hl.reg + Offset()); + memory.Write(addr, memory.Read(PC++)); + break; + + case 0x37: // SCF + clock.Add(4); + F = (F & (Z80Flags.Sign | Z80Flags.Zero | Z80Flags.PV)) + | Z80Flags.Carry + | H35table[A]; + break; + + case 0x38: // JR C,d + JR_COND(Z80Flags.Carry, Z80Flags.Carry); + break; + + case 0x39: // ADD HL, SP + clock.Add(11); + ADD16(ref hl.reg, SP); + break; + + case 0x3a: // LD A,(nnnnn) + clock.Add(13); + addr = FetchWord(); + A = memory.Read(addr); + break; + + case 0x3b: // DEC SP + clock.Add(6); + SP--; + break; + + case 0x3c: // INC A + clock.Add(4); + INC8(ref A); + break; + + case 0x2d: // DEC A + clock.Add(4); + DEC8(ref A); + break; + + case 0x3e: // LD A,n + clock.Add(7); + A = memory.Read(PC++); + break; + + case 0x3f: // CCF + clock.Add(4); + + if ((F & Z80Flags.Carry) == Z80Flags.Carry) + { + SetFlag(Z80Flags.HalfCarry); + } + else + { + ClearFlag(Z80Flags.HalfCarry); + } + + F ^= Z80Flags.Carry; + ClearFlag(Z80Flags.Hidden); + SetFlag(H35table[A]); + break; + + default: + break; + } + } + } +} diff --git a/src/Noddybox.Emulation.EightBit/Binary.cs b/src/Noddybox.Emulation.EightBit/Binary.cs index 0b1928b..59d2752 100644 --- a/src/Noddybox.Emulation.EightBit/Binary.cs +++ b/src/Noddybox.Emulation.EightBit/Binary.cs @@ -1,13 +1,4 @@ using System; -using System.Net; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows.Ink; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Windows.Shapes; namespace Noddybox.Emulation.EightBit { diff --git a/src/Noddybox.Emulation.EightBit/ICpu.cs b/src/Noddybox.Emulation.EightBit/ICpu.cs index dc2f811..4f333bc 100644 --- a/src/Noddybox.Emulation.EightBit/ICpu.cs +++ b/src/Noddybox.Emulation.EightBit/ICpu.cs @@ -2,15 +2,6 @@ // Copyright (c) 2012 Ian Cowburn // using System; -using System.Net; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows.Ink; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Windows.Shapes; namespace Noddybox.Emulation.EightBit { diff --git a/src/Noddybox.Emulation.EightBit/IDevice.cs b/src/Noddybox.Emulation.EightBit/IDevice.cs index b8d234a..b5117fb 100644 --- a/src/Noddybox.Emulation.EightBit/IDevice.cs +++ b/src/Noddybox.Emulation.EightBit/IDevice.cs @@ -2,15 +2,6 @@ // Copyright (c) 2012 Ian Cowburn // using System; -using System.Net; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows.Ink; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Windows.Shapes; namespace Noddybox.Emulation.EightBit { diff --git a/src/Noddybox.Emulation.EightBit/IMemory.cs b/src/Noddybox.Emulation.EightBit/IMemory.cs index 2aa63d9..43b50cb 100644 --- a/src/Noddybox.Emulation.EightBit/IMemory.cs +++ b/src/Noddybox.Emulation.EightBit/IMemory.cs @@ -2,15 +2,6 @@ // Copyright (c) 2012 Ian Cowburn // using System; -using System.Net; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows.Ink; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Windows.Shapes; namespace Noddybox.Emulation.EightBit { diff --git a/src/Noddybox.Emulation/Clock.cs b/src/Noddybox.Emulation/Clock.cs index 0b733cb..178b730 100644 --- a/src/Noddybox.Emulation/Clock.cs +++ b/src/Noddybox.Emulation/Clock.cs @@ -2,15 +2,6 @@ // Copyright (c) 2012 Ian Cowburn // using System; -using System.Net; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows.Ink; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Windows.Shapes; namespace Noddybox.Emulation { -- cgit v1.2.3