Exemple #1
0
 /// <summary>
 /// Adds src to a.
 /// </summary>
 /// <param name="op">The op.</param>
 /// <param name="memory">The memory.</param>
 /// <returns>The number of ticks the operation took to complete.</returns>
 /// <remarks>Affected flags: Z 0 H C</remarks>
 public static int Add(Opcode op, GbMemory memory) => ArithOp8Func(op, memory, (mem, val) =>
 {
     byte s  = (byte)(mem.R.A + val);
     mem.R.F = (byte)((s == 0 ? RFlags.ZB : 0) |
                      ((((mem.R.A & 0x0F) + (val & 0x0F)) & 0x10) == 0x10 ? RFlags.HB : 0) | (s < mem.R.A ? RFlags.CB : 0));
     mem.R.A = s;
 });
Exemple #2
0
#pragma warning restore S1067 // Expressions should not be too complex

        /// <summary>
        /// Subtracts src from a.
        /// </summary>
        /// <param name="op">The op.</param>
        /// <param name="memory">The memory.</param>
        /// <returns>The number of ticks the operation took to complete.</returns>
        /// <remarks>Affected flags: Z 1 H C</remarks>
        public static int Sub(Opcode op, GbMemory memory) => ArithOp8Func(op, memory, (mem, val) =>
        {
            byte s  = (byte)(mem.R.A - val);
            mem.R.F = (byte)((s == 0 ? RFlags.ZNB : RFlags.NB) |
                             ((mem.R.A & 0xF) < (val & 0xF) ? RFlags.HB : 0) | (s > mem.R.A ? RFlags.CB : 0));
            mem.R.A = s;
        });
Exemple #3
0
        public static int LdR16(Opcode op, GbMemory mem)
        {
            if (op.Src == 8)
            {
                mem.WriteCycle((op.Dest == 2 || op.Dest == 3) ? mem.R.Hl : mem.R.GetR16Sp(op.Dest), mem.R.A);
            }
            else
            {
                mem.R.A = mem.ReadCycle((op.Src == 2 || op.Src == 3) ? mem.R.Hl : mem.R.GetR16Sp(op.Src));
            }

            if (op.Src == 2 || op.Dest == 2)
            {
                mem.R.Hl++;
            }
            else if (op.Src == 3 || op.Dest == 3)
            {
                mem.R.Hl--;
            }
            else
            {
                // Do nothing.
            }

            return(2);
        }
Exemple #4
0
        /// <summary>
        /// Disassembles an instruction.
        /// </summary>
        /// <param name="memory">The memory.</param>
        /// <returns>A string representing the instruction at <paramref name="memory"/>.R.PC</returns>
        private static string DisassembleInstructionInternal(GbMemory memory)
        {
            byte b = memory.GetMappedMemory(memory.R.Pc);

            if (b >= 0x40 && b < 0xC0)
            {
                if (b < 0x80)
                {
                    if (b == 0x76)
                    {
                        return("HALT");
                    }

                    int dest = ((b >> 3) & 7);
                    int src  = (b & 7);
                    return("LD " + GetR8(dest) + "," + GetR8(src));
                }

                return(DisassembleInstructionArith(b));
            }

            if (b == 0xCB)
            {
                return(DisassembleInstructionCb(memory.GetMappedMemory((ushort)(memory.R.Pc + 1))));
            }

            return(nmOpStrings[b]);
        }
Exemple #5
0
        public static int LdD16(Opcode op, GbMemory mem)
        {
            byte low = mem.ReadCycleI8();

            mem.R.SetR16(op.Dest, new GbUInt16(mem.ReadCycleI8(), low));
            return(3);
        }
Exemple #6
0
        public static int LdA16Sp(Opcode op, GbMemory mem)
        {
            byte low  = mem.ReadCycleI8();
            byte high = mem.ReadCycleI8();

            mem.WriteCycle(new GbUInt16(high, low), mem.R.Sp.LowByte);
            mem.WriteCycle((GbUInt16)(new GbUInt16(high, low) + 1), mem.R.Sp.HighByte);
            return(5);
        }
Exemple #7
0
        public static int Push(Opcode op, GbMemory mem)
        {
            GbUInt16 r = mem.R.GetR16Af(op.Dest);

            mem.Update();
            mem.WriteCyclePush(r.HighByte);
            mem.WriteCyclePush(r.LowByte);
            return(4);
        }
Exemple #8
0
#pragma warning disable S1067 // Expressions should not be too complex

        /// <summary>
        /// Subtracts src and the carry flag from A
        /// </summary>
        /// <param name="op">The op.</param>
        /// <param name="memory">The memory.</param>
        /// <returns>The number of ticks the operation took to complete.</returns>
        /// <remarks>Affected flags: Z 1 H C</remarks>
        public static int Sbc(Opcode op, GbMemory memory) => ArithOp8Func(op, memory, (mem, val) =>
        {
            // https://github.com/eightlittlebits/elbgb/blob/dffc28001a7a01f93ef9e8abecd7161bcf03cc95/elbgb_core/CPU/LR35902.cs#L1084
            // Reimplemented on 8/26/2017 thanks to the previous link.
            int cIn = mem.R.F.GetBit(RFlags.CF) ? 1 : 0;
            int res = mem.R.A - val - cIn;
            mem.R.F = (byte)(((res & 0xFF) == 0 ? RFlags.ZNB : RFlags.NB) |
                             ((mem.R.A & 0xF) - (val & 0xF) - cIn < 0 ? RFlags.HB : 0) | (res < 0 ? RFlags.CB : 0));
            mem.R.A = (byte)res;
        });
Exemple #9
0
        public static int LdHlSpR8(Opcode op, GbMemory mem)
        {
            sbyte s = (sbyte)mem.ReadCycleI8();

            mem.Update();
            mem.R.F = (((mem.R.Sp & 0xFF) +
                        (s & 0xFF)) > 0xFF ? RFlags.CB : (byte)0).AssignBit(RFlags.HF, ((mem.R.Sp & 0x0F) + (s & 0x0F)) > 0x0F);
            mem.R.Hl = mem.R.Sp + s;
            return(3);
        }
Exemple #10
0
 /// <summary>
 /// Adds src and the carry flag to a.
 /// </summary>
 /// <param name="op">The op.</param>
 /// <param name="memory">The memory.</param>
 /// <returns>The number of ticks the operation took to complete.</returns>
 /// <remarks>Affected flags: Z 0 H C</remarks>
 public static int Adc(Opcode op, GbMemory memory) => ArithOp8Func(op, memory, (mem, val) =>
 {
     // https://github.com/eightlittlebits/elbgb/blob/dffc28001a7a01f93ef9e8abecd7161bcf03cc95/elbgb_core/CPU/LR35902.cs#L1038
     // Reimplemented on 8/26/2017 thanks to the previous link.
     int cIn = mem.R.F.GetBit(RFlags.CF) ? 1 : 0;
     int res = val + cIn + mem.R.A;
     mem.R.F = ((res & 0xFF) == 0 ? RFlags.ZB : byte.MinValue).AssignBit(RFlags.HF,
                                                                         (mem.R.A & 0x0F) + (val & 0x0F) + cIn > 0x0F).AssignBit(RFlags.CF, res > 0xFF);
     mem.R.A = (byte)res;
 });
Exemple #11
0
        public static int AddHl(Opcode op, GbMemory mem)
        {
            mem.Update();
            GbUInt16 val = mem.R.GetR16Sp(op.Src);

            mem.R.F = mem.R.F.Res(RFlags.NF).AssignBit(RFlags.HF, (((mem.R.Hl & 0xFFF) + (val & 0xFFF)) & 0x1000) == 0x1000)
                      .AssignBit(RFlags.CF, val + mem.R.Hl < mem.R.Hl);
            mem.R.Hl += val;
            return(2);
        }
Exemple #12
0
        public static int Ret(Opcode op, GbMemory mem)
        {
            byte low = mem.ReadCyclePop();

            mem.R.Pc = new GbUInt16(mem.ReadCyclePop(), low);
            mem.Update();
            mem.IME         |= op.Dest != 0; // Unlike EI IME gets enabled right away.
            mem.NextIMEValue = mem.IME;
            return(4);
        }
Exemple #13
0
        /// <summary>
        /// Adds a 8 bit signed value to the Stack Pointer.
        /// </summary>
        /// <param name="op">The op.</param>
        /// <param name="memory">The memory.</param>
        /// <returns>The number of ticks the operation took to complete.</returns>
        /// <remarks>Affected Flags: - - H C</remarks>
        public static int AddSpR8(Opcode op, GbMemory memory)
        {
            sbyte v = (sbyte)memory.ReadCycleI8();

            memory.Update();
            memory.Update();
            memory.R.F = (((memory.R.Sp & 0x0F) + (v & 0x0F)) > 0x0F ? RFlags.HB : byte.MinValue)
                         .AssignBit(RFlags.CF, ((memory.R.Sp & 0xFF) + (v & 0xFF)) > 0xFF);
            memory.R.Sp += v;
            return(4);
        }
