|
|
|
|
|
|
|
|
|
|
|
|
|
|
#![allow(dead_code, non_snake_case)]
|
|
|
|
|
|
|
|
|
|
use super::{R6502, Bus, Flags, addressing_modes::{AddressingModes, ModeID}};
|
|
|
|
|
|
|
|
|
|
// Instruction decoding:
|
|
|
|
|
// https://llx.com/Neil/a2/opcodes.html
|
|
|
|
|
|
|
|
|
|
// GROUP ONE
|
|
|
|
|
// 000 ORA
|
|
|
|
|
// 001 AND
|
|
|
|
|
// 010 EOR
|
|
|
|
|
// 011 ADC
|
|
|
|
|
// 100 STA
|
|
|
|
|
// 101 LDA
|
|
|
|
|
// 110 CMP
|
|
|
|
|
// 111 SBC
|
|
|
|
|
|
|
|
|
|
pub struct Instructions;
|
|
|
|
|
|
|
|
|
|
impl Instructions
|
|
|
|
|
{
|
|
|
|
|
pub const GROUP_ONE_OPS: [fn(&mut R6502, &mut dyn Bus); 8] = [
|
|
|
|
|
Instructions::ORA,
|
|
|
|
|
Instructions::AND,
|
|
|
|
|
Instructions::EOR,
|
|
|
|
|
Instructions::ADC,
|
|
|
|
|
Instructions::STA,
|
|
|
|
|
Instructions::LDA,
|
|
|
|
|
Instructions::CMP,
|
|
|
|
|
Instructions::SBC,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
pub const GROUP_TWO_OPS: [fn(&mut R6502, &mut dyn Bus); 8] = [
|
|
|
|
|
Instructions::ASL, // 000
|
|
|
|
|
Instructions::ROL, // 001
|
|
|
|
|
Instructions::LSR, // 010
|
|
|
|
|
Instructions::ROR, // 011
|
|
|
|
|
Instructions::STX, // 100
|
|
|
|
|
Instructions::LDX, // 101
|
|
|
|
|
Instructions::DEC, // 110
|
|
|
|
|
Instructions::INC, // 111
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
pub const GROUP_THREE_OPS: [fn(&mut R6502, &mut dyn Bus); 8] = [
|
|
|
|
|
Instructions::ERR,
|
|
|
|
|
Instructions::BIT, // 001 BIT
|
|
|
|
|
Instructions::JMP, // 010 JMP
|
|
|
|
|
Instructions::JMP, // 011 JMP (abs)
|
|
|
|
|
Instructions::STY, // 100 STY
|
|
|
|
|
Instructions::LDY, // 101 LDY
|
|
|
|
|
Instructions::CPY, // 110 CPY
|
|
|
|
|
Instructions::CPX, // 111 CPX
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
pub const GROUP_BRANCHING_OPS: [fn(&mut R6502, &mut dyn Bus); 8] = [
|
|
|
|
|
Instructions::BPL,
|
|
|
|
|
Instructions::BMI,
|
|
|
|
|
Instructions::BVC,
|
|
|
|
|
Instructions::BVS,
|
|
|
|
|
Instructions::BCC,
|
|
|
|
|
Instructions::BCS,
|
|
|
|
|
Instructions::BNE,
|
|
|
|
|
Instructions::BEQ,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Instructions
|
|
|
|
|
{
|
|
|
|
|
pub fn ERR(_cpu: &mut R6502, _bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
// TODO: Better error handling
|
|
|
|
|
println!("ERROR: Invalid Instruction");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
// GROUP ONE
|
|
|
|
|
pub fn ORA(cpu: &mut R6502, _bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
let data = cpu.working_data as u8;
|
|
|
|
|
cpu.a = cpu.a | data;
|
|
|
|
|
if cpu.a == 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cpu.a & 0x80 != 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn AND(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
let data = cpu.working_data as u8;
|
|
|
|
|
cpu.a = cpu.a & data;
|
|
|
|
|
if cpu.a == 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cpu.a & 0x80 != 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn EOR(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
let data = cpu.working_data as u8;
|
|
|
|
|
cpu.a = cpu.a ^ data;
|
|
|
|
|
if cpu.a == 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cpu.a & 0x80 != 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Using a technique written javidx9
|
|
|
|
|
// The code in this function falls under the License (OLC-3) SEE LICENSE FILE
|
|
|
|
|
// https://github.com/OneLoneCoder/olcNES/blob/master/Part%232%20-%20CPU/olc6502.cpp#L659
|
|
|
|
|
pub fn ADC(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
let carry = cpu.check_flag(Flags::C) as u16;
|
|
|
|
|
|
|
|
|
|
// 16 bit addition to capture the carry easier
|
|
|
|
|
let temp: u16 = cpu.a as u16 + cpu.working_data + carry;
|
|
|
|
|
|
|
|
|
|
if temp > 255
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::C);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if temp == 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let did_overflow = (!((cpu.a as u16) ^ (cpu.working_data as u16)) & ((cpu.a as u16) ^ temp)) & 0x0080;
|
|
|
|
|
cpu.clear_flag(Flags::V);
|
|
|
|
|
if did_overflow > 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::V);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::N);
|
|
|
|
|
if temp & 0x80 > 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.a = (temp & 0x00FF) as u8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn STA(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
bus.write(cpu.working_addr, cpu.a);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn LDA(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
let data = cpu.working_data as u8;
|
|
|
|
|
cpu.a = data;
|
|
|
|
|
|
|
|
|
|
if cpu.a == 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cpu.a & 0x80 != 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn CMP(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
let data = cpu.working_data as u8;
|
|
|
|
|
if cpu.a >= data
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::C);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cpu.clear_flag(Flags::C);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cpu.a == data
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cpu.clear_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cpu.a < data
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
cpu.clear_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Using a technique written javidx9
|
|
|
|
|
// The code in this function falls under the License (OLC-3) SEE LICENSE FILE
|
|
|
|
|
// https://github.com/OneLoneCoder/olcNES/blob/master/Part%232%20-%20CPU/olc6502.cpp#L714
|
|
|
|
|
//
|
|
|
|
|
// More info about the carry bit:
|
|
|
|
|
// http://forum.6502.org/viewtopic.php?t=18
|
|
|
|
|
pub fn SBC(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
let value = cpu.working_data ^ 0x00FF;
|
|
|
|
|
let carry = cpu.check_flag(Flags::C) as u16;
|
|
|
|
|
|
|
|
|
|
let temp: u16 = cpu.a as u16 + value + carry;
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::C);
|
|
|
|
|
if temp > 255
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::C);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::Z);
|
|
|
|
|
if temp == 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let did_overflow = (!((cpu.a as u16) ^ (value)) & ((cpu.a as u16) ^ temp)) & 0x0080;
|
|
|
|
|
cpu.clear_flag(Flags::V);
|
|
|
|
|
if did_overflow > 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::V);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::N);
|
|
|
|
|
if temp & 0x80 > 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.a = (temp & 0x00FF) as u8;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
// GROUP TWO
|
|
|
|
|
pub fn ASL(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
cpu.clear_flag(Flags::C);
|
|
|
|
|
if cpu.working_data as u8 & 0x80 > 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::C);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let result = cpu.working_data << 1;
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::Z);
|
|
|
|
|
if result == 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if result as u8 & 0x80 > 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cpu.addr_mode == ModeID::ACM
|
|
|
|
|
{
|
|
|
|
|
cpu.a = result as u8;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bus.write(cpu.working_addr, result as u8);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn ROL(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
let old_bit_7 = (cpu.working_data & 0x80) > 0;
|
|
|
|
|
let carry = cpu.check_flag(Flags::C) as u16;
|
|
|
|
|
let result = (cpu.working_data << 1) ^ carry;
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::C);
|
|
|
|
|
if old_bit_7
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::C);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::N);
|
|
|
|
|
if result & 0x80 > 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::Z);
|
|
|
|
|
if result == 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cpu.addr_mode == ModeID::ACM
|
|
|
|
|
{
|
|
|
|
|
cpu.a = result as u8;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bus.write(cpu.working_addr, result as u8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn LSR(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
let old_bit_0 = (cpu.working_data & 0x01) > 0;
|
|
|
|
|
let carry = cpu.check_flag(Flags::C) as u16;
|
|
|
|
|
let result = cpu.working_data >> 1;
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::C);
|
|
|
|
|
if old_bit_0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::C);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::N);
|
|
|
|
|
if result & 0x80 > 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::Z);
|
|
|
|
|
if result == 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cpu.addr_mode == ModeID::ACM
|
|
|
|
|
{
|
|
|
|
|
cpu.a = result as u8;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bus.write(cpu.working_addr, result as u8);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn ROR(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
let old_bit_0 = (cpu.working_data & 0x01) > 0;
|
|
|
|
|
let carry = cpu.check_flag(Flags::C) as u16;
|
|
|
|
|
let temp = carry << 7;
|
|
|
|
|
let result = (cpu.working_data >> 1) ^ (carry << 7);
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::C);
|
|
|
|
|
if old_bit_0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::C);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::N);
|
|
|
|
|
if result & 0x80 > 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::Z);
|
|
|
|
|
if result == 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cpu.addr_mode == ModeID::ACM
|
|
|
|
|
{
|
|
|
|
|
cpu.a = result as u8;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bus.write(cpu.working_addr, result as u8);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn STX(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
bus.write(cpu.working_addr, cpu.x);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn LDX(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
let data = cpu.working_data as u8;
|
|
|
|
|
cpu.x = data;
|
|
|
|
|
|
|
|
|
|
if cpu.x == 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cpu.x & 0x80 != 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn DEC(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
let dec_val = bus.read(cpu.working_addr) - 1;
|
|
|
|
|
bus.write(cpu.working_addr, dec_val);
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::Z);
|
|
|
|
|
if dec_val == 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::N);
|
|
|
|
|
if dec_val & 0x80 > 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn INC(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
let dec_val = bus.read(cpu.working_addr) + 1;
|
|
|
|
|
bus.write(cpu.working_addr, dec_val);
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::Z);
|
|
|
|
|
if dec_val == 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::N);
|
|
|
|
|
if dec_val & 0x80 > 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
// GROUP THREE
|
|
|
|
|
pub fn BIT(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::Z);
|
|
|
|
|
if cpu.a & (cpu.working_data as u8) > 0
|
|
|
|
|
{
|
|
|
|
|
cpu.clear_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::V);
|
|
|
|
|
if cpu.working_data & 0x0040 > 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::V);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::N);
|
|
|
|
|
if cpu.working_data & 0x0080 > 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn JMP(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
cpu.pc = cpu.working_addr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// JMP (abs)
|
|
|
|
|
// pub fn JPA(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
// {
|
|
|
|
|
// cpu.pc = cpu.working_addr;
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
pub fn STY(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
bus.write(cpu.working_addr, cpu.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn LDY(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
let data = cpu.working_data as u8;
|
|
|
|
|
cpu.y = data;
|
|
|
|
|
|
|
|
|
|
if cpu.y == 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cpu.y & 0x80 != 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn CPY(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
cpu.clear_flag(Flags::C);
|
|
|
|
|
if cpu.y as u16 >= cpu.working_data
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::C);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::Z);
|
|
|
|
|
if cpu.y == cpu.working_data as u8
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::N);
|
|
|
|
|
if (cpu.y as u16 - cpu.working_data) & 0x80 > 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn CPX(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
cpu.clear_flag(Flags::C);
|
|
|
|
|
if cpu.x as u16 >= cpu.working_data
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::C);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::Z);
|
|
|
|
|
if cpu.x == cpu.working_data as u8
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::Z);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.clear_flag(Flags::N);
|
|
|
|
|
if (cpu.x as u16 - cpu.working_data) & 0x80 > 0
|
|
|
|
|
{
|
|
|
|
|
cpu.set_flag(Flags::N);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
// BRANCHING
|
|
|
|
|
fn BPL(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
if cpu.check_flag(Flags::N) == 0
|
|
|
|
|
{
|
|
|
|
|
cpu.pc += cpu.working_data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn BMI(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
if cpu.check_flag(Flags::N) != 0
|
|
|
|
|
{
|
|
|
|
|
cpu.pc += cpu.working_data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn BVC(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
if cpu.check_flag(Flags::V) == 0
|
|
|
|
|
{
|
|
|
|
|
cpu.pc += cpu.working_data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn BVS(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
if cpu.check_flag(Flags::V) != 0
|
|
|
|
|
{
|
|
|
|
|
cpu.pc += cpu.working_data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn BCC(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
if cpu.check_flag(Flags::C) == 0
|
|
|
|
|
{
|
|
|
|
|
cpu.pc += cpu.working_data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn BCS(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
if cpu.check_flag(Flags::C) != 0
|
|
|
|
|
{
|
|
|
|
|
cpu.pc += cpu.working_data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn BNE(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
if cpu.check_flag(Flags::Z) == 0
|
|
|
|
|
{
|
|
|
|
|
cpu.pc += cpu.working_data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn BEQ(cpu: &mut R6502, bus: &mut dyn Bus)
|
|
|
|
|
{
|
|
|
|
|
if cpu.check_flag(Flags::Z) != 0
|
|
|
|
|
{
|
|
|
|
|
cpu.pc += cpu.working_data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
// INTERRUPT AND SUBROUTINE
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
|
|
|
// SINGLE BYTE
|
|
|
|
|
|
|
|
|
|
}
|