예제 #1
0
 /// <summary>
 /// Branch on EQual
 /// </summary>
 /// <param name="mode"></param>
 /// <param name="address"></param>
 public void BEQ(AdressingMode mode, ushort address)
 {
     if (SF.Zero)
     {
         Branch(address);
     }
 }
예제 #2
0
 /// <summary>
 /// Branch on Carry Set
 /// </summary>
 /// <param name="mode"></param>
 /// <param name="address"></param>
 public void BCS(AdressingMode mode, ushort address)
 {
     if (SF.Carry)
     {
         Branch(address);
     }
 }
예제 #3
0
        /// <summary>
        /// CPX - Compare X Register
        /// Z,C,N = X-M
        /// This instruction compares the contents of the X register with another memory held value and sets the zero and carry flags as appropriate.
        /// </summary>
        /// <param name="mode"></param>
        /// <param name="address"></param>
        public void CPX(AdressingMode mode, ushort address)
        {
            byte Operand = ReadByte(address);

            SF.Carry = X >= Operand;
            Set_Negative_and_Zero((byte)(X - Operand));
        }
예제 #4
0
 /// <summary>
 /// Branch on MInus
 /// </summary>
 /// <param name="mode"></param>
 /// <param name="address"></param>
 public void BMI(AdressingMode mode, ushort address)
 {
     if (SF.Negative)
     {
         Branch(address);
     }
 }
예제 #5
0
        /// <summary>
        /// ROL - Rotate Left
        /// Move each of the bits in either A or M one place to the left. Bit 0 is filled with the current value of the carry flag whilst the old bit 7 becomes the new carry flag value.
        /// </summary>
        /// <param name="mode"></param>
        /// <param name="address"></param>
        public void ROL(AdressingMode mode, ushort address)
        {
            if (mode == AdressingMode.Accumulator)
            {
                bool orignalCarry = SF.Carry;

                SF.Carry = (A & 0b1000_0000) != 0;
                A      <<= 1;
                A       |= (byte)(orignalCarry ? 1 : 0);

                Set_Negative_and_Zero(A);
            }
            else
            {
                bool orignalCarry = SF.Carry;
                byte value        = ReadByte(address);

                SF.Carry = (value & 0b1000_0000) != 0;
                value  <<= 1;
                value   |= (byte)(orignalCarry ? 1 : 0);

                WriteByte(address, value);
                Set_Negative_and_Zero(value);
            }
        }
예제 #6
0
 /// <summary>
 /// Branch on oVerflow Set
 /// </summary>
 /// <param name="mode"></param>
 /// <param name="address"></param>
 public void BVS(AdressingMode mode, ushort address)
 {
     if (SF.Overflow)
     {
         Branch(address);
     }
 }
예제 #7
0
        /// <summary>
        /// LDX (Load X Index With Memory) loads the X Index Register with the specified memory. It is similar in function to LDA and LDY opcodes. Unlike LDA, there aren't as many addressing modes available for LDX.
        /// </summary>
        /// <param name="mode"></param>
        /// <param name="address"></param>
        public void LDX(AdressingMode mode, ushort address)
        {
            byte Operand = ReadByte(address);

            Set_Negative_and_Zero(Operand);
            X = Operand;
        }
예제 #8
0
        /// <summary>
        /// ROR - Rotate Right
        /// Move each of the bits in either A or M one place to the right. Bit 7 is filled with the current value of the carry flag whilst the old bit 0 becomes the new carry flag value.
        /// </summary>
        /// <param name="mode"></param>
        /// <param name="address"></param>
        public void ROR(AdressingMode mode, ushort address)
        {
            if (mode == AdressingMode.Accumulator)
            {
                bool orignalCarry = SF.Carry;

                SF.Carry = (A & 1) == 1;
                A      >>= 1;
                A       |= (byte)(orignalCarry ? 0x80 : 0);

                Set_Negative_and_Zero(A);
            }
            else
            {
                bool orignalCarry = SF.Carry;
                byte value        = ReadByte(address);

                SF.Carry = (value & 1) == 1;
                value  >>= 1;
                value   |= (byte)(orignalCarry ? 0x80 : 0);

                WriteByte(address, value);
                Set_Negative_and_Zero(value);
            }
        }
