Skip to content
Snippets Groups Projects
Verified Commit ef7a9754 authored by Jana Dönszelmann's avatar Jana Dönszelmann :sparkling_heart:
Browse files

release 1

parent 7c41463e
No related branches found
No related tags found
No related merge requests found
......@@ -1020,18 +1020,19 @@ dependencies = [
[[package]]
name = "tudelft-nes-ppu"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41174fa93758dbce9574e20951200a4b2ab3e0a4656d132338d3de3f1936568e"
dependencies = [
"itertools",
"log",
"pixels",
"winit",
]
[[package]]
name = "tudelft-nes-test"
version = "0.1.1"
version = "1.0.0"
dependencies = [
"bitflags",
"log",
"thiserror",
"tudelft-nes-ppu",
]
......
[package]
name = "tudelft-nes-test"
version = "0.1.1"
version = "1.0.0"
edition = "2021"
authors = [
"Victor Roest <victor@xirion.net>",
......@@ -15,5 +15,7 @@ license = "MIT"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tudelft-nes-ppu = "1.0.3"
tudelft-nes-ppu = {version="1.0.3", path="../tudelft-nes-ppu"}
thiserror = "1.0.32"
bitflags = "1.3.2"
log = "0.4.17"
use crate::{TestError, TestableCpu};
pub(crate) fn all_instrs_status_code(cpu: &impl TestableCpu) -> Result<(), TestError> {
let status = cpu.memory_read(0x6000);
let m1 = cpu.memory_read(0x6001);
let m2 = cpu.memory_read(0x6002);
let m3 = cpu.memory_read(0x6003);
if m1 != 0xde || m2 != 0xb0 || m3 != 0x61 {
return Err(TestError::String(format!(
"invalid magic sequence: {m1:x}{m2:x}{m3:x}. the test output was corrupted"
)));
}
if status == 0 {
Ok(())
} else {
Err(TestError::String(format!(
"exited with status {status}:\n {}",
read_status_string(cpu)
)))
}
}
pub(crate) fn read_status_string(cpu: &impl TestableCpu) -> String {
let mut res = String::new();
for i in 0x6004..=0x7000 {
let b = cpu.memory_read(i);
if b == 0 {
break;
}
res.push(char::from_u32(u32::from(b)).unwrap_or('�'))
}
res
}
use crate::all_instrs::{all_instrs_status_code, read_status_string};
use bitflags::bitflags;
use std::error::Error;
use std::thread;
use std::thread::JoinHandle;
use thiserror::Error;
use tudelft_nes_ppu::{Cpu, Mirroring};
use tudelft_nes_ppu::{run_cpu_headless_for, Cpu, Mirroring};
mod all_instrs;
mod nestest;
use crate::nestest::nestest_status_code;
pub use tudelft_nes_ppu::run_cpu_headless_for;
pub trait TestableCpu: Cpu + Sized + 'static {
fn get_cpu(rom: &[u8]) -> Result<Self, Box<dyn Error>>;
......@@ -15,12 +17,108 @@ pub trait TestableCpu: Cpu + Sized + 'static {
fn memory_read(&self, address: u16) -> u8;
}
pub fn run_all_tests<T: TestableCpu>() -> Result<(), String> {
bitflags! {
/// Select which tests you want to run
pub struct TestSelector: u32 {
const NESTEST = 0b00000001;
const ALL_INSTRS = 0b00000010;
const OFFICIAL_INSTRS = 0b00000100;
const ALL = Self::NESTEST.bits | Self::ALL_INSTRS.bits;
const DEFAULT = Self::OFFICIAL_INSTRS.bits;
}
}
impl Default for TestSelector {
fn default() -> Self {
Self::DEFAULT
}
}
pub fn run_tests<T: TestableCpu>(selector: TestSelector) -> Result<(), String> {
if selector.contains(TestSelector::ALL_INSTRS) {
all_instrs::<T>(false)?;
}
if selector.contains(TestSelector::OFFICIAL_INSTRS) {
all_instrs::<T>(true)?;
}
if selector.contains(TestSelector::NESTEST) {
nestest::<T>()?;
}
Ok(())
}
/// Tests the emulator using "all_instrs.nes" or "official_only.nes":
/// https://github.com/christopherpow/nes-test-roms/tree/master/instr_test-v5
fn all_instrs<T: TestableCpu + 'static>(only_official: bool) -> Result<(), String> {
let (rom, limit) = if only_official {
(include_bytes!("roms/official_only.nes"), 350)
} else {
(include_bytes!("roms/all_instrs.nes"), 500)
};
let handle = thread::spawn(move || {
// TODO: make initial program counter obsolete by modifying nestest
let mut cpu = T::get_cpu(rom).map_err(|i| TestError::Custom(i.to_string()))?;
let mut prev = String::new();
for i in 0..limit {
if let Err(e1) = run_cpu_headless_for(&mut cpu, Mirroring::Horizontal, 200_000) {
if let Err(e2) = all_instrs_status_code(&cpu) {
return Err(TestError::Custom(format!(
"{e1}, possibly due to a test that didn't pass: '{e2}'"
)));
} else {
return Err(TestError::Custom(format!("{e1}")));
}
}
let status = read_status_string(&cpu);
if status.contains("Failed") {
break;
}
let status = status.split('\n').next().unwrap().trim().to_string();
if !status.is_empty() && status != prev {
log::info!("{:05}k cycles passed: {}", i * 200, status);
}
prev = status;
}
let result = run_cpu_headless_for(&mut cpu, Mirroring::Horizontal, 200_000);
match result {
Err(e1) => {
if let Err(e2) = all_instrs_status_code(&cpu) {
Err(TestError::Custom(format!(
"{e1}, possibly due to a test that didn't pass: '{e2}'"
)))
} else {
Err(TestError::Custom(format!("{e1}")))
}
}
Ok(()) => all_instrs_status_code(&cpu),
}
});
process_handle(
&format!(
"all instructions{}",
if only_official {
" (official only)"
} else {
""
}
),
handle,
)
}
/// Runs the nestest rom:
/// https://github.com/christopherpow/nes-test-roms/blob/master/other/nestest.nes
fn nestest<T: TestableCpu + 'static>() -> Result<(), String> {
let rom = include_bytes!("roms/nestest.nes");
......@@ -31,15 +129,15 @@ fn nestest<T: TestableCpu + 'static>() -> Result<(), String> {
let result = run_cpu_headless_for(&mut cpu, Mirroring::Horizontal, 1_000_000);
match result {
Err(e) => {
if let Err(e) =
Err(e1) => {
if let Err(e2) =
nestest_status_code(cpu.memory_read(0x0002), cpu.memory_read(0x0003))
{
Err(TestError::Custom(format!(
"{e}, possibly due to a test that didn't pass: '{e}'"
"{e1}, possibly due to a test that didn't pass: '{e2}'"
)))
} else {
Err(TestError::Custom(format!("{e}")))
Err(TestError::Custom(format!("{e1}")))
}
}
Ok(()) => nestest_status_code(cpu.memory_read(0x0002), cpu.memory_read(0x0003)),
......@@ -61,7 +159,7 @@ fn process_handle(name: &str, handle: JoinHandle<Result<(), TestError>>) -> Resu
match handle.join() {
// <- waits for the thread to complete or panic
Ok(Ok(_)) => {
println!("{name} finished succesfully");
log::info!("{name} finished succesfully");
Ok(())
}
Ok(Err(e)) => match e {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment