1026 lines
28 KiB
Rust
1026 lines
28 KiB
Rust
use crate::address_mode::AddressMode;
|
|
use crate::constants::constants_isa_op::{
|
|
ISA_OP_ADC_ABS, ISA_OP_ADC_ABSX, ISA_OP_ADC_ABSY, ISA_OP_ADC_I, ISA_OP_ADC_INDX,
|
|
ISA_OP_ADC_INDY, ISA_OP_ADC_Z, ISA_OP_ADC_ZX, ISA_OP_AND_ABS, ISA_OP_AND_ABSX, ISA_OP_AND_ABSY,
|
|
ISA_OP_AND_I, ISA_OP_AND_INDX, ISA_OP_AND_INDY, ISA_OP_AND_Z, ISA_OP_AND_ZX, ISA_OP_ASL_A,
|
|
ISA_OP_ASL_ABS, ISA_OP_ASL_ABSX, ISA_OP_ASL_Z, ISA_OP_ASL_ZX, ISA_OP_BCC, ISA_OP_BCS,
|
|
ISA_OP_BEQ, ISA_OP_BIT_ABS, ISA_OP_BIT_ZP, ISA_OP_BMI, ISA_OP_BNE, ISA_OP_BPL, ISA_OP_BRK,
|
|
ISA_OP_BVC, ISA_OP_BVS, ISA_OP_CLC, ISA_OP_CLD, ISA_OP_CLI, ISA_OP_CLV, ISA_OP_CMP_ABS,
|
|
ISA_OP_CMP_ABSX, ISA_OP_CMP_ABSY, ISA_OP_CMP_I, ISA_OP_CMP_INDX, ISA_OP_CMP_INDY,
|
|
ISA_OP_CMP_ZP, ISA_OP_CMP_ZPX, ISA_OP_CPX_ABS, ISA_OP_CPX_I, ISA_OP_CPX_ZP, ISA_OP_CPY_ABS,
|
|
ISA_OP_CPY_I, ISA_OP_CPY_ZP, ISA_OP_DEC_ABS, ISA_OP_DEC_ABSX, ISA_OP_DEC_ZP, ISA_OP_DEC_ZPX,
|
|
ISA_OP_DEX, ISA_OP_DEY, ISA_OP_EOR_ABS, ISA_OP_EOR_ABSX, ISA_OP_EOR_ABSY, ISA_OP_EOR_I,
|
|
ISA_OP_EOR_INDX, ISA_OP_EOR_INDY, ISA_OP_EOR_ZP, ISA_OP_EOR_ZPX, ISA_OP_INC_ABS,
|
|
ISA_OP_INC_ABSX, ISA_OP_INC_ZP, ISA_OP_INC_ZPX, ISA_OP_INX, ISA_OP_INY, ISA_OP_JMP_ABS,
|
|
ISA_OP_JMP_IND, ISA_OP_JSR, ISA_OP_LDA_ABS, ISA_OP_LDA_ABSX, ISA_OP_LDA_ABSY, ISA_OP_LDA_I,
|
|
ISA_OP_LDA_INDX, ISA_OP_LDA_INDY, ISA_OP_LDA_Z, ISA_OP_LDA_ZX, ISA_OP_LDX_ABS, ISA_OP_LDX_ABSY,
|
|
ISA_OP_LDX_I, ISA_OP_LDX_ZP, ISA_OP_LDX_ZPY, ISA_OP_LDY_ABS, ISA_OP_LDY_ABSX, ISA_OP_LDY_I,
|
|
ISA_OP_LDY_ZP, ISA_OP_LDY_ZPX, ISA_OP_LSR_A, ISA_OP_LSR_ABS, ISA_OP_LSR_ABSX, ISA_OP_LSR_ZP,
|
|
ISA_OP_LSR_ZPX, ISA_OP_NOP, ISA_OP_ORA_ABS, ISA_OP_ORA_ABSX, ISA_OP_ORA_ABSY, ISA_OP_ORA_I,
|
|
ISA_OP_ORA_INDX, ISA_OP_ORA_INDY, ISA_OP_ORA_ZP, ISA_OP_ORA_ZPX, ISA_OP_PHA, ISA_OP_PHP,
|
|
ISA_OP_PLA, ISA_OP_PLP, ISA_OP_ROL_A, ISA_OP_ROL_ABS, ISA_OP_ROL_ABSX, ISA_OP_ROL_ZP,
|
|
ISA_OP_ROL_ZPX, ISA_OP_ROR_A, ISA_OP_ROR_ABS, ISA_OP_ROR_ABSX, ISA_OP_ROR_ZP, ISA_OP_ROR_ZPX,
|
|
ISA_OP_RTI, ISA_OP_RTS, ISA_OP_SBC_ABS, ISA_OP_SBC_ABSX, ISA_OP_SBC_ABSY, ISA_OP_SBC_I,
|
|
ISA_OP_SBC_INDX, ISA_OP_SBC_INDY, ISA_OP_SBC_ZP, ISA_OP_SBC_ZPX, ISA_OP_SEC, ISA_OP_SED,
|
|
ISA_OP_SEI, ISA_OP_STA_ABS, ISA_OP_STA_ABSX, ISA_OP_STA_ABSY, ISA_OP_STA_INDX, ISA_OP_STA_INDY,
|
|
ISA_OP_STA_ZP, ISA_OP_STA_ZPX, ISA_OP_STX_ABS, ISA_OP_STX_ZP, ISA_OP_STX_ZPY, ISA_OP_STY_ABS,
|
|
ISA_OP_STY_ZP, ISA_OP_STY_ZPX, ISA_OP_TAX, ISA_OP_TAY, ISA_OP_TSX, ISA_OP_TXA, ISA_OP_TXS,
|
|
ISA_OP_TYA,
|
|
};
|
|
use crate::op_info::OpInfo;
|
|
use crate::operation::Operation;
|
|
use crate::operation::Operation::*;
|
|
|
|
pub fn instruction_cycles(instruction: u8) -> u8 {
|
|
INSTRUCTION_TABLE[instruction as usize].unwrap().cycles
|
|
}
|
|
|
|
pub fn instruction_length(instruction: u8) -> u8 {
|
|
INSTRUCTION_TABLE[instruction as usize].unwrap().length
|
|
}
|
|
|
|
pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
|
|
let mut table: [Option<OpInfo>; 256] = [const { None }; 256];
|
|
|
|
table[ISA_OP_ADC_I as usize] = Some(OpInfo {
|
|
operation: ADC,
|
|
mode: AddressMode::Immediate,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_ADC_Z as usize] = Some(OpInfo {
|
|
operation: ADC,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 3,
|
|
});
|
|
table[ISA_OP_ADC_ZX as usize] = Some(OpInfo {
|
|
operation: ADC,
|
|
mode: AddressMode::ZeroPageX,
|
|
length: 2,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_ADC_ABS as usize] = Some(OpInfo {
|
|
operation: ADC,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_ADC_ABSX as usize] = Some(OpInfo {
|
|
operation: ADC,
|
|
mode: AddressMode::AbsoluteX,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_ADC_ABSY as usize] = Some(OpInfo {
|
|
operation: ADC,
|
|
mode: AddressMode::AbsoluteY,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_ADC_INDX as usize] = Some(OpInfo {
|
|
operation: ADC,
|
|
mode: AddressMode::IndirectX,
|
|
length: 2,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_ADC_INDY as usize] = Some(OpInfo {
|
|
operation: ADC,
|
|
mode: AddressMode::IndirectY,
|
|
length: 2,
|
|
cycles: 5,
|
|
});
|
|
|
|
table[ISA_OP_AND_I as usize] = Some(OpInfo {
|
|
operation: AND,
|
|
mode: AddressMode::Immediate,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_AND_Z as usize] = Some(OpInfo {
|
|
operation: AND,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 3,
|
|
});
|
|
table[ISA_OP_AND_ZX as usize] = Some(OpInfo {
|
|
operation: AND,
|
|
mode: AddressMode::ZeroPageX,
|
|
length: 2,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_AND_ABS as usize] = Some(OpInfo {
|
|
operation: AND,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_AND_ABSX as usize] = Some(OpInfo {
|
|
operation: AND,
|
|
mode: AddressMode::AbsoluteX,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_AND_ABSY as usize] = Some(OpInfo {
|
|
operation: AND,
|
|
mode: AddressMode::AbsoluteY,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_AND_INDX as usize] = Some(OpInfo {
|
|
operation: AND,
|
|
mode: AddressMode::IndirectX,
|
|
length: 2,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_AND_INDY as usize] = Some(OpInfo {
|
|
operation: AND,
|
|
mode: AddressMode::IndirectY,
|
|
length: 2,
|
|
cycles: 5,
|
|
});
|
|
table[ISA_OP_ASL_A as usize] = Some(OpInfo {
|
|
operation: ASL,
|
|
mode: AddressMode::Accumulator,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_ASL_Z as usize] = Some(OpInfo {
|
|
operation: ASL,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 5,
|
|
});
|
|
table[ISA_OP_ASL_ZX as usize] = Some(OpInfo {
|
|
operation: ASL,
|
|
mode: AddressMode::ZeroPageX,
|
|
length: 2,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_ASL_ABS as usize] = Some(OpInfo {
|
|
operation: ASL,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_ASL_ABSX as usize] = Some(OpInfo {
|
|
operation: ASL,
|
|
mode: AddressMode::AbsoluteX,
|
|
length: 3,
|
|
cycles: 7,
|
|
});
|
|
|
|
table[ISA_OP_BCC as usize] = Some(OpInfo {
|
|
operation: BCC,
|
|
mode: AddressMode::Implied,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_BCS as usize] = Some(OpInfo {
|
|
operation: BCS,
|
|
mode: AddressMode::Implied,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_BEQ as usize] = Some(OpInfo {
|
|
operation: BEQ,
|
|
mode: AddressMode::Implied,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
|
|
table[ISA_OP_BIT_ZP as usize] = Some(OpInfo {
|
|
operation: BIT,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 3,
|
|
});
|
|
table[ISA_OP_BIT_ABS as usize] = Some(OpInfo {
|
|
operation: BIT,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
|
|
table[ISA_OP_BMI as usize] = Some(OpInfo {
|
|
operation: BMI,
|
|
mode: AddressMode::Implied,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
|
|
table[ISA_OP_BNE as usize] = Some(OpInfo {
|
|
operation: BNE,
|
|
mode: AddressMode::Implied,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_BPL as usize] = Some(OpInfo {
|
|
operation: Operation::BPL,
|
|
mode: AddressMode::Implied,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_BRK as usize] = Some(OpInfo {
|
|
operation: BRK,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 7,
|
|
});
|
|
table[ISA_OP_BVC as usize] = Some(OpInfo {
|
|
operation: BVC,
|
|
mode: AddressMode::Implied,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_BVS as usize] = Some(OpInfo {
|
|
operation: BVS,
|
|
mode: AddressMode::Implied,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_CLC as usize] = Some(OpInfo {
|
|
operation: CLC,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_CLD as usize] = Some(OpInfo {
|
|
operation: CLD,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_CLI as usize] = Some(OpInfo {
|
|
operation: CLI,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_CLV as usize] = Some(OpInfo {
|
|
operation: CLV,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
|
|
table[ISA_OP_CMP_I as usize] = Some(OpInfo {
|
|
operation: CMP,
|
|
mode: AddressMode::Immediate,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_CMP_ZP as usize] = Some(OpInfo {
|
|
operation: CMP,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 3,
|
|
});
|
|
table[ISA_OP_CMP_ZPX as usize] = Some(OpInfo {
|
|
operation: CMP,
|
|
mode: AddressMode::ZeroPageX,
|
|
length: 2,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_CMP_ABS as usize] = Some(OpInfo {
|
|
operation: CMP,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_CMP_ABSX as usize] = Some(OpInfo {
|
|
operation: CMP,
|
|
mode: AddressMode::AbsoluteX,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_CMP_ABSY as usize] = Some(OpInfo {
|
|
operation: CMP,
|
|
mode: AddressMode::AbsoluteY,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_CMP_INDX as usize] = Some(OpInfo {
|
|
operation: CMP,
|
|
mode: AddressMode::IndirectX,
|
|
length: 2,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_CMP_INDY as usize] = Some(OpInfo {
|
|
operation: CMP,
|
|
mode: AddressMode::IndirectY,
|
|
length: 2,
|
|
cycles: 5,
|
|
});
|
|
|
|
table[ISA_OP_CPX_I as usize] = Some(OpInfo {
|
|
operation: CPX,
|
|
mode: AddressMode::Immediate,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_CPX_ZP as usize] = Some(OpInfo {
|
|
operation: CPX,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 3,
|
|
});
|
|
table[ISA_OP_CPX_ABS as usize] = Some(OpInfo {
|
|
operation: CPX,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_CPY_I as usize] = Some(OpInfo {
|
|
operation: CPY,
|
|
mode: AddressMode::Immediate,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_CPY_ZP as usize] = Some(OpInfo {
|
|
operation: CPY,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 3,
|
|
});
|
|
table[ISA_OP_CPY_ABS as usize] = Some(OpInfo {
|
|
operation: CPY,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
|
|
table[ISA_OP_DEC_ZP as usize] = Some(OpInfo {
|
|
operation: DEC,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 5,
|
|
});
|
|
table[ISA_OP_DEC_ZPX as usize] = Some(OpInfo {
|
|
operation: DEC,
|
|
mode: AddressMode::ZeroPageX,
|
|
length: 2,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_DEC_ABS as usize] = Some(OpInfo {
|
|
operation: DEC,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_DEC_ABSX as usize] = Some(OpInfo {
|
|
operation: DEC,
|
|
mode: AddressMode::AbsoluteX,
|
|
length: 3,
|
|
cycles: 7,
|
|
});
|
|
table[ISA_OP_DEX as usize] = Some(OpInfo {
|
|
operation: DEX,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_DEY as usize] = Some(OpInfo {
|
|
operation: DEY,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_EOR_I as usize] = Some(OpInfo {
|
|
operation: EOR,
|
|
mode: AddressMode::Immediate,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_EOR_ZP as usize] = Some(OpInfo {
|
|
operation: EOR,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 3,
|
|
});
|
|
table[ISA_OP_EOR_ZPX as usize] = Some(OpInfo {
|
|
operation: EOR,
|
|
mode: AddressMode::ZeroPageX,
|
|
length: 2,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_EOR_ABS as usize] = Some(OpInfo {
|
|
operation: EOR,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_EOR_ABSX as usize] = Some(OpInfo {
|
|
operation: EOR,
|
|
mode: AddressMode::AbsoluteX,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_EOR_ABSY as usize] = Some(OpInfo {
|
|
operation: EOR,
|
|
mode: AddressMode::AbsoluteY,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_EOR_INDX as usize] = Some(OpInfo {
|
|
operation: EOR,
|
|
mode: AddressMode::IndirectX,
|
|
length: 2,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_EOR_INDY as usize] = Some(OpInfo {
|
|
operation: EOR,
|
|
mode: AddressMode::IndirectY,
|
|
length: 2,
|
|
cycles: 5,
|
|
});
|
|
|
|
table[ISA_OP_INC_ZP as usize] = Some(OpInfo {
|
|
operation: INC,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 5,
|
|
});
|
|
table[ISA_OP_INC_ZPX as usize] = Some(OpInfo {
|
|
operation: INC,
|
|
mode: AddressMode::ZeroPageX,
|
|
length: 2,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_INC_ABS as usize] = Some(OpInfo {
|
|
operation: INC,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_INC_ABSX as usize] = Some(OpInfo {
|
|
operation: INC,
|
|
mode: AddressMode::AbsoluteX,
|
|
length: 3,
|
|
cycles: 7,
|
|
});
|
|
table[ISA_OP_INX as usize] = Some(OpInfo {
|
|
operation: INX,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_INY as usize] = Some(OpInfo {
|
|
operation: INY,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_JMP_ABS as usize] = Some(OpInfo {
|
|
operation: JMP,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 3,
|
|
});
|
|
table[ISA_OP_JMP_IND as usize] = Some(OpInfo {
|
|
operation: JMP,
|
|
mode: AddressMode::Indirect,
|
|
length: 3,
|
|
cycles: 5,
|
|
});
|
|
table[ISA_OP_JSR as usize] = Some(OpInfo {
|
|
operation: JSR,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 6,
|
|
});
|
|
|
|
table[ISA_OP_LDA_I as usize] = Some(OpInfo {
|
|
operation: Operation::LDA,
|
|
mode: AddressMode::Immediate,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_LDA_Z as usize] = Some(OpInfo {
|
|
operation: LDA,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 3,
|
|
});
|
|
table[ISA_OP_LDA_ZX as usize] = Some(OpInfo {
|
|
operation: LDA,
|
|
mode: AddressMode::ZeroPageX,
|
|
length: 2,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_LDA_ABS as usize] = Some(OpInfo {
|
|
operation: Operation::LDA,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_LDA_ABSX as usize] = Some(OpInfo {
|
|
operation: LDA,
|
|
mode: AddressMode::AbsoluteX,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_LDA_ABSY as usize] = Some(OpInfo {
|
|
operation: LDA,
|
|
mode: AddressMode::AbsoluteY,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_LDA_INDX as usize] = Some(OpInfo {
|
|
operation: Operation::LDA,
|
|
mode: AddressMode::IndirectX,
|
|
length: 2,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_LDA_INDY as usize] = Some(OpInfo {
|
|
operation: LDA,
|
|
mode: AddressMode::IndirectY,
|
|
length: 2,
|
|
cycles: 5,
|
|
});
|
|
|
|
table[ISA_OP_LDX_I as usize] = Some(OpInfo {
|
|
operation: Operation::LDX,
|
|
mode: AddressMode::Immediate,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_LDX_ZP as usize] = Some(OpInfo {
|
|
operation: Operation::LDX,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 3,
|
|
});
|
|
table[ISA_OP_LDX_ZPY as usize] = Some(OpInfo {
|
|
operation: LDX,
|
|
mode: AddressMode::ZeroPageY,
|
|
length: 2,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_LDX_ABS as usize] = Some(OpInfo {
|
|
operation: Operation::LDX,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_LDX_ABSY as usize] = Some(OpInfo {
|
|
operation: Operation::LDX,
|
|
mode: AddressMode::AbsoluteY,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
|
|
table[ISA_OP_LDY_I as usize] = Some(OpInfo {
|
|
operation: LDY,
|
|
mode: AddressMode::Immediate,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_LDY_ZP as usize] = Some(OpInfo {
|
|
operation: LDY,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 3,
|
|
});
|
|
table[ISA_OP_LDY_ZPX as usize] = Some(OpInfo {
|
|
operation: Operation::LDY,
|
|
mode: AddressMode::ZeroPageX,
|
|
length: 2,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_LDY_ABS as usize] = Some(OpInfo {
|
|
operation: LDY,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_LDY_ABSX as usize] = Some(OpInfo {
|
|
operation: LDY,
|
|
mode: AddressMode::AbsoluteX,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
|
|
table[ISA_OP_LSR_A as usize] = Some(OpInfo {
|
|
operation: Operation::LSR,
|
|
mode: AddressMode::Accumulator,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_LSR_ZP as usize] = Some(OpInfo {
|
|
operation: LSR,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 5,
|
|
});
|
|
table[ISA_OP_LSR_ZPX as usize] = Some(OpInfo {
|
|
operation: LSR,
|
|
mode: AddressMode::ZeroPageX,
|
|
length: 2,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_LSR_ABS as usize] = Some(OpInfo {
|
|
operation: Operation::LSR,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_LSR_ABSX as usize] = Some(OpInfo {
|
|
operation: Operation::LSR,
|
|
mode: AddressMode::AbsoluteX,
|
|
length: 3,
|
|
cycles: 7,
|
|
});
|
|
|
|
table[ISA_OP_NOP as usize] = Some(OpInfo {
|
|
operation: Operation::NOP,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
|
|
table[ISA_OP_ORA_I as usize] = Some(OpInfo {
|
|
operation: Operation::ORA,
|
|
mode: AddressMode::Immediate,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_ORA_ZP as usize] = Some(OpInfo {
|
|
operation: Operation::ORA,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 3,
|
|
});
|
|
table[ISA_OP_ORA_ZPX as usize] = Some(OpInfo {
|
|
operation: Operation::ORA,
|
|
mode: AddressMode::ZeroPageX,
|
|
length: 2,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_ORA_ABS as usize] = Some(OpInfo {
|
|
operation: Operation::ORA,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
|
|
table[ISA_OP_ORA_ABSX as usize] = Some(OpInfo {
|
|
operation: Operation::ORA,
|
|
mode: AddressMode::AbsoluteX,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_ORA_ABSY as usize] = Some(OpInfo {
|
|
operation: Operation::ORA,
|
|
mode: AddressMode::AbsoluteY,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_ORA_INDX as usize] = Some(OpInfo {
|
|
operation: Operation::ORA,
|
|
mode: AddressMode::IndirectX,
|
|
length: 2,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_ORA_INDY as usize] = Some(OpInfo {
|
|
operation: Operation::ORA,
|
|
mode: AddressMode::IndirectY,
|
|
length: 2,
|
|
cycles: 5,
|
|
});
|
|
|
|
table[ISA_OP_PHA as usize] = Some(OpInfo {
|
|
operation: PHA,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 3,
|
|
});
|
|
table[ISA_OP_PHP as usize] = Some(OpInfo {
|
|
operation: Operation::PHP,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 3,
|
|
});
|
|
table[ISA_OP_PLA as usize] = Some(OpInfo {
|
|
operation: Operation::PLA,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_PLP as usize] = Some(OpInfo {
|
|
operation: Operation::PLP,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 4,
|
|
});
|
|
|
|
table[ISA_OP_ROL_A as usize] = Some(OpInfo {
|
|
operation: Operation::ROL,
|
|
mode: AddressMode::Accumulator,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_ROL_ZP as usize] = Some(OpInfo {
|
|
operation: Operation::ROL,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 5,
|
|
});
|
|
table[ISA_OP_ROL_ZPX as usize] = Some(OpInfo {
|
|
operation: Operation::ROL,
|
|
mode: AddressMode::ZeroPageX,
|
|
length: 2,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_ROL_ABS as usize] = Some(OpInfo {
|
|
operation: Operation::ROL,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_ROL_ABSX as usize] = Some(OpInfo {
|
|
operation: Operation::ROL,
|
|
mode: AddressMode::AbsoluteX,
|
|
length: 3,
|
|
cycles: 7,
|
|
});
|
|
|
|
table[ISA_OP_ROR_A as usize] = Some(OpInfo {
|
|
operation: Operation::ROR,
|
|
mode: AddressMode::Accumulator,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_ROR_ZP as usize] = Some(OpInfo {
|
|
operation: Operation::ROR,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 5,
|
|
});
|
|
table[ISA_OP_ROR_ZPX as usize] = Some(OpInfo {
|
|
operation: Operation::ROR,
|
|
mode: AddressMode::ZeroPageX,
|
|
length: 2,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_ROR_ABS as usize] = Some(OpInfo {
|
|
operation: Operation::ROR,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_ROR_ABSX as usize] = Some(OpInfo {
|
|
operation: Operation::ROR,
|
|
mode: AddressMode::AbsoluteX,
|
|
length: 3,
|
|
cycles: 7,
|
|
});
|
|
|
|
table[ISA_OP_RTI as usize] = Some(OpInfo {
|
|
operation: Operation::RTI,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_RTS as usize] = Some(OpInfo {
|
|
operation: Operation::RTS,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
|
|
table[ISA_OP_SBC_I as usize] = Some(OpInfo {
|
|
operation: Operation::SBC,
|
|
mode: AddressMode::Immediate,
|
|
length: 2,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_SBC_ZP as usize] = Some(OpInfo {
|
|
operation: Operation::SBC,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 3,
|
|
});
|
|
table[ISA_OP_SBC_ZPX as usize] = Some(OpInfo {
|
|
operation: Operation::SBC,
|
|
mode: AddressMode::ZeroPageX,
|
|
length: 2,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_SBC_ABS as usize] = Some(OpInfo {
|
|
operation: Operation::SBC,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_SBC_ABSX as usize] = Some(OpInfo {
|
|
operation: Operation::SBC,
|
|
mode: AddressMode::AbsoluteX,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_SBC_ABSY as usize] = Some(OpInfo {
|
|
operation: Operation::SBC,
|
|
mode: AddressMode::AbsoluteY,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_SBC_INDX as usize] = Some(OpInfo {
|
|
operation: Operation::SBC,
|
|
mode: AddressMode::IndirectX,
|
|
length: 2,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_SBC_INDY as usize] = Some(OpInfo {
|
|
operation: Operation::SBC,
|
|
mode: AddressMode::IndirectY,
|
|
length: 2,
|
|
cycles: 5,
|
|
});
|
|
|
|
table[ISA_OP_SEC as usize] = Some(OpInfo {
|
|
operation: SEC,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_SED as usize] = Some(OpInfo {
|
|
operation: Operation::SED,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_SEI as usize] = Some(OpInfo {
|
|
operation: Operation::SEI,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
|
|
table[ISA_OP_STA_ZP as usize] = Some(OpInfo {
|
|
operation: Operation::STA,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 3,
|
|
});
|
|
table[ISA_OP_STA_ZPX as usize] = Some(OpInfo {
|
|
operation: Operation::STA,
|
|
mode: AddressMode::ZeroPageX,
|
|
length: 2,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_STA_ABS as usize] = Some(OpInfo {
|
|
operation: Operation::STA,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_STA_ABSX as usize] = Some(OpInfo {
|
|
operation: Operation::STA,
|
|
mode: AddressMode::AbsoluteX,
|
|
length: 3,
|
|
cycles: 5,
|
|
});
|
|
table[ISA_OP_STA_ABSY as usize] = Some(OpInfo {
|
|
operation: Operation::STA,
|
|
mode: AddressMode::AbsoluteY,
|
|
length: 3,
|
|
cycles: 5,
|
|
});
|
|
table[ISA_OP_STA_INDX as usize] = Some(OpInfo {
|
|
operation: Operation::STA,
|
|
mode: AddressMode::IndirectX,
|
|
length: 2,
|
|
cycles: 6,
|
|
});
|
|
table[ISA_OP_STA_INDY as usize] = Some(OpInfo {
|
|
operation: Operation::STA,
|
|
mode: AddressMode::IndirectY,
|
|
length: 2,
|
|
cycles: 6,
|
|
});
|
|
|
|
table[ISA_OP_STX_ZP as usize] = Some(OpInfo {
|
|
operation: Operation::STX,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 3,
|
|
});
|
|
table[ISA_OP_STX_ZPY as usize] = Some(OpInfo {
|
|
operation: Operation::STX,
|
|
mode: AddressMode::ZeroPageY,
|
|
length: 2,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_STX_ABS as usize] = Some(OpInfo {
|
|
operation: Operation::STX,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
|
|
table[ISA_OP_STY_ZP as usize] = Some(OpInfo {
|
|
operation: Operation::STY,
|
|
mode: AddressMode::ZeroPage,
|
|
length: 2,
|
|
cycles: 3,
|
|
});
|
|
table[ISA_OP_STY_ZPX as usize] = Some(OpInfo {
|
|
operation: Operation::STY,
|
|
mode: AddressMode::ZeroPageX,
|
|
length: 2,
|
|
cycles: 4,
|
|
});
|
|
table[ISA_OP_STY_ABS as usize] = Some(OpInfo {
|
|
operation: Operation::STY,
|
|
mode: AddressMode::Absolute,
|
|
length: 3,
|
|
cycles: 4,
|
|
});
|
|
|
|
table[ISA_OP_TAX as usize] = Some(OpInfo {
|
|
operation: Operation::TAX,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_TAY as usize] = Some(OpInfo {
|
|
operation: TAY,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_TSX as usize] = Some(OpInfo {
|
|
operation: TSX,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_TXA as usize] = Some(OpInfo {
|
|
operation: Operation::TXA,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_TXS as usize] = Some(OpInfo {
|
|
operation: Operation::TXS,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
table[ISA_OP_TYA as usize] = Some(OpInfo {
|
|
operation: TYA,
|
|
mode: AddressMode::Implied,
|
|
length: 1,
|
|
cycles: 2,
|
|
});
|
|
|
|
table
|
|
};
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
#[test]
|
|
fn test_instruction_table_completeness() {
|
|
use INSTRUCTION_TABLE; // Adjust to your actual path
|
|
|
|
let mut defined_count = 0;
|
|
let mut defined_opcodes = vec![];
|
|
|
|
for (i, entry) in INSTRUCTION_TABLE.iter().enumerate() {
|
|
if let Some(info) = entry {
|
|
defined_count += 1;
|
|
defined_opcodes.push(i);
|
|
// Optional: sanity check
|
|
assert!(
|
|
info.length > 0 && info.cycles > 0,
|
|
"Invalid OpInfo at opcode {:#04x?}",
|
|
i
|
|
);
|
|
}
|
|
}
|
|
|
|
println!("Defined opcodes: {}", defined_count);
|
|
for i in 0..256 {
|
|
if defined_opcodes.contains(&i) {
|
|
print!("{:02x} ", i);
|
|
}
|
|
}
|
|
println!("\nMissing opcodes:");
|
|
for i in 0..256 {
|
|
if !defined_opcodes.contains(&i) {
|
|
print!("{:02X} ", i);
|
|
}
|
|
}
|
|
println!();
|
|
|
|
// The standard 6502 has 151 documented opcodes
|
|
assert_eq!(
|
|
defined_count, 151,
|
|
"Expected 151 opcodes, found {}",
|
|
defined_count
|
|
);
|
|
}
|
|
}
|