예제 #9
0
        /// <summary>
        /// Add with carry. Adds Operand to A register, sets Zero, Negative, Carry, Overflow flags
        /// https://stackoverflow.com/questions/29193303/6502-emulation-proper-way-to-implement-adc-and-sbc
        /// </summary>
        /// <param name="mode"></param>
        /// <param name="address"></param>
        public void ADC(AdressingMode mode, ushort address)
        {
            //Decimal mode was cut from NES

            byte Operand = ReadByte(address);
            int  carry   = SF.Carry ? 1 : 0;

            byte sum = (byte)(A + Operand + carry);

            Set_Negative_and_Zero(sum);

            SF.Carry    = (A + Operand + carry) > 0xFF;
            SF.Overflow = (~(A ^ Operand) & (A ^ sum) & 0x80) != 0;

            A = sum;

            //0b1xxx_xxxx       0011
            //0b0xxx_xxxx       0101
            //-----------  XOR  ----
            //0b1xxx_xxxx       0110

            //(A ^ Operand)     (Different)Negative and Positive
            //~(A ^ Operand)    Same

            //(A ^ sum)         Different

            //0x80=0b1000_0000  Extract the important bit
        }
예제 #10
0
        /// <summary>
        /// PLA - Pull Accumulator
        /// Pulls an 8 bit value from the stack and into the accumulator. The zero and negative flags are set as appropriate.
        /// </summary>
        /// <param name="mode"></param>
        /// <param name="address"></param>
        public void PLA(AdressingMode mode, ushort address)
        {
            byte Operand = PopByte();

            Set_Negative_and_Zero(Operand);
            A = Operand;
        }
예제 #11
0
        /// <summary>
        /// BIT sets the Z flag as though the value in the address tested were ANDed with the accumulator. The S and V flags are set to match bits 7 and 6 respectively in the value stored at the tested address.
        /// </summary>
        /// <param name="mode"></param>
        /// <param name="address"></param>
        public void BIT(AdressingMode mode, ushort address)
        {
            byte value = ReadByte(address);

            SetNegative(value);
            SetOverflow(value);
            SetZero((byte)(value & A));
        }
예제 #12
0
        /// <summary>
        /// EOR (Exclusive OR Memory With Accumulator) performs a logical XOR on the operand and the accumulator and stores the result in the accumulator. This opcode is similar in function to AND and ORA.
        /// </summary>
        /// <param name="mode"></param>
        /// <param name="address"></param>
        public void EOR(AdressingMode mode, ushort address)
        {
            byte Operand = ReadByte(address);

            Operand ^= A;
            Set_Negative_and_Zero(Operand);
            A = Operand;
        }
예제 #13
0
 /// <summary>
 /// When the MOS 6502 processor was modified into the Ricoh 2A03 chip for the NES, the BRK (Force Break) opcode was preserved. As on other 6502 family CPUs, the BRK instruction advances the program counter by 2, pushes the Program Counter Register and processor status register to the stack, sets the Interrupt Flag to temporarily prevent other IRQs from being executed, and reloads the Program Counter from the vector at $FFFE-$FFFF.
 /// </summary>
 /// <param name="mode"></param>
 /// <param name="address"></param>
 public void BRK(AdressingMode mode, ushort address)
 {
     Push16(PC);
     Push16(SF.P);
     SF.Bit5 = true;
     SF.Bit4 = true;
     PC      = Read16(0xFFFE);
 }
예제 #14
0
        /// <summary>
        /// Substract with carry. Substracts Operand from A register, sets Zero, Negative, Carry, Overflow flags
        /// https://stackoverflow.com/questions/29193303/6502-emulation-proper-way-to-implement-adc-and-sbc
        /// </summary>
        /// <param name="mode"></param>
        /// <param name="address"></param>
        public void SBC(AdressingMode mode, ushort address)
        {
            //same as ADC with with complement value input

            byte Operand = (byte)~ReadByte(address); //Complement
            int  carry   = SF.Carry ? 1 : 0;

            byte sum = (byte)(A + Operand + carry);

            Set_Negative_and_Zero(sum);

            SF.Carry    = (A + Operand + carry) > 0xFF;
            SF.Overflow = (~(A ^ Operand) & (A ^ sum) & 0x80) != 0;

            A = sum;
        }
예제 #15
0
 /// <summary>
 /// LSR - Logical Shift Right
 /// A,C,Z,N = A/2 or M,C,Z,N = M/2
 /// Each of the bits in A or M is shift one place to the right.The bit that was in bit 0 is shifted into the carry flag.Bit 7 is set to zero.
 /// </summary>
 /// <param name="mode"></param>
 /// <param name="address"></param>
 public void LSR(AdressingMode mode, ushort address)
 {
     if (mode == AdressingMode.Accumulator)
     {
         SF.Carry = (A & 1) == 1; //overflow goes carry instead of wrap around
         A      >>= 1;
         Set_Negative_and_Zero(A);
     }
     else
     {
         byte value = ReadByte(address);
         SF.Carry = (value & 1) == 1;
         value  >>= 1;
         Set_Negative_and_Zero(value);
         WriteByte(address, value);
     }
 }
예제 #16
0
 /// <summary>
 /// ASL (Arithmetic Shift Left)
 /// ASL shifts all bits left one position. 0 is shifted into bit 0 and the original bit 7 is shifted into the Carry.
 /// </summary>
 /// <param name="mode"></param>
 /// <param name="address"></param>
 public void ASL(AdressingMode mode, ushort address)
 {
     if (mode == AdressingMode.Accumulator)
     {
         SF.Carry = (A & 0b1000_0000) != 0; //overflow goes to carry from bit 7 instead of wrap around
         A      <<= 1;
         Set_Negative_and_Zero(A);
     }
     else
     {
         byte value = ReadByte(address);
         SF.Carry = (value & 0b1000_0000) != 0; //overflow goes bit 7 instead of wrap around
         value  <<= 1;
         Set_Negative_and_Zero(value);
         WriteByte(address, value);
     }
 }
예제 #17
0
 /// <summary>
 /// CLD (Clear Decimal Flag) clears the Decimal Flag in the Processor Status Register by setting the 3rd bit 0. To set the decimal flag, use SED. Even though the NES doesn't use decimal mode, the opcodes to clear and set the flag do work, so if you need to store a bit, this acts as a free space.
 /// </summary>
 /// <param name="mode"></param>
 /// <param name="address"></param>
 public void CLD(AdressingMode mode, ushort address)
 {
     SF.Decimal = false;
 }
예제 #18
0
 /// <summary>
 /// TXS (Transfer X Index to Stack Pointer) transfers the value in the X index to the stack pointer. The reverse of this opcode is TSX.
 /// </summary>
 /// <param name="mode"></param>
 /// <param name="address"></param>
 public void TXS(AdressingMode mode, ushort address)
 {
     S = X;
     Set_Negative_and_Zero(S);
 }
예제 #19
0
 /// <summary>
 /// TSX (Transfer Stack Pointer to X Index) transfers the value in the stack pointer to the X index. The reverse of this opcode is TXS.
 /// </summary>
 /// <param name="mode"></param>
 /// <param name="address"></param>
 public void TSX(AdressingMode mode, ushort address)
 {
     X = S;
     Set_Negative_and_Zero(X);
 }
예제 #20
0
 /// <summary>
 /// TXA (Transfer X Index to Accumulator) transfers the value in the X index to the accumulator. The reverse of this opcode is TAX.
 /// </summary>
 /// <param name="mode"></param>
 /// <param name="address"></param>
 public void TXA(AdressingMode mode, ushort address)
 {
     A = X;
     Set_Negative_and_Zero(A);
 }
예제 #21
0
 /// <summary>
 /// TAY (Transfer Accumulator to Y Index) transfers the value in the accumulator to the Y index. The reverse of this opcode is TYA.
 /// </summary>
 /// <param name="mode"></param>
 /// <param name="address"></param>
 public void TAY(AdressingMode mode, ushort address)
 {
     Y = A;
     Set_Negative_and_Zero(Y);
 }
예제 #22
0
 /// <summary>
 /// STX (Store X Index In Memory) stores the X index into a specified memory address. It is similar in function to STA and STY.
 /// </summary>
 /// <param name="mode"></param>
 /// <param name="address"></param>
 public void STX(AdressingMode mode, ushort address)
 {
     WriteByte(address, X);
 }
예제 #23
0
 /// <summary>
 /// SED (Set Decimal Flag) set the Decimal Flag in the Processor Status Register by setting the 3rd bit 1. To clear the decimal flag, use CLD. Even though the NES doesn't use decimal mode, the opcodes to clear and set the flag do work, so if you need to store a bit, this acts as a free space.
 /// </summary>
 /// <param name="mode"></param>
 /// <param name="address"></param>
 public void SED(AdressingMode mode, ushort address)
 {
     SF.Decimal = true;
 }
예제 #24
0
 /// <summary>
 /// CLV (Clear Overflow Flag) clears the Overflow Flag in the Processor Status Register by setting the 6th bit 0. There is no opcode for setting the overflow flag.
 /// </summary>
 /// <param name="mode"></param>
 /// <param name="address"></param>
 public void CLV(AdressingMode mode, ushort address)
 {
     SF.Overflow = false;
 }