Added more options to run select tests to harte test runner

This commit is contained in:
transistor 2022-09-10 14:08:01 -07:00
parent f3a177489e
commit c53253c050
9 changed files with 179 additions and 86 deletions

112
Cargo.lock generated
View File

@ -170,27 +170,26 @@ dependencies = [
[[package]]
name = "clap"
version = "3.0.0-beta.5"
version = "3.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "feff3878564edb93745d58cf63e17b63f24142506e7a20c87a5521ed7bfb1d63"
checksum = "23b71c3ce99b7611011217b366d923f1d0a7e07a92bb2dbf1e84508c673ca3bd"
dependencies = [
"atty",
"bitflags",
"clap_derive",
"clap_lex",
"indexmap",
"lazy_static",
"os_str_bytes",
"once_cell",
"strsim 0.10.0",
"termcolor",
"textwrap 0.14.2",
"unicase",
"textwrap 0.15.0",
]
[[package]]
name = "clap_derive"
version = "3.0.0-beta.5"
version = "3.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b15c6b4f786ffb6192ffe65a36855bc1fc2444bcd0945ae16748dcd6ed7d0d3"
checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
dependencies = [
"heck",
"proc-macro-error",
@ -199,6 +198,15 @@ dependencies = [
"syn",
]
[[package]]
name = "clap_lex"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "cmake"
version = "0.1.46"
@ -398,6 +406,18 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "harte_tests"
version = "0.1.0"
dependencies = [
"clap 3.2.20",
"flate2",
"moa",
"serde",
"serde_derive",
"serde_json",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
@ -406,12 +426,9 @@ checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "heck"
version = "0.3.3"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hermit-abi"
@ -453,6 +470,12 @@ dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "itoa"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
[[package]]
name = "jni"
version = "0.19.0"
@ -621,7 +644,7 @@ dependencies = [
name = "moa-minifb"
version = "0.1.0"
dependencies = [
"clap 3.0.0-beta.5",
"clap 3.2.20",
"minifb",
"moa",
"moa-common",
@ -812,9 +835,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.8.0"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0"
[[package]]
name = "orbclient"
@ -833,12 +856,9 @@ dependencies = [
[[package]]
name = "os_str_bytes"
version = "4.2.0"
version = "6.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "addaa943333a514159c80c97ff4a93306530d965d27e139188283cd13e06a799"
dependencies = [
"memchr",
]
checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
[[package]]
name = "parking_lot"
@ -1034,6 +1054,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "ryu"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
[[package]]
name = "same-file"
version = "1.0.6"
@ -1083,6 +1109,28 @@ version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
[[package]]
name = "serde_derive"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "shlex"
version = "0.1.1"
@ -1175,12 +1223,9 @@ dependencies = [
[[package]]
name = "textwrap"
version = "0.14.2"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
dependencies = [
"unicode-width",
]
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
[[package]]
name = "thiserror"
@ -1211,21 +1256,6 @@ dependencies = [
"serde",
]
[[package]]
name = "unicase"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
dependencies = [
"version_check",
]
[[package]]
name = "unicode-segmentation"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
[[package]]
name = "unicode-width"
version = "0.1.9"

View File

@ -6,6 +6,7 @@ use crate::devices::{Address, Addressable, Debuggable};
use super::state::M68k;
use super::decode::M68kDecoder;
#[derive(Clone)]
pub struct StackTracer {
pub calls: Vec<u32>,
}
@ -27,6 +28,7 @@ impl StackTracer {
}
#[derive(Clone)]
pub struct M68kDebugger {
pub enabled: bool,
pub breakpoints: Vec<u32>,
@ -68,10 +70,10 @@ impl Debuggable for M68k {
}
}
fn print_current_step(&mut self, system: &System) -> Result<(), Error> {
fn print_current_step(&mut self, _system: &System) -> Result<(), Error> {
self.decoder.decode_at(&mut self.port, self.state.pc)?;
self.decoder.dump_decoded(&mut self.port);
self.dump_state(system);
self.dump_state();
Ok(())
}

View File

@ -38,6 +38,7 @@ const OPCG_SHIFT: u8 = 0xE;
const OPCG_FLINE: u8 = 0xF;
#[derive(Clone)]
pub struct M68kDecoder {
pub cputype: M68kType,
pub start: u32,

View File

@ -31,8 +31,8 @@ impl Steppable for M68k {
self.step_internal(system)
}
fn on_error(&mut self, system: &System) {
self.dump_state(system);
fn on_error(&mut self, _system: &System) {
self.dump_state();
}
}

View File

@ -1,5 +1,4 @@
use crate::system::System;
use crate::devices::Address;
use crate::timers::CpuTimer;
use crate::memory::BusPort;
@ -121,6 +120,7 @@ impl M68kState {
}
}
#[derive(Clone)]
pub struct M68k {
pub cputype: M68kType,
pub frequency: u32,
@ -154,7 +154,7 @@ impl M68k {
self.debugger = M68kDebugger::new();
}
pub fn dump_state(&mut self, _system: &System) {
pub fn dump_state(&mut self) {
println!("Status: {:?}", self.state.status);
println!("PC: {:#010x}", self.state.pc);
println!("SR: {:#06x}", self.state.sr);

View File

@ -111,12 +111,14 @@ impl Transmutable for AddressAdapter {
}
#[derive(Clone)]
pub struct Block {
pub base: Address,
pub length: usize,
pub dev: TransmutableBox,
}
#[derive(Clone)]
pub struct Bus {
blocks: Vec<Block>,
ignore_unmapped: bool,
@ -238,6 +240,7 @@ impl Addressable for Bus {
}
}
#[derive(Clone)]
pub struct BusPort {
offset: Address,
address_mask: Address,

View File

@ -47,6 +47,7 @@ impl fmt::Display for AverageTimer {
}
#[derive(Clone)]
pub struct CpuTimer {
pub decode: AverageTimer,
pub execute: AverageTimer,

10
tests/harte_tests/run_all.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/bash
COMMIT=$(git rev-parse HEAD)
DATE=$(date --iso)
LOCATION=$(dirname ${BASH_SOURCE[0]})
{
cd $LOCATION
echo "Last run on $DATE at commit $COMMIT" | tee latest.txt
echo "" | tee -a latest.txt
cargo run -- -q --testsuite "../ProcessorTests/680x0/68000/uncompressed/" | tee -a latest.txt
}

View File

@ -1,5 +1,5 @@
const HART_TESTS: &str = "tests/ProcessorTests/680x0/68000/v1/";
const DEFAULT_HART_TESTS: &str = "tests/ProcessorTests/680x0/68000/v1/";
use std::io::prelude::*;
use std::fmt::Debug;
@ -23,6 +23,9 @@ use moa::cpus::m68k::state::Status;
struct Args {
/// Filter the tests by gzip file name
filter: Option<String>,
/// Only run the one test with the given number
#[clap(short, long)]
only: Option<String>,
/// Dump the CPU state when a test fails
#[clap(short, long)]
debug: bool,
@ -32,27 +35,14 @@ struct Args {
/// Also test instruction timing
#[clap(short, long)]
timing: bool,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
enum InfoLevel {
Quiet,
Normal,
Debug,
/// Directory to the test suite to run
#[clap(long, default_value = DEFAULT_HART_TESTS)]
testsuite: String,
}
fn main() {
let args = Args::parse();
let level = if args.debug {
InfoLevel::Debug
} else if args.quiet {
InfoLevel::Quiet
} else {
InfoLevel::Normal
};
run_all_tests(args, level);
run_all_tests(&args);
}
@ -91,6 +81,44 @@ struct TestCase {
length: usize
}
impl TestState {
pub fn dump(&self) {
println!("d0: {:08x} a0: {:08x}", self.d0, self.a0);
println!("d1: {:08x} a1: {:08x}", self.d1, self.a1);
println!("d2: {:08x} a2: {:08x}", self.d2, self.a2);
println!("d3: {:08x} a3: {:08x}", self.d3, self.a3);
println!("d4: {:08x} a4: {:08x}", self.d4, self.a4);
println!("d5: {:08x} a5: {:08x}", self.d5, self.a5);
println!("d6: {:08x} a6: {:08x}", self.d6, self.a6);
println!("d7: {:08x} usp: {:08x}", self.d7, self.usp);
println!("pc: {:08x} ssp: {:08x}", self.pc, self.ssp);
println!("sr: {:04x}", self.sr);
print!("prefetch: ");
for word in self.prefetch.iter() {
print!("{:04x} ", *word);
}
println!("");
println!("ram: ");
for (addr, byte) in self.ram.iter() {
println!("{:08x} {:02x} ", *addr, *byte);
}
}
}
impl TestCase {
pub fn dump(&self) {
println!("{}", self.name);
println!("initial:");
self.initial_state.dump();
println!("final:");
self.final_state.dump();
println!("cycles: {}", self.length);
}
}
fn init_execute_test(cputype: M68kType, state: &TestState) -> Result<(M68k, System), Error> {
let mut system = System::new();
@ -205,17 +233,21 @@ fn step_cpu_and_assert(cpu: &mut M68k, system: &System, case: &TestCase, test_ti
Ok(())
}
fn run_test(case: &TestCase, level: InfoLevel, test_timing: bool) -> Result<(), Error> {
let (mut cpu, system) = init_execute_test(M68kType::MC68010, &case.initial_state).unwrap();
fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> {
let (mut cpu, system) = init_execute_test(M68kType::MC68000, &case.initial_state).unwrap();
let mut initial_cpu = cpu.clone();
let result = step_cpu_and_assert(&mut cpu, &system, case, test_timing);
let result = step_cpu_and_assert(&mut cpu, &system, case, args.timing);
match result {
Ok(()) => Ok(()),
Err(err) => {
if level > InfoLevel::Quiet {
if level == InfoLevel::Debug {
cpu.dump_state(&system);
if !args.quiet {
if args.debug {
case.dump();
println!("");
initial_cpu.dump_state();
cpu.dump_state();
}
println!("FAILED: {}", err.msg);
}
@ -224,24 +256,37 @@ fn run_test(case: &TestCase, level: InfoLevel, test_timing: bool) -> Result<(),
}
}
fn test_json_file(path: PathBuf, level: InfoLevel, test_timing: bool) -> (usize, usize, String) {
let file = File::open(&path).unwrap();
let mut decoder = GzDecoder::new(file);
let mut data = String::new();
decoder.read_to_string(&mut data).unwrap();
let cases: Vec<TestCase> = serde_json::from_str(&data).unwrap();
fn test_json_file(path: PathBuf, args: &Args) -> (usize, usize, String) {
let extension = path.extension().unwrap();
let cases: Vec<TestCase> = if extension == "gz" {
let file = File::open(&path).unwrap();
let mut decoder = GzDecoder::new(file);
let mut data = String::new();
decoder.read_to_string(&mut data).unwrap();
serde_json::from_str(&data).unwrap()
} else {
let data = fs::read(&path).unwrap();
serde_json::from_slice(&data).unwrap()
};
let mut passed = 0;
let mut failed = 0;
for case in cases {
if level > InfoLevel::Quiet {
if let Some(only) = args.only.as_ref() {
if !case.name.ends_with(only) {
continue;
}
}
if !args.quiet {
println!("Running test {}", case.name);
}
let result = run_test(&case, level, test_timing);
let result = run_test(&case, args);
if let Err(err) = result {
failed += 1;
if level > InfoLevel::Quiet {
if !args.quiet {
println!("FAILED: {:?}", err);
}
} else {
@ -260,13 +305,13 @@ fn test_json_file(path: PathBuf, level: InfoLevel, test_timing: bool) -> (usize,
}
fn run_all_tests(args: Args, level: InfoLevel) {
fn run_all_tests(args: &Args) {
let mut passed = 0;
let mut failed = 0;
let mut messages = vec![];
let mut tests: Vec<PathBuf> = fs::read_dir(HART_TESTS)
let mut tests: Vec<PathBuf> = fs::read_dir(&args.testsuite)
.unwrap()
.map(|dirent| dirent.unwrap().path())
.collect();
@ -275,7 +320,8 @@ fn run_all_tests(args: Args, level: InfoLevel) {
let start = SystemTime::now();
for path in tests {
// Only test gzip files (the repo has .md files as well)
if path.extension().unwrap() != "gz" {
let extension = path.extension().unwrap();
if extension != "json" && extension != "gz" {
continue;
}
@ -287,10 +333,10 @@ fn run_all_tests(args: Args, level: InfoLevel) {
}
// Run every test in the file
let (test_passed, test_failed, message) = test_json_file(path, level, args.timing);
let (test_passed, test_failed, message) = test_json_file(path, args);
// In quiet mode, print each summary as it's received to give a progress update
if level == InfoLevel::Quiet {
if args.quiet {
println!("{}", message);
}
@ -301,7 +347,7 @@ fn run_all_tests(args: Args, level: InfoLevel) {
let elapsed_secs = start.elapsed().unwrap().as_secs();
// Print the stored summary if not in quite mode
if level > InfoLevel::Quiet {
if !args.quiet {
for message in messages {
println!("{}", message);
}