Skip to content

Commit

Permalink
Add Klaus tests for 65C02
Browse files Browse the repository at this point in the history
  • Loading branch information
breqdev committed Nov 23, 2023
1 parent f102c47 commit ad5810e
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 11 deletions.
File renamed without changes.
Binary file added bin/klaus_65C02.bin
Binary file not shown.
76 changes: 73 additions & 3 deletions src/cpu/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -758,8 +758,13 @@ impl Mos6502 {
0x89 | 0x34 | 0x3C => {
// BIT (3 extra addressing modes)
let (value, cycles) = self.fetch_operand_value(opcode);
self.registers.sr.write(flags::NEGATIVE, value & 0x80 != 0);
self.registers.sr.write(flags::OVERFLOW, value & 0x40 != 0);

if opcode != 0x89 {
// N, V flags not set for immediate
self.registers.sr.write(flags::NEGATIVE, value & 0x80 != 0);
self.registers.sr.write(flags::OVERFLOW, value & 0x40 != 0);
}

self
.registers
.sr
Expand Down Expand Up @@ -828,6 +833,11 @@ impl Mos6502 {
// Note: 0x9C breaks the typical addressing mode pattern
let (address, cycles) = match opcode {
0x9C => (self.fetch_word(), 4),
0x9E => {
let base = self.fetch_word();
let indexed = base + self.registers.x as u16;
(indexed, 4)
}
_ => self.fetch_operand_address(opcode),
};

Expand Down Expand Up @@ -871,8 +881,68 @@ impl Mos6502 {
Ok(cycles)
}

0x0F | 0x1F | 0x2F | 0x3F | 0x4F | 0x5F | 0x6F | 0x7F | 0x8F | 0x9F | 0xAF | 0xBF | 0xCF
| 0xDF | 0xEF | 0xFF => {
// BBS and BBR
let address = self.fetch() as u16;
let value = self.read(address);
let offset = self.fetch() as i8;

let bit = (opcode >> 4) & 0b111;
let bit_value = ((1 << bit) & value) != 0;
let target_value = opcode & 0x80 != 0;

if target_value == bit_value {
self.registers.pc.offset(offset);
Ok(3)
} else {
Ok(2)
}
}

0x07 | 0x17 | 0x27 | 0x37 | 0x47 | 0x57 | 0x67 | 0x77 | 0x87 | 0x97 | 0xA7 | 0xB7 | 0xC7
| 0xD7 | 0xE7 | 0xF7 => {
// RMB and SMB
let address = self.fetch() as u16;
let value = self.read(address);

let bit = (opcode >> 4) & 0b111;

let value = if opcode & 0x80 == 0 {
value & !(1 << bit)
} else {
value | (1 << bit)
};
self.write(address, value);

Ok(2)
}

0x02 | 0x22 | 0x42 | 0x62 | 0x82 | 0xA2 | 0xC2 | 0xE2 => {
// NOP (2-byte)
self.fetch();
Ok(2)
}
0x44 => {
self.fetch();
Ok(3)
}
0x54 | 0xD4 | 0xF4 => {
self.fetch();
Ok(4)
}
0x5C => {
self.fetch_word();
Ok(8)
}
0xDC | 0xFC => {
self.fetch_word();
Ok(4)
}

_ => {
todo!();
// NOP
Ok(1)
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/cpu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ impl InterruptHandler for Mos6502 {
self.push(self.registers.sr.get() & !flags::BREAK);
}

if let Mos6502Variant::CMOS = self.variant {
self.registers.sr.clear(flags::DECIMAL);
}

self.registers.sr.set(flags::INTERRUPT);

let dest = match maskable {
Expand Down
11 changes: 10 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ struct Args {

#[cfg(not(target_arch = "wasm32"))]
fn main() {
use libnoentiendo::{cpu::Mos6502Variant, systems::klaus::KlausSystemConfig};

let args = Args::parse();

let mut platform: Box<dyn SyncPlatform> = match args.platform {
Expand All @@ -75,7 +77,14 @@ fn main() {
let system = match args.system {
SystemArg::Basic => BasicSystemBuilder::build(romfile.unwrap(), (), platform.provider()),
SystemArg::Easy => Easy6502SystemBuilder::build(romfile.unwrap(), (), platform.provider()),
SystemArg::Klaus => KlausSystemBuilder::build(romfile.unwrap(), None, platform.provider()),
SystemArg::Klaus => KlausSystemBuilder::build(
romfile.unwrap(),
KlausSystemConfig {
pc_report: None,
variant: Mos6502Variant::NMOS,
},
platform.provider(),
),
SystemArg::Pet => PetSystemBuilder::build(
PetSystemRoms::from_disk(),
PetSystemConfig { mapping },
Expand Down
52 changes: 45 additions & 7 deletions src/systems/klaus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,29 @@ use std::sync::Arc;

use super::SystemBuilder;

pub struct KlausSystemConfig {
pub pc_report: Option<Rc<Cell<u16>>>,
pub variant: Mos6502Variant,
}

/// A factory for creating a system that runs Klaus Dormann's 6502 CPU test suite.
pub struct KlausSystemBuilder;

impl SystemBuilder<KlausSystem, RomFile, Option<Rc<Cell<u16>>>> for KlausSystemBuilder {
impl SystemBuilder<KlausSystem, RomFile, KlausSystemConfig> for KlausSystemBuilder {
fn build(
rom: RomFile,
config: Option<Rc<Cell<u16>>>,
config: KlausSystemConfig,
_platform: Arc<dyn PlatformProvider>,
) -> Box<dyn System> {
let rom = BlockMemory::from_file(0x10000, rom).set_writeable(true);
let mut cpu = Mos6502::new(rom, Mos6502Variant::NMOS);
let mut cpu = Mos6502::new(rom, config.variant);

cpu.registers.pc.load(0x0400);

Box::new(KlausSystem { cpu, pc: config })
Box::new(KlausSystem {
cpu,
pc: config.pc_report,
})
}
}

Expand Down Expand Up @@ -61,16 +69,46 @@ mod tests {
use super::*;

#[test]
fn test_klaus() {
let roms = RomFile::from_file("bin/klaus.bin");
fn test_klaus_6502() {
let roms = RomFile::from_file("bin/klaus_6502.bin");
let platform = TextPlatform::new();
let pc = Rc::new(Cell::new(0));
let mut system = KlausSystemBuilder::build(roms, Some(pc.clone()), platform.provider());

let mut system = KlausSystemBuilder::build(
roms,
KlausSystemConfig {
pc_report: Some(pc.clone()),
variant: Mos6502Variant::NMOS,
},
platform.provider(),
);

for _ in 0..=100000000 {
system.tick();
}

assert_eq!(pc.get(), 0x3469);
}

#[test]
fn test_klaus_65c02() {
let roms = RomFile::from_file("bin/klaus_65C02.bin");
let platform = TextPlatform::new();
let pc = Rc::new(Cell::new(0));

let mut system = KlausSystemBuilder::build(
roms,
KlausSystemConfig {
pc_report: Some(pc.clone()),
variant: Mos6502Variant::CMOS,
},
platform.provider(),
);

for _ in 0..=100000000 {
system.tick();
}

assert_eq!(pc.get(), 0x24f1);
}
}

0 comments on commit ad5810e

Please sign in to comment.