예제 #1
0
 /// <summary>
 /// Constructs a new CPU instance "wired" with the specified Bus instance.
 /// </summary>
 /// <param name="bus">The Bus instance for accessing other devices.</param>
 public CPU(Bus bus)
 {
     this.bus          = bus;
     State             = new CPUState();
     interruptHandlers = new Dictionary <InterruptType, ushort>()
     {
         { InterruptType.Reset, 0xFFFC },
         { InterruptType.IRQ, 0xFFFC },
         { InterruptType.NMI, 0xFFFA }
     };
 }
예제 #2
0
        /// <summary>
        /// Invokes the reset sequence of the processor.
        /// </summary>
        public void InvokeReset()
        {
            // Reset register values
            State = new CPUState();

            // Read the RESET vector and set its contents to the program counter register
            byte[] newAddress = bus.Read(interruptHandlers[InterruptType.Reset], 2);
            State.PC   = BitConverter.ToUInt16(newAddress, 0);
            lastOpcode = 0;

            // Update the UI
            UpdateEvent(null);
        }
예제 #3
0
        /// <summary>
        /// Gets the final operand value for this operation.
        /// </summary>
        /// <param name="state">The CPUState instance containing register values and other state properties of the CPU.</param>
        /// <param name="bus">The Bus instance for accessing devices.</param>
        /// <returns>A single byte of data.</returns>
        protected byte GetOperandValue(CPUState state, Bus bus)
        {
            if (Instruction.AddressMode == AddressMode.Implied)
            {
                return(0);
            }

            if (Instruction.AddressMode == AddressMode.Accumulator)
            {
                return(state.Accumulator);
            }

            if (Instruction.AddressMode != AddressMode.Immediate)
            {
                int effectiveAddress = CalculateEffectiveAddress(state, bus);
                return(bus.Read(effectiveAddress));
            }

            return(Operand[0]);
        }
예제 #4
0
        /// <summary>
        /// Calculates an effective address from the operand based on the address mode of the instruction.
        /// </summary>
        /// <param name="state">The CPUState instance containing register values and other state properties of the CPU.</param>
        /// <param name="bus">The Bus instance for accessing devices.</param>
        /// <returns>The effective address in the memory.</returns>
        protected int CalculateEffectiveAddress(CPUState state, Bus bus)
        {
            byte[] addressBytes;
            switch (Instruction.AddressMode)
            {
            case AddressMode.Absolute:
                return(GetUInt16FromBytes(Operand));

            case AddressMode.AbsoluteX:
                return(GetUInt16FromBytes(Operand) + state.RegisterX);

            case AddressMode.AbsoluteY:
                return(GetUInt16FromBytes(Operand) + state.RegisterY);

            case AddressMode.ZeroPage:
                return(Operand[0]);

            case AddressMode.ZeroPageX:
                return(Operand[0] + state.RegisterX);

            case AddressMode.ZeroPageY:
                return(Operand[0] + state.RegisterY);

            case AddressMode.Relative:
                return(state.PC + (sbyte)Operand[0]);    // Cast the operand to signed byte (offset can be negative - used in branching instructions)

            case AddressMode.Indirect:
                addressBytes = bus.Read(GetUInt16FromBytes(Operand), 2);
                return(GetUInt16FromBytes(addressBytes));

            case AddressMode.IndirectX:
                addressBytes = bus.Read(Operand[0] + state.RegisterX, 2);
                return(GetUInt16FromBytes(addressBytes));

            case AddressMode.IndirectY:
                addressBytes = bus.Read(Operand[0], 2);
                return(GetUInt16FromBytes(addressBytes) + state.RegisterY);
            }

            return(0);
        }
