From 4a14a990665f766e349b9027dbf980bc39f395f6 Mon Sep 17 00:00:00 2001 From: Ian C Date: Sat, 31 Dec 2011 00:10:45 +0000 Subject: Development check-in. --- Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs | 40 ++- .../Z80CpuBaseOpcodes.cs | 394 ++++++++++++++++++++- Noddybox.Emulation.EightBit/IMemory.cs | 11 +- Noddybox.Emulation.EightBit/IRegister16.cs | 37 -- .../Noddybox.Emulation.EightBit.csproj | 5 +- Noddybox.Emulation.EightBit/Register16.cs | 88 +++++ Noddybox.Emulation.EightBit/Register16BigEndian.cs | 56 --- Noddybox.Emulation.EightBit/Register16Factory.cs | 34 -- .../Register16LittleEndian.cs | 56 --- Noddybox.Emulation.suo | Bin 40448 -> 42496 bytes 10 files changed, 494 insertions(+), 227 deletions(-) delete mode 100644 Noddybox.Emulation.EightBit/IRegister16.cs create mode 100644 Noddybox.Emulation.EightBit/Register16.cs delete mode 100644 Noddybox.Emulation.EightBit/Register16BigEndian.cs delete mode 100644 Noddybox.Emulation.EightBit/Register16Factory.cs delete mode 100644 Noddybox.Emulation.EightBit/Register16LittleEndian.cs diff --git a/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs b/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs index 1583ae0..5c40854 100644 --- a/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs +++ b/Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs @@ -58,20 +58,20 @@ namespace Noddybox.Emulation.EightBit.Z80 // private byte A; private Z80Flags F; - private IRegister16 BC = Register16Factory.Create(); - private IRegister16 DE = Register16Factory.Create(); - private IRegister16 HL = Register16Factory.Create(); - private IRegister16 IX = Register16Factory.Create(); - private IRegister16 IY = Register16Factory.Create(); + private Register16 BC = new Register16(0); + private Register16 DE = new Register16(0); + private Register16 HL = new Register16(0); + private Register16 IX = new Register16(0); + private Register16 IY = new Register16(0); private ushort SP; private ushort PC; // Alternate registers // - private IRegister16 AF_ = Register16Factory.Create(); - private IRegister16 BC_ = Register16Factory.Create(); - private IRegister16 DE_ = Register16Factory.Create(); - private IRegister16 HL_ = Register16Factory.Create(); + private Register16 AF_ = new Register16(0); + private Register16 BC_ = new Register16(0); + private Register16 DE_ = new Register16(0); + private Register16 HL_ = new Register16(0); // Auxilliary registers and flags // @@ -101,16 +101,16 @@ namespace Noddybox.Emulation.EightBit.Z80 A = 0xff; F = (Z80Flags)0xff; - BC.Value = 0xffff; - DE.Value = 0xffff; - HL.Value = 0xffff; - AF_.Value = 0xffff; - BC_.Value = 0xffff; - DE_.Value = 0xffff; - HL_.Value = 0xffff; + BC.reg = 0xffff; + DE.reg = 0xffff; + HL.reg = 0xffff; + AF_.reg = 0xffff; + BC_.reg = 0xffff; + DE_.reg = 0xffff; + HL_.reg = 0xffff; - IX.Value = 0xffff; - IY.Value = 0xffff; + IX.reg = 0xffff; + IY.reg = 0xffff; SP = 0xffff; @@ -155,6 +155,10 @@ namespace Noddybox.Emulation.EightBit.Z80 public Z80Cpu() { + // Verify runtime + // + Register16.Verify(); + // Setup lookup tables // for(int f = 0; f < 256; f++) diff --git a/Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs b/Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs index c42c163..40b31ca 100644 --- a/Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs +++ b/Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs @@ -16,29 +16,49 @@ namespace Noddybox.Emulation.EightBit.Z80 { public partial class Z80Cpu { + #region Status register helpers + + /// + /// Set a flag in the status register. + /// + /// The flag. + private void SetFlag(Z80Flags flag) + { + F |= flag; + } + + /// + /// Clear a flag in the status register. + /// + /// The flag. + private void ClearFlag(Z80Flags flag) + { + F &= ~flag; + } + + #endregion + #region Stack commands /// /// Push a value on the stack. /// /// The value. - private void Push(ushort val) + private void PUSH(ushort val) { - unchecked - { - memory.Write(--SP, val & 0xff); - memory.Write(--SP, Binary.ShiftRight(val, 8) & 0xff); - } + memory.Write(--SP, (byte)(val & 0xff)); + memory.Write(--SP, (byte)(Binary.ShiftRight(val, 8) & 0xff)); } /// /// Pop a value from the stack. /// /// - private ushort Pop() + private ushort POP() { SP = (ushort)((SP + 2) & 0xffff); - return (ushort)(memory.Read(SP-2) | (memory.Read(SP - 1) >> 8)); + return (ushort)(memory.Read((ushort)(SP-2)) | + (memory.Read((ushort)(SP - 1)) >> 8)); } #endregion @@ -286,10 +306,7 @@ namespace Noddybox.Emulation.EightBit.Z80 /// The register to increment. void Inc8(ref byte reg) { - unchecked - { - reg++; - } + reg++; F = Z80Flags.Carry; @@ -310,10 +327,7 @@ namespace Noddybox.Emulation.EightBit.Z80 /// The register to decrement. void Dec8(ref byte reg) { - unchecked - { - reg--; - } + reg--; F = Z80Flags.Carry | Z80Flags.Neg; @@ -329,5 +343,353 @@ namespace Noddybox.Emulation.EightBit.Z80 } #endregion + + #region ALU rotate and shift operations + + /// + /// Do RRCA. + /// + private void RRCA() + { + F &= Z80Flags.Sign | Z80Flags.Zero | Z80Flags.PV; + F |= (Z80Flags)(A & 1); + A = (byte)(Binary.ShiftRight(A, 1) | Binary.ShiftLeft(A, 7)); + F |= H35table[A]; + } + + /// + /// Do RRA. + /// + private void RRA() + { + byte carry = (byte)(F & Z80Flags.Carry); + F &= Z80Flags.Sign | Z80Flags.Zero | Z80Flags.PV; + F |= (Z80Flags)(A & 1); + A = (byte)(Binary.ShiftRight(A, 1) | Binary.ShiftLeft(carry, 7)); + F |= H35table[A]; + } + + /// + /// Do RRC. + /// + /// The register to operate on. + private void RRC(ref byte reg) + { + F = (Z80Flags)(reg & (int)Z80Flags.Carry); + reg = (byte)(Binary.ShiftRight(reg, 1) | Binary.ShiftLeft(reg, 7)); + F |= PSZtable[reg] | H35table[reg]; + } + + /// + /// Do RR. + /// + /// The register to operate on. + private void RR(ref byte reg) + { + byte carry = (byte)(F & Z80Flags.Carry); + F = (Z80Flags)(reg & (int)Z80Flags.Carry); + reg = (byte)(Binary.ShiftRight(reg, 1) | Binary.ShiftLeft(carry, 7)); + F |= PSZtable[reg] | H35table[reg]; + } + + /// + /// Do RLCA. + /// + private void RLCA() + { + F = (F & Z80Flags.PV | Z80Flags.Sign | Z80Flags.Zero) + | (Z80Flags)Binary.ShiftRight(A, 7); + + A = (byte)(Binary.ShiftLeft(A, 1) | Binary.ShiftRight(A, 7)); + + F |= H35table[A]; + } + + /// + /// Do RLA. + /// + private void RLA() + { + byte carry = (byte)(F & Z80Flags.Carry); + F = (F & Z80Flags.PV | Z80Flags.Sign | Z80Flags.Zero) + | (Z80Flags)Binary.ShiftRight(A, 7); + A = (byte)(Binary.ShiftRight(A, 1) | carry); + F |= H35table[A]; + } + + /// + /// Do RLC. + /// + /// The register to operate on. + private void RLC(ref byte reg) + { + byte carry = Binary.ShiftRight(reg, 7); + reg = (byte)(Binary.ShiftLeft(reg, 1) | carry); + F = PSZtable[reg] | (Z80Flags)carry | H35table[reg]; + } + + /// + /// Do RL. + /// + /// The register to operate on. + private void RL(ref byte reg) + { + byte carry = Binary.ShiftRight(reg, 7); + reg = (byte)(Binary.ShiftLeft(reg, 1) | (int)(F & Z80Flags.Carry)); + F = PSZtable[reg] | (Z80Flags)carry | H35table[reg]; + } + + /// + /// Do SRL. + /// + /// The register to operate on. + private void SRL(ref byte reg) + { + byte carry = (byte)(reg & 1); + reg = Binary.ShiftLeft(reg, 1); + F = PSZtable[reg] | (Z80Flags)carry | H35table[reg]; + } + + /// + /// Do SRA. + /// + /// The register to operate on. + private void SRA(ref byte reg) + { + byte carry = (byte)(reg & 1); + reg = (byte)(Binary.ShiftLeft(reg, 1) | (reg & 0x80)); + F = PSZtable[reg] | (Z80Flags)carry | H35table[reg]; + } + + /// + /// Do SLL. + /// + /// The register to operate on. + private void SLL(ref byte reg) + { + byte carry = Binary.ShiftRight(reg, 7); + reg = (byte)(Binary.ShiftRight(reg, 1) | 0x01); + F = PSZtable[reg] | (Z80Flags)carry | H35table[reg]; + } + + /// + /// Do SLA. + /// + /// The register to operate on. + private void SLA(ref byte reg) + { + byte carry = Binary.ShiftRight(reg, 7); + reg = Binary.ShiftRight(reg, 1); + F = PSZtable[reg] | (Z80Flags)carry | H35table[reg]; + } + + #endregion + + #region ALU boolean operations + + /// + /// AND a value with the accumulator. + /// + /// The value. + void AND(byte val) + { + A &= val; + F = PSZtable[A] | Z80Flags.HalfCarry | H35table[A]; + } + + /// + /// OR a value with the accumulator. + /// + /// The value. + void OR(byte val) + { + A |= val; + F = PSZtable[A] | Z80Flags.HalfCarry | H35table[A]; + } + + /// + /// XOR a value with the accumulator. + /// + /// The value. + void XOR(byte val) + { + A ^= val; + F = PSZtable[A] | Z80Flags.HalfCarry | H35table[A]; + } + + /// + /// Perform the BIT operation. + /// + /// The register to operate on. + /// The bit to test. + void BIT(ref byte reg, int bit) + { + F &= Z80Flags.Carry; + F |= Z80Flags.HalfCarry; + + if ((reg & (1 << bit)) != 0) + { + if (bit == 7 && (reg & (int)Z80Flags.Sign) != 0) + { + F |= Z80Flags.Sign; + } + + if (bit == 5 && (reg & (int)Z80Flags.Hidden5) != 0) + { + F |= Z80Flags.Hidden5; + } + + if (bit == 3 && (reg & (int)Z80Flags.Hidden3) != 0) + { + F |= Z80Flags.Hidden3; + } + } + else + { + F |= Z80Flags.Zero | Z80Flags.PV; + } + } + + /// + /// Perform the bit set operation. + /// + /// The register to operate on. + /// The bit to test. + void BIT_SET(ref byte reg, int bit) + { + reg |= (byte)(1 << bit); + } + + /// + /// Perform the bit clear operation. + /// + /// The register to operate on. + /// The bit to test. + void BIT_RES(ref byte reg, int bit) + { + reg &= (byte)~(1 << bit); + } + + #endregion + + #region Jump operations + + /// + /// The call operation. + /// + private void CALL() + { + PUSH((ushort)(PC + 2)); + PC = (ushort)(memory.Read(PC) | memory.Read((ushort)(PC+1)) >> 8); + } + + /// + /// The jump operation. + /// + private void JP() + { + PC = (ushort)(memory.Read(PC) | memory.Read((ushort)(PC+1)) >> 8); + } + + /// + /// The jump relative operation. + /// + private void JR() + { + PC = (ushort)(PC + (sbyte)memory.Read(PC) + 1); + } + + /// + /// Jump relative if the passed condition flag ANDed with the flag + /// register equals the passed check value. + /// + /// The condition flag. + /// The check value. + private void JR_COND(Z80Flags cond, Z80Flags val) + { + if ((F & cond) == val) + { + clock.Add(12); + JR(); + } + else + { + clock.Add(7); + PC++; + } + } + + /// + /// Jump if the passed condition flag ANDed with the flag + /// register equals the passed check value. + /// + /// The condition flag. + /// The check value. + private void JP_COND(Z80Flags cond, Z80Flags val) + { + clock.Add(10); + + if ((F & cond) == val) + { + JP(); + } + else + { + PC+=2; + } + } + + /// + /// Call if the passed condition flag ANDed with the flag + /// register equals the passed check value. + /// + /// The condition flag. + /// The check value. + private void CALL_COND(Z80Flags cond, Z80Flags val) + { + if ((F & cond) == val) + { + clock.Add(17); + CALL(); + } + else + { + clock.Add(10); + PC+=2; + } + } + + /// + /// Return if the passed condition flag ANDed with the flag + /// register equals the passed check value. + /// + /// The condition flag. + /// The check value. + private void RET_COND(Z80Flags cond, Z80Flags val) + { + if ((F & cond) == val) + { + clock.Add(11); + PC = POP(); + } + else + { + clock.Add(5); + } + } + + /// + /// Reset the PC to an address + /// register equals the passed check value. + /// + /// The address. + private void RST(ushort addr) + { + clock.Add(11); + PUSH(PC); + PC = addr; + } + + #endregion } } diff --git a/Noddybox.Emulation.EightBit/IMemory.cs b/Noddybox.Emulation.EightBit/IMemory.cs index ee41500..2aa63d9 100644 --- a/Noddybox.Emulation.EightBit/IMemory.cs +++ b/Noddybox.Emulation.EightBit/IMemory.cs @@ -15,8 +15,7 @@ using System.Windows.Shapes; namespace Noddybox.Emulation.EightBit { /// - /// Defines an interface for memory. Note that ints are used rather than smaller unsigned types due to the pain of - /// doing boolean operations on anything else in C# without copious casting. + /// Defines an interface for memory. /// public interface IMemory { @@ -24,14 +23,14 @@ namespace Noddybox.Emulation.EightBit /// Reads a byte at a given address. /// /// The address to read. - /// The value at that address in the lower 8-bits. - int Read(int address); + /// The value at that address. + byte Read(ushort address); /// /// Writes a byte at a given address. /// /// The address to write to. - /// The value to write. Only the lower 8-bits are taken. - void Write(int address, int value); + /// The value to write. + void Write(ushort address, byte value); } } diff --git a/Noddybox.Emulation.EightBit/IRegister16.cs b/Noddybox.Emulation.EightBit/IRegister16.cs deleted file mode 100644 index 4356756..0000000 --- a/Noddybox.Emulation.EightBit/IRegister16.cs +++ /dev/null @@ -1,37 +0,0 @@ -// -// 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 -{ - /// - /// Provides a common 8-bit register pattern, which is two 8-bit registers rolled into one. - /// - public interface IRegister16 - { - /// - /// Get/set the low byte of the 16-bit register. - /// - byte Low {get; set;} - - /// - /// Get/set the high byte of the 16-bit register. - /// - byte High {get; set;} - - /// - /// Get/set the value of the 16-bit register. - /// - ushort Value {get; set;} - } -} diff --git a/Noddybox.Emulation.EightBit/Noddybox.Emulation.EightBit.csproj b/Noddybox.Emulation.EightBit/Noddybox.Emulation.EightBit.csproj index 801adae..2136f3c 100644 --- a/Noddybox.Emulation.EightBit/Noddybox.Emulation.EightBit.csproj +++ b/Noddybox.Emulation.EightBit/Noddybox.Emulation.EightBit.csproj @@ -53,11 +53,8 @@ - - - - + diff --git a/Noddybox.Emulation.EightBit/Register16.cs b/Noddybox.Emulation.EightBit/Register16.cs new file mode 100644 index 0000000..06c9c01 --- /dev/null +++ b/Noddybox.Emulation.EightBit/Register16.cs @@ -0,0 +1,88 @@ +// +// Copyright (c) 2012 Ian Cowburn +// +using System; +using System.Runtime.InteropServices; + +namespace Noddybox.Emulation.EightBit +{ + /// + /// Provides a common 8-bit register pattern, which is two 8-bit registers rolled into one. + /// While this could be done at runtime using this + /// method was chosen for speed reasons; interfaces cannot define fields, which is sensible + /// enoough, but accessing fields directly would allow ref variables to be used with this type's + /// fields. + /// + [StructLayout(LayoutKind.Explicit)] + public struct Register16 + { +#if TARGET_IS_BIGENDIAN + + /// + /// The 16-bit register. + /// + [FieldOffset(0)] + public ushort reg; + + /// + /// The high 8-bits of the register. + /// + [FieldOffset(0)] + public byte high; + + /// + /// The low 8-bits of the register. + /// + [FieldOffset(1)] + public byte low; + +#else + + /// + /// The 16-bit register. + /// + [FieldOffset(0)] + public ushort reg; + + /// + /// The low 8-bits of the register. + /// + [FieldOffset(0)] + public byte low; + + /// + /// The high 8-bits of the register. + /// + [FieldOffset(1)] + public byte high; + +#endif + + /// + /// Public constructor. This is provided to stop the compiler complaining when you use the struct as it + /// doesn't realise that setting will also set and . + /// + /// The 16-bit value to assign. + public Register16(ushort val) + { + high = 0; + low = 0; + reg = val; + } + + /// + /// Used to verify the compile-time setting at runtime. + /// + public static void Verify() + { + Register16 r = new Register16(0); + + r.reg = 0x1234; + + if (r.low != 0x24 || r.high != 0x12) + { + throw new Exception("Compile time endian setting incorrect"); + } + } + } +} diff --git a/Noddybox.Emulation.EightBit/Register16BigEndian.cs b/Noddybox.Emulation.EightBit/Register16BigEndian.cs deleted file mode 100644 index e7a3780..0000000 --- a/Noddybox.Emulation.EightBit/Register16BigEndian.cs +++ /dev/null @@ -1,56 +0,0 @@ -// -// 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; -using System.Runtime.InteropServices; - -namespace Noddybox.Emulation.EightBit -{ - [StructLayout(LayoutKind.Explicit)] - public struct Register16BigEndian : IRegister16 - { - #region Register fields - - [FieldOffset(0)] - ushort reg; - - [FieldOffset(1)] - byte low; - - [FieldOffset(0)] - byte high; - - #endregion - - #region IRegister16 Members - - public byte Low - { - get {return low;} - set {low = value;} - } - - public byte High - { - get {return high;} - set {high = value;} - } - - public ushort Value - { - get {return reg;} - set {reg = value;} - } - - #endregion - } -} diff --git a/Noddybox.Emulation.EightBit/Register16Factory.cs b/Noddybox.Emulation.EightBit/Register16Factory.cs deleted file mode 100644 index 249e668..0000000 --- a/Noddybox.Emulation.EightBit/Register16Factory.cs +++ /dev/null @@ -1,34 +0,0 @@ -// -// 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 -{ - /// - /// Defines a common 16-bit register, which is two bytes which are separately addressable. - /// - public static class Register16Factory - { - public static IRegister16 Create() - { - if (BitConverter.IsLittleEndian) - { - return new Register16LittleEndian(); - } - else - { - return new Register16BigEndian(); - } - } - } -} diff --git a/Noddybox.Emulation.EightBit/Register16LittleEndian.cs b/Noddybox.Emulation.EightBit/Register16LittleEndian.cs deleted file mode 100644 index ccecdaf..0000000 --- a/Noddybox.Emulation.EightBit/Register16LittleEndian.cs +++ /dev/null @@ -1,56 +0,0 @@ -// -// 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; -using System.Runtime.InteropServices; - -namespace Noddybox.Emulation.EightBit -{ - [StructLayout(LayoutKind.Explicit)] - public struct Register16LittleEndian : IRegister16 - { - #region Register fields - - [FieldOffset(0)] - ushort reg; - - [FieldOffset(0)] - byte low; - - [FieldOffset(1)] - byte high; - - #endregion - - #region IRegister16 Members - - public byte Low - { - get {return low;} - set {low = value;} - } - - public byte High - { - get {return high;} - set {high = value;} - } - - public ushort Value - { - get {return reg;} - set {reg = value;} - } - - #endregion - } -} diff --git a/Noddybox.Emulation.suo b/Noddybox.Emulation.suo index a6b0b10..e96b21c 100644 Binary files a/Noddybox.Emulation.suo and b/Noddybox.Emulation.suo differ -- cgit v1.2.3