adds a few more address modes and unit tests for instructions

master
Joey Pollack 2 years ago
parent 99ff781d3d
commit 4987266110

@ -1,6 +1,6 @@
mod tests;
mod r6502;
use r6502::{R6502, Flags, Bus};
@ -42,9 +42,11 @@ fn main()
cpu.clear_flag(Flags::I);
println!("\nI Flag is: {}", cpu.check_flag(Flags::I));
// run_simple_or_program(&mut cpu);
run_simple_or_program(&mut cpu);
run_addition_test(&mut cpu);
println!("\nFinished.");
}
@ -77,6 +79,11 @@ fn run_addition_test(cpu: &mut R6502)
bus.write(addr + 2, 0x69); // ADC - Immediate mode
bus.write(addr + 3, 0x17); // Argument
// Store result into memory to also test the STA instruction
bus.write(addr + 4, 0x85); // STA - Zero Page mode
bus.write(addr + 5, 0x02); // Argument
////////////////////
// Run the program!
////////////////////
@ -84,11 +91,14 @@ fn run_addition_test(cpu: &mut R6502)
// Restart cpu
cpu.reset(&mut bus);
// Clock the cpu twice (Clock essentially runs one full instruction)
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
cpu.clock(&mut bus);
cpu.clock(&mut bus);
println!("\nProgram result, A register: {}", cpu.a);
println!("\nProgram result, A register: {}", cpu.debug_get_reg(r6502::Registers::A));
let result = bus.read(0x0002);
println!("\nValue at 0x0002: {}", result);
}
@ -132,5 +142,5 @@ fn run_simple_or_program(cpu: &mut R6502)
cpu.clock(&mut bus);
cpu.clock(&mut bus);
println!("\nProgram result, A register: {}", cpu.a);
println!("\nProgram result, A register: {}", cpu.debug_get_reg(r6502::Registers::A));
}

@ -1,5 +1,5 @@
#![allow(dead_code, non_snake_case)]
#![allow(unused_variables, dead_code, non_snake_case)]
use super::{R6502, Bus};
@ -46,48 +46,82 @@ impl AddressingModes
// This is also the accumulator mode
pub fn IMP(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.working_data = cpu.a as u16;
}
pub fn IMM(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.working_data = bus.read(cpu.pc);
cpu.working_data = bus.read(cpu.pc) as u16;
cpu.pc += 1;
}
pub fn ZP0(cpu: &mut R6502, bus: &mut dyn Bus)
{
let working_addr = bus.read(cpu.pc) as u16 & 0x00FF;
cpu.pc += 1;
cpu.working_data = bus.read(working_addr) as u16;
}
pub fn ZPX(cpu: &mut R6502, bus: &mut dyn Bus)
{
let mut working_addr = bus.read(cpu.pc) as u16 & 0x00FF;
working_addr += cpu.x as u16;
cpu.pc += 1;
cpu.working_data = bus.read(working_addr) as u16;
}
pub fn ZPY(cpu: &mut R6502, bus: &mut dyn Bus)
{
let mut working_addr = bus.read(cpu.pc) as u16 & 0x00FF;
working_addr += cpu.y as u16;
cpu.pc += 1;
cpu.working_data = bus.read(working_addr) as u16;
}
pub fn REL(cpu: &mut R6502, bus: &mut dyn Bus)
{
// NOTE: Not sure if we can use the working_data variable for this.
// if any instruction using this address mode needs extra data read
// then we need another variable to store this address
cpu.working_data = bus.read(cpu.pc) as u16;
cpu.pc += 1;
}
pub fn ABS(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.working_data = bus.read(cpu.pc) as u16;
cpu.pc += 1;
cpu.working_data |= (bus.read(cpu.pc) as u16) << 8;
cpu.pc += 1;
cpu.working_data = bus.read(cpu.working_data) as u16 & 0x00FF;
}
pub fn ABX(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.working_data = bus.read(cpu.pc) as u16;
cpu.pc += 1;
cpu.working_data |= (bus.read(cpu.pc) as u16) << 8;
cpu.pc += 1;
cpu.working_data += cpu.x as u16;
cpu.working_data = bus.read(cpu.working_data) as u16 & 0x00FF;
}
pub fn ABY(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.working_data = bus.read(cpu.pc) as u16;
cpu.pc += 1;
cpu.working_data |= (bus.read(cpu.pc) as u16) << 8;
cpu.pc += 1;
cpu.working_data += cpu.y as u16;
cpu.working_data = bus.read(cpu.working_data) as u16 & 0x00FF;
}
pub fn IND(cpu: &mut R6502, bus: &mut dyn Bus)

