From f8083db181c584eaec605eee1bbae3dede032477 Mon Sep 17 00:00:00 2001 From: transistor Date: Tue, 9 May 2023 21:50:42 -0700 Subject: [PATCH] Added raddad772/jsmoo's Z80 test runner Special thanks to raddad772 https://github.com/raddad772 Also added some fixes to the Z80 for panicking math operations, but it still won't complete due to an unimplemented instruction --- .gitignore | 2 + Cargo.lock | 13 + Cargo.toml | 3 +- README.md | 8 + docs/log.txt | 12 + emulator/core/src/devices.rs | 50 ++ emulator/cpus/m68k/src/execute.rs | 20 +- emulator/cpus/z80/src/debugger.rs | 2 +- emulator/cpus/z80/src/decode.rs | 5 +- emulator/cpus/z80/src/execute.rs | 15 +- emulator/cpus/z80/src/state.rs | 1 + tests/README.md | 46 ++ tests/harte_tests/Cargo.toml | 2 +- tests/harte_tests/run_all.sh | 2 +- tests/harte_tests/run_exclude_addr.sh | 2 +- tests/harte_tests/src/main.rs | 4 +- tests/rad_tests/Cargo.toml | 13 + tests/rad_tests/README.md | 19 + tests/rad_tests/latest.txt | 1053 +++++++++++++++++++++++++ tests/rad_tests/run_all.sh | 11 + tests/rad_tests/src/main.rs | 351 +++++++++ todo.txt | 2 +- 22 files changed, 1609 insertions(+), 27 deletions(-) create mode 100644 tests/README.md create mode 100644 tests/rad_tests/Cargo.toml create mode 100644 tests/rad_tests/README.md create mode 100644 tests/rad_tests/latest.txt create mode 100755 tests/rad_tests/run_all.sh create mode 100644 tests/rad_tests/src/main.rs diff --git a/.gitignore b/.gitignore index 0f8a86c..3521e22 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ binaries/*/*.bin binaries/*/*.smd emulator/frontends/pixels/dist/ +tests/ProcessorTests/ +tests/jsmoo/ diff --git a/Cargo.lock b/Cargo.lock index 7683046..a6e0736 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1031,6 +1031,19 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rad_tests" +version = "0.1.0" +dependencies = [ + "clap 3.2.22", + "flate2", + "moa_core", + "moa_z80", + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "raw-window-handle" version = "0.3.4" diff --git a/Cargo.toml b/Cargo.toml index 9803f97..d1b3911 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,8 @@ members = [ "emulator/frontends/common", "emulator/frontends/console", "emulator/frontends/minifb", - "tests/harte_tests" + "tests/harte_tests", + "tests/rad_tests" ] exclude = [ "emulator/frontends/pixels", diff --git a/README.md b/README.md index 4d75e61..82983a9 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,12 @@ For more details on how it works, check out this post about how I started the pr For more about the Sega Genesis support, check out this series I wrote about implementing it: [Emulating the Sega Genesis](http://jabberwocky.ca/posts/2022-01-emulating_the_sega_genesis_part1.html) +I've also generated rustdocs of the workspace. All the various crates within moa +are listed in the crates section in the sidebar on the left. There's not a lot +of doc comments in the code yet but I plan to eventually write more: +[rustdocs for moa_core](http://jabberwocky.ca/moa/doc/moa_core/) +[rustdocs for ym2612](http://jabberwocky.ca/moa/doc/moa_peripherals_yamaha/ym2612/index.html) + Sega Genesis/MegaDrive ---------------------- @@ -67,6 +73,7 @@ though that doesn't happen during normal play ![alt text](images/sega-genesis-sonic2-demo.gif) + Computie -------- @@ -84,6 +91,7 @@ host, and set up host routing. The exact commands in `src/machines/computie.rs` might need to be adjusted to work on different hosts. + TRS-80 ------ diff --git a/docs/log.txt b/docs/log.txt index da559bf..06d711a 100644 --- a/docs/log.txt +++ b/docs/log.txt @@ -416,3 +416,15 @@ General Work making the fps drop down to 47-50 instead of 60. I'm not sure if that's because the older js version does some funny clock stuff or if the concept itself adds a lot of overhead for some as yet unknown reason + +2023-05-08 +- audio works in Sonic1. Mortal Kombat 2 has a bit of audio, but periods of silence where it's + clearly turning notes on and off and changing frequencies, but nothing is coming out. Then every + other has silence but they seems to write to the ym2612 registers with note on/off (reg 0x28), and + total level or frequency changes which make sense for audio to be playing but nothing. I had sort + of suspected the coprocessor communication until I printed the register set values which clearly + shows audio is being requested but nothing is produced, so still some big issues with the ym2612 +- looking at earthworm jim, it's sending a lot of commands to the 0x40s on bank 0 and 1, which + doesn't make a heck of a lot of sense to be changing the volume level but nothing else all the + time. It doesn't seem to set the initial frequencies. So it's possible that a bug in the Z80 + code is making it run incorrectly and thus not producing correct register commands to the ym2612 diff --git a/emulator/core/src/devices.rs b/emulator/core/src/devices.rs index 07c7cff..d0e39ef 100644 --- a/emulator/core/src/devices.rs +++ b/emulator/core/src/devices.rs @@ -211,3 +211,53 @@ impl Device { } +/* +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct DeviceId(usize); + +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum Interrupt { + Number(usize), +} + +pub enum InterruptPriority { + NonMaskable, + Number(usize), +} + +struct InterruptPort { + id: usize, + controller: TransmutableBox, +} + +impl InterruptPort { + fn check_pending(&self) -> Option { + self.controller.borrow_mut().as_interrupt_controller().check_pending(self.id) + } + + fn acknowledge(&self, interrupt: Interrupt) -> Result<(), Error> { + self.controller.borrow_mut().as_interrupt_controller().acknowledge(self.id, interrupt) + } +} + +//pub trait InterruptPort { +// fn check_pending(&mut self, id: DeviceId) -> Option; +// fn acknowledge(&mut self, id: DeviceId, interrupt: Interrupt) -> Result<(), Error>; +//} + +//pub trait Interrupter { +// fn trigger(&mut self, id: DeviceId, interrupt: Interrupt) -> Result<(), Error>; +//} + +struct Interrupter { + input_id: usize, + interrupt: Interrupt, + controller: Rc>, +} + +pub trait InterruptController { + fn connect(&mut self, priority: InterruptPriority) -> Result; + fn check_pending(&mut self, id: usize) -> Option; + fn acknowledge(&mut self, id: usize, interrupt: Interrupt) -> Result<(), Error>; +} +*/ diff --git a/emulator/cpus/m68k/src/execute.rs b/emulator/cpus/m68k/src/execute.rs index a37a83a..172bfae 100644 --- a/emulator/cpus/m68k/src/execute.rs +++ b/emulator/cpus/m68k/src/execute.rs @@ -314,11 +314,11 @@ impl M68k { let src_parts = get_nibbles_from_byte(src_val); let dest_parts = get_nibbles_from_byte(dest_val); - let binary_result = src_val + dest_val + extend_flag; - let mut result = src_parts.1 + dest_parts.1 + extend_flag; - if result > 0x09 { result += 0x06 }; + let binary_result = src_val.wrapping_add(dest_val).wrapping_add(extend_flag); + let mut result = src_parts.1.wrapping_add(dest_parts.1).wrapping_add(extend_flag); + if result > 0x09 { result = result.wrapping_add(0x06) }; result += src_parts.0 + dest_parts.0; - if result > 0x99 { result += 0x60 }; + if result > 0x99 { result = result.wrapping_add(0x60) }; let carry = (result & 0xFFFFFF00) != 0; self.set_target_value(dest, result, Size::Byte, Used::Twice)?; @@ -434,7 +434,7 @@ impl M68k { fn execute_bcc(&mut self, cond: Condition, offset: i32) -> Result<(), Error> { let should_branch = self.get_current_condition(cond); if should_branch { - if let Err(err) = self.set_pc((self.decoder.start + 2).wrapping_add(offset as u32)) { + if let Err(err) = self.set_pc(self.decoder.start.wrapping_add(2).wrapping_add(offset as u32)) { self.state.pc -= 2; return Err(err); } @@ -444,7 +444,7 @@ impl M68k { #[inline] fn execute_bra(&mut self, offset: i32) -> Result<(), Error> { - if let Err(err) = self.set_pc((self.decoder.start + 2).wrapping_add(offset as u32)) { + if let Err(err) = self.set_pc(self.decoder.start.wrapping_add(2).wrapping_add(offset as u32)) { self.state.pc -= 2; return Err(err); } @@ -456,7 +456,7 @@ impl M68k { self.push_long(self.state.pc)?; let sp = *self.get_stack_pointer_mut(); self.debugger.stack_tracer.push_return(sp); - if let Err(err) = self.set_pc((self.decoder.start + 2).wrapping_add(offset as u32)) { + if let Err(err) = self.set_pc(self.decoder.start.wrapping_add(2).wrapping_add(offset as u32)) { self.state.pc -= 2; return Err(err); } @@ -629,7 +629,7 @@ impl M68k { let next = ((get_value_sized(self.state.d_reg[reg as usize], Size::Word) as u16) as i16).wrapping_sub(1); set_value_sized(&mut self.state.d_reg[reg as usize], next as u32, Size::Word); if next != -1 { - if let Err(err) = self.set_pc((self.decoder.start + 2).wrapping_add(offset as u32)) { + if let Err(err) = self.set_pc(self.decoder.start.wrapping_add(2).wrapping_add(offset as u32)) { self.state.pc -= 2; return Err(err); } @@ -1000,7 +1000,7 @@ impl M68k { match dir { Direction::ToTarget => { let mut shift = (size.in_bits() as i32) - 8; - let mut addr = ((*self.get_a_reg_mut(areg) as i32) + (offset as i32)) as Address; + let mut addr = (*self.get_a_reg_mut(areg)).wrapping_add_signed(offset as i32) as Address; while shift >= 0 { let byte = (self.state.d_reg[dreg as usize] >> shift) as u8; self.port.write_u8(self.current_clock, addr, byte)?; @@ -1010,7 +1010,7 @@ impl M68k { }, Direction::FromTarget => { let mut shift = (size.in_bits() as i32) - 8; - let mut addr = ((*self.get_a_reg_mut(areg) as i32) + (offset as i32)) as Address; + let mut addr = (*self.get_a_reg_mut(areg)).wrapping_add_signed(offset as i32) as Address; while shift >= 0 { let byte = self.port.read_u8(self.current_clock, addr)?; self.state.d_reg[dreg as usize] |= (byte as u32) << shift; diff --git a/emulator/cpus/z80/src/debugger.rs b/emulator/cpus/z80/src/debugger.rs index 4e45a74..7eb8e4c 100644 --- a/emulator/cpus/z80/src/debugger.rs +++ b/emulator/cpus/z80/src/debugger.rs @@ -5,7 +5,7 @@ use crate::state::Z80; use crate::decode::Z80Decoder; -#[derive(Default)] +#[derive(Clone, Default)] pub struct Z80Debugger { pub enabled: bool, pub breakpoints: Vec, diff --git a/emulator/cpus/z80/src/decode.rs b/emulator/cpus/z80/src/decode.rs index 65cf528..a3e5ff9 100644 --- a/emulator/cpus/z80/src/decode.rs +++ b/emulator/cpus/z80/src/decode.rs @@ -172,6 +172,7 @@ pub enum Instruction { XOR(Target), } +#[derive(Clone)] pub struct Z80Decoder { pub clock: ClockTime, pub start: u16, @@ -678,14 +679,14 @@ impl Z80Decoder { fn read_instruction_byte(&mut self, device: &mut dyn Addressable) -> Result { let byte = device.read_u8(self.clock, self.end as Address)?; - self.end += 1; + self.end = self.end.wrapping_add(1); self.execution_time += 4; Ok(byte) } fn read_instruction_word(&mut self, device: &mut dyn Addressable) -> Result { let word = device.read_leu16(self.clock, self.end as Address)?; - self.end += 2; + self.end = self.end.wrapping_add(2); self.execution_time += 8; Ok(word) } diff --git a/emulator/cpus/z80/src/execute.rs b/emulator/cpus/z80/src/execute.rs index 3adea7e..710c115 100644 --- a/emulator/cpus/z80/src/execute.rs +++ b/emulator/cpus/z80/src/execute.rs @@ -217,7 +217,7 @@ impl Z80 { self.set_register_value(Register::B, result); if result != 0 { - self.state.pc = ((self.state.pc as i16) + (offset as i16)) as u16; + self.state.pc = self.state.pc.wrapping_add_signed(offset as i16); } }, Instruction::EI => { @@ -251,6 +251,7 @@ impl Z80 { }, Instruction::HALT => { self.state.status = Status::Halted; + self.state.pc -= 1; }, Instruction::IM(mode) => { self.state.interrupt_mode = mode; @@ -297,11 +298,11 @@ impl Z80 { } }, Instruction::JR(offset) => { - self.state.pc = ((self.state.pc as i16) + (offset as i16)) as u16; + self.state.pc = self.state.pc.wrapping_add_signed(offset as i16); }, Instruction::JRcc(cond, offset) => { if self.get_current_condition(cond) { - self.state.pc = ((self.state.pc as i16) + (offset as i16)) as u16; + self.state.pc = self.state.pc.wrapping_add_signed(offset as i16); } }, Instruction::LD(dest, src) => { @@ -367,9 +368,9 @@ impl Z80 { //}, //Instruction::OUTic(reg) => { //}, - Instruction::OUTx(port) => { + Instruction::OUTx(_port) => { // TODO this needs to be fixed - println!("OUT ({:x}), {:x} {}", port, self.state.reg[Register::A as usize], self.state.reg[Register::A as usize] as char); + //println!("OUT ({:x}), {:x} {}", port, self.state.reg[Register::A as usize], self.state.reg[Register::A as usize] as char); }, Instruction::POP(regpair) => { let value = self.pop_word()?; @@ -699,7 +700,7 @@ impl Z80 { Ok(self.port.read_u8(self.current_clock, addr as Address)?) }, Target::IndirectOffset(reg, offset) => { - let addr = (self.get_index_register_value(reg) as i16) + (offset as i16); + let addr = self.get_index_register_value(reg).wrapping_add_signed(offset as i16); Ok(self.port.read_u8(self.current_clock, addr as Address)?) }, Target::Immediate(data) => Ok(data), @@ -715,7 +716,7 @@ impl Z80 { self.port.write_u8(self.current_clock, addr as Address, value)?; }, Target::IndirectOffset(reg, offset) => { - let addr = (self.get_index_register_value(reg) as i16) + (offset as i16); + let addr = self.get_index_register_value(reg).wrapping_add_signed(offset as i16); self.port.write_u8(self.current_clock, addr as Address, value)?; }, _ => panic!("Unsupported LoadTarget for set"), diff --git a/emulator/cpus/z80/src/state.rs b/emulator/cpus/z80/src/state.rs index 98bd300..bc8586d 100644 --- a/emulator/cpus/z80/src/state.rs +++ b/emulator/cpus/z80/src/state.rs @@ -104,6 +104,7 @@ impl Z80State { } } +#[derive(Clone)] pub struct Z80 { pub cputype: Z80Type, pub frequency: Frequency, diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..27e5d73 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,46 @@ + +Tests +===== + +This directory contains CPU tests for the 68k and Z80. The test cases themselves are provided by +Tom Harte and raddad772, and must be cloned from their respective repositories before running the +tests. + + +Downloading +----------- + +To download the 68k tests, from the `tests/` directory, run: +```sh +git clone git@github.com:TomHarte/ProcessorTests.git +``` + +To download the Z80 tests, from the `tests/` directory, run: +```sh +git clone --no-checkout git@github.com:raddad772/jsmoo.git +cd jsmoo +git checkout origin/HEAD -- misc/tests/GeneratedTests +``` + + +Running +------- + +The 68k tests can be run from the moa root with: +```sh +tests/harte_tests/run_all.sh +``` +By default, the script will use the compressed versions of the tests which are slower to run because +they must be unzipped every time the tests are run. To speed it up for repeat runs, the tests can be +gunzip'ed to their own directory and the test suite location can be change on the command line or in +the script to point to the uncompressed versions + +The Z80 tests can be run with: +```sh +tests/rad_tests/run_all.sh +``` + + +Thanks to [Tom Harte](https://github.com/TomHarte) and [raddad772](https://github.com/raddad772) for +providing these incredibly valuable tests + diff --git a/tests/harte_tests/Cargo.toml b/tests/harte_tests/Cargo.toml index 046765e..798c818 100644 --- a/tests/harte_tests/Cargo.toml +++ b/tests/harte_tests/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "harte_tests" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] moa_core = { path = "../../emulator/core" } diff --git a/tests/harte_tests/run_all.sh b/tests/harte_tests/run_all.sh index 0e9492d..8480187 100755 --- a/tests/harte_tests/run_all.sh +++ b/tests/harte_tests/run_all.sh @@ -7,5 +7,5 @@ RESULTS=latest.txt cd $LOCATION echo "Last run on $DATE at commit $COMMIT" | tee $RESULTS echo "" | tee -a $RESULTS - cargo run -- -q --testsuite "../ProcessorTests/680x0/68000/uncompressed/" | tee -a $RESULTS + cargo run -- -q --testsuite "../ProcessorTests/680x0/68000/v1/" | tee -a $RESULTS } diff --git a/tests/harte_tests/run_exclude_addr.sh b/tests/harte_tests/run_exclude_addr.sh index 7ae4c26..3805839 100755 --- a/tests/harte_tests/run_exclude_addr.sh +++ b/tests/harte_tests/run_exclude_addr.sh @@ -7,5 +7,5 @@ RESULTS=latest-excluding-addr-error.txt cd $LOCATION echo "Last run on $DATE at commit $COMMIT" | tee $RESULTS echo "" | tee -a $RESULTS - cargo run -- -q --testsuite "../ProcessorTests/680x0/68000/uncompressed/" -e exclude-addr | tee -a $RESULTS + cargo run -- -q --testsuite "../ProcessorTests/680x0/68000/v1/" -e exclude-addr | tee -a $RESULTS } diff --git a/tests/harte_tests/src/main.rs b/tests/harte_tests/src/main.rs index c9792af..dde13b4 100644 --- a/tests/harte_tests/src/main.rs +++ b/tests/harte_tests/src/main.rs @@ -1,5 +1,5 @@ -const DEFAULT_HART_TESTS: &str = "tests/ProcessorTests/680x0/68000/v1/"; +const DEFAULT_HARTE_TESTS: &str = "tests/ProcessorTests/680x0/68000/v1/"; use std::io::prelude::*; use std::fmt::Debug; @@ -41,7 +41,7 @@ struct Args { #[clap(short, long)] timing: bool, /// Directory to the test suite to run - #[clap(long, default_value = DEFAULT_HART_TESTS)] + #[clap(long, default_value = DEFAULT_HARTE_TESTS)] testsuite: String, #[clap(long, short, arg_enum, default_value_t = Selection::Include)] exceptions: Selection, diff --git a/tests/rad_tests/Cargo.toml b/tests/rad_tests/Cargo.toml new file mode 100644 index 0000000..9a88d32 --- /dev/null +++ b/tests/rad_tests/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "rad_tests" +version = "0.1.0" +edition = "2021" + +[dependencies] +moa_core = { path = "../../emulator/core" } +moa_z80 = { path = "../../emulator/cpus/z80" } +serde = "1.0" +serde_json = "1.0" +serde_derive = "1.0" +flate2 = "1.0" +clap = { version = "3.2.20", features = ["derive"] } diff --git a/tests/rad_tests/README.md b/tests/rad_tests/README.md new file mode 100644 index 0000000..5bb834e --- /dev/null +++ b/tests/rad_tests/README.md @@ -0,0 +1,19 @@ + +Rad Test Suite +============== + +This is a test running for moa that uses the [raddad772/jsmoo tests](https://github.com/raddad772/jsmoo). + +To run, the jsmoo repository must be cloned into tests/ and then from the moa project root: +```shell +cargo run -p rad_tests -- [FILTER] +``` + +An optional filter can be specified, which will only run test files who's file name starts with the +filter text. Timing tests are not done by default, but can be run with `-t` or `--timing`. The output +can be increased or decreased with the `--debug` or `--quiet` flags, respectively. + +Special thanks to [raddad772](https://github.com/raddad772) for the incredibly +exhaustive and thorough set of testcases. Emulators everywhere will be better +for your efforts! + diff --git a/tests/rad_tests/latest.txt b/tests/rad_tests/latest.txt new file mode 100644 index 0000000..fd8be2c --- /dev/null +++ b/tests/rad_tests/latest.txt @@ -0,0 +1,1053 @@ +Last run on 2023-05-09 at commit 5e228c377ea6101249c69af7945ee00263f3f87c + +00.json completed, all passed! +01.json completed, all passed! +02.json completed, all passed! +03.json completed, all passed! +04.json completed: 128 passed, 872 FAILED +05.json completed: 135 passed, 865 FAILED +06.json completed, all passed! +07.json completed: 225 passed, 775 FAILED +08.json completed, all passed! +09.json completed: 140 passed, 860 FAILED +0a.json completed, all passed! +0b.json completed, all passed! +0c.json completed: 119 passed, 881 FAILED +0d.json completed: 114 passed, 886 FAILED +0e.json completed, all passed! +0f.json completed: 241 passed, 759 FAILED +10.json completed, all passed! +100.json completed, all passed! +101.json completed, all passed! +11.json completed, all passed! +12.json completed, all passed! +13.json completed, all passed! +14.json completed: 136 passed, 864 FAILED +15.json completed: 129 passed, 871 FAILED +16.json completed, all passed! +17.json completed: 231 passed, 769 FAILED +18.json completed, all passed! +19.json completed: 111 passed, 889 FAILED +1a.json completed, all passed! +1b.json completed, all passed! +1c.json completed: 114 passed, 886 FAILED +1d.json completed: 138 passed, 862 FAILED +1e.json completed, all passed! +1f.json completed: 236 passed, 764 FAILED +20.json completed, all passed! +21.json completed, all passed! +22.json completed: 999 passed, 1 FAILED +23.json completed, all passed! +24.json completed: 119 passed, 881 FAILED +25.json completed: 127 passed, 873 FAILED +26.json completed, all passed! +27.json completed: 0 passed, 1000 FAILED +28.json completed, all passed! +29.json completed: 108 passed, 892 FAILED +2a.json completed, all passed! +2b.json completed, all passed! +2c.json completed: 111 passed, 889 FAILED +2d.json completed: 130 passed, 870 FAILED +2e.json completed, all passed! +2f.json completed: 259 passed, 741 FAILED +30.json completed, all passed! +31.json completed, all passed! +32.json completed, all passed! +33.json completed, all passed! +34.json completed: 126 passed, 874 FAILED +35.json completed: 122 passed, 878 FAILED +36.json completed, all passed! +37.json completed: 409 passed, 591 FAILED +38.json completed, all passed! +39.json completed: 129 passed, 871 FAILED +3a.json completed, all passed! +3b.json completed, all passed! +3c.json completed: 125 passed, 875 FAILED +3d.json completed: 108 passed, 892 FAILED +3e.json completed, all passed! +3f.json completed: 436 passed, 564 FAILED +40.json completed, all passed! +41.json completed, all passed! +42.json completed, all passed! +43.json completed, all passed! +44.json completed, all passed! +45.json completed, all passed! +46.json completed, all passed! +47.json completed, all passed! +48.json completed, all passed! +49.json completed, all passed! +4a.json completed, all passed! +4b.json completed, all passed! +4c.json completed, all passed! +4d.json completed, all passed! +4e.json completed, all passed! +4f.json completed, all passed! +50.json completed, all passed! +51.json completed, all passed! +52.json completed, all passed! +53.json completed, all passed! +54.json completed, all passed! +55.json completed, all passed! +56.json completed, all passed! +57.json completed, all passed! +58.json completed, all passed! +59.json completed, all passed! +5a.json completed, all passed! +5b.json completed, all passed! +5c.json completed, all passed! +5d.json completed, all passed! +5e.json completed, all passed! +5f.json completed, all passed! +60.json completed, all passed! +61.json completed, all passed! +62.json completed, all passed! +63.json completed, all passed! +64.json completed, all passed! +65.json completed, all passed! +66.json completed, all passed! +67.json completed, all passed! +68.json completed, all passed! +69.json completed, all passed! +6a.json completed, all passed! +6b.json completed, all passed! +6c.json completed, all passed! +6d.json completed, all passed! +6e.json completed, all passed! +6f.json completed, all passed! +70.json completed, all passed! +71.json completed, all passed! +72.json completed, all passed! +73.json completed, all passed! +74.json completed, all passed! +75.json completed, all passed! +76.json completed, all passed! +77.json completed, all passed! +78.json completed, all passed! +79.json completed, all passed! +7a.json completed, all passed! +7b.json completed, all passed! +7c.json completed, all passed! +7d.json completed, all passed! +7e.json completed, all passed! +7f.json completed, all passed! +80.json completed: 118 passed, 882 FAILED +81.json completed: 107 passed, 893 FAILED +82.json completed: 85 passed, 915 FAILED +83.json completed: 95 passed, 905 FAILED +84.json completed: 88 passed, 912 FAILED +85.json completed: 99 passed, 901 FAILED +86.json completed: 104 passed, 896 FAILED +87.json completed: 121 passed, 879 FAILED +88.json completed: 88 passed, 912 FAILED +89.json completed: 108 passed, 892 FAILED +8a.json completed: 91 passed, 909 FAILED +8b.json completed: 83 passed, 917 FAILED +8c.json completed: 83 passed, 917 FAILED +8d.json completed: 81 passed, 919 FAILED +8e.json completed: 86 passed, 914 FAILED +8f.json completed: 120 passed, 880 FAILED +90.json completed: 117 passed, 883 FAILED +91.json completed: 101 passed, 899 FAILED +92.json completed: 125 passed, 875 FAILED +93.json completed: 125 passed, 875 FAILED +94.json completed: 135 passed, 865 FAILED +95.json completed: 126 passed, 874 FAILED +96.json completed: 135 passed, 865 FAILED +97.json completed, all passed! +98.json completed: 111 passed, 889 FAILED +99.json completed: 119 passed, 881 FAILED +9a.json completed: 119 passed, 881 FAILED +9b.json completed: 133 passed, 867 FAILED +9c.json completed: 122 passed, 878 FAILED +9d.json completed: 126 passed, 874 FAILED +9e.json completed: 115 passed, 885 FAILED +9f.json completed: 492 passed, 508 FAILED +a0.json completed: 576 passed, 424 FAILED +a1.json completed: 572 passed, 428 FAILED +a2.json completed: 585 passed, 415 FAILED +a3.json completed: 579 passed, 421 FAILED +a4.json completed: 552 passed, 448 FAILED +a5.json completed: 544 passed, 456 FAILED +a6.json completed: 575 passed, 425 FAILED +a7.json completed: 264 passed, 736 FAILED +a8.json completed: 222 passed, 778 FAILED +a9.json completed: 255 passed, 745 FAILED +aa.json completed: 236 passed, 764 FAILED +ab.json completed: 253 passed, 747 FAILED +ac.json completed: 269 passed, 731 FAILED +ad.json completed: 236 passed, 764 FAILED +ae.json completed: 239 passed, 761 FAILED +af.json completed, all passed! +b0.json completed: 60 passed, 940 FAILED +b1.json completed: 69 passed, 931 FAILED +b2.json completed: 70 passed, 930 FAILED +b3.json completed: 72 passed, 928 FAILED +b4.json completed: 68 passed, 932 FAILED +b5.json completed: 63 passed, 937 FAILED +b6.json completed: 77 passed, 923 FAILED +b7.json completed: 247 passed, 753 FAILED +b8.json completed: 113 passed, 887 FAILED +b9.json completed: 123 passed, 877 FAILED +ba.json completed: 130 passed, 870 FAILED +bb.json completed: 133 passed, 867 FAILED +bc.json completed: 129 passed, 871 FAILED +bd.json completed: 141 passed, 859 FAILED +be.json completed: 134 passed, 866 FAILED +bf.json completed: 251 passed, 749 FAILED +c0.json completed, all passed! +c1.json completed, all passed! +c2.json completed, all passed! +c3.json completed, all passed! +c4.json completed, all passed! +c5.json completed, all passed! +c6.json completed: 89 passed, 911 FAILED +c7.json completed, all passed! +c8.json completed, all passed! +c9.json completed, all passed! +ca.json completed, all passed! +cb 00.json completed: 239 passed, 761 FAILED +cb 01.json completed: 262 passed, 738 FAILED +cb 02.json completed: 254 passed, 746 FAILED +cb 03.json completed: 300 passed, 700 FAILED +cb 04.json completed: 252 passed, 748 FAILED +cb 05.json completed: 258 passed, 742 FAILED +cb 06.json completed: 245 passed, 755 FAILED +cb 07.json completed: 251 passed, 749 FAILED +cb 08.json completed: 244 passed, 756 FAILED +cb 09.json completed: 235 passed, 765 FAILED +cb 0a.json completed: 260 passed, 740 FAILED +cb 0b.json completed: 264 passed, 736 FAILED +cb 0c.json completed: 248 passed, 752 FAILED +cb 0d.json completed: 259 passed, 741 FAILED +cb 0e.json completed: 272 passed, 728 FAILED +cb 0f.json completed: 257 passed, 743 FAILED +cb 10.json completed: 261 passed, 739 FAILED +cb 11.json completed: 236 passed, 764 FAILED +cb 12.json completed: 233 passed, 767 FAILED +cb 13.json completed: 228 passed, 772 FAILED +cb 14.json completed: 241 passed, 759 FAILED +cb 15.json completed: 252 passed, 748 FAILED +cb 16.json completed: 230 passed, 770 FAILED +cb 17.json completed: 267 passed, 733 FAILED +cb 18.json completed: 247 passed, 753 FAILED +cb 19.json completed: 245 passed, 755 FAILED +cb 1a.json completed: 239 passed, 761 FAILED +cb 1b.json completed: 245 passed, 755 FAILED +cb 1c.json completed: 263 passed, 737 FAILED +cb 1d.json completed: 218 passed, 782 FAILED +cb 1e.json completed: 252 passed, 748 FAILED +cb 1f.json completed: 259 passed, 741 FAILED +cb 20.json completed: 256 passed, 744 FAILED +cb 21.json completed: 271 passed, 729 FAILED +cb 22.json completed: 249 passed, 751 FAILED +cb 23.json completed: 244 passed, 756 FAILED +cb 24.json completed: 249 passed, 751 FAILED +cb 25.json completed: 243 passed, 757 FAILED +cb 26.json completed: 223 passed, 777 FAILED +cb 27.json completed: 250 passed, 750 FAILED +cb 28.json completed: 236 passed, 764 FAILED +cb 29.json completed: 274 passed, 726 FAILED +cb 2a.json completed: 255 passed, 745 FAILED +cb 2b.json completed: 255 passed, 745 FAILED +cb 2c.json completed: 235 passed, 765 FAILED +cb 2d.json completed: 242 passed, 758 FAILED +cb 2e.json completed: 245 passed, 755 FAILED +cb 2f.json completed: 273 passed, 727 FAILED +cb 30.json completed: 259 passed, 741 FAILED +cb 31.json completed: 243 passed, 757 FAILED +cb 32.json completed: 261 passed, 739 FAILED +cb 33.json completed: 218 passed, 782 FAILED +cb 34.json completed: 252 passed, 748 FAILED +cb 35.json completed: 246 passed, 754 FAILED +cb 36.json completed: 250 passed, 750 FAILED +cb 37.json completed: 263 passed, 737 FAILED +cb 38.json completed: 274 passed, 726 FAILED +cb 39.json completed: 233 passed, 767 FAILED +cb 3a.json completed: 231 passed, 769 FAILED +cb 3b.json completed: 258 passed, 742 FAILED +cb 3c.json completed: 248 passed, 752 FAILED +cb 3d.json completed: 248 passed, 752 FAILED +cb 3e.json completed: 260 passed, 740 FAILED +cb 3f.json completed: 248 passed, 752 FAILED +cb 40.json completed: 54 passed, 946 FAILED +cb 41.json completed: 54 passed, 946 FAILED +cb 42.json completed: 75 passed, 925 FAILED +cb 43.json completed: 58 passed, 942 FAILED +cb 44.json completed: 57 passed, 943 FAILED +cb 45.json completed: 63 passed, 937 FAILED +cb 46.json completed: 61 passed, 939 FAILED +cb 47.json completed: 68 passed, 932 FAILED +cb 48.json completed: 67 passed, 933 FAILED +cb 49.json completed: 52 passed, 948 FAILED +cb 4a.json completed: 60 passed, 940 FAILED +cb 4b.json completed: 61 passed, 939 FAILED +cb 4c.json completed: 74 passed, 926 FAILED +cb 4d.json completed: 67 passed, 933 FAILED +cb 4e.json completed: 61 passed, 939 FAILED +cb 4f.json completed: 47 passed, 953 FAILED +cb 50.json completed: 60 passed, 940 FAILED +cb 51.json completed: 67 passed, 933 FAILED +cb 52.json completed: 69 passed, 931 FAILED +cb 53.json completed: 69 passed, 931 FAILED +cb 54.json completed: 65 passed, 935 FAILED +cb 55.json completed: 57 passed, 943 FAILED +cb 56.json completed: 72 passed, 928 FAILED +cb 57.json completed: 68 passed, 932 FAILED +cb 58.json completed: 64 passed, 936 FAILED +cb 59.json completed: 65 passed, 935 FAILED +cb 5a.json completed: 71 passed, 929 FAILED +cb 5b.json completed: 64 passed, 936 FAILED +cb 5c.json completed: 72 passed, 928 FAILED +cb 5d.json completed: 70 passed, 930 FAILED +cb 5e.json completed: 73 passed, 927 FAILED +cb 5f.json completed: 62 passed, 938 FAILED +cb 60.json completed: 62 passed, 938 FAILED +cb 61.json completed: 55 passed, 945 FAILED +cb 62.json completed: 52 passed, 948 FAILED +cb 63.json completed: 70 passed, 930 FAILED +cb 64.json completed: 55 passed, 945 FAILED +cb 65.json completed: 67 passed, 933 FAILED +cb 66.json completed: 62 passed, 938 FAILED +cb 67.json completed: 54 passed, 946 FAILED +cb 68.json completed: 68 passed, 932 FAILED +cb 69.json completed: 61 passed, 939 FAILED +cb 6a.json completed: 57 passed, 943 FAILED +cb 6b.json completed: 73 passed, 927 FAILED +cb 6c.json completed: 59 passed, 941 FAILED +cb 6d.json completed: 57 passed, 943 FAILED +cb 6e.json completed: 53 passed, 947 FAILED +cb 6f.json completed: 88 passed, 912 FAILED +cb 70.json completed: 54 passed, 946 FAILED +cb 71.json completed: 62 passed, 938 FAILED +cb 72.json completed: 73 passed, 927 FAILED +cb 73.json completed: 64 passed, 936 FAILED +cb 74.json completed: 64 passed, 936 FAILED +cb 75.json completed: 62 passed, 938 FAILED +cb 76.json completed: 54 passed, 946 FAILED +cb 77.json completed: 56 passed, 944 FAILED +cb 78.json completed: 60 passed, 940 FAILED +cb 79.json completed: 61 passed, 939 FAILED +cb 7a.json completed: 71 passed, 929 FAILED +cb 7b.json completed: 49 passed, 951 FAILED +cb 7c.json completed: 53 passed, 947 FAILED +cb 7d.json completed: 84 passed, 916 FAILED +cb 7e.json completed: 62 passed, 938 FAILED +cb 7f.json completed: 69 passed, 931 FAILED +cb 80.json completed, all passed! +cb 81.json completed, all passed! +cb 82.json completed, all passed! +cb 83.json completed, all passed! +cb 84.json completed, all passed! +cb 85.json completed, all passed! +cb 86.json completed, all passed! +cb 87.json completed, all passed! +cb 88.json completed, all passed! +cb 89.json completed, all passed! +cb 8a.json completed, all passed! +cb 8b.json completed, all passed! +cb 8c.json completed, all passed! +cb 8d.json completed, all passed! +cb 8e.json completed, all passed! +cb 8f.json completed, all passed! +cb 90.json completed, all passed! +cb 91.json completed, all passed! +cb 92.json completed, all passed! +cb 93.json completed, all passed! +cb 94.json completed, all passed! +cb 95.json completed, all passed! +cb 96.json completed, all passed! +cb 97.json completed, all passed! +cb 98.json completed, all passed! +cb 99.json completed, all passed! +cb 9a.json completed, all passed! +cb 9b.json completed, all passed! +cb 9c.json completed, all passed! +cb 9d.json completed, all passed! +cb 9e.json completed, all passed! +cb 9f.json completed, all passed! +cb a0.json completed, all passed! +cb a1.json completed, all passed! +cb a2.json completed, all passed! +cb a3.json completed, all passed! +cb a4.json completed, all passed! +cb a5.json completed, all passed! +cb a6.json completed, all passed! +cb a7.json completed, all passed! +cb a8.json completed, all passed! +cb a9.json completed, all passed! +cb aa.json completed, all passed! +cb ab.json completed, all passed! +cb ac.json completed, all passed! +cb ad.json completed, all passed! +cb ae.json completed, all passed! +cb af.json completed, all passed! +cb b0.json completed, all passed! +cb b1.json completed, all passed! +cb b2.json completed, all passed! +cb b3.json completed, all passed! +cb b4.json completed, all passed! +cb b5.json completed, all passed! +cb b6.json completed, all passed! +cb b7.json completed, all passed! +cb b8.json completed, all passed! +cb b9.json completed, all passed! +cb ba.json completed, all passed! +cb bb.json completed, all passed! +cb bc.json completed, all passed! +cb bd.json completed, all passed! +cb be.json completed, all passed! +cb bf.json completed, all passed! +cb c0.json completed, all passed! +cb c1.json completed, all passed! +cb c2.json completed, all passed! +cb c3.json completed, all passed! +cb c4.json completed, all passed! +cb c5.json completed, all passed! +cb c6.json completed, all passed! +cb c7.json completed, all passed! +cb c8.json completed, all passed! +cb c9.json completed, all passed! +cb ca.json completed, all passed! +cb cb.json completed, all passed! +cb cc.json completed, all passed! +cb cd.json completed, all passed! +cb ce.json completed, all passed! +cb cf.json completed, all passed! +cb d0.json completed, all passed! +cb d1.json completed, all passed! +cb d2.json completed, all passed! +cb d3.json completed, all passed! +cb d4.json completed, all passed! +cb d5.json completed, all passed! +cb d6.json completed, all passed! +cb d7.json completed, all passed! +cb d8.json completed, all passed! +cb d9.json completed, all passed! +cb da.json completed, all passed! +cb db.json completed, all passed! +cb dc.json completed, all passed! +cb dd.json completed, all passed! +cb de.json completed, all passed! +cb df.json completed, all passed! +cb e0.json completed, all passed! +cb e1.json completed, all passed! +cb e2.json completed, all passed! +cb e3.json completed, all passed! +cb e4.json completed, all passed! +cb e5.json completed, all passed! +cb e6.json completed, all passed! +cb e7.json completed, all passed! +cb e8.json completed, all passed! +cb e9.json completed, all passed! +cb ea.json completed, all passed! +cb eb.json completed, all passed! +cb ec.json completed, all passed! +cb ed.json completed, all passed! +cb ee.json completed, all passed! +cb ef.json completed, all passed! +cb f0.json completed, all passed! +cb f1.json completed, all passed! +cb f2.json completed, all passed! +cb f3.json completed, all passed! +cb f4.json completed, all passed! +cb f5.json completed, all passed! +cb f6.json completed, all passed! +cb f7.json completed, all passed! +cb f8.json completed, all passed! +cb f9.json completed, all passed! +cb fa.json completed, all passed! +cb fb.json completed, all passed! +cb fc.json completed, all passed! +cb fd.json completed, all passed! +cb fe.json completed, all passed! +cb ff.json completed, all passed! +cc.json completed, all passed! +cd.json completed, all passed! +ce.json completed: 98 passed, 902 FAILED +cf.json completed, all passed! +d0.json completed, all passed! +d1.json completed, all passed! +d2.json completed, all passed! +d3.json completed, all passed! +d4.json completed, all passed! +d5.json completed, all passed! +d6.json completed: 140 passed, 860 FAILED +d7.json completed, all passed! +d8.json completed, all passed! +d9.json completed, all passed! +da.json completed, all passed! +db.json completed: 0 passed, 1000 FAILED +dc.json completed, all passed! +dd 00.json completed, all passed! +dd 01.json completed: 0 passed, 1000 FAILED +dd 02.json completed: 3 passed, 997 FAILED +dd 03.json completed: 0 passed, 1000 FAILED +dd 04.json completed: 0 passed, 1000 FAILED +dd 05.json completed: 0 passed, 1000 FAILED +dd 06.json completed: 0 passed, 1000 FAILED +dd 07.json completed: 0 passed, 1000 FAILED +dd 08.json completed: 0 passed, 1000 FAILED +dd 09.json completed: 139 passed, 861 FAILED +dd 0a.json completed: 2 passed, 998 FAILED +dd 0b.json completed: 0 passed, 1000 FAILED +dd 0c.json completed: 0 passed, 1000 FAILED +dd 0d.json completed: 0 passed, 1000 FAILED +dd 0e.json completed: 0 passed, 1000 FAILED +dd 0f.json completed: 0 passed, 1000 FAILED +dd 10.json completed: 0 passed, 1000 FAILED +dd 100.json completed, all passed! +dd 101.json completed: 0 passed, 1000 FAILED +dd 11.json completed: 0 passed, 1000 FAILED +dd 12.json completed: 5 passed, 995 FAILED +dd 13.json completed: 0 passed, 1000 FAILED +dd 14.json completed: 0 passed, 1000 FAILED +dd 15.json completed: 0 passed, 1000 FAILED +dd 16.json completed: 0 passed, 1000 FAILED +dd 17.json completed: 0 passed, 1000 FAILED +dd 18.json completed: 5 passed, 995 FAILED +dd 19.json completed: 118 passed, 882 FAILED +dd 1a.json completed: 4 passed, 996 FAILED +dd 1b.json completed: 0 passed, 1000 FAILED +dd 1c.json completed: 0 passed, 1000 FAILED +dd 1d.json completed: 0 passed, 1000 FAILED +dd 1e.json completed: 0 passed, 1000 FAILED +dd 1f.json completed: 0 passed, 1000 FAILED +dd 20.json completed: 1 passed, 999 FAILED +dd 21.json completed, all passed! +dd 22.json completed, all passed! +dd 23.json completed, all passed! +dd 24.json completed: 62 passed, 938 FAILED +dd 25.json completed: 0 passed, 1000 FAILED +dd 26.json completed: 98 passed, 902 FAILED +dd 27.json completed: 3 passed, 997 FAILED +dd 28.json completed: 6 passed, 994 FAILED +dd 29.json completed: 133 passed, 867 FAILED +dd 2a.json completed, all passed! +dd 2b.json completed, all passed! +dd 2c.json completed: 68 passed, 932 FAILED +dd 2d.json completed: 0 passed, 1000 FAILED +dd 2e.json completed: 113 passed, 887 FAILED +dd 2f.json completed: 0 passed, 1000 FAILED +dd 30.json completed: 513 passed, 487 FAILED +dd 31.json completed: 0 passed, 1000 FAILED +dd 32.json completed: 0 passed, 1000 FAILED +dd 33.json completed: 0 passed, 1000 FAILED +dd 34.json completed: 120 passed, 880 FAILED +dd 35.json completed: 136 passed, 864 FAILED +dd 36.json completed, all passed! +dd 37.json completed: 0 passed, 1000 FAILED +dd 38.json completed: 506 passed, 494 FAILED +dd 39.json completed: 118 passed, 882 FAILED +dd 3a.json completed: 0 passed, 1000 FAILED +dd 3b.json completed: 0 passed, 1000 FAILED +dd 3c.json completed: 0 passed, 1000 FAILED +dd 3d.json completed: 0 passed, 1000 FAILED +dd 3e.json completed: 5 passed, 995 FAILED +dd 3f.json completed: 0 passed, 1000 FAILED +dd 40.json completed, all passed! +dd 41.json completed: 5 passed, 995 FAILED +dd 42.json completed: 3 passed, 997 FAILED +dd 43.json completed: 8 passed, 992 FAILED +dd 44.json completed, all passed! +dd 45.json completed, all passed! +dd 46.json completed, all passed! +dd 47.json completed: 2 passed, 998 FAILED +dd 48.json completed: 2 passed, 998 FAILED +dd 49.json completed, all passed! +dd 4a.json completed: 2 passed, 998 FAILED +dd 4b.json completed: 7 passed, 993 FAILED +dd 4c.json completed, all passed! +dd 4d.json completed, all passed! +dd 4e.json completed, all passed! +dd 4f.json completed: 4 passed, 996 FAILED +dd 50.json completed: 2 passed, 998 FAILED +dd 51.json completed: 4 passed, 996 FAILED +dd 52.json completed, all passed! +dd 53.json completed: 3 passed, 997 FAILED +dd 54.json completed, all passed! +dd 55.json completed, all passed! +dd 56.json completed, all passed! +dd 57.json completed: 2 passed, 998 FAILED +dd 58.json completed: 6 passed, 994 FAILED +dd 59.json completed: 3 passed, 997 FAILED +dd 5a.json completed: 5 passed, 995 FAILED +dd 5b.json completed, all passed! +dd 5c.json completed, all passed! +dd 5d.json completed, all passed! +dd 5e.json completed, all passed! +dd 5f.json completed: 7 passed, 993 FAILED +dd 60.json completed: 112 passed, 888 FAILED +dd 61.json completed: 103 passed, 897 FAILED +dd 62.json completed: 95 passed, 905 FAILED +dd 63.json completed: 109 passed, 891 FAILED +dd 64.json completed, all passed! +dd 65.json completed: 94 passed, 906 FAILED +dd 66.json completed, all passed! +dd 67.json completed: 106 passed, 894 FAILED +dd 68.json completed: 96 passed, 904 FAILED +dd 69.json completed: 114 passed, 886 FAILED +dd 6a.json completed: 94 passed, 906 FAILED +dd 6b.json completed: 93 passed, 907 FAILED +dd 6c.json completed: 93 passed, 907 FAILED +dd 6d.json completed, all passed! +dd 6e.json completed, all passed! +dd 6f.json completed: 83 passed, 917 FAILED +dd 70.json completed, all passed! +dd 71.json completed, all passed! +dd 72.json completed, all passed! +dd 73.json completed, all passed! +dd 74.json completed, all passed! +dd 75.json completed, all passed! +dd 76.json completed: 0 passed, 1000 FAILED +dd 77.json completed, all passed! +dd 78.json completed: 2 passed, 998 FAILED +dd 79.json completed: 2 passed, 998 FAILED +dd 7a.json completed: 5 passed, 995 FAILED +dd 7b.json completed: 3 passed, 997 FAILED +dd 7c.json completed, all passed! +dd 7d.json completed, all passed! +dd 7e.json completed, all passed! +dd 7f.json completed, all passed! +dd 80.json completed: 0 passed, 1000 FAILED +dd 81.json completed: 0 passed, 1000 FAILED +dd 82.json completed: 0 passed, 1000 FAILED +dd 83.json completed: 0 passed, 1000 FAILED +dd 84.json completed: 105 passed, 895 FAILED +dd 85.json completed: 102 passed, 898 FAILED +dd 86.json completed: 94 passed, 906 FAILED +dd 87.json completed: 0 passed, 1000 FAILED +dd 88.json completed: 0 passed, 1000 FAILED +dd 89.json completed: 0 passed, 1000 FAILED +dd 8a.json completed: 0 passed, 1000 FAILED +dd 8b.json completed: 0 passed, 1000 FAILED +dd 8c.json completed: 104 passed, 896 FAILED +dd 8d.json completed: 104 passed, 896 FAILED +dd 8e.json completed: 83 passed, 917 FAILED +dd 8f.json completed: 0 passed, 1000 FAILED +dd 90.json completed: 0 passed, 1000 FAILED +dd 91.json completed: 0 passed, 1000 FAILED +dd 92.json completed: 0 passed, 1000 FAILED +dd 93.json completed: 0 passed, 1000 FAILED +dd 94.json completed: 131 passed, 869 FAILED +dd 95.json completed: 112 passed, 888 FAILED +dd 96.json completed: 113 passed, 887 FAILED +dd 97.json completed: 0 passed, 1000 FAILED +dd 98.json completed: 0 passed, 1000 FAILED +dd 99.json completed: 0 passed, 1000 FAILED +dd 9a.json completed: 0 passed, 1000 FAILED +dd 9b.json completed: 0 passed, 1000 FAILED +dd 9c.json completed: 134 passed, 866 FAILED +dd 9d.json completed: 102 passed, 898 FAILED +dd 9e.json completed: 107 passed, 893 FAILED +dd 9f.json completed: 0 passed, 1000 FAILED +dd a0.json completed: 0 passed, 1000 FAILED +dd a1.json completed: 1 passed, 999 FAILED +dd a2.json completed: 0 passed, 1000 FAILED +dd a3.json completed: 0 passed, 1000 FAILED +dd a4.json completed: 556 passed, 444 FAILED +dd a5.json completed: 566 passed, 434 FAILED +dd a6.json completed: 562 passed, 438 FAILED +dd a7.json completed: 5 passed, 995 FAILED +dd a8.json completed: 0 passed, 1000 FAILED +dd a9.json completed: 0 passed, 1000 FAILED +dd aa.json completed: 0 passed, 1000 FAILED +dd ab.json completed: 0 passed, 1000 FAILED +dd ac.json completed: 225 passed, 775 FAILED +dd ad.json completed: 236 passed, 764 FAILED +dd ae.json completed: 250 passed, 750 FAILED +dd af.json completed: 0 passed, 1000 FAILED +dd b0.json completed: 0 passed, 1000 FAILED +dd b1.json completed: 1 passed, 999 FAILED +dd b2.json completed: 0 passed, 1000 FAILED +dd b3.json completed: 1 passed, 999 FAILED +dd b4.json completed: 52 passed, 948 FAILED +dd b5.json completed: 57 passed, 943 FAILED +dd b6.json completed: 56 passed, 944 FAILED +dd b7.json completed: 5 passed, 995 FAILED +dd b8.json completed: 4 passed, 996 FAILED +dd b9.json completed: 5 passed, 995 FAILED +dd ba.json completed: 4 passed, 996 FAILED +dd bb.json completed: 2 passed, 998 FAILED +dd bc.json completed: 128 passed, 872 FAILED +dd bd.json completed: 122 passed, 878 FAILED +dd be.json completed: 122 passed, 878 FAILED +dd bf.json completed: 8 passed, 992 FAILED +dd c0.json completed: 500 passed, 500 FAILED +dd c1.json completed: 0 passed, 1000 FAILED +dd c2.json completed: 0 passed, 1000 FAILED +dd c3.json completed: 0 passed, 1000 FAILED +dd c4.json completed: 0 passed, 1000 FAILED +dd c5.json completed: 0 passed, 1000 FAILED +dd c6.json completed: 0 passed, 1000 FAILED +dd c7.json completed: 0 passed, 1000 FAILED +dd c8.json completed: 493 passed, 507 FAILED +dd c9.json completed: 0 passed, 1000 FAILED +dd ca.json completed: 0 passed, 1000 FAILED +dd cb __ 00.json completed: 4 passed, 996 FAILED +dd cb __ 01.json completed: 4 passed, 996 FAILED +dd cb __ 02.json completed: 5 passed, 995 FAILED +dd cb __ 03.json completed: 0 passed, 1000 FAILED +dd cb __ 04.json completed: 3 passed, 997 FAILED +dd cb __ 05.json completed: 5 passed, 995 FAILED +dd cb __ 06.json completed: 237 passed, 763 FAILED +dd cb __ 07.json completed: 5 passed, 995 FAILED +dd cb __ 08.json completed: 3 passed, 997 FAILED +dd cb __ 09.json completed: 5 passed, 995 FAILED +dd cb __ 0a.json completed: 2 passed, 998 FAILED +dd cb __ 0b.json completed: 5 passed, 995 FAILED +dd cb __ 0c.json completed: 6 passed, 994 FAILED +dd cb __ 0d.json completed: 2 passed, 998 FAILED +dd cb __ 0e.json completed: 255 passed, 745 FAILED +dd cb __ 0f.json completed: 4 passed, 996 FAILED +dd cb __ 10.json completed: 2 passed, 998 FAILED +dd cb __ 11.json completed: 0 passed, 1000 FAILED +dd cb __ 12.json completed: 3 passed, 997 FAILED +dd cb __ 13.json completed: 0 passed, 1000 FAILED +dd cb __ 14.json completed: 0 passed, 1000 FAILED +dd cb __ 15.json completed: 2 passed, 998 FAILED +dd cb __ 16.json completed: 251 passed, 749 FAILED +dd cb __ 17.json completed: 0 passed, 1000 FAILED +dd cb __ 18.json completed: 4 passed, 996 FAILED +dd cb __ 19.json completed: 0 passed, 1000 FAILED +dd cb __ 1a.json completed: 1 passed, 999 FAILED +dd cb __ 1b.json completed: 1 passed, 999 FAILED +dd cb __ 1c.json completed: 1 passed, 999 FAILED +dd cb __ 1d.json completed: 1 passed, 999 FAILED +dd cb __ 1e.json completed: 236 passed, 764 FAILED +dd cb __ 1f.json completed: 1 passed, 999 FAILED +dd cb __ 20.json completed: 6 passed, 994 FAILED +dd cb __ 21.json completed: 5 passed, 995 FAILED +dd cb __ 22.json completed: 5 passed, 995 FAILED +dd cb __ 23.json completed: 3 passed, 997 FAILED +dd cb __ 24.json completed: 2 passed, 998 FAILED +dd cb __ 25.json completed: 6 passed, 994 FAILED +dd cb __ 26.json completed: 252 passed, 748 FAILED +dd cb __ 27.json completed: 3 passed, 997 FAILED +dd cb __ 28.json completed: 2 passed, 998 FAILED +dd cb __ 29.json completed: 4 passed, 996 FAILED +dd cb __ 2a.json completed: 2 passed, 998 FAILED +dd cb __ 2b.json completed: 4 passed, 996 FAILED +dd cb __ 2c.json completed: 7 passed, 993 FAILED +dd cb __ 2d.json completed: 6 passed, 994 FAILED +dd cb __ 2e.json completed: 246 passed, 754 FAILED +dd cb __ 2f.json completed: 8 passed, 992 FAILED +dd cb __ 30.json completed: 0 passed, 1000 FAILED +dd cb __ 31.json completed: 0 passed, 1000 FAILED +dd cb __ 32.json completed: 0 passed, 1000 FAILED +dd cb __ 33.json completed: 0 passed, 1000 FAILED +dd cb __ 34.json completed: 0 passed, 1000 FAILED +dd cb __ 35.json completed: 0 passed, 1000 FAILED +dd cb __ 36.json completed: 245 passed, 755 FAILED +dd cb __ 37.json completed: 0 passed, 1000 FAILED +dd cb __ 38.json completed: 5 passed, 995 FAILED +dd cb __ 39.json completed: 1 passed, 999 FAILED +dd cb __ 3a.json completed: 4 passed, 996 FAILED +dd cb __ 3b.json completed: 7 passed, 993 FAILED +dd cb __ 3c.json completed: 3 passed, 997 FAILED +dd cb __ 3d.json completed: 5 passed, 995 FAILED +dd cb __ 3e.json completed: 248 passed, 752 FAILED +dd cb __ 3f.json completed: 6 passed, 994 FAILED +dd cb __ 40.json completed: 63 passed, 937 FAILED +dd cb __ 41.json completed: 61 passed, 939 FAILED +dd cb __ 42.json completed: 72 passed, 928 FAILED +dd cb __ 43.json completed: 53 passed, 947 FAILED +dd cb __ 44.json completed: 80 passed, 920 FAILED +dd cb __ 45.json completed: 72 passed, 928 FAILED +dd cb __ 46.json completed: 67 passed, 933 FAILED +dd cb __ 47.json completed: 69 passed, 931 FAILED +dd cb __ 48.json completed: 66 passed, 934 FAILED +dd cb __ 49.json completed: 54 passed, 946 FAILED +dd cb __ 4a.json completed: 80 passed, 920 FAILED +dd cb __ 4b.json completed: 56 passed, 944 FAILED +dd cb __ 4c.json completed: 66 passed, 934 FAILED +dd cb __ 4d.json completed: 63 passed, 937 FAILED +dd cb __ 4e.json completed: 53 passed, 947 FAILED +dd cb __ 4f.json completed: 70 passed, 930 FAILED +dd cb __ 50.json completed: 73 passed, 927 FAILED +dd cb __ 51.json completed: 64 passed, 936 FAILED +dd cb __ 52.json completed: 65 passed, 935 FAILED +dd cb __ 53.json completed: 55 passed, 945 FAILED +dd cb __ 54.json completed: 64 passed, 936 FAILED +dd cb __ 55.json completed: 62 passed, 938 FAILED +dd cb __ 56.json completed: 60 passed, 940 FAILED +dd cb __ 57.json completed: 63 passed, 937 FAILED +dd cb __ 58.json completed: 54 passed, 946 FAILED +dd cb __ 59.json completed: 61 passed, 939 FAILED +dd cb __ 5a.json completed: 74 passed, 926 FAILED +dd cb __ 5b.json completed: 64 passed, 936 FAILED +dd cb __ 5c.json completed: 66 passed, 934 FAILED +dd cb __ 5d.json completed: 63 passed, 937 FAILED +dd cb __ 5e.json completed: 58 passed, 942 FAILED +dd cb __ 5f.json completed: 63 passed, 937 FAILED +dd cb __ 60.json completed: 57 passed, 943 FAILED +dd cb __ 61.json completed: 76 passed, 924 FAILED +dd cb __ 62.json completed: 66 passed, 934 FAILED +dd cb __ 63.json completed: 81 passed, 919 FAILED +dd cb __ 64.json completed: 65 passed, 935 FAILED +dd cb __ 65.json completed: 49 passed, 951 FAILED +dd cb __ 66.json completed: 67 passed, 933 FAILED +dd cb __ 67.json completed: 73 passed, 927 FAILED +dd cb __ 68.json completed: 63 passed, 937 FAILED +dd cb __ 69.json completed: 60 passed, 940 FAILED +dd cb __ 6a.json completed: 56 passed, 944 FAILED +dd cb __ 6b.json completed: 55 passed, 945 FAILED +dd cb __ 6c.json completed: 64 passed, 936 FAILED +dd cb __ 6d.json completed: 69 passed, 931 FAILED +dd cb __ 6e.json completed: 70 passed, 930 FAILED +dd cb __ 6f.json completed: 53 passed, 947 FAILED +dd cb __ 70.json completed: 67 passed, 933 FAILED +dd cb __ 71.json completed: 60 passed, 940 FAILED +dd cb __ 72.json completed: 53 passed, 947 FAILED +dd cb __ 73.json completed: 61 passed, 939 FAILED +dd cb __ 74.json completed: 48 passed, 952 FAILED +dd cb __ 75.json completed: 73 passed, 927 FAILED +dd cb __ 76.json completed: 70 passed, 930 FAILED +dd cb __ 77.json completed: 54 passed, 946 FAILED +dd cb __ 78.json completed: 63 passed, 937 FAILED +dd cb __ 79.json completed: 61 passed, 939 FAILED +dd cb __ 7a.json completed: 69 passed, 931 FAILED +dd cb __ 7b.json completed: 78 passed, 922 FAILED +dd cb __ 7c.json completed: 54 passed, 946 FAILED +dd cb __ 7d.json completed: 63 passed, 937 FAILED +dd cb __ 7e.json completed: 62 passed, 938 FAILED +dd cb __ 7f.json completed: 64 passed, 936 FAILED +dd cb __ 80.json completed, all passed! +dd cb __ 81.json completed, all passed! +dd cb __ 82.json completed, all passed! +dd cb __ 83.json completed, all passed! +dd cb __ 84.json completed, all passed! +dd cb __ 85.json completed, all passed! +dd cb __ 86.json completed, all passed! +dd cb __ 87.json completed, all passed! +dd cb __ 88.json completed, all passed! +dd cb __ 89.json completed, all passed! +dd cb __ 8a.json completed, all passed! +dd cb __ 8b.json completed, all passed! +dd cb __ 8c.json completed, all passed! +dd cb __ 8d.json completed, all passed! +dd cb __ 8e.json completed, all passed! +dd cb __ 8f.json completed, all passed! +dd cb __ 90.json completed, all passed! +dd cb __ 91.json completed, all passed! +dd cb __ 92.json completed, all passed! +dd cb __ 93.json completed, all passed! +dd cb __ 94.json completed, all passed! +dd cb __ 95.json completed, all passed! +dd cb __ 96.json completed, all passed! +dd cb __ 97.json completed, all passed! +dd cb __ 98.json completed, all passed! +dd cb __ 99.json completed, all passed! +dd cb __ 9a.json completed, all passed! +dd cb __ 9b.json completed, all passed! +dd cb __ 9c.json completed, all passed! +dd cb __ 9d.json completed, all passed! +dd cb __ 9e.json completed, all passed! +dd cb __ 9f.json completed, all passed! +dd cb __ a0.json completed, all passed! +dd cb __ a1.json completed, all passed! +dd cb __ a2.json completed, all passed! +dd cb __ a3.json completed, all passed! +dd cb __ a4.json completed, all passed! +dd cb __ a5.json completed, all passed! +dd cb __ a6.json completed, all passed! +dd cb __ a7.json completed, all passed! +dd cb __ a8.json completed, all passed! +dd cb __ a9.json completed, all passed! +dd cb __ aa.json completed, all passed! +dd cb __ ab.json completed, all passed! +dd cb __ ac.json completed, all passed! +dd cb __ ad.json completed, all passed! +dd cb __ ae.json completed, all passed! +dd cb __ af.json completed, all passed! +dd cb __ b0.json completed, all passed! +dd cb __ b1.json completed, all passed! +dd cb __ b2.json completed, all passed! +dd cb __ b3.json completed, all passed! +dd cb __ b4.json completed, all passed! +dd cb __ b5.json completed, all passed! +dd cb __ b6.json completed, all passed! +dd cb __ b7.json completed, all passed! +dd cb __ b8.json completed, all passed! +dd cb __ b9.json completed, all passed! +dd cb __ ba.json completed, all passed! +dd cb __ bb.json completed, all passed! +dd cb __ bc.json completed, all passed! +dd cb __ bd.json completed, all passed! +dd cb __ be.json completed, all passed! +dd cb __ bf.json completed, all passed! +dd cb __ c0.json completed, all passed! +dd cb __ c1.json completed, all passed! +dd cb __ c2.json completed, all passed! +dd cb __ c3.json completed, all passed! +dd cb __ c4.json completed, all passed! +dd cb __ c5.json completed, all passed! +dd cb __ c6.json completed, all passed! +dd cb __ c7.json completed, all passed! +dd cb __ c8.json completed, all passed! +dd cb __ c9.json completed, all passed! +dd cb __ ca.json completed, all passed! +dd cb __ cb.json completed, all passed! +dd cb __ cc.json completed, all passed! +dd cb __ cd.json completed, all passed! +dd cb __ ce.json completed, all passed! +dd cb __ cf.json completed, all passed! +dd cb __ d0.json completed, all passed! +dd cb __ d1.json completed, all passed! +dd cb __ d2.json completed, all passed! +dd cb __ d3.json completed, all passed! +dd cb __ d4.json completed, all passed! +dd cb __ d5.json completed, all passed! +dd cb __ d6.json completed, all passed! +dd cb __ d7.json completed, all passed! +dd cb __ d8.json completed, all passed! +dd cb __ d9.json completed, all passed! +dd cb __ da.json completed, all passed! +dd cb __ db.json completed, all passed! +dd cb __ dc.json completed, all passed! +dd cb __ dd.json completed, all passed! +dd cb __ de.json completed, all passed! +dd cb __ df.json completed, all passed! +dd cb __ e0.json completed, all passed! +dd cb __ e1.json completed, all passed! +dd cb __ e2.json completed, all passed! +dd cb __ e3.json completed, all passed! +dd cb __ e4.json completed, all passed! +dd cb __ e5.json completed, all passed! +dd cb __ e6.json completed, all passed! +dd cb __ e7.json completed, all passed! +dd cb __ e8.json completed, all passed! +dd cb __ e9.json completed, all passed! +dd cb __ ea.json completed, all passed! +dd cb __ eb.json completed, all passed! +dd cb __ ec.json completed, all passed! +dd cb __ ed.json completed, all passed! +dd cb __ ee.json completed, all passed! +dd cb __ ef.json completed, all passed! +dd cb __ f0.json completed, all passed! +dd cb __ f1.json completed, all passed! +dd cb __ f2.json completed, all passed! +dd cb __ f3.json completed, all passed! +dd cb __ f4.json completed, all passed! +dd cb __ f5.json completed, all passed! +dd cb __ f6.json completed, all passed! +dd cb __ f7.json completed, all passed! +dd cb __ f8.json completed, all passed! +dd cb __ f9.json completed, all passed! +dd cb __ fa.json completed, all passed! +dd cb __ fb.json completed, all passed! +dd cb __ fc.json completed, all passed! +dd cb __ fd.json completed, all passed! +dd cb __ fe.json completed, all passed! +dd cb __ ff.json completed, all passed! +dd cc.json completed: 0 passed, 1000 FAILED +dd cd.json completed: 0 passed, 1000 FAILED +dd ce.json completed: 0 passed, 1000 FAILED +dd cf.json completed: 0 passed, 1000 FAILED +dd d0.json completed: 508 passed, 492 FAILED +dd d1.json completed: 0 passed, 1000 FAILED +dd d2.json completed: 0 passed, 1000 FAILED +dd d3.json completed: 0 passed, 1000 FAILED +dd d4.json completed: 0 passed, 1000 FAILED +dd d5.json completed: 0 passed, 1000 FAILED +dd d6.json completed: 0 passed, 1000 FAILED +dd d7.json completed: 0 passed, 1000 FAILED +dd d8.json completed: 507 passed, 493 FAILED +dd d9.json completed: 0 passed, 1000 FAILED +dd da.json completed: 0 passed, 1000 FAILED +dd db.json completed: 0 passed, 1000 FAILED +dd dc.json completed: 0 passed, 1000 FAILED +dd de.json completed: 0 passed, 1000 FAILED +dd df.json completed: 0 passed, 1000 FAILED +dd e0.json completed: 491 passed, 509 FAILED +dd e1.json completed, all passed! +dd e2.json completed: 0 passed, 1000 FAILED +dd e3.json completed, all passed! +dd e4.json completed: 0 passed, 1000 FAILED +dd e5.json completed, all passed! +dd e6.json completed: 0 passed, 1000 FAILED +dd e7.json completed: 0 passed, 1000 FAILED +dd e8.json completed: 524 passed, 476 FAILED +dd e9.json completed, all passed! +dd ea.json completed: 0 passed, 1000 FAILED +dd eb.json completed: 0 passed, 1000 FAILED +dd ec.json completed: 0 passed, 1000 FAILED +dd ee.json completed: 0 passed, 1000 FAILED +dd ef.json completed: 0 passed, 1000 FAILED +dd f0.json completed: 535 passed, 465 FAILED +dd f1.json completed: 0 passed, 1000 FAILED +dd f2.json completed: 0 passed, 1000 FAILED +dd f3.json completed, all passed! +dd f4.json completed: 0 passed, 1000 FAILED +dd f5.json completed: 0 passed, 1000 FAILED +dd f6.json completed: 0 passed, 1000 FAILED +dd f7.json completed: 0 passed, 1000 FAILED +dd f8.json completed: 500 passed, 500 FAILED +dd f9.json completed, all passed! +dd fa.json completed: 0 passed, 1000 FAILED +dd fb.json completed, all passed! +dd fc.json completed: 0 passed, 1000 FAILED +dd fe.json completed: 0 passed, 1000 FAILED +dd ff.json completed: 0 passed, 1000 FAILED +de.json completed: 127 passed, 873 FAILED +df.json completed, all passed! +e0.json completed, all passed! +e1.json completed, all passed! +e2.json completed, all passed! +e3.json completed, all passed! +e4.json completed, all passed! +e5.json completed, all passed! +e6.json completed: 573 passed, 427 FAILED +e7.json completed, all passed! +e8.json completed, all passed! +e9.json completed, all passed! +ea.json completed, all passed! +eb.json completed, all passed! +ec.json completed, all passed! +ed 40.json completed: 0 passed, 1000 FAILED +ed 41.json completed: 0 passed, 1000 FAILED +ed 42.json completed: 89 passed, 911 FAILED +ed 43.json completed, all passed! +ed 44.json completed: 138 passed, 862 FAILED +ed 45.json completed: 0 passed, 1000 FAILED +ed 46.json completed, all passed! +ed 47.json completed, all passed! +ed 48.json completed: 0 passed, 1000 FAILED +ed 49.json completed: 0 passed, 1000 FAILED +ed 4a.json completed: 70 passed, 930 FAILED +ed 4b.json completed, all passed! +ed 4c.json completed: 123 passed, 877 FAILED +ed 4d.json completed: 0 passed, 1000 FAILED +ed 4e.json completed, all passed! +ed 4f.json completed, all passed! +ed 50.json completed: 0 passed, 1000 FAILED +ed 51.json completed: 0 passed, 1000 FAILED +ed 52.json completed: 98 passed, 902 FAILED +ed 53.json completed, all passed! +ed 54.json completed: 128 passed, 872 FAILED +ed 55.json completed: 0 passed, 1000 FAILED +ed 56.json completed, all passed! +ed 57.json completed: 0 passed, 1000 FAILED +ed 58.json completed: 0 passed, 1000 FAILED +ed 59.json completed: 0 passed, 1000 FAILED +ed 5a.json completed: 67 passed, 933 FAILED +ed 5b.json completed, all passed! +ed 5c.json completed: 155 passed, 845 FAILED +ed 5d.json completed: 0 passed, 1000 FAILED +ed 5e.json completed, all passed! +ed 5f.json completed: 0 passed, 1000 FAILED +ed 60.json completed: 0 passed, 1000 FAILED +ed 61.json completed: 0 passed, 1000 FAILED +ed 62.json completed: 521 passed, 479 FAILED +ed 63.json completed, all passed! +ed 64.json completed: 154 passed, 846 FAILED +ed 65.json completed: 0 passed, 1000 FAILED +ed 66.json completed, all passed! +ed 67.json completed: 0 passed, 1000 FAILED +ed 68.json completed: 0 passed, 1000 FAILED +ed 69.json completed: 0 passed, 1000 FAILED +ed 6a.json completed: 63 passed, 937 FAILED +ed 6b.json completed, all passed! +ed 6c.json completed: 122 passed, 878 FAILED +ed 6d.json completed: 0 passed, 1000 FAILED +ed 6e.json completed, all passed! +ed 6f.json completed: 0 passed, 1000 FAILED diff --git a/tests/rad_tests/run_all.sh b/tests/rad_tests/run_all.sh new file mode 100755 index 0000000..30c1e49 --- /dev/null +++ b/tests/rad_tests/run_all.sh @@ -0,0 +1,11 @@ +#!/bin/bash +COMMIT=$(git rev-parse HEAD) +DATE=$(date --iso) +LOCATION=$(dirname ${BASH_SOURCE[0]}) +RESULTS=latest.txt +{ + cd $LOCATION + echo "Last run on $DATE at commit $COMMIT" | tee $RESULTS + echo "" | tee -a $RESULTS + cargo run -- -q --testsuite "../jsmoo/misc/tests/GeneratedTests/z80/v1/" | tee -a $RESULTS +} diff --git a/tests/rad_tests/src/main.rs b/tests/rad_tests/src/main.rs new file mode 100644 index 0000000..8724107 --- /dev/null +++ b/tests/rad_tests/src/main.rs @@ -0,0 +1,351 @@ + +const DEFAULT_RAD_TESTS: &str = "tests/jsmoo/misc/tests/GeneratedTests/z80/v1/"; + +use std::io::prelude::*; +use std::fmt::Debug; +use std::path::PathBuf; +use std::time::SystemTime; +use std::fs::{self, File}; + +use clap::{Parser, ArgEnum}; +use flate2::read::GzDecoder; +use serde_derive::Deserialize; + +use moa_core::{System, Error, MemoryBlock, BusPort, Frequency, Address, Addressable, Steppable, wrap_transmutable}; + +use moa_z80::{Z80, Z80Type}; +use moa_z80::state::Status; + +#[derive(Copy, Clone, PartialEq, Eq, ArgEnum)] +enum Selection { + Include, + Exclude, + ExcludeAddr, + Only, +} + +#[derive(Parser)] +struct Args { + /// Filter the tests by gzip file name + filter: Option, + /// Only run the one test with the given number + #[clap(short, long)] + only: Option, + /// Dump the CPU state when a test fails + #[clap(short, long)] + debug: bool, + /// Only print a summary for each test file + #[clap(short, long)] + quiet: bool, + /// Directory to the test suite to run + #[clap(long, default_value = DEFAULT_RAD_TESTS)] + testsuite: String, + #[clap(long, short, arg_enum, default_value_t = Selection::Include)] + exceptions: Selection, +} + +fn main() { + let args = Args::parse(); + run_all_tests(&args); +} + + +#[derive(Debug, Deserialize)] +struct TestState { + pc: u16, + sp: u16, + a: u8, + b: u8, + c: u8, + d: u8, + e: u8, + f: u8, + h: u8, + l: u8, + //i: u8, + //r: u8, + //ei: u8, + //wz: u8, + ix: u16, + iy: u16, + af_: u16, + bc_: u16, + de_: u16, + hl_: u16, + //im: u8, + //p: u8, + //q: u8, + //iff1: u8, + //iff2: u8, + ram: Vec<(u16, u8)>, +} + +#[derive(Debug, Deserialize)] +struct TestCase { + name: String, + #[serde(rename(deserialize = "initial"))] + initial_state: TestState, + #[serde(rename(deserialize = "final"))] + final_state: TestState, +} + +impl TestState { + pub fn dump(&self) { + println!(" a: {:02x} a': {:02x}", self.a, self.af_ >> 8); + println!(" b: {:02x} b': {:02x}", self.b, self.bc_ & 0xff); + println!(" c: {:02x} c': {:02x}", self.c, self.bc_ >> 8); + println!(" d: {:02x} d': {:02x}", self.d, self.de_ & 0xff); + println!(" e: {:02x} e': {:02x}", self.e, self.de_ >> 8); + println!(" f: {:02x} f': {:02x}", self.f, self.af_ & 0xff); + println!(" h: {:02x} h': {:02x}", self.h, self.hl_ >> 8); + println!(" l: {:02x} l': {:02x}", self.l, self.hl_ & 0xff); + println!("pc: {:04x} sp: {:04x}", self.pc, self.sp); + println!("ix: {:04x} iy: {:04x}", self.ix, self.iy); + + println!("ram: "); + for (addr, byte) in self.ram.iter() { + println!("{:04x} {:02x} ", *addr, *byte); + } + } +} + +impl TestCase { + pub fn dump(&self) { + println!("{}", self.name); + println!("initial:"); + self.initial_state.dump(); + println!("final:"); + self.final_state.dump(); + } +} + + +fn init_execute_test(cputype: Z80Type, state: &TestState) -> Result<(Z80, System), Error> { + let mut system = System::default(); + + // Insert basic initialization + let data = vec![0; 0x01000000]; + let mem = MemoryBlock::new(data); + system.add_addressable_device(0x00000000, wrap_transmutable(mem)).unwrap(); + + let port = BusPort::new(0, 16, 8, system.bus.clone()); + let mut cpu = Z80::new(cputype, Frequency::from_mhz(10), port); + cpu.state.status = Status::Running; + + load_state(&mut cpu, &mut system, state)?; + + Ok((cpu, system)) +} + +fn assert_value(actual: T, expected: T, message: &str) -> Result<(), Error> { + if actual == expected { + Ok(()) + } else { + Err(Error::assertion(&format!("{:?} != {:?}, {}", actual, expected, message))) + } +} + +fn load_state(cpu: &mut Z80, system: &mut System, initial: &TestState) -> Result<(), Error> { + cpu.state.reg[0] = initial.b; + cpu.state.reg[1] = initial.c; + cpu.state.reg[2] = initial.d; + cpu.state.reg[3] = initial.e; + cpu.state.reg[4] = initial.h; + cpu.state.reg[5] = initial.l; + cpu.state.reg[6] = initial.a; + cpu.state.reg[7] = initial.f; + cpu.state.shadow_reg[0] = (initial.bc_ >> 8) as u8; + cpu.state.shadow_reg[1] = (initial.bc_ & 0xff) as u8; + cpu.state.shadow_reg[2] = (initial.de_ >> 8) as u8; + cpu.state.shadow_reg[3] = (initial.de_ & 0xff) as u8; + cpu.state.shadow_reg[4] = (initial.hl_ >> 8) as u8; + cpu.state.shadow_reg[5] = (initial.hl_ & 0xff) as u8; + cpu.state.shadow_reg[6] = (initial.af_ >> 8) as u8; + cpu.state.shadow_reg[7] = (initial.af_ & 0xff) as u8; + + cpu.state.ix = initial.ix; + cpu.state.iy = initial.iy; + cpu.state.sp = initial.sp; + cpu.state.pc = initial.pc; + + // Load data bytes into memory + for (addr, byte) in initial.ram.iter() { + system.get_bus().write_u8(system.clock, *addr as u64, *byte)?; + } + + Ok(()) +} + +fn assert_state(cpu: &Z80, system: &System, expected: &TestState) -> Result<(), Error> { + assert_value(cpu.state.reg[0], expected.b, "b")?; + assert_value(cpu.state.reg[1], expected.c, "c")?; + assert_value(cpu.state.reg[2], expected.d, "d")?; + assert_value(cpu.state.reg[3], expected.e, "e")?; + assert_value(cpu.state.reg[4], expected.h, "h")?; + assert_value(cpu.state.reg[5], expected.l, "l")?; + assert_value(cpu.state.reg[6], expected.a, "a")?; + assert_value(cpu.state.reg[7], expected.f, "f")?; + assert_value(cpu.state.shadow_reg[0], (expected.bc_ >> 8) as u8, "b'")?; + assert_value(cpu.state.shadow_reg[1], (expected.bc_ & 0xff) as u8, "c'")?; + assert_value(cpu.state.shadow_reg[2], (expected.de_ >> 8) as u8, "d'")?; + assert_value(cpu.state.shadow_reg[3], (expected.de_ & 0xff) as u8, "e'")?; + assert_value(cpu.state.shadow_reg[4], (expected.hl_ >> 8) as u8, "h'")?; + assert_value(cpu.state.shadow_reg[5], (expected.hl_ & 0xff) as u8, "l'")?; + assert_value(cpu.state.shadow_reg[6], (expected.af_ >> 8) as u8, "a'")?; + assert_value(cpu.state.shadow_reg[7], (expected.af_ & 0xff) as u8, "f'")?; + + assert_value(cpu.state.ix, expected.ix, "ix")?; + assert_value(cpu.state.iy, expected.iy, "iy")?; + assert_value(cpu.state.sp, expected.sp, "sp")?; + assert_value(cpu.state.pc, expected.pc, "pc")?; + + let addr_mask = cpu.port.address_mask(); + + // Load data bytes into memory + for (addr, byte) in expected.ram.iter() { + let actual = system.get_bus().read_u8(system.clock, *addr as Address & addr_mask)?; + assert_value(actual, *byte, &format!("ram at {:x}", addr))?; + } + + Ok(()) +} + +fn step_cpu_and_assert(cpu: &mut Z80, system: &System, case: &TestCase) -> Result<(), Error> { + let _clock_elapsed = cpu.step(&system)?; + + assert_state(&cpu, &system, &case.final_state)?; + + Ok(()) +} + +fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> { + let (mut cpu, system) = init_execute_test(Z80Type::Z80, &case.initial_state).unwrap(); + let mut initial_cpu = cpu.clone(); + + let result = step_cpu_and_assert(&mut cpu, &system, case); + + match result { + Ok(()) => Ok(()), + Err(err) => { + if !args.quiet { + if args.debug { + case.dump(); + println!(""); + initial_cpu.dump_state(system.clock); + cpu.dump_state(system.clock); + } + println!("FAILED: {}", err.msg); + } + Err(err) + }, + } +} + +fn test_json_file(path: PathBuf, args: &Args) -> (usize, usize, String) { + let extension = path.extension().unwrap(); + + let cases: Vec = 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 mut case in cases { + if let Some(only) = args.only.as_ref() { + if !case.name.ends_with(only) { + continue; + } + } + + // Sort the ram memory for debugging help + if args.debug { + case.initial_state.ram.sort_by_key(|(addr, _)| *addr); + case.final_state.ram.sort_by_key(|(addr, _)| *addr); + } + + if !args.quiet { + println!("Running test {}", case.name); + } + let result = run_test(&case, args); + + if let Err(err) = result { + failed += 1; + if !args.quiet { + println!("FAILED: {:?}", err); + } + } else { + passed += 1 + } + } + + let name = path.file_name().unwrap().to_str().unwrap(); + let message = if failed == 0 { + format!("{} completed, all passed!", name) + } else { + format!("{} completed: {} passed, {} FAILED", name, passed, failed) + }; + + (passed, failed, message) +} + + +fn run_all_tests(args: &Args) { + let mut passed = 0; + let mut failed = 0; + let mut messages = vec![]; + + + let mut tests: Vec = fs::read_dir(&args.testsuite) + .unwrap() + .map(|dirent| dirent.unwrap().path()) + .collect(); + tests.sort(); + + let start = SystemTime::now(); + for path in tests { + // Only test gzip files (the repo has .md files as well) + let extension = path.extension().unwrap(); + if extension != "json" && extension != "gz" { + continue; + } + + // If specified, only test files that start with a given string + if let Some(filter) = &args.filter { + if !path.file_name().unwrap().to_str().unwrap().starts_with(filter) { + continue; + } + } + + // Run every test in the file + 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 args.quiet { + println!("{}", message); + } + + passed += test_passed; + failed += test_failed; + messages.push(message); + } + let elapsed_secs = start.elapsed().unwrap().as_secs(); + + // Print the stored summary if not in quite mode + if !args.quiet { + for message in messages { + println!("{}", message); + } + } + + println!(""); + println!("passed: {}, failed: {}, total {:.0}%", passed, failed, ((passed as f32) / (passed as f32 + failed as f32)) * 100.0); + println!("completed in {}m {}s", elapsed_secs / 60, elapsed_secs % 60); +} + diff --git a/todo.txt b/todo.txt index cbe4762..6789bb8 100644 --- a/todo.txt +++ b/todo.txt @@ -38,7 +38,7 @@ * I think the overflowing add and subs return the original number and not the overflowed result. I might have already checked that in the m68k impl but I should check again * double check the functioning of the banked areas and register settings for Z80 coprocessor -* test the Z80 more, add tests +* test the Z80 more, add tests like jsmoo's * add opentelemetry if it can be wasm compatible, or some kind of timing for giving an average framerate * improve performance