Exemple #14
0
        /// <summary>
        /// Sets the dest bit of the src byte to true
        /// </summary>
        /// <param name="opcode">The opcode.</param>
        /// <param name="memory">The memory.</param>
        /// <returns>The number of ticks the operation took to complete.</returns>
        /// <remarks>Affected Flags: None.</remarks>
        public static int Set(Opcode opcode, GbMemory memory)
        {
            if (opcode.Src != 6)
            {
                memory.R.SetR8(opcode.Src, (byte)(memory.R.GetR8(opcode.Src) | (1 << opcode.Dest)));
                return(1);
            }

            memory.WriteCycleHl((byte)(memory.ReadCycleHl() | (1 << opcode.Dest)));
            return(3);
        }
Exemple #15
0
        /// <summary>
        /// Resources the specified code.
        /// </summary>
        /// <param name="opcode">The opcode.</param>
        /// <param name="memory">The memory.</param>
        /// <returns>The number of ticks the operation took to complete.</returns>
        public static int Res(Opcode opcode, GbMemory memory)
        {
            if (opcode.Src != 6)
            {
                memory.R.SetR8(opcode.Src, memory.R.GetR8(opcode.Src).Res(opcode.Dest));
                return(1);
            }

            memory.WriteCycleHl(memory.ReadCycleHl().Res(opcode.Dest));
            return(3);
        }
Exemple #16
0
        public static int LdD8(Opcode op, GbMemory mem)
        {
            byte val = mem.ReadCycleI8();

            if (op.Dest == 6)
            {
                mem.WriteCycle(mem.R.Hl, val);
                return(3);
            }

            mem.R.SetR8(op.Dest, val);
            return(2);
        }
Exemple #17
0
        public static int LdH(Opcode op, GbMemory mem)
        {
            if (op.Dest == 7)
            {
                mem.R.A = mem.ReadCycle(new GbUInt16(0xFF, mem.ReadCycleI8()));
            }
            else
            {
                mem.WriteCycle(new GbUInt16(0xFF, mem.ReadCycleI8()), mem.R.A);
            }

            return(3);
        }
Exemple #18
0
        /// <summary>
        /// Checks if the dest bit of the src register is true.
        /// </summary>
        /// <param name="code">The code.</param>
        /// <param name="memory">The memory.</param>
        /// <returns>The number of ticks the operation took to complete.</returns>
        public static int Bit(Opcode code, GbMemory memory)
        {
            if (code.Src != 6)
            {
                memory.R.F = (byte)(memory.R.F.AssignBit(RFlags.ZF, !memory.R.GetR8(code.Src).GetBit(code.Dest))
                                    .Res(RFlags.NF) | RFlags.HB);
                return(1);
            }

            memory.R.F = (byte)(memory.R.F.AssignBit(RFlags.ZF, !memory.ReadCycleHl().GetBit(code.Dest))
                                .Res(RFlags.NF) | RFlags.HB);
            return(2);
        }
Exemple #19
0
        public static int Jr8(Opcode op, GbMemory mem)
        {
            byte val = mem.ReadCycleI8();

            if (op.Src != 0 && GetConditionalJumpState(op.Dest, op.Src, mem.R.F))
            {
                return(2);
            }

            mem.Update();
            mem.R.Pc += (sbyte)val;
            return(3);
        }
Exemple #20
0
        /// <summary>
        /// Conditional Return.
        /// </summary>
        /// <param name="op">The opcode.</param>
        /// <param name="mem">The memory.</param>
        public static int RetC(Opcode op, GbMemory mem)
        {
            mem.Update();
            if (GetConditionalJumpState(op.Dest, op.Src, mem.R.F))
            {
                return(2);
            }

            byte low = mem.ReadCyclePop();

            mem.R.Pc = new GbUInt16(mem.ReadCyclePop(), low);
            mem.Update();
            return(5);
        }
Exemple #21
0
        public static int Call(Opcode op, GbMemory mem)
        {
            byte low  = mem.ReadCycleI8();
            byte high = mem.ReadCycleI8();

            if (op.Src != 0 && GetConditionalJumpState(op.Dest, op.Src, mem.R.F))
            {
                return(3);
            }

            mem.Update();
            mem.Call(new GbUInt16(high, low));
            return(6);
        }
Exemple #22
0
        /// <summary>
        /// Runs an instruction and returns the number of ticks it took to complete.
        /// </summary>
        /// <param name="memory">The memory.</param>
        /// <returns>The number of ticks that the instruction took to run.</returns>
        public static int Run(GbMemory memory)
        {
            memory.Update(1);
            byte opcode = memory.LdI8();

            memory.Update(1);
            if (memory.HaltBugged)
            {
                memory.HaltBugged = false;
                memory.R.Pc--;
            }

            return(NmOps[opcode].Invoke(memory));
        }