@ -39,7 +39,8 @@ impl Instructions
// GROUP ONE
pub fn ORA(cpu: &mut R6502, _bus: &mut dyn Bus)
{
cpu.a = cpu.a | cpu.working_data;
let data = cpu.working_data as u8;
cpu.a = cpu.a | data;
if cpu.a == 0
{
cpu.set_flag(Flags::Z);
@ -53,7 +54,8 @@ impl Instructions
pub fn AND(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.a = cpu.a & cpu.working_data;
let data = cpu.working_data as u8;
cpu.a = cpu.a & data;
if cpu.a == 0
{
cpu.set_flag(Flags::Z);
@ -67,7 +69,8 @@ impl Instructions
pub fn EOR(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.a = cpu.a ^ cpu.working_data;
let data = cpu.working_data as u8;
cpu.a = cpu.a ^ data;
if cpu.a == 0
{
cpu.set_flag(Flags::Z);
@ -85,7 +88,7 @@ impl Instructions
pub fn ADC(cpu: &mut R6502, bus: &mut dyn Bus)
{
// 16 bit addition to capture the carry easier
let temp: u16 = cpu.a as u16 + cpu.working_data as u16;
let temp: u16 = cpu.a as u16 + cpu.working_data;
if temp > 255
{
@ -115,12 +118,13 @@ impl Instructions
pub fn STA(cpu: &mut R6502, bus: &mut dyn Bus)
{
bus.write(cpu.working_data, cpu.a);
}
pub fn LDA(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.a = cpu.working_data;
let data = cpu.working_data as u8;
cpu.a = data;
if cpu.a == 0
{

@ -1,5 +1,5 @@
#![allow(dead_code)]
#![allow(unused_variables, dead_code, non_snake_case)]
mod addressing_modes;
mod instructions;
@ -32,9 +32,20 @@ pub enum Flags
N = (1 << 7), // Negative Flag
}
pub enum Registers
{
A,
X,
Y,
PC,
SP,
STATUS,
}
#[derive(Clone, Copy, PartialEq)]
pub struct R6502
{
pub a: u8, // Accumulator
a: u8, // Accumulator
x: u8, // X Register
y: u8, // Y Register
@ -45,9 +56,8 @@ pub struct R6502
cycles: u32, // Track cycles
// Helper Vars
working_data: u8, // value fetched for the ALU
addr_abs: u16,
addr_rel: u16,
working_data: u16, // value fetched for the ALU
// working_addr: u16,
}
impl R6502
@ -55,7 +65,38 @@ impl R6502
// constructor
pub fn new() -> R6502
{
R6502 { a: 0, x: 0, y: 0, pc: 0, sp: 0, status: 0, cycles: 0, working_data: 0, addr_abs: 0, addr_rel: 0 }
R6502 { a: 0, x: 0, y: 0, pc: 0, sp: 0, status: 0, cycles: 0, working_data: 0 }
}
// Debug Access
pub fn debug_get_reg(&self, reg: Registers) -> u16
{
match reg
{
Registers::A => self.a as u16,
Registers::X => self.x as u16,
Registers::Y => self.y as u16,
Registers::PC => self.pc,
Registers::SP => self.sp as u16,
Registers::STATUS => self.status as u16,
}
}
pub fn debug_set_reg(&mut self, reg: Registers, value: u16)
{
match reg
{
Registers::A => self.a = value as u8,
Registers::X => self.x = value as u8,
Registers::Y => self.y = value as u8,
Registers::PC => self.pc = value,
Registers::SP => self.sp = value as u8,
Registers::STATUS => self.status = value as u8,
}
}
// signals
@ -90,8 +131,7 @@ impl R6502
// internal helper variables
self.working_data = 0;
self.addr_abs = 0;
self.addr_rel = 0;
// self.working_addr = 0;
self.cycles = 8;
}

@ -0,0 +1,631 @@
#![allow(dead_code, non_snake_case)]
mod test_bus;
#[cfg(test)]
mod instructions
{
use super::test_bus::RAMBus;
use crate::r6502::{R6502, Bus, Registers};
//////////////////////////////////////////////////////////////////
/// ORA ORA ORA ORA
//////////////////////////////////////////////////////////////////
#[test]
fn ORA_IMM()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// ORA #2
bus.write(addr, 0x09); // ORA - Immediate mode
bus.write(addr + 1, 0x02); // Argument
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::A, 0x09);
// Clock the cpu twice (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x0B in the A register?
assert_eq!(0x0B, cpu.debug_get_reg(Registers::A));
}
#[test]
fn ORA_ZP0()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x02 into memory in the zero page
bus.write(0x000A, 0x02);
// ORA #2
bus.write(addr, 0x05); // ORA - Zero Page mode
bus.write(addr +1, 0x0A); // Argument (memory address of the value we want to OR with)
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::A, 0x09);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x0B in the A register?
assert_eq!(0x0B, cpu.debug_get_reg(Registers::A));
}
#[test]
fn ORA_ZPX()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x02 into memory in the zero page
bus.write(0x000A, 0x02);
// ORA #2
bus.write(addr, 0x15); // ORA - Zero Page, X mode
bus.write(addr + 1, 0x04); // Argument (memory address of the value we want to OR with)
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::X, 0x06);
cpu.debug_set_reg(Registers::A, 0x09);
// Clock the cpu twice (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x0B in the A register?
assert_eq!(0x0B, cpu.debug_get_reg(Registers::A));
}
#[test]
fn ORA_ABS()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x02 into memory in the zero page
bus.write(0x010A, 0x02);
// ORA #2
bus.write(addr, 0x0D); // ORA - Absolute mode
bus.write(addr + 1, 0x0A); // Argument (memory address of the value we want to OR with)
bus.write(addr + 2, 0x01); // Argument (memory address of the value we want to OR with)
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
// cpu.debug_set_reg(Registers::X, 0x06);
cpu.debug_set_reg(Registers::A, 0x09);
// Clock the cpu twice (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x0B in the A register?
assert_eq!(0x0B, cpu.debug_get_reg(Registers::A));
}
#[test]
fn ORA_ABX()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x02 into memory in the zero page
bus.write(0x010B, 0x02);
// ORA #2
bus.write(addr, 0x1D); // ORA - Absolute, X mode
bus.write(addr + 1, 0x0A); // Argument (memory address of the value we want to OR with)
bus.write(addr + 2, 0x01); // Argument (memory address of the value we want to OR with)
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::X, 0x01);
cpu.debug_set_reg(Registers::A, 0x09);
// Clock the cpu twice (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x0B in the A register?
assert_eq!(0x0B, cpu.debug_get_reg(Registers::A));
}
#[test]
fn ORA_ABY()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x02 into memory in the zero page
bus.write(0x010B, 0x02);
// ORA #2
bus.write(addr, 0x19); // ORA - Absolute, X mode
bus.write(addr + 1, 0x0A); // Argument (memory address of the value we want to OR with)
bus.write(addr + 2, 0x01); // Argument (memory address of the value we want to OR with)
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::Y, 0x01);
cpu.debug_set_reg(Registers::A, 0x09);
// Clock the cpu twice (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x0B in the A register?
assert_eq!(0x0B, cpu.debug_get_reg(Registers::A));
}
//////////////////////////////////////////////////////////////////
/// AND AND AND AND
//////////////////////////////////////////////////////////////////
#[test]
fn AND_IMM()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// AND #3
bus.write(addr, 0x29); // AND - Immediate mode
bus.write(addr + 1, 0x03); // Argument
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::A, 0x0A);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x02 in the A register?
assert_eq!(0x02, cpu.debug_get_reg(Registers::A));
}
#[test]
fn AND_ZP0()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x0A into memory in the zero page
bus.write(0x000B, 0x03);
// AND #3
bus.write(addr, 0x25); // AND - Zero Page mode
bus.write(addr + 1, 0x0B); // Argument
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::A, 0x0A);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x02 in the A register?
assert_eq!(0x02, cpu.debug_get_reg(Registers::A));
}
#[test]
fn AND_ZPX()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x0A into memory in the zero page
bus.write(0x000B, 0x03);
// AND #3
bus.write(addr, 0x35); // AND - Zero Page, X mode
bus.write(addr + 1, 0x0A); // Argument
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::A, 0x0A);
cpu.debug_set_reg(Registers::X, 0x01);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x02 in the A register?
assert_eq!(0x02, cpu.debug_get_reg(Registers::A));
}
#[test]
fn AND_ABS()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x0A into memory in the zero page
bus.write(0x010B, 0x03);
// AND #3
bus.write(addr, 0x2D); // AND - Absolute mode
bus.write(addr + 1, 0x0B); // Argument
bus.write(addr + 2, 0x01); // Argument
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::A, 0x0A);
//cpu.debug_set_reg(Registers::X, 0x01);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x02 in the A register?
assert_eq!(0x02, cpu.debug_get_reg(Registers::A));
}
#[test]
fn AND_ABX()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x0A into memory in the zero page
bus.write(0x010C, 0x03);
// AND #3
bus.write(addr, 0x3D); // AND - Absolute, X mode
bus.write(addr + 1, 0x0B); // Argument
bus.write(addr + 2, 0x01); // Argument
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::A, 0x0A);
cpu.debug_set_reg(Registers::X, 0x01);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x02 in the A register?
assert_eq!(0x02, cpu.debug_get_reg(Registers::A));
}
#[test]
fn AND_ABY()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x0A into memory in the zero page
bus.write(0x010C, 0x03);
// AND #3
bus.write(addr, 0x39); // AND - Absolute, X mode
bus.write(addr + 1, 0x0B); // Argument
bus.write(addr + 2, 0x01); // Argument
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::A, 0x0A);
cpu.debug_set_reg(Registers::Y, 0x01);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x02 in the A register?
assert_eq!(0x02, cpu.debug_get_reg(Registers::A));
}
//////////////////////////////////////////////////////////////////
/// LDA LDA LDA LDA
//////////////////////////////////////////////////////////////////
#[test]
fn LDA_IMM()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Program to load 0x08 into the accumulator
bus.write(addr, 0xA9); // LDA - Immediate mode
bus.write(addr + 1, 0x08); // Argument
// Restart cpu
cpu.reset(&mut bus);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x08 in the A register?
assert_eq!(0x08, cpu.debug_get_reg(Registers::A));
}
#[test]
fn LDA_ZP0()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x08 into memory in the zero page
bus.write(0x000A, 0x08);
// Program to load 0x08 into the accumulator
bus.write(addr, 0xA5); // LDA - Zero Page mode
bus.write(addr + 1, 0x0A); // Argument
// Restart cpu
cpu.reset(&mut bus);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x08 in the A register?
assert_eq!(0x08, cpu.debug_get_reg(Registers::A));
}
#[test]
fn LDA_ZPX()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x08 into memory in the zero page
bus.write(0x000A, 0x08);
// Program to load 0x08 into the accumulator
bus.write(addr, 0xB5); // LDA - Zero Page, X mode
bus.write(addr + 1, 0x04); // Argument
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::X, 0x06);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x08 in the A register?
assert_eq!(0x08, cpu.debug_get_reg(Registers::A));
}
#[test]
fn LDA_ABS()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x08 into memory in the zero page
bus.write(0x010A, 0x08);
// Program to load 0x08 into the accumulator
bus.write(addr, 0xAD); // LDA - Absolute mode
bus.write(addr + 1, 0x0A); // Argument lo word
bus.write(addr + 2, 0x01); // Argument hi word
// Restart cpu
cpu.reset(&mut bus);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x08 in the A register?
assert_eq!(0x08, cpu.debug_get_reg(Registers::A));
}
#[test]
fn LDA_ABX()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x08 into memory in the zero page
bus.write(0x010B, 0x08);
// Program to load 0x08 into the accumulator
bus.write(addr, 0xBD); // LDA - Absolute, X mode
bus.write(addr + 1, 0x0A); // Argument lo word
bus.write(addr + 2, 0x01); // Argument hi word
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::X, 0x01);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x08 in the A register?
assert_eq!(0x08, cpu.debug_get_reg(Registers::A));
}
#[test]
fn LDA_ABY()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x08 into memory in the zero page
bus.write(0x010B, 0x08);
// Program to load 0x08 into the accumulator
bus.write(addr, 0xB9); // LDA - Absolute, X mode
bus.write(addr + 1, 0x0A); // Argument lo word
bus.write(addr + 2, 0x01); // Argument hi word
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::Y, 0x01);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x08 in the A register?
assert_eq!(0x08, cpu.debug_get_reg(Registers::A));
}
}

