mod illegal;
use super::address_modes::*;
use super::{AddressModeFunction, Interface6502, OpcodeFunction, StatusFlag, MOS6502};
use illegal::*;
#[derive(Clone, Copy)]
pub(super) struct Instruction<'a> {
name: &'a str, function: OpcodeFunction,
address_mode: AddressModeFunction,
cycles: u8,
}
impl Instruction<'_> {
pub(super) fn get_name(&self) -> &str {
return self.name;
}
pub(super) fn execute_instruction(&self, cpu: &mut MOS6502, interface: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
(self.function)(cpu, interface, address_mode_value);
}
pub(super) fn find_address(&self, cpu: &mut MOS6502, interface: &mut dyn Interface6502) -> AddressModeValue {
return (self.address_mode)(cpu, interface);
}
pub(super) fn get_cycles(&self) -> u8 {
return self.cycles;
}
}
pub(super) static OPCODE_TABLE: [Instruction; 256] = [
Instruction {
name: "brk",
function: brk,
address_mode: implied,
cycles: 7,
}, Instruction {
name: "ora",
function: ora,
address_mode: indirect_x,
cycles: 6,
}, Instruction {
name: "kil",
function: kil,
address_mode: implied,
cycles: 0,
}, Instruction {
name: "slo",
function: slo,
address_mode: indirect_x,
cycles: 8,
}, Instruction {
name: "nop",
function: nop,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "ora",
function: ora,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "asl",
function: asl,
address_mode: zero_page,
cycles: 5,
}, Instruction {
name: "slo",
function: slo,
address_mode: zero_page,
cycles: 5,
}, Instruction {
name: "php",
function: php,
address_mode: implied,
cycles: 3,
}, Instruction {
name: "ora",
function: ora,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "asl",
function: asl,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "anc",
function: anc,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "nop",
function: nop,
address_mode: absolute,
cycles: 4,
}, Instruction {
name: "ora",
function: ora,
address_mode: absolute,
cycles: 4,
}, Instruction {
name: "asl",
function: asl,
address_mode: absolute,
cycles: 6,
}, Instruction {
name: "slo",
function: slo,
address_mode: absolute,
cycles: 6,
}, Instruction {
name: "bpl",
function: bpl,
address_mode: relative,
cycles: 2,
}, Instruction {
name: "ora",
function: ora,
address_mode: indirect_y,
cycles: 5,
}, Instruction {
name: "kil",
function: kil,
address_mode: implied,
cycles: 0,
}, Instruction {
name: "slo",
function: slo,
address_mode: indirect_y_const,
cycles: 8,
}, Instruction {
name: "nop",
function: nop,
address_mode: zero_page_x,
cycles: 4,
}, Instruction {
name: "ora",
function: ora,
address_mode: zero_page_x,
cycles: 4,
}, Instruction {
name: "asl",
function: asl,
address_mode: zero_page_x,
cycles: 6,
}, Instruction {
name: "slo",
function: slo,
address_mode: zero_page_x,
cycles: 6,
}, Instruction {
name: "clc",
function: clc,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "ora",
function: ora,
address_mode: absolute_y,
cycles: 4,
}, Instruction {
name: "nop",
function: nop,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "slo",
function: slo,
address_mode: absolute_y_const,
cycles: 7,
}, Instruction {
name: "nop",
function: nop,
address_mode: absolute_x,
cycles: 4,
}, Instruction {
name: "ora",
function: ora,
address_mode: absolute_x,
cycles: 4,
}, Instruction {
name: "asl",
function: asl,
address_mode: absolute_x_const,
cycles: 7,
}, Instruction {
name: "slo",
function: slo,
address_mode: absolute_x_const,
cycles: 7,
}, Instruction {
name: "jsr",
function: jsr,
address_mode: absolute,
cycles: 6,
}, Instruction {
name: "and",
function: and,
address_mode: indirect_x,
cycles: 6,
}, Instruction {
name: "kil",
function: kil,
address_mode: implied,
cycles: 0,
}, Instruction {
name: "rla",
function: rla,
address_mode: indirect_x,
cycles: 8,
}, Instruction {
name: "bit",
function: bit,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "and",
function: and,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "rol",
function: rol,
address_mode: zero_page,
cycles: 5,
}, Instruction {
name: "rla",
function: rla,
address_mode: zero_page,
cycles: 5,
}, Instruction {
name: "plp",
function: plp,
address_mode: implied,
cycles: 4,
}, Instruction {
name: "and",
function: and,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "rol",
function: rol,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "anc",
function: anc,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "bit",
function: bit,
address_mode: absolute,
cycles: 4,
}, Instruction {
name: "and",
function: and,
address_mode: absolute,
cycles: 4,
}, Instruction {
name: "rol",
function: rol,
address_mode: absolute,
cycles: 6,
}, Instruction {
name: "rla",
function: rla,
address_mode: absolute,
cycles: 6,
}, Instruction {
name: "bmi",
function: bmi,
address_mode: relative,
cycles: 2,
}, Instruction {
name: "and",
function: and,
address_mode: indirect_y,
cycles: 5,
}, Instruction {
name: "kil",
function: kil,
address_mode: implied,
cycles: 0,
}, Instruction {
name: "rla",
function: rla,
address_mode: indirect_y_const,
cycles: 8,
}, Instruction {
name: "nop",
function: nop,
address_mode: zero_page_x,
cycles: 4,
}, Instruction {
name: "and",
function: and,
address_mode: zero_page_x,
cycles: 4,
}, Instruction {
name: "rol",
function: rol,
address_mode: zero_page_x,
cycles: 6,
}, Instruction {
name: "rla",
function: rla,
address_mode: zero_page_x,
cycles: 6,
}, Instruction {
name: "sec",
function: sec,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "and",
function: and,
address_mode: absolute_y,
cycles: 4,
}, Instruction {
name: "nop",
function: nop,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "rla",
function: rla,
address_mode: absolute_y_const,
cycles: 7,
}, Instruction {
name: "nop",
function: nop,
address_mode: absolute_x,
cycles: 4,
}, Instruction {
name: "and",
function: and,
address_mode: absolute_x,
cycles: 4,
}, Instruction {
name: "rol",
function: rol,
address_mode: absolute_x_const,
cycles: 7,
}, Instruction {
name: "rla",
function: rla,
address_mode: absolute_x_const,
cycles: 7,
}, Instruction {
name: "rti",
function: rti,
address_mode: implied,
cycles: 6,
}, Instruction {
name: "eor",
function: eor,
address_mode: indirect_x,
cycles: 6,
}, Instruction {
name: "kil",
function: kil,
address_mode: implied,
cycles: 0,
}, Instruction {
name: "sre",
function: sre,
address_mode: indirect_x,
cycles: 8,
}, Instruction {
name: "nop",
function: nop,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "eor",
function: eor,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "lsr",
function: lsr,
address_mode: zero_page,
cycles: 5,
}, Instruction {
name: "sre",
function: sre,
address_mode: zero_page,
cycles: 5,
}, Instruction {
name: "pha",
function: pha,
address_mode: implied,
cycles: 3,
}, Instruction {
name: "eor",
function: eor,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "lsr",
function: lsr,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "alr",
function: alr,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "jmp",
function: jmp,
address_mode: absolute,
cycles: 3,
}, Instruction {
name: "eor",
function: eor,
address_mode: absolute,
cycles: 4,
}, Instruction {
name: "lsr",
function: lsr,
address_mode: absolute,
cycles: 6,
}, Instruction {
name: "sre",
function: sre,
address_mode: absolute,
cycles: 6,
}, Instruction {
name: "bvc",
function: bvc,
address_mode: relative,
cycles: 2,
}, Instruction {
name: "eor",
function: eor,
address_mode: indirect_y,
cycles: 5,
}, Instruction {
name: "kil",
function: kil,
address_mode: implied,
cycles: 0,
}, Instruction {
name: "sre",
function: sre,
address_mode: indirect_y_const,
cycles: 8,
}, Instruction {
name: "nop",
function: nop,
address_mode: zero_page_x,
cycles: 4,
}, Instruction {
name: "eor",
function: eor,
address_mode: zero_page_x,
cycles: 4,
}, Instruction {
name: "lsr",
function: lsr,
address_mode: zero_page_x,
cycles: 6,
}, Instruction {
name: "sre",
function: sre,
address_mode: zero_page_x,
cycles: 6,
}, Instruction {
name: "cli",
function: cli,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "eor",
function: eor,
address_mode: absolute_y,
cycles: 4,
}, Instruction {
name: "nop",
function: nop,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "sre",
function: sre,
address_mode: absolute_y_const,
cycles: 7,
}, Instruction {
name: "nop",
function: nop,
address_mode: absolute_x,
cycles: 4,
}, Instruction {
name: "eor",
function: eor,
address_mode: absolute_x,
cycles: 4,
}, Instruction {
name: "lsr",
function: lsr,
address_mode: absolute_x_const,
cycles: 7,
}, Instruction {
name: "sre",
function: sre,
address_mode: absolute_x_const,
cycles: 7,
}, Instruction {
name: "rts",
function: rts,
address_mode: implied,
cycles: 6,
}, Instruction {
name: "adc",
function: adc,
address_mode: indirect_x,
cycles: 6,
}, Instruction {
name: "kil",
function: kil,
address_mode: implied,
cycles: 0,
}, Instruction {
name: "rra",
function: rra,
address_mode: indirect_x,
cycles: 8,
}, Instruction {
name: "nop",
function: nop,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "adc",
function: adc,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "ror",
function: ror,
address_mode: zero_page,
cycles: 5,
}, Instruction {
name: "rra",
function: rra,
address_mode: zero_page,
cycles: 5,
}, Instruction {
name: "pla",
function: pla,
address_mode: implied,
cycles: 4,
}, Instruction {
name: "adc",
function: adc,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "ror",
function: ror,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "arr",
function: arr,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "jmp",
function: jmp,
address_mode: indirect,
cycles: 5,
}, Instruction {
name: "adc",
function: adc,
address_mode: absolute,
cycles: 4,
}, Instruction {
name: "ror",
function: ror,
address_mode: absolute,
cycles: 6,
}, Instruction {
name: "rra",
function: rra,
address_mode: absolute,
cycles: 6,
}, Instruction {
name: "bvs",
function: bvs,
address_mode: relative,
cycles: 2,
}, Instruction {
name: "adc",
function: adc,
address_mode: indirect_y,
cycles: 5,
}, Instruction {
name: "kil",
function: kil,
address_mode: implied,
cycles: 0,
}, Instruction {
name: "rra",
function: rra,
address_mode: indirect_y_const,
cycles: 8,
}, Instruction {
name: "nop",
function: nop,
address_mode: zero_page_x,
cycles: 4,
}, Instruction {
name: "adc",
function: adc,
address_mode: zero_page_x,
cycles: 4,
}, Instruction {
name: "ror",
function: ror,
address_mode: zero_page_x,
cycles: 6,
}, Instruction {
name: "rra",
function: rra,
address_mode: zero_page_x,
cycles: 6,
}, Instruction {
name: "sei",
function: sei,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "adc",
function: adc,
address_mode: absolute_y,
cycles: 4,
}, Instruction {
name: "nop",
function: nop,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "rra",
function: rra,
address_mode: absolute_y_const,
cycles: 7,
}, Instruction {
name: "nop",
function: nop,
address_mode: absolute_x,
cycles: 4,
}, Instruction {
name: "adc",
function: adc,
address_mode: absolute_x,
cycles: 4,
}, Instruction {
name: "ror",
function: ror,
address_mode: absolute_x_const,
cycles: 7,
}, Instruction {
name: "rra",
function: rra,
address_mode: absolute_x_const,
cycles: 7,
}, Instruction {
name: "nop",
function: nop,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "sta",
function: sta,
address_mode: indirect_x,
cycles: 6,
}, Instruction {
name: "nop",
function: nop,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "sax",
function: sax,
address_mode: indirect_x,
cycles: 6,
}, Instruction {
name: "sty",
function: sty,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "sta",
function: sta,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "stx",
function: stx,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "sax",
function: sax,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "dey",
function: dey,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "nop",
function: nop,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "txa",
function: txa,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "xaa",
function: xaa,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "sty",
function: sty,
address_mode: absolute,
cycles: 4,
}, Instruction {
name: "sta",
function: sta,
address_mode: absolute,
cycles: 4,
}, Instruction {
name: "stx",
function: stx,
address_mode: absolute,
cycles: 4,
}, Instruction {
name: "sax",
function: sax,
address_mode: absolute,
cycles: 4,
}, Instruction {
name: "bcc",
function: bcc,
address_mode: relative,
cycles: 2,
}, Instruction {
name: "sta",
function: sta,
address_mode: indirect_y,
cycles: 6,
}, Instruction {
name: "kil",
function: kil,
address_mode: implied,
cycles: 0,
}, Instruction {
name: "ahx",
function: ahx,
address_mode: indirect_y,
cycles: 6,
}, Instruction {
name: "sty",
function: sty,
address_mode: zero_page_x,
cycles: 4,
}, Instruction {
name: "sta",
function: sta,
address_mode: zero_page_x,
cycles: 4,
}, Instruction {
name: "stx",
function: stx,
address_mode: zero_page_y,
cycles: 4,
}, Instruction {
name: "sax",
function: sax,
address_mode: zero_page_y,
cycles: 4,
}, Instruction {
name: "tya",
function: tya,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "sta",
function: sta,
address_mode: absolute_y_const,
cycles: 5,
}, Instruction {
name: "txs",
function: txs,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "tas",
function: tas,
address_mode: absolute_y,
cycles: 5,
}, Instruction {
name: "shy",
function: shy,
address_mode: absolute_x,
cycles: 5,
}, Instruction {
name: "sta",
function: sta,
address_mode: absolute_x_const,
cycles: 5,
}, Instruction {
name: "shx",
function: shx,
address_mode: absolute_y,
cycles: 5,
}, Instruction {
name: "ahx",
function: ahx,
address_mode: absolute_y,
cycles: 5,
}, Instruction {
name: "ldy",
function: ldy,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "lda",
function: lda,
address_mode: indirect_x,
cycles: 6,
}, Instruction {
name: "ldx",
function: ldx,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "lax",
function: lax,
address_mode: indirect_x,
cycles: 6,
}, Instruction {
name: "ldy",
function: ldy,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "lda",
function: lda,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "ldx",
function: ldx,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "lax",
function: lax,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "tay",
function: tay,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "lda",
function: lda,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "tax",
function: tax,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "lax",
function: lax,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "ldy",
function: ldy,
address_mode: absolute,
cycles: 4,
}, Instruction {
name: "lda",
function: lda,
address_mode: absolute,
cycles: 4,
}, Instruction {
name: "ldx",
function: ldx,
address_mode: absolute,
cycles: 4,
}, Instruction {
name: "lax",
function: lax,
address_mode: absolute,
cycles: 4,
}, Instruction {
name: "bcs",
function: bcs,
address_mode: relative,
cycles: 2,
}, Instruction {
name: "lda",
function: lda,
address_mode: indirect_y,
cycles: 5,
}, Instruction {
name: "kil",
function: kil,
address_mode: implied,
cycles: 0,
}, Instruction {
name: "lax",
function: lax,
address_mode: indirect_y,
cycles: 5,
}, Instruction {
name: "ldy",
function: ldy,
address_mode: zero_page_x,
cycles: 4,
}, Instruction {
name: "lda",
function: lda,
address_mode: zero_page_x,
cycles: 4,
}, Instruction {
name: "ldx",
function: ldx,
address_mode: zero_page_y,
cycles: 4,
}, Instruction {
name: "lax",
function: lax,
address_mode: zero_page_y,
cycles: 4,
}, Instruction {
name: "clv",
function: clv,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "lda",
function: lda,
address_mode: absolute_y,
cycles: 4,
}, Instruction {
name: "tsx",
function: tsx,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "las",
function: las,
address_mode: absolute_y,
cycles: 4,
}, Instruction {
name: "ldy",
function: ldy,
address_mode: absolute_x,
cycles: 4,
}, Instruction {
name: "lda",
function: lda,
address_mode: absolute_x,
cycles: 4,
}, Instruction {
name: "ldx",
function: ldx,
address_mode: absolute_y,
cycles: 4,
}, Instruction {
name: "lax",
function: lax,
address_mode: absolute_y,
cycles: 4,
}, Instruction {
name: "cpy",
function: cpy,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "cmp",
function: cmp,
address_mode: indirect_x,
cycles: 6,
}, Instruction {
name: "nop",
function: nop,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "dcp",
function: dcp,
address_mode: indirect_x,
cycles: 8,
}, Instruction {
name: "cpy",
function: cpy,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "cmp",
function: cmp,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "dec",
function: dec,
address_mode: zero_page,
cycles: 5,
}, Instruction {
name: "dcp",
function: dcp,
address_mode: zero_page,
cycles: 5,
}, Instruction {
name: "iny",
function: iny,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "cmp",
function: cmp,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "dex",
function: dex,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "axs",
function: axs,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "cpy",
function: cpy,
address_mode: absolute,
cycles: 4,
}, Instruction {
name: "cmp",
function: cmp,
address_mode: absolute,
cycles: 4,
}, Instruction {
name: "dec",
function: dec,
address_mode: absolute,
cycles: 6,
}, Instruction {
name: "dcp",
function: dcp,
address_mode: absolute,
cycles: 6,
}, Instruction {
name: "bne",
function: bne,
address_mode: relative,
cycles: 2,
}, Instruction {
name: "cmp",
function: cmp,
address_mode: indirect_y,
cycles: 5,
}, Instruction {
name: "kil",
function: kil,
address_mode: implied,
cycles: 0,
}, Instruction {
name: "dcp",
function: dcp,
address_mode: indirect_y_const,
cycles: 8,
}, Instruction {
name: "nop",
function: nop,
address_mode: zero_page_x,
cycles: 4,
}, Instruction {
name: "cmp",
function: cmp,
address_mode: zero_page_x,
cycles: 4,
}, Instruction {
name: "dec",
function: dec,
address_mode: zero_page_x,
cycles: 6,
}, Instruction {
name: "dcp",
function: dcp,
address_mode: zero_page_x,
cycles: 6,
}, Instruction {
name: "cld",
function: cld,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "cmp",
function: cmp,
address_mode: absolute_y,
cycles: 4,
}, Instruction {
name: "nop",
function: nop,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "dcp",
function: dcp,
address_mode: absolute_y_const,
cycles: 7,
}, Instruction {
name: "nop",
function: nop,
address_mode: absolute_x,
cycles: 4,
}, Instruction {
name: "cmp",
function: cmp,
address_mode: absolute_x,
cycles: 4,
}, Instruction {
name: "dec",
function: dec,
address_mode: absolute_x_const,
cycles: 7,
}, Instruction {
name: "dcp",
function: dcp,
address_mode: absolute_x_const,
cycles: 7,
}, Instruction {
name: "cpx",
function: cpx,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "sbc",
function: sbc,
address_mode: indirect_x,
cycles: 6,
}, Instruction {
name: "nop",
function: nop,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "isc",
function: isc,
address_mode: indirect_x,
cycles: 8,
}, Instruction {
name: "cpx",
function: cpx,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "sbc",
function: sbc,
address_mode: zero_page,
cycles: 3,
}, Instruction {
name: "inc",
function: inc,
address_mode: zero_page,
cycles: 5,
}, Instruction {
name: "isc",
function: isc,
address_mode: zero_page,
cycles: 5,
}, Instruction {
name: "inx",
function: inx,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "sbc",
function: sbc,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "nop",
function: nop,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "sbc",
function: sbc,
address_mode: immediate,
cycles: 2,
}, Instruction {
name: "cpx",
function: cpx,
address_mode: absolute,
cycles: 4,
}, Instruction {
name: "sbc",
function: sbc,
address_mode: absolute,
cycles: 4,
}, Instruction {
name: "inc",
function: inc,
address_mode: absolute,
cycles: 6,
}, Instruction {
name: "isc",
function: isc,
address_mode: absolute,
cycles: 6,
}, Instruction {
name: "beq",
function: beq,
address_mode: relative,
cycles: 2,
}, Instruction {
name: "sbc",
function: sbc,
address_mode: indirect_y,
cycles: 5,
}, Instruction {
name: "kil",
function: kil,
address_mode: implied,
cycles: 0,
}, Instruction {
name: "isc",
function: isc,
address_mode: indirect_y_const,
cycles: 8,
}, Instruction {
name: "nop",
function: nop,
address_mode: zero_page_x,
cycles: 4,
}, Instruction {
name: "sbc",
function: sbc,
address_mode: zero_page_x,
cycles: 4,
}, Instruction {
name: "inc",
function: inc,
address_mode: zero_page_x,
cycles: 6,
}, Instruction {
name: "isc",
function: isc,
address_mode: zero_page_x,
cycles: 6,
}, Instruction {
name: "sed",
function: sed,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "sbc",
function: sbc,
address_mode: absolute_y,
cycles: 4,
}, Instruction {
name: "nop",
function: nop,
address_mode: implied,
cycles: 2,
}, Instruction {
name: "isc",
function: isc,
address_mode: absolute_y_const,
cycles: 7,
}, Instruction {
name: "nop",
function: nop,
address_mode: absolute_x,
cycles: 4,
}, Instruction {
name: "sbc",
function: sbc,
address_mode: absolute_x,
cycles: 4,
}, Instruction {
name: "inc",
function: inc,
address_mode: absolute_x_const,
cycles: 7,
}, Instruction {
name: "isc",
function: isc,
address_mode: absolute_x_const,
cycles: 7,
}, ];
fn adc(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::AbsoluteAddress(address) = address_mode_value {
let value = bus.read(address);
let mut result: u16 = u16::from(cpu.accumulator) + u16::from(value) + cpu.get_flag(StatusFlag::Carry) as u16;
if cfg!(feature = "binary_coded_decimal") && cpu.get_flag(StatusFlag::Decimal) {
let mut sum = (cpu.accumulator & 0xf) + (value & 0xf) + cpu.get_flag(StatusFlag::Carry) as u8;
if sum >= 0xa {
sum = ((sum + 0x6) & 0xf) + 0x10;
}
let mut sum = (cpu.accumulator & 0xf0) as u16 + (value & 0xf0) as u16 + sum as u16;
cpu.set_flag(StatusFlag::Zero, result & 0xff == 0);
cpu.set_flag(StatusFlag::Negative, (sum & 0x80) > 0);
cpu.set_flag(
StatusFlag::Overflow,
(!(cpu.accumulator ^ value) & (cpu.accumulator ^ sum as u8) & StatusFlag::Negative as u8) > 0,
);
if sum >= 0xa0 {
sum += 0x60;
}
cpu.set_flag(StatusFlag::Carry, sum >= 0x100);
result = sum & 0xff;
} else {
cpu.set_flag(StatusFlag::Carry, result > u16::from(u8::max_value()));
cpu.set_flag(StatusFlag::Zero, result as u8 == 0);
cpu.set_flag(
StatusFlag::Overflow,
(!(cpu.accumulator ^ value) & (cpu.accumulator ^ result as u8) & StatusFlag::Negative as u8) > 0,
);
cpu.set_flag(StatusFlag::Negative, result as u8 & StatusFlag::Negative as u8 > 0);
}
cpu.accumulator = result as u8;
} else {
panic!("ADC opcode called with invalid address mode!")
}
}
fn and(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::AbsoluteAddress(address) = address_mode_value {
let value = bus.read(address);
cpu.accumulator &= value;
cpu.set_flag(StatusFlag::Zero, cpu.accumulator == 0);
cpu.set_flag(StatusFlag::Negative, cpu.accumulator & StatusFlag::Negative as u8 > 0);
} else {
panic!("AND opcode called with invalid address mode!")
}
}
fn asl(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
fn asl_wrapped(cpu: &mut MOS6502, value: u8) -> u8 {
cpu.set_flag(StatusFlag::Carry, value >> 7 == 1);
let shifted_value = value << 1;
cpu.set_flag(StatusFlag::Negative, shifted_value & StatusFlag::Negative as u8 > 0);
cpu.set_flag(StatusFlag::Zero, shifted_value == 0);
return shifted_value;
}
match address_mode_value {
AddressModeValue::Implied => {
cpu.accumulator = asl_wrapped(cpu, cpu.accumulator);
}
AddressModeValue::AbsoluteAddress(address) => {
let value = asl_wrapped(cpu, bus.read(address));
bus.write(address, value);
}
_ => panic!("ASL opcode called with invalid address mode!"),
}
}
fn bcc(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
return branch(cpu, !cpu.get_flag(StatusFlag::Carry), address_mode_value);
}
fn bcs(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
return branch(cpu, cpu.get_flag(StatusFlag::Carry), address_mode_value);
}
fn beq(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
return branch(cpu, cpu.get_flag(StatusFlag::Zero), address_mode_value);
}
fn bit(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::AbsoluteAddress(address) = address_mode_value {
let value = bus.read(address);
cpu.set_flag(StatusFlag::Zero, cpu.accumulator & value == 0);
cpu.set_flag(StatusFlag::Overflow, value & StatusFlag::Overflow as u8 > 0);
cpu.set_flag(StatusFlag::Negative, value & StatusFlag::Negative as u8 > 0);
} else {
panic!("BIT opcode called with invalid address mode!")
}
}
fn bmi(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
return branch(cpu, cpu.get_flag(StatusFlag::Negative), address_mode_value);
}
fn bne(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
return branch(cpu, !cpu.get_flag(StatusFlag::Zero), address_mode_value);
}
fn bpl(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
return branch(cpu, !cpu.get_flag(StatusFlag::Negative), address_mode_value);
}
fn brk(cpu: &mut MOS6502, bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {
cpu.push_stack_16(bus, cpu.program_counter + 1);
cpu.set_flag(StatusFlag::Break, true);
cpu.push_stack(bus, cpu.status_register);
cpu.set_flag(StatusFlag::InterruptDisable, true);
cpu.program_counter = super::read_16(bus, super::IRQ_ADDRESS_LOCATION);
}
fn bvc(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
return branch(cpu, !cpu.get_flag(StatusFlag::Overflow), address_mode_value);
}
fn bvs(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
return branch(cpu, cpu.get_flag(StatusFlag::Overflow), address_mode_value);
}
fn clc(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {
cpu.set_flag(StatusFlag::Carry, false);
}
fn cld(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {
cpu.set_flag(StatusFlag::Decimal, false);
}
fn cli(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {
cpu.set_flag(StatusFlag::InterruptDisable, false);
}
fn clv(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {
cpu.set_flag(StatusFlag::Overflow, false);
}
fn cmp(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
compare(cpu, bus, cpu.accumulator, address_mode_value);
}
fn cpx(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
compare(cpu, bus, cpu.x_register, address_mode_value);
}
fn cpy(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
compare(cpu, bus, cpu.y_register, address_mode_value);
}
fn dec(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::AbsoluteAddress(address) = address_mode_value {
let value = bus.read(address).wrapping_sub(1);
cpu.set_flag(StatusFlag::Zero, value == 0);
cpu.set_flag(StatusFlag::Negative, value & StatusFlag::Negative as u8 > 0);
bus.write(address, value);
} else {
panic!("DEC opcode called with invalid address mode!")
}
}
fn dex(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::Implied = address_mode_value {
cpu.x_register = cpu.x_register.wrapping_sub(1);
cpu.set_flag(StatusFlag::Zero, cpu.x_register == 0);
cpu.set_flag(StatusFlag::Negative, cpu.x_register & StatusFlag::Negative as u8 > 0);
} else {
panic!("DEX opcode called with invalid address mode!")
}
}
fn dey(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::Implied = address_mode_value {
cpu.y_register = cpu.y_register.wrapping_sub(1);
cpu.set_flag(StatusFlag::Zero, cpu.y_register == 0);
cpu.set_flag(StatusFlag::Negative, cpu.y_register & StatusFlag::Negative as u8 > 0);
} else {
panic!("DEY opcode called with invalid address mode!")
}
}
fn eor(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::AbsoluteAddress(address) = address_mode_value {
let value = bus.read(address);
cpu.accumulator ^= value;
cpu.set_flag(StatusFlag::Zero, cpu.accumulator == 0);
cpu.set_flag(StatusFlag::Negative, cpu.accumulator & StatusFlag::Negative as u8 > 0);
} else {
panic!("EOR opcode called with invalid address mode!")
}
}
fn inc(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::AbsoluteAddress(address) = address_mode_value {
let value = bus.read(address).wrapping_add(1);
cpu.set_flag(StatusFlag::Zero, value == 0);
cpu.set_flag(StatusFlag::Negative, value & StatusFlag::Negative as u8 > 0);
bus.write(address, value);
} else {
panic!("INC opcode called with invalid address mode!")
}
}
fn inx(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::Implied = address_mode_value {
cpu.x_register = cpu.x_register.wrapping_add(1);
cpu.set_flag(StatusFlag::Zero, cpu.x_register == 0);
cpu.set_flag(StatusFlag::Negative, cpu.x_register & StatusFlag::Negative as u8 > 0);
} else {
panic!("INX opcode called with invalid address mode!")
}
}
fn iny(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::Implied = address_mode_value {
cpu.y_register = cpu.y_register.wrapping_add(1);
cpu.set_flag(StatusFlag::Zero, cpu.y_register == 0);
cpu.set_flag(StatusFlag::Negative, cpu.y_register & StatusFlag::Negative as u8 > 0);
} else {
panic!("INY opcode called with invalid address mode!")
}
}
fn jmp(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::AbsoluteAddress(address) = address_mode_value {
cpu.program_counter = address;
} else {
panic!("JMP opcode called with invalid address mode!")
}
}
fn jsr(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::AbsoluteAddress(address) = address_mode_value {
cpu.push_stack_16(bus, cpu.program_counter - 1);
cpu.program_counter = address;
} else {
panic!("JSR opcode called with invalid address mode!")
}
}
fn lda(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::AbsoluteAddress(address) = address_mode_value {
cpu.accumulator = bus.read(address);
cpu.set_flag(StatusFlag::Zero, cpu.accumulator == 0);
cpu.set_flag(StatusFlag::Negative, cpu.accumulator & StatusFlag::Negative as u8 > 0);
} else {
panic!("LDA opcode called with invalid address mode!")
}
}
fn ldx(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::AbsoluteAddress(address) = address_mode_value {
cpu.x_register = bus.read(address);
cpu.set_flag(StatusFlag::Zero, cpu.x_register == 0);
cpu.set_flag(StatusFlag::Negative, cpu.x_register & StatusFlag::Negative as u8 > 0);
} else {
panic!("LDX opcode called with invalid address mode!")
}
}
fn ldy(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::AbsoluteAddress(address) = address_mode_value {
cpu.y_register = bus.read(address);
cpu.set_flag(StatusFlag::Zero, cpu.y_register == 0);
cpu.set_flag(StatusFlag::Negative, cpu.y_register & StatusFlag::Negative as u8 > 0);
} else {
panic!("LDY opcode called with invalid address mode!")
}
}
fn lsr(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
fn lsr_wrapped(cpu: &mut MOS6502, value: u8) -> u8 {
cpu.set_flag(StatusFlag::Carry, value & 1 == 1);
let shifted_value = value >> 1;
cpu.set_flag(StatusFlag::Zero, shifted_value == 0);
cpu.set_flag(StatusFlag::Negative, false); return shifted_value;
}
match address_mode_value {
AddressModeValue::Implied => {
cpu.accumulator = lsr_wrapped(cpu, cpu.accumulator);
}
AddressModeValue::AbsoluteAddress(address) => {
let value = lsr_wrapped(cpu, bus.read(address));
bus.write(address, value);
}
_ => panic!("LSR opcode called with invalid address mode!"),
}
}
fn nop(_cpu: &mut MOS6502, _bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {}
fn ora(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::AbsoluteAddress(address) = address_mode_value {
let value = bus.read(address);
cpu.accumulator |= value;
cpu.set_flag(StatusFlag::Zero, cpu.accumulator == 0);
cpu.set_flag(StatusFlag::Negative, cpu.accumulator & StatusFlag::Negative as u8 > 0);
} else {
panic!("ORA opcode called with invalid address mode!")
}
}
fn pha(cpu: &mut MOS6502, bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {
cpu.push_stack(bus, cpu.accumulator);
}
fn php(cpu: &mut MOS6502, bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {
let status = cpu.status_register;
cpu.push_stack(bus, status | StatusFlag::Break as u8);
}
fn pla(cpu: &mut MOS6502, bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {
cpu.accumulator = cpu.pop_stack(bus);
cpu.set_flag(StatusFlag::Negative, cpu.accumulator & StatusFlag::Negative as u8 > 0);
cpu.set_flag(StatusFlag::Zero, cpu.accumulator == 0);
}
fn plp(cpu: &mut MOS6502, bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {
let status = cpu.pop_stack(bus);
cpu.status_register = (cpu.status_register & (StatusFlag::Break as u8)) | (status & !(StatusFlag::Break as u8));
}
fn rol(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
fn rol_wrapped(cpu: &mut MOS6502, value: u8) -> u8 {
let carry = cpu.get_flag(StatusFlag::Carry) as u8;
cpu.set_flag(StatusFlag::Carry, value >> 7 == 1);
let shifted_value = (value << 1) + carry;
cpu.set_flag(StatusFlag::Negative, shifted_value & StatusFlag::Negative as u8 > 0);
cpu.set_flag(StatusFlag::Zero, shifted_value == 0);
return shifted_value;
}
match address_mode_value {
AddressModeValue::Implied => {
cpu.accumulator = rol_wrapped(cpu, cpu.accumulator);
}
AddressModeValue::AbsoluteAddress(address) => {
let value = rol_wrapped(cpu, bus.read(address));
bus.write(address, value);
}
_ => panic!("ROL opcode called with invalid address mode!"),
}
}
fn ror(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
fn ror_wrapped(cpu: &mut MOS6502, value: u8) -> u8 {
let carry = cpu.get_flag(StatusFlag::Carry) as u8;
cpu.set_flag(StatusFlag::Carry, value & 1 == 1);
let shifted_value = (value >> 1) + (carry << 7);
cpu.set_flag(StatusFlag::Negative, shifted_value & StatusFlag::Negative as u8 > 0);
cpu.set_flag(StatusFlag::Zero, shifted_value == 0);
return shifted_value;
}
match address_mode_value {
AddressModeValue::Implied => {
cpu.accumulator = ror_wrapped(cpu, cpu.accumulator);
}
AddressModeValue::AbsoluteAddress(address) => {
let value = ror_wrapped(cpu, bus.read(address));
bus.write(address, value);
}
_ => panic!("ROR opcode called with invalid address mode!"),
}
}
fn rti(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
plp(cpu, bus, address_mode_value);
cpu.program_counter = cpu.pop_stack_16(bus);
}
fn rts(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::Implied = address_mode_value {
cpu.program_counter = cpu.pop_stack_16(bus) + 1;
} else {
panic!("RTS opcode called with invalid address mode!")
}
}
fn sbc(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::AbsoluteAddress(address) = address_mode_value {
let value = bus.read(address);
let carry = cpu.get_flag(StatusFlag::Carry);
let mut result = u16::from(cpu.accumulator) + u16::from(!value) + carry as u16;
cpu.set_flag(StatusFlag::Carry, result > u16::from(u8::max_value()));
cpu.set_flag(StatusFlag::Zero, result as u8 == 0);
cpu.set_flag(
StatusFlag::Overflow,
((cpu.accumulator ^ value) & (cpu.accumulator ^ result as u8) & StatusFlag::Negative as u8) > 0,
);
cpu.set_flag(StatusFlag::Negative, result as u8 & StatusFlag::Negative as u8 > 0);
if cfg!(feature = "binary_coded_decimal") && cpu.get_flag(StatusFlag::Decimal) {
let value = value as i16;
let mut sum = (cpu.accumulator & 0xf) as i16 - (value & 0xf) + carry as i16 - 1;
if sum < 0 {
sum = ((sum - 0x6) & 0xf) - 0x10;
}
let mut sum = (cpu.accumulator & 0xf0) as i16 - (value & 0xf0) + sum;
if sum < 0 {
sum -= 0x60;
}
result = (sum & 0xff) as u16;
}
cpu.accumulator = result as u8;
} else {
panic!("SBC opcode called with invalid address mode!")
}
}
fn sec(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {
cpu.set_flag(StatusFlag::Carry, true);
}
fn sed(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {
cpu.set_flag(StatusFlag::Decimal, true);
}
fn sei(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {
cpu.set_flag(StatusFlag::InterruptDisable, true);
}
fn sta(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::AbsoluteAddress(address) = address_mode_value {
bus.write(address, cpu.accumulator);
} else {
panic!("STA opcode called with invalid address mode!")
}
}
fn stx(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::AbsoluteAddress(address) = address_mode_value {
bus.write(address, cpu.x_register);
} else {
panic!("STX opcode called with invalid address mode!")
}
}
fn sty(cpu: &mut MOS6502, bus: &mut dyn Interface6502, address_mode_value: AddressModeValue) {
if let AddressModeValue::AbsoluteAddress(address) = address_mode_value {
bus.write(address, cpu.y_register);
} else {
panic!("STY opcode called with invalid address mode!")
}
}
fn tax(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {
cpu.x_register = cpu.accumulator;
cpu.set_flag(StatusFlag::Negative, cpu.x_register & StatusFlag::Negative as u8 > 0);
cpu.set_flag(StatusFlag::Zero, cpu.x_register == 0);
}
fn tay(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {
cpu.y_register = cpu.accumulator;
cpu.set_flag(StatusFlag::Negative, cpu.y_register & StatusFlag::Negative as u8 > 0);
cpu.set_flag(StatusFlag::Zero, cpu.y_register == 0);
}
fn tsx(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {
cpu.x_register = cpu.stack_pointer;
cpu.set_flag(StatusFlag::Negative, cpu.x_register & StatusFlag::Negative as u8 > 0);
cpu.set_flag(StatusFlag::Zero, cpu.x_register == 0);
}
fn txa(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {
cpu.accumulator = cpu.x_register;
cpu.set_flag(StatusFlag::Negative, cpu.accumulator & StatusFlag::Negative as u8 > 0);
cpu.set_flag(StatusFlag::Zero, cpu.accumulator == 0);
}
fn txs(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {
cpu.stack_pointer = cpu.x_register;
}
fn tya(cpu: &mut MOS6502, _bus: &mut dyn Interface6502, _address_mode_value: AddressModeValue) {
cpu.accumulator = cpu.y_register;
cpu.set_flag(StatusFlag::Negative, cpu.y_register & StatusFlag::Negative as u8 > 0);
cpu.set_flag(StatusFlag::Zero, cpu.y_register == 0);
}
fn signed_8_bit_to_16(value: u8) -> u16 {
let mut value = u16::from(value);
if value & 0x80 > 0 {
value |= 0xff00;
}
return value;
}
fn branch(cpu: &mut MOS6502, branch_condition: bool, address_mode_value: AddressModeValue) {
if let AddressModeValue::RelativeAddress(relative_address) = address_mode_value {
let address = signed_8_bit_to_16(relative_address).wrapping_add(cpu.program_counter);
if branch_condition {
if address & 0xff00 != cpu.program_counter & 0xff00 {
cpu.remaining_cycles += 2;
} else {
cpu.remaining_cycles += 1;
}
cpu.program_counter = address;
}
} else {
panic!("Branching opcode called with invalid address mode!")
}
}
fn compare(cpu: &mut MOS6502, bus: &mut dyn Interface6502, register: u8, address_mode_value: AddressModeValue) -> u8 {
if let AddressModeValue::AbsoluteAddress(address) = address_mode_value {
let value = bus.read(address);
cpu.set_flag(StatusFlag::Carry, register >= value);
cpu.set_flag(StatusFlag::Zero, register == value);
let register = register.wrapping_sub(value);
cpu.set_flag(StatusFlag::Negative, register & StatusFlag::Negative as u8 > 0);
return register;
} else {
panic!("Compare opcode called with invalid address mode!")
}
}
#[cfg(test)]
mod test {
#![allow(unused_variables, unused_mut)]
use super::*;
use crate::address_modes::AddressModeValue;
use crate::test_utilities::StubInterface6502;
use crate::{StatusFlag, MOS6502};
#[test]
fn test_adc() {
let mut cpu_initial = MOS6502 {
accumulator: 0x09,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Carry, true);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x10,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x1a,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Carry, false);
adc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_adc_zero_carry_flags() {
let mut cpu_initial = MOS6502 {
accumulator: 0xff,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x01,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Zero, true);
cpu_expected.set_flag(StatusFlag::Carry, true);
adc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_adc_overflow_negative_flags() {
let mut cpu_initial = MOS6502 {
accumulator: 0x7f,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x01,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x80,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Overflow, true);
cpu_expected.set_flag(StatusFlag::Negative, true);
adc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_adc_decimal_mode() {
let mut cpu_initial = MOS6502 {
accumulator: 0x09,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, true);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x09,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x19,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Carry, false);
adc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_adc_decimal_mode_zero_carry_flags() {
let mut cpu_initial = MOS6502 {
accumulator: 0x98,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, true);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x01,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Zero, false);
cpu_expected.set_flag(StatusFlag::Negative, true);
adc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_adc_decimal_1() {
const INPUT: (u8, u8, bool) = (0x00, 0x00, false);
const EXPECTED: (u8, bool, bool, bool, bool) = (0x00, false, false, true, false);
let mut cpu_initial = MOS6502 {
accumulator: INPUT.0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, INPUT.2);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| INPUT.1,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: EXPECTED.0,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, EXPECTED.1);
cpu_expected.set_flag(StatusFlag::Overflow, EXPECTED.2);
cpu_expected.set_flag(StatusFlag::Zero, EXPECTED.3);
cpu_expected.set_flag(StatusFlag::Carry, EXPECTED.4);
adc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_adc_decimal_2() {
const INPUT: (u8, u8, bool) = (0x79, 0x00, true);
const EXPECTED: (u8, bool, bool, bool, bool) = (0x80, true, true, false, false);
let mut cpu_initial = MOS6502 {
accumulator: INPUT.0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, INPUT.2);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| INPUT.1,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: EXPECTED.0,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, EXPECTED.1);
cpu_expected.set_flag(StatusFlag::Overflow, EXPECTED.2);
cpu_expected.set_flag(StatusFlag::Zero, EXPECTED.3);
cpu_expected.set_flag(StatusFlag::Carry, EXPECTED.4);
adc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_adc_decimal_3() {
const INPUT: (u8, u8, bool) = (0x24, 0x56, false);
const EXPECTED: (u8, bool, bool, bool, bool) = (0x80, true, true, false, false);
let mut cpu_initial = MOS6502 {
accumulator: INPUT.0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, INPUT.2);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| INPUT.1,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: EXPECTED.0,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, EXPECTED.1);
cpu_expected.set_flag(StatusFlag::Overflow, EXPECTED.2);
cpu_expected.set_flag(StatusFlag::Zero, EXPECTED.3);
cpu_expected.set_flag(StatusFlag::Carry, EXPECTED.4);
adc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_adc_decimal_4() {
const INPUT: (u8, u8, bool) = (0x93, 0x82, false);
const EXPECTED: (u8, bool, bool, bool, bool) = (0x75, false, true, false, true);
let mut cpu_initial = MOS6502 {
accumulator: INPUT.0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, INPUT.2);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| INPUT.1,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: EXPECTED.0,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, EXPECTED.1);
cpu_expected.set_flag(StatusFlag::Overflow, EXPECTED.2);
cpu_expected.set_flag(StatusFlag::Zero, EXPECTED.3);
cpu_expected.set_flag(StatusFlag::Carry, EXPECTED.4);
adc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_adc_decimal_5() {
const INPUT: (u8, u8, bool) = (0x89, 0x76, false);
const EXPECTED: (u8, bool, bool, bool, bool) = (0x65, false, false, false, true);
let mut cpu_initial = MOS6502 {
accumulator: INPUT.0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, INPUT.2);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| INPUT.1,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: EXPECTED.0,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, EXPECTED.1);
cpu_expected.set_flag(StatusFlag::Overflow, EXPECTED.2);
cpu_expected.set_flag(StatusFlag::Zero, EXPECTED.3);
cpu_expected.set_flag(StatusFlag::Carry, EXPECTED.4);
adc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_adc_decimal_6() {
const INPUT: (u8, u8, bool) = (0x89, 0x76, true);
const EXPECTED: (u8, bool, bool, bool, bool) = (0x66, false, false, true, true);
let mut cpu_initial = MOS6502 {
accumulator: INPUT.0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, INPUT.2);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| INPUT.1,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: EXPECTED.0,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, EXPECTED.1);
cpu_expected.set_flag(StatusFlag::Overflow, EXPECTED.2);
cpu_expected.set_flag(StatusFlag::Zero, EXPECTED.3);
cpu_expected.set_flag(StatusFlag::Carry, EXPECTED.4);
adc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_adc_decimal_7() {
const INPUT: (u8, u8, bool) = (0x80, 0xf0, false);
const EXPECTED: (u8, bool, bool, bool, bool) = (0xd0, false, true, false, true);
let mut cpu_initial = MOS6502 {
accumulator: INPUT.0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, INPUT.2);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| INPUT.1,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: EXPECTED.0,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, EXPECTED.1);
cpu_expected.set_flag(StatusFlag::Overflow, EXPECTED.2);
cpu_expected.set_flag(StatusFlag::Zero, EXPECTED.3);
cpu_expected.set_flag(StatusFlag::Carry, EXPECTED.4);
adc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_adc_decimal_8() {
const INPUT: (u8, u8, bool) = (0x80, 0xfa, false);
const EXPECTED: (u8, bool, bool, bool, bool) = (0xe0, true, false, false, true);
let mut cpu_initial = MOS6502 {
accumulator: INPUT.0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, INPUT.2);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| INPUT.1,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: EXPECTED.0,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, EXPECTED.1);
cpu_expected.set_flag(StatusFlag::Overflow, EXPECTED.2);
cpu_expected.set_flag(StatusFlag::Zero, EXPECTED.3);
cpu_expected.set_flag(StatusFlag::Carry, EXPECTED.4);
adc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_adc_decimal_9() {
const INPUT: (u8, u8, bool) = (0x2f, 0x4f, false);
const EXPECTED: (u8, bool, bool, bool, bool) = (0x74, false, false, false, false);
let mut cpu_initial = MOS6502 {
accumulator: INPUT.0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, INPUT.2);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| INPUT.1,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: EXPECTED.0,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, EXPECTED.1);
cpu_expected.set_flag(StatusFlag::Overflow, EXPECTED.2);
cpu_expected.set_flag(StatusFlag::Zero, EXPECTED.3);
cpu_expected.set_flag(StatusFlag::Carry, EXPECTED.4);
adc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_adc_decimal_10() {
const INPUT: (u8, u8, bool) = (0x6f, 0x00, true);
const EXPECTED: (u8, bool, bool, bool, bool) = (0x76, false, false, false, false);
let mut cpu_initial = MOS6502 {
accumulator: INPUT.0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, INPUT.2);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| INPUT.1,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: EXPECTED.0,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, EXPECTED.1);
cpu_expected.set_flag(StatusFlag::Overflow, EXPECTED.2);
cpu_expected.set_flag(StatusFlag::Zero, EXPECTED.3);
cpu_expected.set_flag(StatusFlag::Carry, EXPECTED.4);
adc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_adc_decimal_mode_overflow_negative_flags() {
let mut cpu_initial = MOS6502 {
accumulator: 0x75,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x06,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x81,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, true);
cpu_expected.set_flag(StatusFlag::Overflow, true);
adc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_and() {
let mut cpu_initial = MOS6502 {
accumulator: 0x95,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x80,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x80,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, true);
and(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_and_zero_flag() {
let mut cpu_initial = MOS6502 {
accumulator: 0xf0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x0f,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Zero, true);
and(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_asl() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x4f,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
assert_eq!(address, 0x00ff);
assert_eq!(data, 0x4f << 1);
},
..Default::default()
};
let mut cpu_expected = MOS6502 { ..cpu_initial };
cpu_expected.set_flag(StatusFlag::Negative, true);
asl(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_asl_accumulator_zero_flag() {
let mut cpu_initial = MOS6502 {
accumulator: 0x80,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Carry, true);
cpu_expected.set_flag(StatusFlag::Zero, true);
asl(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_brk() {
let mut cpu_initial = MOS6502 {
accumulator: 0x80,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x4000,
stack_pointer: 0xfd,
status_register: 0x81,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0xfffe => 0x01,
0xffff => 0x80,
_ => panic!("Unintended Address Accessed {:4X}", address),
},
write: |address, data, write_count| match address {
0x01fd => assert_eq!(data, 0x40),
0x01fc => assert_eq!(data, 0x01),
0x01fb => assert_eq!(data, 0x81 | StatusFlag::Break as u8),
_ => panic!("Unintended Address Accessed {:4X}", address),
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
program_counter: 0x8001,
stack_pointer: 0xfa,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Break, true);
cpu_expected.set_flag(StatusFlag::InterruptDisable, true);
brk(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_branch() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x00fb,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut cpu_expected = MOS6502 {
program_counter: 0x0100,
remaining_cycles: 2,
..cpu_initial
};
branch(&mut cpu_initial, true, AddressModeValue::RelativeAddress(0x05));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_branch_backwards() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x000a,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut cpu_expected = MOS6502 {
program_counter: 0x0005,
remaining_cycles: 1,
..cpu_initial
};
branch(&mut cpu_initial, true, AddressModeValue::RelativeAddress(0xfb));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_branch_fail() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x000a,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut cpu_expected = MOS6502 { ..cpu_initial };
branch(&mut cpu_initial, false, AddressModeValue::RelativeAddress(0xfb));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_bit() {
let mut cpu_initial = MOS6502 {
accumulator: 0xf0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x000a,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x0f,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 { ..cpu_initial };
cpu_expected.set_flag(StatusFlag::Zero, true);
bit(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_bit_negative_overflow_flags() {
let mut cpu_initial = MOS6502 {
accumulator: 0x0f,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x000a,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0xc0,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 { ..cpu_initial };
cpu_expected.set_flag(StatusFlag::Zero, true);
cpu_expected.set_flag(StatusFlag::Negative, true);
cpu_expected.set_flag(StatusFlag::Overflow, true);
bit(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_compare() {
let mut cpu_initial = MOS6502 {
accumulator: 0xff,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0xff,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 { ..cpu_initial };
cpu_expected.set_flag(StatusFlag::Zero, true);
cpu_expected.set_flag(StatusFlag::Carry, true);
compare(&mut cpu_initial, &mut stub_bus, 0xff, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_compare_less() {
let mut cpu_initial = MOS6502 {
accumulator: 0x0f,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x10,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 { ..cpu_initial };
cpu_expected.set_flag(StatusFlag::Negative, true);
compare(&mut cpu_initial, &mut stub_bus, 0x0f, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_dec() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x01,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
assert_eq!(address, 0x00ff);
assert_eq!(data, 0x00);
},
..Default::default()
};
let mut cpu_expected = MOS6502 { ..cpu_initial };
cpu_expected.set_flag(StatusFlag::Zero, true);
dec(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_dec_negative() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x00,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
assert_eq!(address, 0x00ff);
assert_eq!(data, 0xff);
},
..Default::default()
};
let mut cpu_expected = MOS6502 { ..cpu_initial };
cpu_expected.set_flag(StatusFlag::Negative, true);
dec(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_dex() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x01,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
x_register: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Zero, true);
dex(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_dex_negative() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
x_register: 0xff,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, true);
dex(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_dey() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x01,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
y_register: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Zero, true);
dey(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_dey_negative() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
y_register: 0xff,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, true);
dey(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_eor() {
let mut cpu_initial = MOS6502 {
accumulator: 0x10,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x80,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x90,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, true);
eor(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_eor_zero_flag() {
let mut cpu_initial = MOS6502 {
accumulator: 0xff,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0xff,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Zero, true);
eor(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_inc() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0xff,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
assert_eq!(address, 0x00ff);
assert_eq!(data, 0x00);
},
..Default::default()
};
let mut cpu_expected = MOS6502 { ..cpu_initial };
cpu_expected.set_flag(StatusFlag::Zero, true);
inc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_inc_negative() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x7f,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
assert_eq!(address, 0x00ff);
assert_eq!(data, 0x80);
},
..Default::default()
};
let mut cpu_expected = MOS6502 { ..cpu_initial };
cpu_expected.set_flag(StatusFlag::Negative, true);
inc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_inx() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0xff,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
x_register: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Zero, true);
inx(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_inx_negative() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x7f,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
x_register: 0x80,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, true);
inx(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_iny() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0xff,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
y_register: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Zero, true);
iny(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_iny_negative() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x7f,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
y_register: 0x80,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, true);
iny(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_jmp() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let cpu_expected = MOS6502 {
program_counter: 0x00ff,
..cpu_initial
};
jmp(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_jsr() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x00bb,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| match address {
0x01fd => assert_eq!(data, 0x00),
0x01fc => assert_eq!(data, 0xba),
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
..Default::default()
};
let cpu_expected = MOS6502 {
program_counter: 0x00ff,
stack_pointer: 0xfb,
..cpu_initial
};
jsr(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_lda() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| 0xff,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0xff,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, true);
lda(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_lda_negative() {
let mut cpu_initial = MOS6502 {
accumulator: 0xff,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| 0x00,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Zero, true);
lda(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_ldx() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| 0xff,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
x_register: 0xff,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, true);
ldx(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_ldx_negative() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0xff,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| 0x00,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
x_register: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Zero, true);
ldx(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_ldy() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| 0xff,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
y_register: 0xff,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, true);
ldy(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_ldy_negative() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0xff,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| 0x00,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
y_register: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Zero, true);
ldy(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_lsr() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0xff,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
assert_eq!(address, 0x00ff);
assert_eq!(data, 0xff >> 1);
},
..Default::default()
};
let mut cpu_expected = MOS6502 { ..cpu_initial };
cpu_expected.set_flag(StatusFlag::Carry, true);
lsr(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_lsr_accumulator_zero_flag() {
let mut cpu_initial = MOS6502 {
accumulator: 0x01,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Zero, true);
cpu_expected.set_flag(StatusFlag::Carry, true);
lsr(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_ora() {
let mut cpu_initial = MOS6502 {
accumulator: 0x10,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x80,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x90,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, true);
ora(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_ora_zero_flag() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x00,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Zero, true);
ora(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_pha() {
let mut cpu_initial = MOS6502 {
accumulator: 0x10,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| match address {
0x01fd => assert_eq!(data, 0x10),
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
..Default::default()
};
let cpu_expected = MOS6502 {
stack_pointer: 0xfc,
..cpu_initial
};
pha(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_php() {
let mut cpu_initial = MOS6502 {
accumulator: 0x10,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| match address {
0x01fd => assert_eq!(data, StatusFlag::Break as u8),
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
stack_pointer: 0xfc,
..cpu_initial
};
php(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_pla() {
let mut cpu_initial = MOS6502 {
accumulator: 0x10,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfc,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x01fd => 0xff,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let cpu_expected = MOS6502 {
accumulator: 0xff,
stack_pointer: 0xfd,
status_register: 0x80,
..cpu_initial
};
pla(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_plp() {
let mut cpu_initial = MOS6502 {
accumulator: 0x10,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfc,
status_register: 0x24,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x01fd => 0xb1,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let cpu_expected = MOS6502 {
status_register: 0xa1,
stack_pointer: 0xfd,
..cpu_initial
};
plp(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_rol() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Carry, true);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x41,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
assert_eq!(address, 0x00ff);
assert_eq!(data, 0x83);
},
..Default::default()
};
let mut cpu_expected = MOS6502 { ..cpu_initial };
cpu_expected.set_flag(StatusFlag::Negative, true);
cpu_expected.set_flag(StatusFlag::Carry, false);
rol(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_rol_accumulator() {
let mut cpu_initial = MOS6502 {
accumulator: 0x80,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Zero, true);
cpu_expected.set_flag(StatusFlag::Carry, true);
rol(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_ror() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Carry, true);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x00ff => 0x02,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
assert_eq!(address, 0x00ff);
assert_eq!(data, 0x81);
},
..Default::default()
};
let mut cpu_expected = MOS6502 { ..cpu_initial };
cpu_expected.set_flag(StatusFlag::Negative, true);
cpu_expected.set_flag(StatusFlag::Carry, false);
ror(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_ror_accumulator() {
let mut cpu_initial = MOS6502 {
accumulator: 0x01,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Zero, true);
cpu_expected.set_flag(StatusFlag::Carry, true);
ror(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_rti() {
let mut cpu_initial = MOS6502 {
accumulator: 0x01,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfa,
status_register: 0x20,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x01fb => 0xf1,
0x01fc => 0x01,
0x01fd => 0x40,
_ => panic!("Unintended Address Accessed: {:4X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let cpu_expected = MOS6502 {
program_counter: 0x4001,
status_register: 0xe1,
stack_pointer: 0xfd,
..cpu_initial
};
rti(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_rts() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x00bb,
stack_pointer: 0xfb,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| match address {
0x01fc => 0x00,
0x01fd => 0x10,
_ => panic!("Unintended Address Accessed: 0x{:X}", address),
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let cpu_expected = MOS6502 {
program_counter: 0x1001,
stack_pointer: 0xfd,
..cpu_initial
};
rts(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_sbc() {
let mut cpu_initial = MOS6502 {
accumulator: 0x10,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Carry, true);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| 0x08,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let cpu_expected = MOS6502 {
accumulator: 0x08,
..cpu_initial
};
sbc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_sbc_overflow() {
let mut cpu_initial = MOS6502 {
accumulator: 0x81,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Carry, true);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| 0x02,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x7f,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Overflow, true);
sbc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_sbc_zero() {
let mut cpu_initial = MOS6502 {
accumulator: 0x10,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Carry, true);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| 0x10,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Zero, true);
sbc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_sbc_carry_negative() {
let mut cpu_initial = MOS6502 {
accumulator: 0x10,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Carry, true);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| 0x11,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0xff,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Carry, false);
cpu_expected.set_flag(StatusFlag::Negative, true);
sbc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_sbc_decimal() {
let mut cpu_initial = MOS6502 {
accumulator: 0x12,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, true);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| 0x06,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let cpu_expected = MOS6502 {
accumulator: 0x06,
..cpu_initial
};
sbc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_sbc_decimal_carry_negative() {
let mut cpu_initial = MOS6502 {
accumulator: 0x12,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, true);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| 0x18,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x94,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Carry, false);
cpu_expected.set_flag(StatusFlag::Negative, true);
sbc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_sbc_decimal_1() {
const INPUT: (u8, u8, bool) = (0x00, 0x00, false);
const EXPECTED: (u8, bool, bool, bool, bool) = (0x99, true, false, false, false);
let mut cpu_initial = MOS6502 {
accumulator: INPUT.0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, INPUT.2);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| INPUT.1,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: EXPECTED.0,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, EXPECTED.1);
cpu_expected.set_flag(StatusFlag::Overflow, EXPECTED.2);
cpu_expected.set_flag(StatusFlag::Zero, EXPECTED.3);
cpu_expected.set_flag(StatusFlag::Carry, EXPECTED.4);
sbc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_sbc_decimal_2() {
const INPUT: (u8, u8, bool) = (0x00, 0x00, true);
const EXPECTED: (u8, bool, bool, bool, bool) = (0x00, false, false, true, true);
let mut cpu_initial = MOS6502 {
accumulator: INPUT.0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, INPUT.2);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| INPUT.1,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: EXPECTED.0,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, EXPECTED.1);
cpu_expected.set_flag(StatusFlag::Overflow, EXPECTED.2);
cpu_expected.set_flag(StatusFlag::Zero, EXPECTED.3);
cpu_expected.set_flag(StatusFlag::Carry, EXPECTED.4);
sbc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_sbc_decimal_3() {
const INPUT: (u8, u8, bool) = (0x00, 0x01, true);
const EXPECTED: (u8, bool, bool, bool, bool) = (0x99, true, false, false, false);
let mut cpu_initial = MOS6502 {
accumulator: INPUT.0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, INPUT.2);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| INPUT.1,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: EXPECTED.0,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, EXPECTED.1);
cpu_expected.set_flag(StatusFlag::Overflow, EXPECTED.2);
cpu_expected.set_flag(StatusFlag::Zero, EXPECTED.3);
cpu_expected.set_flag(StatusFlag::Carry, EXPECTED.4);
sbc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_sbc_decimal_4() {
const INPUT: (u8, u8, bool) = (0x0a, 0x00, true);
const EXPECTED: (u8, bool, bool, bool, bool) = (0x0a, false, false, false, true);
let mut cpu_initial = MOS6502 {
accumulator: INPUT.0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, INPUT.2);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| INPUT.1,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: EXPECTED.0,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, EXPECTED.1);
cpu_expected.set_flag(StatusFlag::Overflow, EXPECTED.2);
cpu_expected.set_flag(StatusFlag::Zero, EXPECTED.3);
cpu_expected.set_flag(StatusFlag::Carry, EXPECTED.4);
sbc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_sbc_decimal_5() {
const INPUT: (u8, u8, bool) = (0x0b, 0x00, false);
const EXPECTED: (u8, bool, bool, bool, bool) = (0x0a, false, false, false, true);
let mut cpu_initial = MOS6502 {
accumulator: INPUT.0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, INPUT.2);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| INPUT.1,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: EXPECTED.0,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, EXPECTED.1);
cpu_expected.set_flag(StatusFlag::Overflow, EXPECTED.2);
cpu_expected.set_flag(StatusFlag::Zero, EXPECTED.3);
cpu_expected.set_flag(StatusFlag::Carry, EXPECTED.4);
sbc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_sbc_decimal_6() {
const INPUT: (u8, u8, bool) = (0x9a, 0x00, true);
const EXPECTED: (u8, bool, bool, bool, bool) = (0x9a, true, false, false, true);
let mut cpu_initial = MOS6502 {
accumulator: INPUT.0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, INPUT.2);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| INPUT.1,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: EXPECTED.0,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, EXPECTED.1);
cpu_expected.set_flag(StatusFlag::Overflow, EXPECTED.2);
cpu_expected.set_flag(StatusFlag::Zero, EXPECTED.3);
cpu_expected.set_flag(StatusFlag::Carry, EXPECTED.4);
sbc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
#[cfg(feature = "binary_coded_decimal")]
fn test_sbc_decimal_7() {
const INPUT: (u8, u8, bool) = (0x9b, 0x00, false);
const EXPECTED: (u8, bool, bool, bool, bool) = (0x9a, true, false, false, true);
let mut cpu_initial = MOS6502 {
accumulator: INPUT.0,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
cpu_initial.set_flag(StatusFlag::Decimal, true);
cpu_initial.set_flag(StatusFlag::Carry, INPUT.2);
let mut stub_bus = StubInterface6502 {
read: |address, read_count| INPUT.1,
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: EXPECTED.0,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, EXPECTED.1);
cpu_expected.set_flag(StatusFlag::Overflow, EXPECTED.2);
cpu_expected.set_flag(StatusFlag::Zero, EXPECTED.3);
cpu_expected.set_flag(StatusFlag::Carry, EXPECTED.4);
sbc(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_sta() {
let mut cpu_initial = MOS6502 {
accumulator: 0x01,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
assert_eq!(address, 0x00ff);
assert_eq!(data, 0x01);
},
..Default::default()
};
let cpu_expected = MOS6502 { ..cpu_initial };
sta(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_stx() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x01,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
assert_eq!(address, 0x00ff);
assert_eq!(data, 0x01);
},
..Default::default()
};
let cpu_expected = MOS6502 { ..cpu_initial };
stx(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_sty() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x01,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
assert_eq!(address, 0x00ff);
assert_eq!(data, 0x01);
},
..Default::default()
};
let cpu_expected = MOS6502 { ..cpu_initial };
sty(&mut cpu_initial, &mut stub_bus, AddressModeValue::AbsoluteAddress(0x00ff));
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_tax() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x01,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
x_register: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Zero, true);
tax(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_tay() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x01,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
y_register: 0x00,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Zero, true);
tay(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_tsx() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
x_register: 0xfd,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, true);
tsx(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_txa() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x80,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let mut cpu_expected = MOS6502 {
accumulator: 0x80,
..cpu_initial
};
cpu_expected.set_flag(StatusFlag::Negative, true);
txa(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_txs() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x00,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let cpu_expected = MOS6502 {
stack_pointer: 0x00,
..cpu_initial
};
txs(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
#[test]
fn test_tya() {
let mut cpu_initial = MOS6502 {
accumulator: 0x00,
x_register: 0x00,
y_register: 0x01,
program_counter: 0x0000,
stack_pointer: 0xfd,
status_register: 0x00,
..Default::default()
};
let mut stub_bus = StubInterface6502 {
read: |address, read_count| {
panic! {"Read function was called"}
},
write: |address, data, write_count| {
panic! {"Write function was called"}
},
..Default::default()
};
let cpu_expected = MOS6502 {
accumulator: 0x01,
..cpu_initial
};
tya(&mut cpu_initial, &mut stub_bus, AddressModeValue::Implied);
assert_eq!(cpu_initial, cpu_expected);
}
}