use crate::cpu::mos6502::{MemoryIO, Mos6502};
use super::Mos6502Variant;
pub trait Fetch {
fn fetch(&mut self) -> u8;
fn fetch_word(&mut self) -> u16;
fn fetch_operand_value(&mut self, opcode: u8) -> (u8, u8);
fn fetch_operand_address(&mut self, opcode: u8) -> (u16, u8);
}
impl Fetch for Mos6502 {
fn fetch(&mut self) -> u8 {
let result = self.read(self.registers.pc.address());
self.registers.pc.increment();
result
}
fn fetch_word(&mut self) -> u16 {
let lo = self.fetch();
let hi = self.fetch();
(hi as u16) << 8 | lo as u16
}
fn fetch_operand_value(&mut self, opcode: u8) -> (u8, u8) {
match opcode & 0x1F {
0x00 | 0x02 | 0x09 | 0x0B => (self.fetch(), 2), 0x08 | 0x18 | 0x1A => panic!("Implied operand has no value"),
0x0A => (self.registers.a, 0),
_ => {
let (address, cycles) = self.fetch_operand_address(opcode);
(self.read(address), cycles)
}
}
}
#[allow(clippy::manual_range_patterns)]
fn fetch_operand_address(&mut self, opcode: u8) -> (u16, u8) {
match opcode & 0x1F {
0x00 | 0x02 | 0x09 | 0x0B => panic!("Immediate operand has no address"),
0x01 | 0x03 => {
let base = self.fetch();
let pointer = (base as u16 + self.registers.x as u16) & 0xFF;
(self.read_word(pointer), 6)
}
0x04 | 0x05 | 0x06 | 0x07 => (self.fetch() as u16, 3), 0x08 | 0x0A | 0x18 | 0x1A => panic!("Implied operand has no address"),
0x0C | 0x0D | 0x0E | 0x0F => (self.fetch_word(), 4), 0x10 => (self.fetch() as i8 as u16, 2), 0x11 | 0x13 => {
let base = self.fetch();
let pointer = self.read_word(base as u16);
(pointer + self.registers.y as u16, 5)
}
0x12 => match self.variant {
Mos6502Variant::NMOS => {
panic!("Invalid opcode");
}
Mos6502Variant::CMOS => {
let base = self.fetch();
let pointer = self.read_word(base as u16);
(pointer, 5)
}
},
0x14 | 0x15 => {
let base = self.fetch();
((base as u16 + self.registers.x as u16) & 0xFF, 4)
}
0x16 | 0x17 => {
let base = self.fetch();
if opcode & 0xC0 == 0x80 {
((base as u16 + self.registers.y as u16) & 0xFF, 5)
} else {
((base as u16 + self.registers.x as u16) & 0xFF, 5)
}
}
0x19 | 0x1B => {
let base = self.fetch_word();
(base + self.registers.y as u16, 4)
}
0x1C | 0x1D => {
let base = self.fetch_word();
let indexed = base + self.registers.x as u16;
if self.variant == Mos6502Variant::NMOS && base & 0xFF00 != indexed & 0xFF00 {
self.read(base & 0xFF00 | indexed & 0x00FF);
(indexed, 5)
} else {
(indexed, 4)
}
}
0x1E | 0x1F => {
let base = self.fetch_word();
let indexed = if opcode & 0xC0 == 0x80 {
base + self.registers.y as u16
} else {
base + self.registers.x as u16
};
if self.variant == Mos6502Variant::NMOS && base & 0xFF00 != indexed & 0xFF00 {
self.read(base & 0xFF00 | indexed & 0x00FF);
(indexed, 5)
} else {
(indexed, 4)
}
}
_ => unreachable!(),
}
}
}