@ -0,0 +1,28 @@
use crate::r6502::Bus;
// All-RAM bus for testing
pub struct RAMBus
{
ram: [u8; 64 * 1024]
}
impl RAMBus
{
pub fn new() -> RAMBus
{
RAMBus { ram: [0; 64 * 1024] }
}
}
impl Bus for RAMBus
{
fn read(&self, addr: u16) -> u8
{
self.ram[addr as usize]
}
fn write(&mut self, addr: u16, value: u8)
{
self.ram[addr as usize] = value;
}
}

@ -1,19 +1,29 @@
General:
✔ Add unit tests for each instruction and address mode @done(23-11-07 19:57)
☐ Fully implement clock cycle tracking
☐ Add a disassembler for debugging
☐ Debug data lookup for instructions
CPU:
Signals:
✔ Clock @done(23-11-07 20:45)
✔ Reset @done(23-11-07 20:46)
☐ irq function
☐ nmi function
Addressing modes:
☐ IMP - Implied
✔ IMP - Implied @done(23-11-07 14:01)
✔ IMM - Immediate @done(23-11-06 19:01)
☐ ZP0 - Zero Page
☐ ZPX - Zero Page, X
☐ ZPY - Zero Page, Y
✔ ZP0 - Zero Page @done(23-11-07 14:40)
✔ ZPX - Zero Page, X @done(23-11-07 14:40)
✔ ZPY - Zero Page, Y @done(23-11-07 14:40)
☐ REL - Relative
☐ ABS - Absolute
☐ ABX - Absolute, X
☐ ABY - Absolute, Y
✔ Code @done(23-11-07 20:44)
☐ Test
✔ ABS - Absolute @done(23-11-07 20:25)
✔ ABX - Absolute, X @done(23-11-07 20:25)
✔ ABY - Absolute, Y @done(23-11-07 20:25)
☐ IND - Indirect
☐ IZX - Indirect, X
☐ IZY - Indirect, Y
@ -21,10 +31,10 @@ Addressing modes:
Instructions:
GROUP ONE:
✔ 000 ORA @done(23-11-06 18:55)
☐ 001 AND
☐ 010 EOR
☐ 011 ADC
☐ 100 STA
✔ 001 AND @done(23-11-07 13:43)
✔ 010 EOR @done(23-11-07 13:43)
✔ 011 ADC @done(23-11-06 19:59)
✔ 100 STA @done(23-11-07 15:04)
✔ 101 LDA @done(23-11-06 18:55)
☐ 110 CMP
☐ 111 SBC

Loading…
Cancel
Save