private static string FlagsString(CpuFlags flags) { return(new StringBuilder() .Append(flags.HasFlag(CpuFlags.Zero) ? 'Z' : ' ') .Append(flags.HasFlag(CpuFlags.Sub) ? 'N' : ' ') .Append(flags.HasFlag(CpuFlags.HalfCarry) ? 'H' : ' ') .Append(flags.HasFlag(CpuFlags.Carry) ? 'C' : ' ') .ToString()); }
private void SetFlag(CpuFlags flag, bool value) { if (value) { flags |= flag; } else { flags &= ~flag; } }
public void SetFlag(CpuFlags flag, bool value) { if (value) { P |= flag; } else { P &= ~flag; } }
private void HandlePrefixCb(PrefixCbOpCodes cbOpCode) { Debug.WriteLine($"[cpu] Handling PrefixCB: {cbOpCode}"); switch (cbOpCode) { case PrefixCbOpCodes.TestMsbE: if (BitOperations.MostSignificantBit(_regHl.HighByte) != 0) { _regFlags |= CpuFlags.Zero; } else { _regFlags &= ~CpuFlags.Zero; } _regFlags |= CpuFlags.HalfCarry; _regFlags &= ~CpuFlags.Subtract; break; } }
private bool GetFlag(CpuFlags flag) => flags.HasFlag(flag);
public void Step() { var opByte = _gb.Mmu.ReadByte(_regPc.Word); var op = (OpCode)opByte; Debug.WriteLine($"[cpu] STEP#{_steps} -> {op.ToString()}({opByte.ToString("X2")}) | PC:{_regPc.Word:X4} SP:{_regSp.Word:X4} AF:{_regAf.Word:X4} BC:{_regBc.Word:X4} DE:{_regDe.Word:X4} HL:{_regHl.Word:X4} Z{(_regFlags.HasFlag(CpuFlags.Zero) ? "+" : "-")} N{(_regFlags.HasFlag(CpuFlags.Subtract) ? "+" : "-")} H{(_regFlags.HasFlag(CpuFlags.HalfCarry) ? "+" : "-")} C{(_regFlags.HasFlag(CpuFlags.Carry) ? "+" : "-")}"); switch (op) { // Don't do anything case OpCode.Nop: break; /* * // Decrement Register B * case OpCode.DecB: * _regBc.LowByte--; * * if(_regBc.LowByte == 0) * _regFlags |= CpuFlags.Zero; * else * _regFlags &= ~CpuFlags.Zero; * * _regFlags |= CpuFlags.Subtract; * //TODO carry?! * break; * * // Load 8bit parameter into Register B * case OpCode.LdBD8: * _regBc.LowByte = _gb.Mmu.ReadByte(_regPc.Word + 1); * break; * * case OpCode.DecC: * _regBc.HighByte--; * * if(_regBc.HighByte == 0) * _regFlags |= CpuFlags.Zero; * else * _regFlags &= ~CpuFlags.Zero; * * _regFlags |= CpuFlags.Subtract; * //TODO carry?! * break; * * // Load 8bit parameter into Register C * case OpCode.LdCD8: * _regBc.HighByte = _gb.Mmu.ReadByte(_regPc.Word + 1); * break; * * // Wait for input TODO * case OpCode.Stop: * break; * * case OpCode.IncD: * _regDe.LowByte++; * * if(_regDe.LowByte == 0) * _regFlags |= CpuFlags.Zero; * else * _regFlags &= ~CpuFlags.Zero; * * _regFlags &= ~CpuFlags.Subtract; * * //TODO carry * break; * * case OpCode.DecD: * _regDe.LowByte--; * * if(_regDe.LowByte == 0) * _regFlags |= CpuFlags.Zero; * else * _regFlags &= ~CpuFlags.Zero; * * _regFlags |= CpuFlags.Subtract; * //TODO carry?! * break; * * // Load 8bit parameter into D * case OpCode.LdDD8: * _regDe.LowByte = _gb.Mmu.ReadByte(_regPc.Word + 1); * break; * * // Add 16bit HL to DE * case OpCode.AddHlDe: * { * _regHl.Word += _regDe.Word; * * _regFlags &= ~CpuFlags.Subtract; * * //TODO carry * } * break; * * // Decrement Register E * case OpCode.DecE: * _regDe.HighByte--; * * if(_regDe.HighByte == 0) * _regFlags |= CpuFlags.Zero; * else * _regFlags &= ~CpuFlags.Zero; * * _regFlags |= CpuFlags.Subtract; * //TODO carry?! * break; * * // Rotate A to the right * case OpCode.Rra: * _regAf.LowByte = (byte) ((_regAf.LowByte >> 1) | (_regAf.LowByte << (32 - 1))); * break; * * // If Zero flag is not set, add 8bit parameter to current address and jump to it * case OpCode.JrNzR8: * if (!_regFlags.HasFlag(CpuFlags.Zero)) * { * _regPc.Word += _gb.Mmu.ReadByte(_regPc.Word + 1); * return; * } * break; * * // Load 16bit parameter into Registers HL * case OpCode.LdHlD16: * _regHl.Word = _gb.Mmu.ReadWord(_regPc.Word + 1); * break; * * // Decrement Register H * case OpCode.DecH: * _regHl.LowByte--; * * if(_regHl.LowByte == 0) * _regFlags |= CpuFlags.Zero; * else * _regFlags &= ~CpuFlags.Zero; * * _regFlags |= CpuFlags.Subtract; * break; * * // Add 16bit HL to HL * case OpCode.AddHlHl: * { * _regHl.Word *= 2; * * _regFlags &= ~CpuFlags.Subtract; * * //TODO carry * } * break; * * // Put Register A into memory at offset in Registers HL, then decrement offset in Registers HL * case OpCode.LdHlMinusA: * { * _gb.Mmu.WriteByte(_regHl.Word, _regAf.LowByte); * * _regHl.Word--; * } * break; * * // Put 8bit parameter into memory at Registers HL * case OpCode.LdHl: * { * var offset = _gb.Mmu.ReadWord(_regHl.Word); * _gb.Mmu.WriteByte(offset, _gb.Mmu.ReadByte(_regPc.Word + 1)); * } * break; * * // Load 8bit parameter into Register A * case OpCode.LdAD8: * _regAf.LowByte = _gb.Mmu.ReadByte(_regPc.Word + 1); * break; * * // Put Register A into memory at Registers HL * case OpCode.LdHlA: * { * _gb.Mmu.WriteByte(_regHl.Word, _regAf.LowByte); * } * break; * * // Load Register E into Register A * case OpCode.LdAE: * _regAf.LowByte = _regDe.HighByte; * break; * * // XOR Register A with Register A * case OpCode.XorA: * _regAf.LowByte = (byte) (_regAf.LowByte ^ _regAf.LowByte); * * if (_regAf.LowByte == 0) * _regFlags |= CpuFlags.Zero; * else * _regFlags &= ~CpuFlags.Zero; * break; * * // OR Register B with Register A, result in A * case OpCode.OrB: * _regAf.LowByte = (byte) (_regAf.LowByte | _regBc.LowByte); * * _regFlags = CpuFlags.None; * * if (_regAf.LowByte == 0) * _regFlags |= CpuFlags.Zero; * else * _regFlags &= ~CpuFlags.Zero; * break; * * case OpCode.CpA: * // TODO What? * if (_regAf.LowByte == _regAf.LowByte) * _regFlags |= CpuFlags.Zero; * else * _regFlags &= ~CpuFlags.Zero; * * _regFlags |= CpuFlags.Subtract; * * // TODO carry * break; * * // Jump to offset at 16bit parameter * case OpCode.JpA16: * _regPc.Word = _gb.Mmu.ReadWord(_regPc.Word + 1); * return; * * // Put Register A into memory at $FF00 + 8bit parameter * case OpCode.LdhA8A: * _gb.Mmu.WriteByte(0xFF00 + _gb.Mmu.ReadByte(_regPc.Word + 1), _regAf.LowByte); * break; * * // Put Register A into address at 16bit parameter * case OpCode.LdA16A: * _gb.Mmu.WriteByte(_gb.Mmu.ReadWord(_regPc.Word + 1), _regAf.LowByte); * break; * * // Put memory at $FF00 + 8bit parameter into Register A * case OpCode.LdhAA8: * _regAf.LowByte = _gb.Mmu.ReadByte(0xFF00 + _gb.Mmu.ReadByte(_regPc.Word + 1)); * break; * * // Disable interrupts on the next instruction * case OpCode.Di: * // TODO * throw new NotImplementedException(); * break; * * // Enable interrupts on the next instruction * case OpCode.Ei: * // TODO * throw new NotImplementedException(); * break; * * // Compare Register A with 8bit parameter, throw away result * case OpCode.CpD8: * if (_regAf.LowByte == _gb.Mmu.ReadByte(_regPc.Word + 1)) * _regFlags |= CpuFlags.Zero; * else * _regFlags &= ~CpuFlags.Zero; * * _regFlags |= CpuFlags.Subtract; * * // TODO carry * break; */ // Load word parameter into Stack Pointer case OpCode.LdSpD16: var parameter = _gb.Mmu.ReadWord(_regPc.Word + 1); _regSp.Word = parameter; break; // XOR Register A with Register A case OpCode.XorA: _regAf.HighByte ^= _regAf.HighByte; if (_regAf.HighByte == 0) { _regFlags |= CpuFlags.Zero; } else { _regFlags &= ~CpuFlags.Zero; } break; // Load 16bit parameter into Registers HL case OpCode.LdHlD16: _regHl.Word = _gb.Mmu.ReadWord(_regPc.Word + 1); break; // Put Register A into memory at offset in Registers HL, then decrement offset in Registers HL case OpCode.LdHlMinusA: _gb.Mmu.WriteByte(_regHl.Word, _regAf.HighByte); _regHl.Word--; break; case OpCode.PrefixCb: HandlePrefixCb((PrefixCbOpCodes)_gb.Mmu.ReadByte(_regPc.Word + 1)); break; // If Zero flag is not set, add 8bit parameter to current address and jump to it case OpCode.JrNzR8: if (!_regFlags.HasFlag(CpuFlags.Zero)) { var jumpTo = (sbyte)(_gb.Mmu.ReadByte(_regPc.Word + 1) + 2); _regPc.Word += jumpTo; return; } break; default: throw new Exception($"Unhandled OpCode: {op.ToString()}({opByte.ToString("X2")})"); } _regPc.Word += op.GetLength(); _steps++; }
public byte SP = 255; // StackPointer public CpuRegister() { Flag = new CpuFlags(this); }
public FlagsAffectedAttribute(CpuFlags affectedFlags) { this.AffectedFlags = affectedFlags; }
public static string ToPrettyString(this CpuFlags cpuFlags) { return($"{(cpuFlags.HasFlag(CpuFlags.N) ? "N" : "n")}{(cpuFlags.HasFlag(CpuFlags.V) ? "V" : "v")}--{(cpuFlags.HasFlag(CpuFlags.D) ? "D" : "d")}{(cpuFlags.HasFlag(CpuFlags.I) ? "I" : "i")}{(cpuFlags.HasFlag(CpuFlags.Z) ? "Z" : "z")}{(cpuFlags.HasFlag(CpuFlags.C) ? "C" : "c")}"); }
public bool GetFlag(CpuFlags flag) => (P & flag) != 0;