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; mod r6502;
use r6502::{R6502, Flags, Bus}; use r6502::{R6502, Flags, Bus};
@ -42,9 +42,11 @@ fn main()
cpu.clear_flag(Flags::I); cpu.clear_flag(Flags::I);
println!("\nI Flag is: {}", cpu.check_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); run_addition_test(&mut cpu);
println!("\nFinished."); println!("\nFinished.");
} }
@ -52,7 +54,7 @@ fn run_addition_test(cpu: &mut R6502)
{ {
println!("\nRunning a simple addition test with no overflow or carry: 8 + 23"); println!("\nRunning a simple addition test with no overflow or carry: 8 + 23");
////////////////////////////////// //////////////////////////////////
// Setup Bus with program address // Setup Bus with program address
////////////////////////////////// //////////////////////////////////
@ -77,6 +79,11 @@ fn run_addition_test(cpu: &mut R6502)
bus.write(addr + 2, 0x69); // ADC - Immediate mode bus.write(addr + 2, 0x69); // ADC - Immediate mode
bus.write(addr + 3, 0x17); // Argument 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! // Run the program!
//////////////////// ////////////////////
@ -84,11 +91,14 @@ fn run_addition_test(cpu: &mut R6502)
// Restart cpu // Restart cpu
cpu.reset(&mut bus); 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);
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);
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}; use super::{R6502, Bus};
@ -46,48 +46,82 @@ impl AddressingModes
// This is also the accumulator mode // This is also the accumulator mode
pub fn IMP(cpu: &mut R6502, bus: &mut dyn Bus) 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) 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; cpu.pc += 1;
} }
pub fn ZP0(cpu: &mut R6502, bus: &mut dyn Bus) 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) 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) 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) 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) 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) 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) 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) pub fn IND(cpu: &mut R6502, bus: &mut dyn Bus)

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

@ -1,5 +1,5 @@
#![allow(dead_code)] #![allow(unused_variables, dead_code, non_snake_case)]
mod addressing_modes; mod addressing_modes;
mod instructions; mod instructions;
@ -32,9 +32,20 @@ pub enum Flags
N = (1 << 7), // Negative Flag N = (1 << 7), // Negative Flag
} }
pub enum Registers
{
A,
X,
Y,
PC,
SP,
STATUS,
}
#[derive(Clone, Copy, PartialEq)]
pub struct R6502 pub struct R6502
{ {
pub a: u8, // Accumulator a: u8, // Accumulator
x: u8, // X Register x: u8, // X Register
y: u8, // Y Register y: u8, // Y Register
@ -45,9 +56,8 @@ pub struct R6502
cycles: u32, // Track cycles cycles: u32, // Track cycles
// Helper Vars // Helper Vars
working_data: u8, // value fetched for the ALU working_data: u16, // value fetched for the ALU
addr_abs: u16, // working_addr: u16,
addr_rel: u16,
} }
impl R6502 impl R6502
@ -55,7 +65,38 @@ impl R6502
// constructor // constructor
pub fn new() -> R6502 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 // signals
@ -90,8 +131,7 @@ impl R6502
// internal helper variables // internal helper variables
self.working_data = 0; self.working_data = 0;
self.addr_abs = 0; // self.working_addr = 0;
self.addr_rel = 0;
self.cycles = 8; 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: General:
✔ Add unit tests for each instruction and address mode @done(23-11-07 19:57)
☐ Fully implement clock cycle tracking ☐ Fully implement clock cycle tracking
☐ Add a disassembler for debugging ☐ Add a disassembler for debugging
☐ Debug data lookup for instructions ☐ 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: Addressing modes:
☐ IMP - Implied ✔ IMP - Implied @done(23-11-07 14:01)
✔ IMM - Immediate @done(23-11-06 19:01) ✔ IMM - Immediate @done(23-11-06 19:01)
☐ ZP0 - Zero Page ✔ ZP0 - Zero Page @done(23-11-07 14:40)
☐ ZPX - Zero Page, X ✔ ZPX - Zero Page, X @done(23-11-07 14:40)
☐ ZPY - Zero Page, Y ✔ ZPY - Zero Page, Y @done(23-11-07 14:40)
☐ REL - Relative ☐ REL - Relative
☐ ABS - Absolute ✔ Code @done(23-11-07 20:44)
☐ ABX - Absolute, X ☐ Test
☐ ABY - Absolute, Y ✔ 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 ☐ IND - Indirect
☐ IZX - Indirect, X ☐ IZX - Indirect, X
☐ IZY - Indirect, Y ☐ IZY - Indirect, Y
@ -21,10 +31,10 @@ Addressing modes:
Instructions: Instructions:
GROUP ONE: GROUP ONE:
✔ 000 ORA @done(23-11-06 18:55) ✔ 000 ORA @done(23-11-06 18:55)
☐ 001 AND ✔ 001 AND @done(23-11-07 13:43)
☐ 010 EOR ✔ 010 EOR @done(23-11-07 13:43)
☐ 011 ADC ✔ 011 ADC @done(23-11-06 19:59)
☐ 100 STA ✔ 100 STA @done(23-11-07 15:04)
✔ 101 LDA @done(23-11-06 18:55) ✔ 101 LDA @done(23-11-06 18:55)
☐ 110 CMP ☐ 110 CMP
☐ 111 SBC ☐ 111 SBC

Loading…
Cancel
Save