Beispiel #1
0
        void IClockSink.OnPowerUp()
        {
            _nextOpCodeStatus = OpCodeStatus.None;
            _nextMicroCode    = MicroCode.None;

            // see also: https://wiki.nesdev.com/w/index.php/CPU_power_up_state
            Status.Value = 0x34;

            Registers.A = 0;
            Registers.X = 0;
            Registers.Y = 0;
            Registers.S = 0xFD;

            // _masterClient.Value = 0;
            // _masterClient.Write(0x4017); // frame irq enabled
            // _masterClient.Write(0x4015); // all channels disabled

            // $4000 -$400F = $00
            // for (ushort i = 0x4000; i <= 0x400F; i++)
            //    _masterClient.Write(i);

            // TODO:
            // All 15 bits of noise channel LFSR = $0000[3].The first time the LFSR is clocked from the all-0s state, it will shift in a 1.
            Interrupt(InterruptType.Reset);
        }
Beispiel #2
0
        private (MicroCode nextMicroCode, OpCodeStatus nextOpCodeStatus) ExecuteOpCode(OpCodeStatus code)
        {
            switch (code)
            {
            case OpCodeStatus.Interrupt_1:
                _addressState.ResultA = (byte)(Registers.PC >> 8);
                return(MicroCode.Push, OpCodeStatus.Interrupt_2);

            case OpCodeStatus.Interrupt_2:
                _addressState.ResultA = (byte)Registers.PC;
                return(MicroCode.Push, OpCodeStatus.Interrupt_3);

            case OpCodeStatus.Interrupt_3:
                _addressState.ResultA = Status.Value;
                return(MicroCode.Push, OpCodeStatus.Interrupt_4);

            case OpCodeStatus.Interrupt_4:
                _addressState.MemoryAddress = _interruptVectors[(byte)_interruptType.Value];
                _masterClient.Read(_addressState.MemoryAddress);
                _addressState.ResultA = _masterClient.Value;
                return(MicroCode.Nop, OpCodeStatus.Interrupt_5);

            case OpCodeStatus.Interrupt_5:
                _addressState.MemoryAddress++;
                _masterClient.Read(_addressState.MemoryAddress);
                _addressState.ResultB = _masterClient.Value;
                return(MicroCode.Nop, OpCodeStatus.Interrupt_6);

            case OpCodeStatus.Interrupt_6:
                _addressState.MemoryAddress = (ushort)((_addressState.ResultB << 8) | _addressState.ResultA);
                Status.I       = true;
                _interruptType = null;
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.PC, AddressOperation.None, false);
                return(MicroCode.Addressing, OpCodeStatus.None);

            case OpCodeStatus.Relative_Jump:
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.PC, AddressOperation.None, false);
                return(MicroCode.Relative, OpCodeStatus.None);

            case OpCodeStatus.SEI_1_Implied:
                return(MicroCode.SEI, OpCodeStatus.None);

            case OpCodeStatus.CLC_1_Implied:
                return(MicroCode.CLC, OpCodeStatus.None);

            case OpCodeStatus.CLD_1_Implied:
                return(MicroCode.CLD, OpCodeStatus.None);

            case OpCodeStatus.STY_1_Absolute:
                _addressState.Set(AddressOperand.Y, AddressOperand.None, AddressOperand.Memory, AddressOperation.None, false);
                return(MicroCode.Absolute_1, OpCodeStatus.None);

            case OpCodeStatus.STY_1_ZeroPage:
                _addressState.Set(AddressOperand.Y, AddressOperand.None, AddressOperand.Memory, AddressOperation.None, false);
                return(MicroCode.ZeroPage_1, OpCodeStatus.None);

            case OpCodeStatus.STA_1_ZeroPage:
                _addressState.Set(AddressOperand.A, AddressOperand.None, AddressOperand.Memory, AddressOperation.None, false);
                return(MicroCode.ZeroPage_1, OpCodeStatus.None);

            case OpCodeStatus.STA_1_ZeroPageX:
                _addressState.Set(AddressOperand.A, AddressOperand.None, AddressOperand.Memory, AddressOperation.None, false);
                return(MicroCode.ZeroPageX_1, OpCodeStatus.None);

            case OpCodeStatus.STA_1_AbsoluteX:
                _addressState.Set(AddressOperand.A, AddressOperand.None, AddressOperand.Memory, AddressOperation.None, false);
                return(MicroCode.AbsoluteX_1, OpCodeStatus.None);

            case OpCodeStatus.STA_1_Absolute:
                _addressState.Set(AddressOperand.A, AddressOperand.None, AddressOperand.Memory, AddressOperation.None, false);
                return(MicroCode.Absolute_1, OpCodeStatus.None);

            case OpCodeStatus.STX_1_ZeroPage:
                _addressState.Set(AddressOperand.X, AddressOperand.None, AddressOperand.Memory, AddressOperation.None, false);
                return(MicroCode.ZeroPage_1, OpCodeStatus.None);

            case OpCodeStatus.STX_1_Absolute:
                _addressState.Set(AddressOperand.X, AddressOperand.None, AddressOperand.Memory, AddressOperation.None, false);
                return(MicroCode.Absolute_1, OpCodeStatus.None);

            case OpCodeStatus.LDY_1_Immediate:
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.Y, AddressOperation.None, true);
                return(MicroCode.Immediate, OpCodeStatus.None);

            case OpCodeStatus.LDY_1_Absolute:
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.Y, AddressOperation.None, true);
                return(MicroCode.Absolute_1, OpCodeStatus.None);

            case OpCodeStatus.LDY_1_ZeroPage:
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.Y, AddressOperation.None, true);
                return(MicroCode.ZeroPage_1, OpCodeStatus.None);

            case OpCodeStatus.LDX_1_Immediate:
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.X, AddressOperation.None, true);
                return(MicroCode.Immediate, OpCodeStatus.None);

            case OpCodeStatus.TAX_1_Implied:
                _addressState.Set(AddressOperand.A, AddressOperand.None, AddressOperand.X, AddressOperation.None, true);
                return(MicroCode.Addressing, OpCodeStatus.None);

            case OpCodeStatus.TAY_1_Implied:
                _addressState.Set(AddressOperand.A, AddressOperand.None, AddressOperand.Y, AddressOperation.None, true);
                return(MicroCode.Addressing, OpCodeStatus.None);

            case OpCodeStatus.TXA_1_Implied:
                _addressState.Set(AddressOperand.X, AddressOperand.None, AddressOperand.A, AddressOperation.None, true);
                return(MicroCode.Addressing, OpCodeStatus.None);

            case OpCodeStatus.TYA_1_Implied:
                _addressState.Set(AddressOperand.Y, AddressOperand.None, AddressOperand.A, AddressOperation.None, true);
                return(MicroCode.Addressing, OpCodeStatus.None);

            case OpCodeStatus.TXS_1_Implied:
                _addressState.Set(AddressOperand.X, AddressOperand.None, AddressOperand.S, AddressOperation.None, false);
                return(MicroCode.Addressing, OpCodeStatus.None);

            case OpCodeStatus.INC_1_ZeroPage:
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.None, AddressOperation.None, false);
                return(MicroCode.ZeroPage_1, OpCodeStatus.INC_2_ZeroPage);

            case OpCodeStatus.INC_2_ZeroPage:
                Registers.PC--;
                _addressState.Set(AddressOperand.None, AddressOperand.None, AddressOperand.Memory, AddressOperation.Inc, true);
                return(MicroCode.ZeroPage_1, OpCodeStatus.None);

            case OpCodeStatus.DEC_1_ZeroPage:
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.None, AddressOperation.None, false);
                return(MicroCode.ZeroPage_1, OpCodeStatus.DEC_2_ZeroPage);

            case OpCodeStatus.DEC_2_ZeroPage:
                Registers.PC--;
                _addressState.Set(AddressOperand.None, AddressOperand.None, AddressOperand.Memory, AddressOperation.Dec, true);
                return(MicroCode.ZeroPage_1, OpCodeStatus.None);

            case OpCodeStatus.INX_1_Implied:
                _addressState.Set(AddressOperand.X, AddressOperand.None, AddressOperand.X, AddressOperation.Inc, true);
                return(MicroCode.Addressing, OpCodeStatus.None);

            case OpCodeStatus.INY_1_Implied:
                _addressState.Set(AddressOperand.Y, AddressOperand.None, AddressOperand.Y, AddressOperation.Inc, true);
                return(MicroCode.Addressing, OpCodeStatus.None);

            case OpCodeStatus.DEX_1_Implied:
                _addressState.Set(AddressOperand.X, AddressOperand.None, AddressOperand.X, AddressOperation.Dec, true);
                return(MicroCode.Addressing, OpCodeStatus.None);

            case OpCodeStatus.DEY_1_Implied:
                _addressState.Set(AddressOperand.Y, AddressOperand.None, AddressOperand.Y, AddressOperation.Dec, true);
                return(MicroCode.Addressing, OpCodeStatus.None);

            case OpCodeStatus.LDA_1_Immediate:
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.A, AddressOperation.None, true);
                return(MicroCode.Immediate, OpCodeStatus.None);

            case OpCodeStatus.LDA_1_Absolute:
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.A, AddressOperation.None, true);
                return(MicroCode.Absolute_1, OpCodeStatus.None);

            case OpCodeStatus.LDA_1_AbsoluteX:
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.A, AddressOperation.None, true);
                return(MicroCode.AbsoluteX_1, OpCodeStatus.None);

            case OpCodeStatus.LDA_1_AbsoluteY:
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.A, AddressOperation.None, true);
                return(MicroCode.AbsoluteY_1, OpCodeStatus.None);

            case OpCodeStatus.LDA_1_IndirectY:
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.A, AddressOperation.None, true);
                return(MicroCode.IndirectY_1, OpCodeStatus.None);

            case OpCodeStatus.LDA_1_ZeroPage:
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.A, AddressOperation.None, true);
                return(MicroCode.ZeroPage_1, OpCodeStatus.None);

            case OpCodeStatus.LDA_1_ZeroPageX:
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.A, AddressOperation.None, true);
                return(MicroCode.ZeroPageX_1, OpCodeStatus.None);

            case OpCodeStatus.JSR_1_Absolute:
                _addressState.ResultA = (byte)((Registers.PC + 1) >> 8);
                return(MicroCode.Push, OpCodeStatus.JSR_2_Absolute);

            case OpCodeStatus.JSR_2_Absolute:
                _addressState.ResultA = (byte)((Registers.PC + 1) & 0xFF);
                return(MicroCode.Push, OpCodeStatus.JSR_3_Absolute);

            case OpCodeStatus.JSR_3_Absolute:
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.PC, AddressOperation.None, false);
                return(MicroCode.Absolute_1, OpCodeStatus.None);

            case OpCodeStatus.BIT_1_Absolute:
                _addressState.Set(AddressOperand.A, AddressOperand.Memory, AddressOperand.None, AddressOperation.BitTest, true);
                return(MicroCode.Absolute_1, OpCodeStatus.None);

            case OpCodeStatus.BPL_1_Relative:
                if (Status.N)
                {
                    Registers.PC++;
                    return(MicroCode.Nop, OpCodeStatus.None);
                }
                else
                {
                    return(MicroCode.Nop, OpCodeStatus.Relative_Jump);
                }

            case OpCodeStatus.BNE_1_Relative:
                if (Status.Z)
                {
                    Registers.PC++;
                    return(MicroCode.Nop, OpCodeStatus.None);
                }
                else
                {
                    return(MicroCode.Nop, OpCodeStatus.Relative_Jump);
                }

            case OpCodeStatus.BEQ_1_Relative:
                if (Status.Z)
                {
                    return(MicroCode.Nop, OpCodeStatus.Relative_Jump);
                }
                else
                {
                    Registers.PC++;
                    return(MicroCode.Nop, OpCodeStatus.None);
                }

            case OpCodeStatus.BCC_1_Relative:
                if (Status.C)
                {
                    Registers.PC++;
                    return(MicroCode.Nop, OpCodeStatus.None);
                }
                else
                {
                    return(MicroCode.Nop, OpCodeStatus.Relative_Jump);
                }

            case OpCodeStatus.BMI_1_Relative:
                if (Status.N)
                {
                    return(MicroCode.Nop, OpCodeStatus.Relative_Jump);
                }
                else
                {
                    Registers.PC++;
                    return(MicroCode.Nop, OpCodeStatus.None);
                }

            case OpCodeStatus.CMP_1_Immediate:
                _addressState.Set(AddressOperand.A, AddressOperand.Memory, AddressOperand.None, AddressOperation.Compare, true);
                return(MicroCode.Immediate, OpCodeStatus.None);

            case OpCodeStatus.CMP_1_ZeroPage:
                _addressState.Set(AddressOperand.A, AddressOperand.Memory, AddressOperand.None, AddressOperation.Compare, true);
                return(MicroCode.ZeroPage_1, OpCodeStatus.None);

            case OpCodeStatus.CMP_1_Absolute:
                _addressState.Set(AddressOperand.A, AddressOperand.Memory, AddressOperand.None, AddressOperation.Compare, true);
                return(MicroCode.Absolute_1, OpCodeStatus.None);

            case OpCodeStatus.CMP_1_ZeroPageX:
                _addressState.Set(AddressOperand.A, AddressOperand.Memory, AddressOperand.None, AddressOperation.Compare, true);
                return(MicroCode.ZeroPageX_1, OpCodeStatus.None);

            case OpCodeStatus.CPX_1_Immediate:
                _addressState.Set(AddressOperand.X, AddressOperand.Memory, AddressOperand.None, AddressOperation.Compare, true);
                return(MicroCode.Immediate, OpCodeStatus.None);

            case OpCodeStatus.CPY_1_Immediate:
                _addressState.Set(AddressOperand.Y, AddressOperand.Memory, AddressOperand.None, AddressOperation.Compare, true);
                return(MicroCode.Immediate, OpCodeStatus.None);

            case OpCodeStatus.AND_1_Immediate:
                _addressState.Set(AddressOperand.A, AddressOperand.Memory, AddressOperand.A, AddressOperation.And, true);
                return(MicroCode.Immediate, OpCodeStatus.None);

            case OpCodeStatus.AND_1_ZeroPageX:
                _addressState.Set(AddressOperand.A, AddressOperand.Memory, AddressOperand.A, AddressOperation.And, true);
                return(MicroCode.ZeroPageX_1, OpCodeStatus.None);

            case OpCodeStatus.ORA_1_Immediate:
                _addressState.Set(AddressOperand.A, AddressOperand.Memory, AddressOperand.A, AddressOperation.Or, true);
                return(MicroCode.Immediate, OpCodeStatus.None);

            case OpCodeStatus.ORA_1_ZeroPage:
                _addressState.Set(AddressOperand.A, AddressOperand.Memory, AddressOperand.A, AddressOperation.Or, true);
                return(MicroCode.ZeroPage_1, OpCodeStatus.None);

            case OpCodeStatus.RTI_1_Implied:
                return(MicroCode.Pop, OpCodeStatus.RTI_2_Implied);

            case OpCodeStatus.RTI_2_Implied:
                Status.Value = _addressState.ResultA;
                return(MicroCode.Pop, OpCodeStatus.RTI_3_Implied);

            case OpCodeStatus.RTI_3_Implied:
                _addressState.MemoryAddress = _addressState.ResultA;
                return(MicroCode.Pop, OpCodeStatus.RTI_4_Implied);

            case OpCodeStatus.RTI_4_Implied:
                _addressState.MemoryAddress |= (ushort)(_addressState.ResultA << 8);
                return(MicroCode.Nop, OpCodeStatus.RTI_5_Implied);

            case OpCodeStatus.RTI_5_Implied:
                _addressState.Set(AddressOperand.None, AddressOperand.None, AddressOperand.PC, AddressOperation.None, false);
                return(MicroCode.Addressing, OpCodeStatus.None);

            case OpCodeStatus.JMP_1_Absolute:
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.PC, AddressOperation.None, false);
                return(MicroCode.Absolute_1, OpCodeStatus.None);

            case OpCodeStatus.RTS_1_Implied:
                return(MicroCode.Pop, OpCodeStatus.RTS_2_Implied);

            case OpCodeStatus.RTS_2_Implied:
                _addressState.MemoryAddress = _addressState.ResultA;
                return(MicroCode.Pop, OpCodeStatus.RTS_3_Implied);

            case OpCodeStatus.RTS_3_Implied:
                _addressState.MemoryAddress |= (ushort)(_addressState.ResultA << 8);
                return(MicroCode.Nop, OpCodeStatus.RTS_4_Implied);

            case OpCodeStatus.RTS_4_Implied:
                _addressState.MemoryAddress++;
                return(MicroCode.Nop, OpCodeStatus.RTS_5_Implied);

            case OpCodeStatus.RTS_5_Implied:
                _addressState.Set(AddressOperand.None, AddressOperand.None, AddressOperand.PC, AddressOperation.None, false);
                return(MicroCode.Addressing, OpCodeStatus.None);

            case OpCodeStatus.ADC_1_Immediate:
                _addressState.Set(AddressOperand.A, AddressOperand.Memory, AddressOperand.A, AddressOperation.Adc, true);
                return(MicroCode.Immediate, OpCodeStatus.None);

            case OpCodeStatus.ROL_1_ZeroPage:
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.None, AddressOperation.None, false);
                return(MicroCode.ZeroPage_1, OpCodeStatus.ROL_2_ZeroPage);

            case OpCodeStatus.ROL_2_ZeroPage:
                Registers.PC--;
                _addressState.Set(AddressOperand.None, AddressOperand.None, AddressOperand.Memory, AddressOperation.Rol, true);
                return(MicroCode.ZeroPage_1, OpCodeStatus.None);

            case OpCodeStatus.ASL_1_ZeroPage:
                _addressState.Set(AddressOperand.Memory, AddressOperand.None, AddressOperand.None, AddressOperation.None, false);
                return(MicroCode.ZeroPage_1, OpCodeStatus.ASL_2_ZeroPage);

            case OpCodeStatus.ASL_2_ZeroPage:
                Registers.PC--;
                _addressState.Set(AddressOperand.None, AddressOperand.None, AddressOperand.Memory, AddressOperation.Asl, true);
                return(MicroCode.ZeroPage_1, OpCodeStatus.None);

            case OpCodeStatus.EOR_1_Immediate:
                _addressState.Set(AddressOperand.A, AddressOperand.Memory, AddressOperand.A, AddressOperation.Xor, true);
                return(MicroCode.Immediate, OpCodeStatus.None);

            default:
                throw new InvalidProgramException($"invalid op code status: 0x{code:X}.");
            }
        }