//
// 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 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)
{
memory.Write(--SP, (byte)(val & 0xff));
memory.Write(--SP, (byte)(Binary.ShiftRight(val, 8) & 0xff));
}
///
/// Pop a value from the stack.
///
///
private ushort POP()
{
SP = (ushort)((SP + 2) & 0xffff);
return (ushort)(memory.Read((ushort)(SP-2)) |
(memory.Read((ushort)(SP - 1)) >> 8));
}
#endregion
#region ALU arithmetic and comparison
///
/// Add an 8-bit value to the accumulator without carry.
///
/// The vakue.
private void Add8(byte b)
{
int w = A + b;
F = SZtable[w] | H35table[w & 0xff];
if (((A ^ w ^ b) & (int)Z80Flags.HalfCarry) == (int)Z80Flags.HalfCarry)
{
F |= Z80Flags.HalfCarry;
}
if (((b ^ A) & (b ^ w) & 0x80) > 0)
{
F |= Z80Flags.PV;
}
A = (byte)(w & 0xff);
}
///
/// Add an 8-bit value to the accumulator with carry.
///
/// The vakue.
private void Adc8(byte b)
{
int w = A + b + (int)(F & Z80Flags.Carry);
F = SZtable[w] | H35table[w & 0xff];
if (((A ^ w ^ b) & (int)Z80Flags.HalfCarry) == (int)Z80Flags.HalfCarry)
{
F |= Z80Flags.HalfCarry;
}
if (((b ^ A) & (b ^ w) & 0x80) > 0)
{
F |= Z80Flags.PV;
}
A = (byte)(w & 0xff);
}
///
/// Subtract an 8-bit value from the accumulator without carry.
///
/// The vakue.
private void Sub8(byte b)
{
int w = A - b;
if (w < 0)
{
w += 0x200;
}
F = SZtable[w] | H35table[w & 0xff] | Z80Flags.Neg;
if (((A ^ w ^ b) & (int)Z80Flags.HalfCarry) == (int)Z80Flags.HalfCarry)
{
F |= Z80Flags.HalfCarry;
}
if (((b ^ A) & (b ^ w) & 0x80) > 0)
{
F |= Z80Flags.PV;
}
A = (byte)(w & 0xff);
}
///
/// Compare an 8-bit value with the accumulator.
///
/// The vakue.
private void Cmp8(byte b)
{
int w = A - b;
if (w < 0)
{
w += 0x200;
}
F = SZtable[w] | H35table[w & 0xff] | Z80Flags.Neg;
if (((A ^ w ^ b) & (int)Z80Flags.HalfCarry) == (int)Z80Flags.HalfCarry)
{
F |= Z80Flags.HalfCarry;
}
if (((b ^ A) & (b ^ w) & 0x80) > 0)
{
F |= Z80Flags.PV;
}
}
///
/// Subtract an 8-bit value from the accumulator with carry.
///
/// The vakue.
private void Sbc8(byte b)
{
int w = A - b - (int)(F & Z80Flags.Carry);
if (w < 0)
{
w += 0x200;
}
F = SZtable[w] | H35table[w & 0xff] | Z80Flags.Neg;
if (((A ^ w ^ b) & (int)Z80Flags.HalfCarry) == (int)Z80Flags.HalfCarry)
{
F |= Z80Flags.HalfCarry;
}
if (((b ^ A) & (b ^ w) & 0x80) > 0)
{
F |= Z80Flags.PV;
}
A = (byte)(w & 0xff);
}
///
/// Add a 16-bit value to a register without carry.
///
/// The vakue.
private void Add16(ref ushort reg, ushort b)
{
int w = reg + b;
F &= Z80Flags.Sign | Z80Flags.Zero | Z80Flags.PV;
if (w > 0xffff)
{
F |= Z80Flags.Carry;
}
if ((reg ^ w ^ b) == 0x1000)
{
F |= Z80Flags.HalfCarry;
}
reg = (ushort)(w & 0xffff);
F |= H35table[reg >> 8];
}
///
/// Add a 16-bit value to a register with carry.
///
/// The vakue.
private void Adc16(ref ushort reg, ushort b)
{
int w = reg + b + (int)(F & Z80Flags.Carry);
F = Z80Flags.None;
if ((w & 0xffff) == 0)
{
F |= Z80Flags.Zero;
}
if ((w & 0x8000) == 0x8000)
{
F |= Z80Flags.Sign;
}
if (w > 0xffff)
{
F |= Z80Flags.Carry;
}
if (((b ^ reg ^ 0x8000) & ((reg ^ w) & 0x8000)) == 0x8000)
{
F |= Z80Flags.PV;
}
if ((reg ^ w ^ b) == 0x1000)
{
F |= Z80Flags.HalfCarry;
}
reg = (ushort)(w & 0xffff);
F |= H35table[reg >> 8];
}
///
/// Subtract a 16-bit value from a register with carry.
///
/// The vakue.
private void Sbc16(ref ushort reg, ushort b)
{
int w = reg - b - (int)(F & Z80Flags.Carry);
F = Z80Flags.Neg;
if (w < 0)
{
w += 0x10000;
F |= Z80Flags.Carry;
}
if ((w & 0xffff) == 0)
{
F |= Z80Flags.Zero;
}
if ((w & 0x8000) == 0x8000)
{
F |= Z80Flags.Sign;
}
if (((b ^ reg) & ((reg ^ w) & 0x8000)) == 0x8000)
{
F |= Z80Flags.PV;
}
if ((reg ^ w ^ b) == 0x1000)
{
F |= Z80Flags.HalfCarry;
}
reg = (ushort)(w & 0xffff);
F |= H35table[reg >> 8];
}
///
/// Increment an 8-bit register.
///
/// The register to increment.
void Inc8(ref byte reg)
{
reg++;
F = Z80Flags.Carry;
if (reg == 0x80)
{
F |= Z80Flags.PV;
}
if ((reg & 0x0f) == 0x00)
{
F |= Z80Flags.HalfCarry;
}
}
///
/// Decrement an 8-bit register.
///
/// The register to decrement.
void Dec8(ref byte reg)
{
reg--;
F = Z80Flags.Carry | Z80Flags.Neg;
if (reg == 0x7f)
{
F |= Z80Flags.PV;
}
if ((reg & 0x0f) == 0x0f)
{
F |= Z80Flags.HalfCarry;
}
}
#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
}
}