mirror of
https://github.com/FranLMSP/snes.git
synced 2026-08-03 08:30:01 -04:00
WIP script to run tests
This commit is contained in:
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = ["snes-core", "snes-frontend"]
|
members = ["snes-core", "snes-cpu-test-runner", "snes-frontend"]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ impl Bus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn map_address(address: u32) -> MemoryMap {
|
fn map_address(address: u32) -> MemoryMap {
|
||||||
|
return MemoryMap::Cartridge;
|
||||||
let (bank, sub_address) = {
|
let (bank, sub_address) = {
|
||||||
let bank = (address >> 16) as u8;
|
let bank = (address >> 16) as u8;
|
||||||
let sub_address = address as u16;
|
let sub_address = address as u16;
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ fn common_conditions(cpu_registers: &Registers, addressing_mode: AddressingMode,
|
|||||||
|
|
||||||
fn common_bytes_cycles_arithmetic(addressing_mode: AddressingMode) -> (u16, usize) {
|
fn common_bytes_cycles_arithmetic(addressing_mode: AddressingMode) -> (u16, usize) {
|
||||||
match addressing_mode {
|
match addressing_mode {
|
||||||
|
A::Accumulator => (1, 2),
|
||||||
A::Immediate => (2, 2),
|
A::Immediate => (2, 2),
|
||||||
A::Absolute => (3, 4),
|
A::Absolute => (3, 4),
|
||||||
A::AbsoluteLong => (4, 5),
|
A::AbsoluteLong => (4, 5),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
pub mod lo_rom;
|
pub mod lo_rom;
|
||||||
|
pub mod special_ram_cart;
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
use super::ROM;
|
||||||
|
|
||||||
|
pub struct SpecialRAMCart {
|
||||||
|
data: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpecialRAMCart {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
data: vec![0x00; 0x1000000],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ROM for SpecialRAMCart {
|
||||||
|
fn load(&mut self, _filename: &str) -> std::io::Result<bool> {
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&self, address: u32) -> u8 {
|
||||||
|
match self.data.get(address as usize) {
|
||||||
|
Some(byte) => *byte,
|
||||||
|
None => 0x00,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, address: u32, value: u8) {
|
||||||
|
self.data[address as usize] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SpecialRAMCart {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "snes-cpu-test-runner"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
snes-core = { path = "../snes-core" }
|
||||||
|
|
||||||
|
serde = { version = "1.0.195", features = ["derive"] }
|
||||||
|
serde_json = "1.0.111"
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
use snes_core::cpu::bus::Bus;
|
||||||
|
use snes_core::cpu::registers::Registers;
|
||||||
|
/// https://github.com/TomHarte/ProcessorTests/tree/main/65816
|
||||||
|
|
||||||
|
use snes_core::emulator::Emulator;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::Result;
|
||||||
|
use snes_core::rom::special_ram_cart::SpecialRAMCart;
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct TestState {
|
||||||
|
pc: usize,
|
||||||
|
s: usize,
|
||||||
|
p: usize,
|
||||||
|
a: usize,
|
||||||
|
x: usize,
|
||||||
|
y: usize,
|
||||||
|
dbr: usize,
|
||||||
|
d: usize,
|
||||||
|
pbr: usize,
|
||||||
|
e: usize,
|
||||||
|
ram: Vec<(usize, usize)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct TestSuite {
|
||||||
|
name: String,
|
||||||
|
initial: TestState,
|
||||||
|
r#final: TestState,
|
||||||
|
cycles: Vec<(usize, Option<usize>, String)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct TestSuiteList(Vec<TestSuite>);
|
||||||
|
|
||||||
|
fn print_failed(expected_state: &TestState, bus: &Bus, cpu_registers: &Registers) {
|
||||||
|
eprintln!("FAILED!");
|
||||||
|
eprintln!("----------");
|
||||||
|
eprintln!("Expected:");
|
||||||
|
eprintln!("{:?}", expected_state);
|
||||||
|
eprintln!("Result:");
|
||||||
|
let mut result_ram = vec![];
|
||||||
|
for (address, _) in &expected_state.ram {
|
||||||
|
result_ram.push((*address, bus.read_external(*address as u32) as usize))
|
||||||
|
}
|
||||||
|
let result_state = TestState {
|
||||||
|
pc: cpu_registers.pc as usize,
|
||||||
|
s: cpu_registers.sp as usize,
|
||||||
|
p: cpu_registers.p as usize,
|
||||||
|
a: cpu_registers.a as usize,
|
||||||
|
x: cpu_registers.x as usize,
|
||||||
|
y: cpu_registers.y as usize,
|
||||||
|
dbr: cpu_registers.dbr as usize,
|
||||||
|
d: cpu_registers.d as usize,
|
||||||
|
pbr: cpu_registers.pbr as usize,
|
||||||
|
e: if cpu_registers.emulation_mode {1} else {0},
|
||||||
|
ram: result_ram,
|
||||||
|
};
|
||||||
|
eprintln!("{:?}", result_state);
|
||||||
|
eprintln!("----------");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let args: Vec<String> = std::env::args().collect();
|
||||||
|
if args.len() < 2 {
|
||||||
|
eprintln!("A test file must be provided");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
let filename = args.get(1).unwrap();
|
||||||
|
if filename.is_empty() {
|
||||||
|
eprintln!("A test file must be provided");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
let mut file = File::open(filename).unwrap();
|
||||||
|
let mut buff = String::new();
|
||||||
|
file.read_to_string(&mut buff).unwrap();
|
||||||
|
|
||||||
|
let tests: TestSuiteList = serde_json::from_str(&buff)?;
|
||||||
|
|
||||||
|
let mut emulator = Emulator::new();
|
||||||
|
emulator.bus.rom = Box::new(SpecialRAMCart::new());
|
||||||
|
|
||||||
|
for test in tests.0 {
|
||||||
|
println!("running test case {}", test.name);
|
||||||
|
|
||||||
|
emulator.cpu.registers.pc = test.initial.pc as u16;
|
||||||
|
emulator.cpu.registers.sp = test.initial.s as u16;
|
||||||
|
emulator.cpu.registers.p = test.initial.p as u8;
|
||||||
|
emulator.cpu.registers.a = test.initial.p as u16;
|
||||||
|
emulator.cpu.registers.x = test.initial.x as u16;
|
||||||
|
emulator.cpu.registers.y = test.initial.y as u16;
|
||||||
|
emulator.cpu.registers.dbr = test.initial.dbr as u8;
|
||||||
|
emulator.cpu.registers.d = test.initial.d as u16;
|
||||||
|
emulator.cpu.registers.pbr = test.initial.pbr as u8;
|
||||||
|
emulator.cpu.registers.emulation_mode = test.initial.e == 1;
|
||||||
|
|
||||||
|
for (address, value) in test.initial.ram {
|
||||||
|
emulator.bus.write(address as u32, value as u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
emulator.tick();
|
||||||
|
|
||||||
|
// compare the results
|
||||||
|
if
|
||||||
|
emulator.cpu.registers.pc as usize != test.r#final.pc ||
|
||||||
|
emulator.cpu.registers.sp as usize != test.r#final.s ||
|
||||||
|
emulator.cpu.registers.p as usize != test.r#final.p ||
|
||||||
|
emulator.cpu.registers.a as usize != test.r#final.p ||
|
||||||
|
emulator.cpu.registers.x as usize != test.r#final.x ||
|
||||||
|
emulator.cpu.registers.y as usize != test.r#final.y ||
|
||||||
|
emulator.cpu.registers.dbr as usize != test.r#final.dbr ||
|
||||||
|
emulator.cpu.registers.d as usize != test.r#final.d ||
|
||||||
|
emulator.cpu.registers.pbr as usize != test.r#final.pbr ||
|
||||||
|
emulator.cpu.registers.emulation_mode != (test.r#final.e == 1)
|
||||||
|
{
|
||||||
|
print_failed(&test.r#final, &emulator.bus, &emulator.cpu.registers);
|
||||||
|
}
|
||||||
|
for (address, value) in &test.r#final.ram {
|
||||||
|
if *value != emulator.bus.read_external(*address as u32) as usize {
|
||||||
|
print_failed(&test.r#final, &emulator.bus, &emulator.cpu.registers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("PASSED!");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user