use mos6502::{make_optable, make_addrtable};
mod disops {
make_optable!(OPS, &str);
ids2strs!(adc, and, asl, bcc, bcs, beq, bit, bmi,
bne, bpl, brk, bvc, bvs, clc, cld, cli,
clv, cmp, cpx, cpy, dec, dex, dey, eor,
inc, inx, iny, jmp, jsr, lda, ldx, ldy,
lsr, nop, ora, pha, php, pla, plp, rol,
ror, rti, rts, sbc, sec, sed, sei, sta,
stx, sty, tax, tay, tsx, txa, txs, tya, nil);
}
mod disaddr {
pub type T<'a, 'b> = &'a mut Iterator<Item=&'b u8>;
make_addrtable!(ADDR_MODES, fn (T) -> String);
fn acc(_code: T) -> String {
"a".to_string()
}
fn imm(code: T) -> String {
format!("#${:02x}", code.next().unwrap())
}
fn zpg(code: T) -> String {
format!("${:02x}", code.next().unwrap())
}
fn zpx(code: T) -> String {
format!("${:02x}, x", code.next().unwrap())
}
fn zpy(code: T) -> String {
format!("${:02x}, y", code.next().unwrap())
}
fn rel(code: T) -> String {
let b = *code.next().unwrap() as i8 as i16;
if b >= 0 {
format!("+${:02x}, x", b)
} else {
format!("-${:02x}, x", -b)
}
}
fn abs(code: T) -> String {
let low = *code.next().unwrap() as u16;
let high = *code.next().unwrap() as u16;
format!("${:04x}", (high << 8) | low)
}
fn abx(code: T) -> String {
let low = *code.next().unwrap() as u16;
let high = *code.next().unwrap() as u16;
format!("${:04x}, x", (high << 8) | low)
}
fn aby(code: T) -> String {
let low = *code.next().unwrap() as u16;
let high = *code.next().unwrap() as u16;
format!("${:04x}, y", (high << 8) | low)
}
fn ind(code: T) -> String {
let low = *code.next().unwrap() as u16;
let high = *code.next().unwrap() as u16;
format!("(${:04x})", (high << 8) | low)
}
fn xin(code: T) -> String {
format!("(${:02x}, x)", code.next().unwrap())
}
fn iny(code: T) -> String {
format!("(${:02x}), y", code.next().unwrap())
}
fn nil(_code: T) -> String {
"".to_string()
}
}
pub struct Disassembler<'a, T> where T: Iterator<Item=&'a u8> {
raw_code: T
}
impl<'a, T> Disassembler<'a, T> where T: Iterator<Item=&'a u8> {
pub fn new(raw_code: T) -> Self {
Disassembler{raw_code}
}
fn parse(opcode: u8, code: &mut T) -> String {
format!("{} {}", disops::OPS[opcode as usize],
disaddr::ADDR_MODES[opcode as usize](code))
}
}
impl<'a, T> Iterator for Disassembler<'a, T> where T: Iterator<Item=&'a u8> {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
match self.raw_code.next() {
Some(opcode) => Some(Disassembler::parse(*opcode, &mut self.raw_code)),
None => None
}
}
}
pub fn parse(opcode: u8, code: &[u8]) -> String {
Disassembler::parse(opcode, &mut code.iter())
}