summaryrefslogtreecommitdiff
path: root/Noddybox.Emulation.EightBit.Z80
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2011-12-31 00:10:45 +0000
committerIan C <ianc@noddybox.co.uk>2011-12-31 00:10:45 +0000
commit4a14a990665f766e349b9027dbf980bc39f395f6 (patch)
treeba44e3f58e4792d5e496744a8f3651d5b30b3121 /Noddybox.Emulation.EightBit.Z80
parentf96332b0913a8a365db73a1af3443c0e225a23d8 (diff)
Development check-in.
Diffstat (limited to 'Noddybox.Emulation.EightBit.Z80')
-rw-r--r--Noddybox.Emulation.EightBit.Z80/Z80Cpu.cs40
-rw-r--r--Noddybox.Emulation.EightBit.Z80/Z80CpuBaseOpcodes.cs394
2 files changed, 400 insertions, 34 deletions
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
+
+ /// <summary>
+ /// Set a flag in the status register.
+ /// </summary>
+ /// <param name="flag">The flag.</param>
+ private void SetFlag(Z80Flags flag)
+ {
+ F |= flag;
+ }
+
+ /// <summary>
+ /// Clear a flag in the status register.
+ /// </summary>
+ /// <param name="flag">The flag.</param>
+ private void ClearFlag(Z80Flags flag)
+ {
+ F &= ~flag;
+ }
+
+ #endregion
+
#region Stack commands
/// <summary>
/// Push a value on the stack.
/// </summary>
/// <param name="val">The value.</param>
- 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));
}
/// <summary>
/// Pop a value from the stack.
/// </summary>
/// <returns></returns>
- 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
/// <param name="reg">The register to increment.</param>
void Inc8(ref byte reg)
{
- unchecked
- {
- reg++;
- }
+ reg++;
F = Z80Flags.Carry;
@@ -310,10 +327,7 @@ namespace Noddybox.Emulation.EightBit.Z80
/// <param name="reg">The register to decrement.</param>
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
+
+ /// <summary>
+ /// Do RRCA.
+ /// </summary>
+ 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];
+ }
+
+ /// <summary>
+ /// Do RRA.
+ /// </summary>
+ 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];
+ }
+
+ /// <summary>
+ /// Do RRC.
+ /// </summary>
+ /// <param name="reg">The register to operate on.</param>
+ 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];
+ }
+
+ /// <summary>
+ /// Do RR.
+ /// </summary>
+ /// <param name="reg">The register to operate on.</param>
+ 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];
+ }
+
+ /// <summary>
+ /// Do RLCA.
+ /// </summary>
+ 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];
+ }
+
+ /// <summary>
+ /// Do RLA.
+ /// </summary>
+ 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];
+ }
+
+ /// <summary>
+ /// Do RLC.
+ /// </summary>
+ /// <param name="reg">The register to operate on.</param>
+ 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];
+ }
+
+ /// <summary>
+ /// Do RL.
+ /// </summary>
+ /// <param name="reg">The register to operate on.</param>
+ 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];
+ }
+
+ /// <summary>
+ /// Do SRL.
+ /// </summary>
+ /// <param name="reg">The register to operate on.</param>
+ private void SRL(ref byte reg)
+ {
+ byte carry = (byte)(reg & 1);
+ reg = Binary.ShiftLeft(reg, 1);
+ F = PSZtable[reg] | (Z80Flags)carry | H35table[reg];
+ }
+
+ /// <summary>
+ /// Do SRA.
+ /// </summary>
+ /// <param name="reg">The register to operate on.</param>
+ 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];
+ }
+
+ /// <summary>
+ /// Do SLL.
+ /// </summary>
+ /// <param name="reg">The register to operate on.</param>
+ 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];
+ }
+
+ /// <summary>
+ /// Do SLA.
+ /// </summary>
+ /// <param name="reg">The register to operate on.</param>
+ 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
+
+ /// <summary>
+ /// AND a value with the accumulator.
+ /// </summary>
+ /// <param name="val">The value.</param>
+ void AND(byte val)
+ {
+ A &= val;
+ F = PSZtable[A] | Z80Flags.HalfCarry | H35table[A];
+ }
+
+ /// <summary>
+ /// OR a value with the accumulator.
+ /// </summary>
+ /// <param name="val">The value.</param>
+ void OR(byte val)
+ {
+ A |= val;
+ F = PSZtable[A] | Z80Flags.HalfCarry | H35table[A];
+ }
+
+ /// <summary>
+ /// XOR a value with the accumulator.
+ /// </summary>
+ /// <param name="val">The value.</param>
+ void XOR(byte val)
+ {
+ A ^= val;
+ F = PSZtable[A] | Z80Flags.HalfCarry | H35table[A];
+ }
+
+ /// <summary>
+ /// Perform the BIT operation.
+ /// </summary>
+ /// <param name="reg">The register to operate on.</param>
+ /// <param name="bit">The bit to test.</param>
+ 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;
+ }
+ }
+
+ /// <summary>
+ /// Perform the bit set operation.
+ /// </summary>
+ /// <param name="reg">The register to operate on.</param>
+ /// <param name="bit">The bit to test.</param>
+ void BIT_SET(ref byte reg, int bit)
+ {
+ reg |= (byte)(1 << bit);
+ }
+
+ /// <summary>
+ /// Perform the bit clear operation.
+ /// </summary>
+ /// <param name="reg">The register to operate on.</param>
+ /// <param name="bit">The bit to test.</param>
+ void BIT_RES(ref byte reg, int bit)
+ {
+ reg &= (byte)~(1 << bit);
+ }
+
+ #endregion
+
+ #region Jump operations
+
+ /// <summary>
+ /// The call operation.
+ /// </summary>
+ private void CALL()
+ {
+ PUSH((ushort)(PC + 2));
+ PC = (ushort)(memory.Read(PC) | memory.Read((ushort)(PC+1)) >> 8);
+ }
+
+ /// <summary>
+ /// The jump operation.
+ /// </summary>
+ private void JP()
+ {
+ PC = (ushort)(memory.Read(PC) | memory.Read((ushort)(PC+1)) >> 8);
+ }
+
+ /// <summary>
+ /// The jump relative operation.
+ /// </summary>
+ private void JR()
+ {
+ PC = (ushort)(PC + (sbyte)memory.Read(PC) + 1);
+ }
+
+ /// <summary>
+ /// Jump relative if the passed condition flag ANDed with the flag
+ /// register equals the passed check value.
+ /// </summary>
+ /// <param name="cond">The condition flag.</param>
+ /// <param name="val">The check value.</param>
+ private void JR_COND(Z80Flags cond, Z80Flags val)
+ {
+ if ((F & cond) == val)
+ {
+ clock.Add(12);
+ JR();
+ }
+ else
+ {
+ clock.Add(7);
+ PC++;
+ }
+ }
+
+ /// <summary>
+ /// Jump if the passed condition flag ANDed with the flag
+ /// register equals the passed check value.
+ /// </summary>
+ /// <param name="cond">The condition flag.</param>
+ /// <param name="val">The check value.</param>
+ private void JP_COND(Z80Flags cond, Z80Flags val)
+ {
+ clock.Add(10);
+
+ if ((F & cond) == val)
+ {
+ JP();
+ }
+ else
+ {
+ PC+=2;
+ }
+ }
+
+ /// <summary>
+ /// Call if the passed condition flag ANDed with the flag
+ /// register equals the passed check value.
+ /// </summary>
+ /// <param name="cond">The condition flag.</param>
+ /// <param name="val">The check value.</param>
+ private void CALL_COND(Z80Flags cond, Z80Flags val)
+ {
+ if ((F & cond) == val)
+ {
+ clock.Add(17);
+ CALL();
+ }
+ else
+ {
+ clock.Add(10);
+ PC+=2;
+ }
+ }
+
+ /// <summary>
+ /// Return if the passed condition flag ANDed with the flag
+ /// register equals the passed check value.
+ /// </summary>
+ /// <param name="cond">The condition flag.</param>
+ /// <param name="val">The check value.</param>
+ private void RET_COND(Z80Flags cond, Z80Flags val)
+ {
+ if ((F & cond) == val)
+ {
+ clock.Add(11);
+ PC = POP();
+ }
+ else
+ {
+ clock.Add(5);
+ }
+ }
+
+ /// <summary>
+ /// Reset the PC to an address
+ /// register equals the passed check value.
+ /// </summary>
+ /// <param name="addr">The address.</param>
+ private void RST(ushort addr)
+ {
+ clock.Add(11);
+ PUSH(PC);
+ PC = addr;
+ }
+
+ #endregion
}
}