Пример #1
0
 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());
 }
Пример #2
0
 private void SetFlag(CpuFlags flag, bool value)
 {
     if (value)
     {
         flags |= flag;
     }
     else
     {
         flags &= ~flag;
     }
 }
Пример #3
0
 public void SetFlag(CpuFlags flag, bool value)
 {
     if (value)
     {
         P |= flag;
     }
     else
     {
         P &= ~flag;
     }
 }
Пример #4
0
        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;
            }
        }
Пример #5
0
 private bool GetFlag(CpuFlags flag) => flags.HasFlag(flag);
Пример #6
0
        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++;
        }
Пример #7
0
    public byte SP = 255; // StackPointer

    public CpuRegister()
    {
        Flag = new CpuFlags(this);
    }
Пример #8
0
 public FlagsAffectedAttribute(CpuFlags affectedFlags)
 {
     this.AffectedFlags = affectedFlags;
 }
Пример #9
0
 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")}");
 }
Пример #10
0
 public bool GetFlag(CpuFlags flag) => (P & flag) != 0;
Пример #11
0
 public FlagsAffectedAttribute(CpuFlags affectedFlags)
 {
     this.AffectedFlags = affectedFlags;
 }