use std::sync::LazyLock;
use crate::cpu::cycle_action::Field;
use crate::cpu::cycle_action::Field::*;
use crate::cpu::cycle_action::{From, To};
use crate::cpu::cycle_action::CycleAction;
use crate::cpu::cycle_action::CycleAction::*;
use crate::cpu::step::Step::{Read, ReadField, Write, WriteField};
pub static OAM_DMA_TRANSFER_STEPS: LazyLock<[Step; 512]> = LazyLock::new(|| {
let read_write = &[
Read(From::DmaAddressTarget, &[]),
Write(To::OAM_DATA, &[IncrementDmaAddress]),
];
read_write.repeat(256).try_into().unwrap()
});
pub const READ_OP_CODE_STEP: Step =
Read(From::ProgramCounterTarget, &[StartNextInstruction, IncrementProgramCounter]);
pub const ADDRESS_BUS_READ_STEP: Step =
Read(From::AddressBusTarget, &[]);
pub const BRANCH_TAKEN_STEP: Step =
Read(From::ProgramCounterTarget,
&[MaybeInsertBranchOopsStep, AddCarryToProgramCounter, StartNextInstruction, IncrementProgramCounter]);
pub const IMPLICIT_ADDRESSING_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, PollInterrupts]),
Read(From::ProgramCounterTarget, &[ExecuteOpCode, StartNextInstruction, IncrementProgramCounter]),
];
pub const IMMEDIATE_ADDRESSING_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter, PollInterrupts]),
Read(From::ProgramCounterTarget, &[ExecuteOpCode, StartNextInstruction, IncrementProgramCounter]),
];
pub const RELATIVE_ADDRESSING_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter, PollInterrupts]),
Read(From::ProgramCounterTarget, &[ExecuteOpCode, StartNextInstruction, IncrementProgramCounter]),
];
pub const ABSOLUTE_READ_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::ProgramCounterTarget, &[StorePendingAddressLowByte, IncrementProgramCounter]),
Read(From::PendingAddressTarget, &[PollInterrupts]),
Read(From::ProgramCounterTarget, &[ExecuteOpCode, StartNextInstruction, IncrementProgramCounter]),
];
pub const ZERO_PAGE_READ_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::PendingZeroPageTarget, &[PollInterrupts]),
Read(From::ProgramCounterTarget, &[ExecuteOpCode, StartNextInstruction, IncrementProgramCounter]),
];
pub const ABSOLUTE_X_READ_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::ProgramCounterTarget, &[StorePendingAddressLowByteWithXOffset, IncrementProgramCounter]),
Read(From::PendingAddressTarget, &[MaybeInsertOopsStep, AddCarryToAddressBus, PollInterrupts]),
Read(From::ProgramCounterTarget, &[ExecuteOpCode, StartNextInstruction, IncrementProgramCounter]),
];
pub const ZERO_PAGE_X_READ_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::PendingZeroPageTarget, &[XOffsetAddressBus]),
Read(From::AddressBusTarget , &[PollInterrupts]),
Read(From::ProgramCounterTarget , &[ExecuteOpCode, StartNextInstruction, IncrementProgramCounter]),
];
pub const ABSOLUTE_Y_READ_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::ProgramCounterTarget, &[StorePendingAddressLowByteWithYOffset, IncrementProgramCounter]),
Read(From::PendingAddressTarget, &[MaybeInsertOopsStep, AddCarryToAddressBus, PollInterrupts]),
Read(From::ProgramCounterTarget, &[ExecuteOpCode, StartNextInstruction, IncrementProgramCounter]),
];
pub const ZERO_PAGE_Y_READ_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::PendingZeroPageTarget, &[YOffsetAddressBus]),
Read(From::AddressBusTarget , &[PollInterrupts]),
Read(From::ProgramCounterTarget , &[ExecuteOpCode, StartNextInstruction, IncrementProgramCounter]),
];
pub const INDEXED_INDIRECT_READ_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::PendingZeroPageTarget, &[XOffsetAddressBus]),
Read(From::AddressBusTarget , &[IncrementAddressBusLow]),
Read(From::AddressBusTarget , &[StorePendingAddressLowByte]),
Read(From::PendingAddressTarget , &[PollInterrupts]),
Read(From::ProgramCounterTarget , &[ExecuteOpCode, StartNextInstruction, IncrementProgramCounter]),
];
pub const INDIRECT_INDEXED_READ_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::PendingZeroPageTarget, &[IncrementAddressBusLow]),
Read(From::AddressBusTarget , &[StorePendingAddressLowByteWithYOffset]),
Read(From::PendingAddressTarget , &[MaybeInsertOopsStep, AddCarryToAddressBus, PollInterrupts]),
Read(From::ProgramCounterTarget , &[ExecuteOpCode, StartNextInstruction, IncrementProgramCounter]),
];
pub const ABSOLUTE_WRITE_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::ProgramCounterTarget, &[StorePendingAddressLowByte, IncrementProgramCounter, PollInterrupts]),
WriteField(OpRegister, To::PendingAddressTarget, &[]),
];
pub const ZERO_PAGE_WRITE_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter, PollInterrupts]),
WriteField(OpRegister, To::PendingZeroPageTarget, &[]),
];
pub const ABSOLUTE_X_WRITE_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::ProgramCounterTarget, &[StorePendingAddressLowByteWithXOffset, IncrementProgramCounter]),
Read(From::PendingAddressTarget, &[AddCarryToAddressBus, PollInterrupts]),
WriteField(OpRegister, To::AddressBusTarget, &[]),
];
pub const ZERO_PAGE_X_WRITE_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::PendingZeroPageTarget, &[XOffsetAddressBus, PollInterrupts]),
WriteField(OpRegister, To::AddressBusTarget, &[]),
];
pub const ABSOLUTE_Y_WRITE_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::ProgramCounterTarget, &[StorePendingAddressLowByteWithYOffset, IncrementProgramCounter]),
Read(From::PendingAddressTarget, &[AddCarryToAddressBus, PollInterrupts]),
WriteField(OpRegister, To::AddressBusTarget, &[]),
];
pub const ZERO_PAGE_Y_WRITE_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::PendingZeroPageTarget, &[YOffsetAddressBus, PollInterrupts]),
WriteField(OpRegister, To::AddressBusTarget, &[]),
];
pub const INDEXED_INDIRECT_WRITE_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::PendingZeroPageTarget, &[XOffsetAddressBus]),
Read(From::AddressBusTarget , &[IncrementAddressBusLow]),
Read(From::AddressBusTarget , &[StorePendingAddressLowByte, PollInterrupts]),
WriteField(OpRegister, To::PendingAddressTarget, &[]),
];
pub const INDIRECT_INDEXED_WRITE_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::PendingZeroPageTarget, &[IncrementAddressBusLow]),
Read(From::AddressBusTarget , &[StorePendingAddressLowByteWithYOffset]),
Read(From::PendingAddressTarget , &[AddCarryToAddressBus, PollInterrupts]),
WriteField(OpRegister, To::AddressBusTarget, &[]),
];
pub const ABSOLUTE_READ_MODIFY_WRITE_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::ProgramCounterTarget , &[StorePendingAddressLowByte, IncrementProgramCounter]),
Read(From::PendingAddressTarget , &[]),
Write(To::AddressBusTarget , &[ExecuteOpCode, PollInterrupts]),
Write(To::AddressBusTarget , &[]),
];
pub const ZERO_PAGE_READ_MODIFY_WRITE_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::PendingZeroPageTarget, &[]),
Write(To::AddressBusTarget , &[ExecuteOpCode, PollInterrupts]),
Write(To::AddressBusTarget , &[]),
];
pub const ABSOLUTE_X_READ_MODIFY_WRITE_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::ProgramCounterTarget, &[StorePendingAddressLowByteWithXOffset, IncrementProgramCounter]),
Read(From::PendingAddressTarget, &[AddCarryToAddressBus]),
Read(From::AddressBusTarget , &[]),
Write(To::AddressBusTarget , &[ExecuteOpCode, PollInterrupts]),
Write(To::AddressBusTarget , &[]),
];
pub const ZERO_PAGE_X_READ_MODIFY_WRITE_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::PendingZeroPageTarget, &[XOffsetAddressBus]),
Read(From::AddressBusTarget , &[]),
Write(To::AddressBusTarget , &[ExecuteOpCode, PollInterrupts]),
Write(To::AddressBusTarget , &[]),
];
pub const ABSOLUTE_Y_READ_MODIFY_WRITE_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::ProgramCounterTarget, &[StorePendingAddressLowByteWithYOffset, IncrementProgramCounter]),
Read(From::PendingAddressTarget, &[AddCarryToAddressBus]),
Read(From::AddressBusTarget , &[]),
Write(To::AddressBusTarget , &[ExecuteOpCode, PollInterrupts]),
Write(To::AddressBusTarget , &[]),
];
pub const ZERO_PAGE_Y_READ_MODIFY_WRITE_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::PendingZeroPageTarget, &[YOffsetAddressBus]),
Read(From::AddressBusTarget , &[]),
Write(To::AddressBusTarget , &[ExecuteOpCode, PollInterrupts]),
Write(To::AddressBusTarget , &[]),
];
pub const INDEXED_INDIRECT_READ_MODIFY_WRITE_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::PendingZeroPageTarget, &[XOffsetAddressBus]),
Read(From::AddressBusTarget , &[IncrementAddressBusLow]),
Read(From::AddressBusTarget , &[StorePendingAddressLowByte]),
Read(From::PendingAddressTarget , &[]),
Write(To::AddressBusTarget , &[ExecuteOpCode, PollInterrupts]),
Write(To::AddressBusTarget , &[]),
];
pub const INDIRECT_INDEXED_READ_MODIFY_WRITE_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::PendingZeroPageTarget, &[IncrementAddressBusLow]),
Read(From::AddressBusTarget , &[StorePendingAddressLowByteWithYOffset]),
Read(From::PendingAddressTarget , &[AddCarryToAddressBus]),
Read(From::AddressBusTarget , &[]),
Write(To::AddressBusTarget , &[ExecuteOpCode, PollInterrupts]),
Write(To::AddressBusTarget , &[]),
];
pub const RESET_STEPS: &[Step] = &[
Read( From::ProgramCounterTarget, &[IncrementProgramCounter]),
Read( From::ProgramCounterTarget, &[]),
Read( From::TopOfStack, &[DecrementStackPointer]),
Read( From::TopOfStack, &[DecrementStackPointer]),
Read( From::TopOfStack, &[DecrementStackPointer, SetInterruptVector]),
Read( From::InterruptVectorLow , &[DisableInterrupts]),
ReadField(ProgramCounterHighByte , From::InterruptVectorHigh, &[ClearInterruptVector]),
];
pub const BRK_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
WriteField(ProgramCounterHighByte, To::TopOfStack, &[DecrementStackPointer]),
WriteField(ProgramCounterLowByte , To::TopOfStack, &[DecrementStackPointer]),
WriteField(Status , To::TopOfStack, &[DecrementStackPointer, SetInterruptVector]),
Read( From::InterruptVectorLow , &[DisableInterrupts]),
ReadField(ProgramCounterHighByte, From::InterruptVectorHigh, &[ClearInterruptVector]),
];
pub const RTI_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode]),
Read( From::TopOfStack, &[IncrementStackPointer]),
ReadField(Status, From::TopOfStack, &[IncrementStackPointer]),
Read( From::TopOfStack, &[IncrementStackPointer, PollInterrupts]),
ReadField(ProgramCounterHighByte, From::TopOfStack, &[]),
];
pub const RTS_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode]),
Read( From::TopOfStack , &[IncrementStackPointer]),
Read( From::TopOfStack , &[IncrementStackPointer]),
ReadField(ProgramCounterHighByte, From::TopOfStack , &[PollInterrupts]),
Read( From::ProgramCounterTarget, &[IncrementProgramCounter]),
];
pub const PHA_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, PollInterrupts]),
WriteField(Accumulator , To::TopOfStack, &[DecrementStackPointer]),
];
pub const PHP_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, PollInterrupts]),
WriteField(Status , To::TopOfStack, &[DecrementStackPointer]),
];
pub const PLA_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode]),
Read(From::TopOfStack , &[IncrementStackPointer]),
Read(From::TopOfStack , &[PollInterrupts]),
Read(From::ProgramCounterTarget, &[ExecuteOpCode, StartNextInstruction, IncrementProgramCounter]),
];
pub const PLP_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode]),
Read(From::TopOfStack, &[IncrementStackPointer]),
Read(From::TopOfStack, &[PollInterrupts]),
Read(From::ProgramCounterTarget, &[ExecuteOpCode, StartNextInstruction, IncrementProgramCounter]),
];
pub const JSR_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read( From::TopOfStack, &[StorePendingAddressLowByte]),
WriteField(ProgramCounterHighByte, To::TopOfStack , &[DecrementStackPointer]),
WriteField(ProgramCounterLowByte , To::TopOfStack , &[DecrementStackPointer]),
Read( From::ProgramCounterTarget, &[PollInterrupts]),
Read( From::PendingAddressTarget, &[CopyAddressToPC, StartNextInstruction, IncrementProgramCounter]),
];
pub const JMP_ABS_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
ReadField(ProgramCounterHighByte, From::ProgramCounterTarget, &[PollInterrupts]),
];
pub const JMP_IND_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::ProgramCounterTarget , &[StorePendingAddressLowByte]),
Read(From::PendingAddressTarget , &[IncrementAddressBusLow] ),
Read(From::AddressBusTarget , &[StorePendingAddressLowByte, PollInterrupts]),
Read(From::PendingAddressTarget , &[CopyAddressToPC, StartNextInstruction, IncrementProgramCounter]),
];
pub const ABSOLUTE_Y_AHX_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::ProgramCounterTarget, &[StorePendingAddressLowByteWithYOffset, IncrementProgramCounter]),
Read(From::PendingAddressTarget, &[AddCarryToAddressBus, PollInterrupts]),
Read(From::AddressBusTarget, &[]),
Read(From::ProgramCounterTarget, &[ExecuteOpCode, StartNextInstruction, IncrementProgramCounter]),
];
pub const INDIRECT_INDEXED_AHX_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::PendingZeroPageTarget, &[IncrementAddressBusLow]),
Read(From::AddressBusTarget , &[StorePendingAddressLowByteWithYOffset]),
Read(From::AddressBusTarget, &[]),
Read(From::PendingAddressTarget , &[AddCarryToAddressBus, PollInterrupts]),
Read(From::ProgramCounterTarget , &[ExecuteOpCode, StartNextInstruction, IncrementProgramCounter]),
];
pub const TAS_STEPS: &[Step] = &[
Read(From::ProgramCounterTarget, &[InterpretOpCode, IncrementProgramCounter]),
Read(From::ProgramCounterTarget, &[StorePendingAddressLowByteWithYOffset, IncrementProgramCounter]),
Read(From::PendingAddressTarget, &[AddCarryToAddressBus, PollInterrupts]),
Read(From::AddressBusTarget, &[]),
Read(From::ProgramCounterTarget, &[ExecuteOpCode, StartNextInstruction, IncrementProgramCounter]),
];
#[derive(Clone, Copy, Debug)]
pub enum Step {
Read(From, &'static [CycleAction]),
Write(To, &'static [CycleAction]),
ReadField(Field, From, &'static [CycleAction]),
WriteField(Field, To, &'static [CycleAction]),
}
impl Step {
pub fn actions(&self) -> &'static [CycleAction] {
match *self {
Step::Read(_, actions) => actions,
Step::Write(_, actions) => actions,
Step::ReadField(_, _, actions) => actions,
Step::WriteField(_, _, actions) => actions,
}
}
pub fn has_start_new_instruction(&self) -> bool {
for action in self.actions() {
if matches!(action, CycleAction::StartNextInstruction) {
return true;
}
}
false
}
pub fn has_interpret_op_code(&self) -> bool {
for action in self.actions() {
if matches!(action, CycleAction::InterpretOpCode) {
return true;
}
}
false
}
}