|
|
|
@ -2,7 +2,7 @@
|
|
|
|
#![allow(dead_code, non_snake_case)]
|
|
|
|
#![allow(dead_code, non_snake_case)]
|
|
|
|
|
|
|
|
|
|
|
|
use crate::tests::test_bus::RAMBus;
|
|
|
|
use crate::tests::test_bus::RAMBus;
|
|
|
|
use crate::r6502::{R6502, Bus, Registers};
|
|
|
|
use crate::r6502::{R6502, Bus, Registers, Flags};
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
// GROUP ONE
|
|
|
|
// GROUP ONE
|
|
|
|
@ -172,4 +172,289 @@ mod SBC;
|
|
|
|
// GROUP TWO
|
|
|
|
// GROUP TWO
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: TEST ASL
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn ASL()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
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 left shift the value in the accumulator
|
|
|
|
|
|
|
|
bus.write(addr, 0x0A); // ASL - Accumulator mode
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Restart cpu
|
|
|
|
|
|
|
|
cpu.reset(&mut bus);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// manually setup the cpu registers
|
|
|
|
|
|
|
|
cpu.debug_set_reg(Registers::A, 0x98);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Clock the cpu to run the program (Clock essentially runs one full instruction)
|
|
|
|
|
|
|
|
cpu.clock(&mut bus);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Is 0x30 in the A register?
|
|
|
|
|
|
|
|
assert_eq!(0x30, cpu.debug_get_reg(Registers::A));
|
|
|
|
|
|
|
|
assert_eq!(0, cpu.check_flag(Flags::Z), "Zero flag should not be set");
|
|
|
|
|
|
|
|
assert_eq!(1, cpu.check_flag(Flags::C), "Carry flag should be set");
|
|
|
|
|
|
|
|
assert_eq!(0, cpu.check_flag(Flags::N), "Negative flag should not be set");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn ASL_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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Write the value into memory
|
|
|
|
|
|
|
|
bus.write(0x05, 0x98);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Program to left shift the value in the accumulator
|
|
|
|
|
|
|
|
bus.write(addr, 0x06); // ASL - Zero Page mode
|
|
|
|
|
|
|
|
bus.write(addr + 1, 0x05); // Zero Page pointer
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Restart cpu
|
|
|
|
|
|
|
|
cpu.reset(&mut bus);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// manually setup the cpu registers
|
|
|
|
|
|
|
|
cpu.debug_set_reg(Registers::A, 0x05);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Clock the cpu to run the program (Clock essentially runs one full instruction)
|
|
|
|
|
|
|
|
cpu.clock(&mut bus);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Is 0x30 in memory?
|
|
|
|
|
|
|
|
assert_eq!(0x30, bus.read(0x05));
|
|
|
|
|
|
|
|
assert_eq!(0, cpu.check_flag(Flags::Z), "Zero flag should not be set");
|
|
|
|
|
|
|
|
assert_eq!(1, cpu.check_flag(Flags::C), "Carry flag should be set");
|
|
|
|
|
|
|
|
assert_eq!(0, cpu.check_flag(Flags::N), "Negative flag should not be set");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn ROL()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
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 left shift the value in the accumulator
|
|
|
|
|
|
|
|
bus.write(addr, 0x2A); // ROL - Accumulator mode
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Restart cpu
|
|
|
|
|
|
|
|
cpu.reset(&mut bus);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// manually setup the cpu registers
|
|
|
|
|
|
|
|
cpu.debug_set_reg(Registers::A, 0x80);
|
|
|
|
|
|
|
|
cpu.set_flag(Flags::C);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Clock the cpu to run the program (Clock essentially runs one full instruction)
|
|
|
|
|
|
|
|
cpu.clock(&mut bus);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Is 0x01 in the A register?
|
|
|
|
|
|
|
|
assert_eq!(0x01, cpu.debug_get_reg(Registers::A));
|
|
|
|
|
|
|
|
assert_eq!(0, cpu.check_flag(Flags::Z), "Zero flag should not be set");
|
|
|
|
|
|
|
|
assert_eq!(1, cpu.check_flag(Flags::C), "Carry flag should be set");
|
|
|
|
|
|
|
|
assert_eq!(0, cpu.check_flag(Flags::N), "Negative flag should not be set");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn LSR()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
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 left shift the value in the accumulator
|
|
|
|
|
|
|
|
bus.write(addr, 0x4A); // LSR - Accumulator mode
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Restart cpu
|
|
|
|
|
|
|
|
cpu.reset(&mut bus);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// manually setup the cpu registers
|
|
|
|
|
|
|
|
cpu.debug_set_reg(Registers::A, 0x81);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Clock the cpu to run the program (Clock essentially runs one full instruction)
|
|
|
|
|
|
|
|
cpu.clock(&mut bus);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Is 0x40 in the A register?
|
|
|
|
|
|
|
|
assert_eq!(0x40, cpu.debug_get_reg(Registers::A));
|
|
|
|
|
|
|
|
assert_eq!(0, cpu.check_flag(Flags::Z), "Zero flag should not be set");
|
|
|
|
|
|
|
|
assert_eq!(1, cpu.check_flag(Flags::C), "Carry flag should be set");
|
|
|
|
|
|
|
|
assert_eq!(0, cpu.check_flag(Flags::N), "Negative flag should not be set");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn ROR()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
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 left shift the value in the accumulator
|
|
|
|
|
|
|
|
bus.write(addr, 0x6A); // ROR - Accumulator mode
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Restart cpu
|
|
|
|
|
|
|
|
cpu.reset(&mut bus);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// manually setup the cpu registers
|
|
|
|
|
|
|
|
cpu.debug_set_reg(Registers::A, 0x81);
|
|
|
|
|
|
|
|
cpu.set_flag(Flags::C);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Clock the cpu to run the program (Clock essentially runs one full instruction)
|
|
|
|
|
|
|
|
cpu.clock(&mut bus);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Is 0xC0 in the A register?
|
|
|
|
|
|
|
|
assert_eq!(0xC0, cpu.debug_get_reg(Registers::A));
|
|
|
|
|
|
|
|
assert_eq!(0, cpu.check_flag(Flags::Z), "Zero flag should not be set");
|
|
|
|
|
|
|
|
assert_eq!(1, cpu.check_flag(Flags::C), "Carry flag should be set");
|
|
|
|
|
|
|
|
assert_eq!(1, cpu.check_flag(Flags::N), "Negative flag should be set");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn STX()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// STX $0A
|
|
|
|
|
|
|
|
bus.write(addr, 0x86); // STX - Zero Page mode
|
|
|
|
|
|
|
|
bus.write(addr + 1, 0x0A); // Argument
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Restart cpu
|
|
|
|
|
|
|
|
cpu.reset(&mut bus);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// manually setup the cpu registers
|
|
|
|
|
|
|
|
cpu.debug_set_reg(Registers::X, 0x0F);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Clock the cpu to run the program (Clock essentially runs one full instruction)
|
|
|
|
|
|
|
|
cpu.clock(&mut bus);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Is 0x0F at memory address 0x0A?
|
|
|
|
|
|
|
|
assert_eq!(0x0F, bus.read(0x0A));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn LDX()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
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, 0xA2); // LDX - 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 X register?
|
|
|
|
|
|
|
|
assert_eq!(0x08, cpu.debug_get_reg(Registers::X));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn DEC()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// put value to decrement into memory
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bus.write(0x08, 0x10);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Program to load 0x08 into the accumulator
|
|
|
|
|
|
|
|
bus.write(addr, 0xC6); // DEC - Zero Page
|
|
|
|
|
|
|
|
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 0x0F in memory at 0x08?
|
|
|
|
|
|
|
|
assert_eq!(0x0F, bus.read(0x08));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
|
|
|
fn INC()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Put value to decrement into memory
|
|
|
|
|
|
|
|
bus.write(0x08, 0x10);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Program to load 0x08 into the accumulator
|
|
|
|
|
|
|
|
bus.write(addr, 0xE6); // INC - Zero Page
|
|
|
|
|
|
|
|
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 0x11 in memory at 0x08?
|
|
|
|
|
|
|
|
assert_eq!(0x11, bus.read(0x08));
|
|
|
|
|
|
|
|
}
|