You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

217 lines
4.7 KiB
Rust

#![allow(dead_code, non_snake_case)]
use super::{R6502, Bus, Flags};
// 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,
];
}
impl Instructions
{
///////////////////////////////////////////////////////////
// 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
pub fn SBC(cpu: &mut R6502, bus: &mut dyn Bus)
{
// Seem to need the + 1 here for javidx9's algorithm to work
let value = (cpu.working_data ^ 0x00FF) + 1;
let carry = cpu.check_flag(Flags::C) as u16;
let temp: u16 = cpu.a as u16 + value + carry;
if temp > 255
{
cpu.set_flag(Flags::C);
}
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
///////////////////////////////////////////////////////////
// GROUP THREE
}