use super::{CPU, System, AddressType, AddressingMode, State, ByteRef, Byte, TaggedByte};
pub type InstructionFn = fn(&mut CPU, &mut dyn System, AddressingMode) -> ();
fn todo(cpu: &mut CPU, _sys: &mut dyn System, _am: AddressingMode) {
todo!("{:02x}", cpu.ir);
}
#[inline(always)]
fn io(cpu: &mut CPU, sys: &mut dyn System) {
let effective = ((cpu.pbr as u32) << 16) | (cpu.pc as u32);
let _ = sys.read(effective, AddressType::Invalid, &cpu.signals);
}
#[inline]
fn implied(cpu: &mut CPU, sys: &mut dyn System) {
AddressingMode::Implied.read(cpu, sys);
if cpu.tcu == 1 {
cpu.state = State::Fetch;
}
}
fn nop(cpu: &mut CPU, sys: &mut dyn System, _am: AddressingMode) {
implied(cpu, sys);
}
fn clc(cpu: &mut CPU, sys: &mut dyn System, _am: AddressingMode) {
implied(cpu, sys);
cpu.flags.carry = false;
}
fn sec(cpu: &mut CPU, sys: &mut dyn System, _am: AddressingMode) {
implied(cpu, sys);
cpu.flags.carry = true;
}
fn cli(cpu: &mut CPU, sys: &mut dyn System, _am: AddressingMode) {
implied(cpu, sys);
cpu.flags.interrupt_disable = false;
}
fn sei(cpu: &mut CPU, sys: &mut dyn System, _am: AddressingMode) {
implied(cpu, sys);
cpu.flags.interrupt_disable = true;
}
fn cld(cpu: &mut CPU, sys: &mut dyn System, _am: AddressingMode) {
implied(cpu, sys);
cpu.flags.decimal = false;
}
fn sed(cpu: &mut CPU, sys: &mut dyn System, _am: AddressingMode) {
implied(cpu, sys);
cpu.flags.decimal = true;
}
fn clv(cpu: &mut CPU, sys: &mut dyn System, _am: AddressingMode) {
implied(cpu, sys);
cpu.flags.overflow = false;
}
fn xce(cpu: &mut CPU, sys: &mut dyn System, _am: AddressingMode) {
implied(cpu, sys);
if cpu.tcu == 1 {
let old_e = cpu.flags.emulation;
cpu.flags.emulation = cpu.flags.carry;
cpu.flags.carry = old_e;
cpu.set_e(cpu.flags.emulation);
}
}
fn lda(cpu: &mut CPU, sys: &mut dyn System, am: AddressingMode) {
match am.read(cpu, sys) {
Some(TaggedByte::Data(Byte::Low(l))) => {
ByteRef::Low(&mut cpu.a).set(l);
if cpu.a8() {
cpu.state = State::Fetch;
cpu.flags.negative = l >> 7 != 0;
cpu.flags.zero = l == 0;
}
}
Some(TaggedByte::Data(Byte::High(h))) => {
ByteRef::High(&mut cpu.a).set(h);
cpu.state = State::Fetch;
cpu.flags.negative = cpu.a >> 15 != 0;
cpu.flags.zero = cpu.a == 0;
}
_ => (),
}
}
#[inline]
fn jsr_al(cpu: &mut CPU, sys: &mut dyn System, _am: AddressingMode) {
match cpu.tcu {
1 => {
let pc = ((cpu.pbr as u32) << 16) | (cpu.pc as u32);
let data = sys.read(pc, AddressType::Program, &cpu.signals);
ByteRef::Low(&mut cpu.temp_addr).set(data);
cpu.pc = cpu.pc.wrapping_add(1);
}
2 => {
let pc = ((cpu.pbr as u32) << 16) | (cpu.pc as u32);
let data = sys.read(pc, AddressType::Program, &cpu.signals);
ByteRef::High(&mut cpu.temp_addr).set(data);
cpu.pc = cpu.pc.wrapping_add(1);
}
3 => {
cpu.stack_push(sys, cpu.pbr, false);
}
4 => {
let mut s = cpu.s.wrapping_add(1);
if cpu.flags.emulation {
ByteRef::High(&mut s).set(0x01);
}
sys.read(s as u32, AddressType::Invalid, &cpu.signals);
}
5 => {
let pc = ((cpu.pbr as u32) << 16) | (cpu.pc as u32);
let data = sys.read(pc, AddressType::Program, &cpu.signals);
cpu.temp_bank = data;
}
6 => {
let pc = ByteRef::High(&mut cpu.pc).get();
cpu.stack_push(sys, pc, false);
}
7 => {
let pc = ByteRef::Low(&mut cpu.pc).get();
cpu.stack_push(sys, pc, false);
cpu.pc = cpu.temp_addr;
cpu.pbr = cpu.temp_bank;
cpu.state = State::Fetch;
}
_ => unreachable!(),
}
}
fn jsr(cpu: &mut CPU, sys: &mut dyn System, am: AddressingMode) {
const ABS: AddressingMode = AddressingMode::Absolute;
const IDX_IN: AddressingMode = AddressingMode::IndexedIndirectX;
match (cpu.tcu, am) {
(1, ABS) | (1, IDX_IN) => {
let pc = ((cpu.pbr as u32) << 16) | (cpu.pc as u32);
let data = sys.read(pc, AddressType::Program, &cpu.signals);
ByteRef::Low(&mut cpu.temp_addr).set(data);
cpu.pc = cpu.pc.wrapping_add(1);
}
(2, ABS) | (4, IDX_IN) => {
let pc = ((cpu.pbr as u32) << 16) | (cpu.pc as u32);
let data = sys.read(pc, AddressType::Program, &cpu.signals);
ByteRef::High(&mut cpu.temp_addr).set(data);
}
(3, ABS) | (5, IDX_IN) => {
io(cpu, sys)
}
(4, ABS) | (2, IDX_IN) => {
let pc = ByteRef::High(&mut cpu.pc).get();
cpu.stack_push(sys, pc, false);
}
(5, ABS) | (3, IDX_IN) => {
let pc = ByteRef::Low(&mut cpu.pc).get();
cpu.stack_push(sys, pc, false);
if am == ABS {
cpu.pc = cpu.temp_addr;
cpu.state = State::Fetch;
}
}
(6, IDX_IN) => {
let pc = ((cpu.pbr as u32) << 16) | ((cpu.temp_addr+cpu.x) as u32);
let data = sys.read(pc, AddressType::Program, &cpu.signals);
ByteRef::Low(&mut cpu.temp_data).set(data);
}
(7, IDX_IN) => {
let pc = ((cpu.pbr as u32) << 16) | ((1+cpu.temp_addr+cpu.x) as u32);
let data = sys.read(pc, AddressType::Program, &cpu.signals);
ByteRef::High(&mut cpu.temp_data).set(data);
cpu.pc = cpu.temp_data;
cpu.state = State::Fetch;
}
_ => unreachable!(),
}
}
fn sep(cpu: &mut CPU, sys: &mut dyn System, am: AddressingMode) {
let effective = ((cpu.pbr as u32) << 16) | (cpu.pc as u32);
let data = match cpu.tcu {
1 => {
cpu.pc = cpu.pc.wrapping_add(1);
sys.read(effective, AddressType::Program, &cpu.signals)
}
2 => sys.read(effective, AddressType::Invalid, &cpu.signals),
_ => unreachable!(),
};
if cpu.tcu == 2 {
cpu.flags.set_mask(data, true);
cpu.signals.m = cpu.flags.mem_sel;
cpu.signals.x = cpu.flags.index_sel;
if cpu.flags.index_sel {
ByteRef::High(&mut cpu.x).set(0);
ByteRef::High(&mut cpu.y).set(0);
}
cpu.state = State::Fetch;
}
}
pub const INSTRUCTIONS: [(InstructionFn, AddressingMode); 0x100] = [
(todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (clc, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (jsr, AddressingMode::Absolute), (todo, AddressingMode::Implied), (jsr_al, AddressingMode::AbsoluteLong), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (sec, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (cli, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (sei, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (lda, AddressingMode::Immediate), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (lda, AddressingMode::Absolute), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (clv, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (cld, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (sep, AddressingMode::Immediate), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (nop, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (sed, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (xce, AddressingMode::Implied), (jsr, AddressingMode::IndexedIndirectX), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), (todo, AddressingMode::Implied), ];