Exemple #23
0
        public static int Pop(Opcode op, GbMemory mem)
        {
            if (op.Dest == 3)
            {
                mem.R.F = (byte)(mem.ReadCyclePop() & 0xF0);
                mem.R.A = mem.ReadCyclePop();
            }
            else
            {
                mem.R.SetR8((op.Dest * 2) + 1, mem.ReadCyclePop());
                mem.R.SetR8(op.Dest * 2, mem.ReadCyclePop());
            }

            return(3);
        }
Exemple #24
0
        public static int LdA16(Opcode op, GbMemory mem)
        {
            byte low  = mem.ReadCycleI8();
            byte high = mem.ReadCycleI8();

            if (op.Dest == 7)
            {
                mem.R.A = mem.ReadCycle(new GbUInt16(high, low));
            }
            else
            {
                mem.WriteCycle(new GbUInt16(high, low), mem.R.A);
            }

            return(4);
        }
Exemple #25
0
        /// <summary>
        /// A framework for calling arithmetic operation instructions.
        /// </summary>
        /// <param name="op">The op.</param>
        /// <param name="memory">The memory.</param>
        /// <param name="operation">The operation.</param>
        /// <exception cref="ArgumentNullException"><paramref name="operation"/> is null</exception>
        internal static int ArithOp8Func(Opcode op, GbMemory memory, ArithOp8 operation)
        {
            if (operation == null)
            {
                throw new ArgumentNullException(nameof(operation));
            }

            if (op.Src != 6 && op.Src != 8)
            {
                operation(memory, memory.R.GetR8(op.Src));
                return(1);
            }

            operation(memory, op.Src == 6 ? memory.ReadCycleHl() : memory.ReadCycleI8());
            return(2);
        }
Exemple #26
0
        /// <summary>
        /// A framework for calling bitwise operation instructions.
        /// </summary>
        /// <param name="op">The op.</param>
        /// <param name="memory">The memory.</param>
        /// <param name="operation">The operation.</param>
        /// <exception cref="ArgumentNullException"><paramref name="operation"/> is null</exception>
        internal static int BitOpFunc(Opcode op, GbMemory memory, BitOp operation)
        {
            if (operation == null)
            {
                throw new ArgumentNullException(nameof(operation));
            }

            if (op.Src != 6)
            {
                memory.R.SetR8(op.Src, operation(memory, memory.R.GetR8(op.Src)));
                return(1);
            }

            memory.WriteCycleHl(operation(memory, memory.ReadCycleHl()));
            return(3);
        }
Exemple #27
0
        /// <summary>
        /// Preforms BCD conversion.
        /// </summary>
        /// <param name="op">The op.</param>
        /// <param name="mem">The memory.</param>
        /// <returns>The number of ticks the operation took to complete.</returns>
        /// <remarks>Affected Flags: Z - 0 C</remarks>
        public static int Daa(Opcode op, GbMemory mem)
        {
            int res = mem.R.A;

            if (mem.R.F.GetBit(RFlags.NF))
            {
                if (mem.R.F.GetBit(RFlags.HF))
                {
                    res = (res - 6) & 0xFF;
                }

                if (mem.R.F.GetBit(RFlags.CF))
                {
                    res -= 0x60;
                }
            }
            else
            {
                if (mem.R.F.GetBit(RFlags.HF) || (res & 0xF) > 9)
                {
                    res += 0x06;
                }

                if (mem.R.F.GetBit(RFlags.CF) || res > 0x9F)
                {
                    res += 0x60;
                }
            }

            mem.R.F = (byte)(mem.R.F & RFlags.NCB);
            if ((res & 0x100) == 0x100)
            {
                mem.R.F |= RFlags.CB;
            }

            res &= 0xFF;

            if (res == 0)
            {
                mem.R.F |= RFlags.ZB;
            }

            mem.R.A = (byte)res;
            return(1);
        }
Exemple #28
0
        public static int Ld8(Opcode op, GbMemory memory)
        {
            if (op.Src == 6 || op.Dest == 6)
            {
                if (op.Src == op.Dest) // By math logic, these are both 6 if this is true.
                {
                    throw new InvalidOperationException("Opcode with dest = 6 and src = 6 is invalid for this instruction.");
                }

                if (op.Src == 6)
                {
                    memory.R.SetR8(op.Dest, memory.ReadCycleHl());
                }
                else
                {
                    memory.WriteCycle(memory.R.Hl, memory.R.GetR8(op.Src));
                }

                return(2);
            }

            memory.R.SetR8(op.Dest, memory.R.GetR8(op.Src));
            return(1);
        }
Exemple #29
0
 public static int Rst(Opcode op, GbMemory mem)
 {
     mem.Update();
     mem.Call(new GbUInt16(0, (byte)(op.Dest * 8)));
     return(4);
 }
Exemple #30
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Timer"/> class.
 /// </summary>
 /// <param name="memory">The memory.</param>
 internal Timer(GbMemory memory) => this.memory = memory;