예제 #5
0
        /// <summary>
        /// Constructs a new UpdateUIEventArgs instance having properties initialized with values from the CPU state and the currently executed Operation.
        /// </summary>
        /// <param name="cpuState">The CPU State instance containing register values and other state properties of the CPU.</param>
        /// <param name="operation">The Operation instance representing the last executed instruction with it's address in the memory and operand value.</param>
        public UpdateUIEventArgs(CPUState cpuState, Operation operation = null)
        {
            RegisterX               = cpuState.RegisterX;
            RegisterY               = cpuState.RegisterY;
            Accumulator             = cpuState.Accumulator;
            StackPointer            = cpuState.SP;
            ProgramCounter          = cpuState.PC;
            Status                  = cpuState.Status;
            HasCarryFlag            = cpuState.HasStatusFlag(StatusFlag.Carry);
            HasNegativeFlag         = cpuState.HasStatusFlag(StatusFlag.Negative);
            HasInterruptDisableFlag = cpuState.HasStatusFlag(StatusFlag.InterruptDisable);
            HasBreakFlag            = cpuState.HasStatusFlag(StatusFlag.Break);
            HasDecimalFlag          = cpuState.HasStatusFlag(StatusFlag.Decimal);
            HasOverflowFlag         = cpuState.HasStatusFlag(StatusFlag.Overflow);
            HasZeroFlag             = cpuState.HasStatusFlag(StatusFlag.Zero);

            if (operation != null)
            {
                OperationAddress = operation.Address;
                OperationOpName  = operation.Instruction.OpcodeName;
                OperationOperand = operation.GetOperandPretty();
            }
        }
예제 #6
0
 /// <summary>
 /// Increments the Stack Pointer by one and pops a single byte from the Stack.
 /// </summary>
 /// <param name="state">The CPUState instance containing register values.</param>
 public byte StackPop(CPUState state)
 {
     state.SP++;
     return(Read(Simulator.STACK_ADDRESS + state.SP));
 }
예제 #7
0
 /// <summary>
 /// Pushes a single byte on the Stack and decrements the Stack Pointer by one.
 /// </summary>
 /// <param name="state">The CPUState instance containing register values.</param>
 /// <param name="data">The single byte to be pushed on the Stack.</param>
 public void StackPush(CPUState state, byte data)
 {
     Write(Simulator.STACK_ADDRESS + state.SP, data);
     state.SP--;
 }
예제 #8
0
 /// <summary>
 /// Executes the operation, all instructions have their own logic implemented in this method.
 /// </summary>
 /// <param name="state">The CPUState instance containing register values and other state properties of the CPU.</param>
 /// <param name="bus">The Bus instance for accessing devices.</param>
 public abstract void Execute(CPUState state, Bus bus);
예제 #9
0
 /// <summary>
 /// Performs some bitwise operations and tests the result. If the result is not equal to zero then the Overflow status flag is set, otherwise the flag is cleared.
 /// More about this here: http://www.righto.com/2012/12/the-6502-overflow-flag-explained.html
 /// </summary>
 /// <param name="state">The CPUState instance containing register values and other state properties of the CPU.</param>
 /// <param name="value">A value to be used in the bitwise operations.</param>
 /// <param name="operandValue">An operand value to be used in the bitwise operations.</param>
 /// <param name="result">A result from the CPU operation.</param>
 protected void CheckOverflowFlag(CPUState state, int value, byte operandValue, int result)
 {
     state.ChangeStatusFlag(StatusFlag.Overflow, ((value ^ result) & (operandValue ^ result) & 0x80) != 0);
 }
예제 #10
0
 /// <summary>
 /// Compares the specified value with the operand value and sets the Carry status flag if the value is greather or equals than the operand value, otherwise the flag is cleared.
 /// </summary>
 /// <param name="state">The CPUState instance containing register values and other state properties of the CPU.</param>
 /// <param name="value">The value to be compared.</param>
 /// <param name="operandValue">The operand value to be compared.</param>
 protected void CheckCarryFlag(CPUState state, int value, byte operandValue)
 {
     state.ChangeStatusFlag(StatusFlag.Carry, value >= operandValue);
 }
예제 #11
0
 /// <summary>
 /// Checks the highest order bit of the specified 16-bit value and sets the Negative status flag if it is not equal to zero, otherwise the flag is cleared.
 /// </summary>
 /// <param name="state">The CPUState instance containing register values and other state properties of the CPU.</param>
 /// <param name="value">The value to be checked.</param>
 protected void CheckNegativeFlag(CPUState state, int value)
 {
     state.ChangeStatusFlag(StatusFlag.Negative, (value & 0x80) != 0);
 }
예제 #12
0
 /// <summary>
 /// Checks the specified value and sets the Zero status flag if it is equal to zero, otherwise the flag is cleared.
 /// </summary>
 /// <param name="state">The CPUState instance containing register values and other state properties of the CPU.</param>
 /// <param name="value">The value to be checked.</param>
 protected void CheckZeroFlag(CPUState state, int value)
 {
     state.ChangeStatusFlag(StatusFlag.Zero, value == 0);
 }