Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run test roms #60

Merged
merged 13 commits into from
Jul 10, 2024
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ jobs:
- name: Run rustfmt
run: cargo fmt --check
- name: Unit tests
run: cargo test -- --nocapture
run: cargo test -- --include-ignored --nocapture
- name : Clippy
run: cargo clippy --all-features
25 changes: 25 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ RUSTFLAGS='--cfg=web_sys_unstable_apis' trunk serve --release

`cargo test`

Run ignored tests:

`cargo test -- --include-ignored`

## References

### Opcodes
Expand Down
3 changes: 3 additions & 0 deletions fpt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ num-traits = "0.2"
[dev-dependencies]
rstest = "0.18"

[build-dependencies]
serde = {version = "1.0", features = ["derive"]}
serde_json = "1.0"
88 changes: 88 additions & 0 deletions fpt/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process::Command;

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct Suite {
tests: Vec<Test>,
name: String,
}

#[derive(Serialize, Deserialize)]
struct Test {
id: u32,
path: String,
termination_address: String,
passing: Option<bool>,
enabled: Option<bool>,
}

fn generate_rom_tests() {
println!("cargo:rerun-if-changed=tests");
let out_dir = env::var("OUT_DIR").unwrap();
let destination = Path::new(&out_dir).join("tests.rs");
let mut test_file = File::create(destination).unwrap();

write_header(&mut test_file);
write_test(&mut test_file, "tests/rom_tests.json");
}

fn write_test(test_file: &mut File, directory: &str) {
let source = std::fs::read_to_string(directory).unwrap();
let suite: Suite = serde_json::from_str(&source).unwrap();

for test in suite.tests {
if test.enabled.is_some() && !test.enabled.unwrap() {
continue;
}
let test_name = format!("{}_{}", suite.name, test.id);

write!(
test_file,
include_str!("./tests/templates/test"),
name = test_name,
path = test.path,
termination_address = test.termination_address,
passing = if test.passing.unwrap_or(true) {
"true"
} else {
"false"
},
)
.unwrap();
}
}

fn write_header(test_file: &mut File) {
write!(test_file, include_str!("./tests/templates/header")).unwrap();
}

fn run_cmd(cmd: &str) -> String {
let output = Command::new("sh")
.arg("-c")
.arg(cmd)
.output()
.expect("failed to execute process");
if !output.status.success() {
panic!("Command {} failed with exit code: {}", cmd, output.status);
}
String::from_utf8(output.stdout).expect("Failed to convert output to string")
}

fn fetch_mooneye_test_roms() {
println!("cargo:rerun-if-changed=build.rs");
run_cmd("curl -L --create-dirs --output-dir ../target/tmp -O https://gekkio.fi/files/mooneye-test-suite/mts-20240127-1204-74ae166/mts-20240127-1204-74ae166.tar.xz");
run_cmd("mkdir -p ../target/test_roms");
run_cmd("tar -xvf ../target/tmp/mts-20240127-1204-74ae166.tar.xz -C ../target/test_roms");
run_cmd("rm -rf ../target/test_roms/mooneye");
run_cmd("mv ../target/test_roms/mts-20240127-1204-74ae166 ../target/test_roms/mooneye");
}

fn main() {
generate_rom_tests();
fetch_mooneye_test_roms();
}
22 changes: 22 additions & 0 deletions fpt/src/debug_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,25 @@ impl Watchpoint {
}
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Instrpoint {
pub opcode: u16,
pub triggered: bool,
}

impl Instrpoint {
pub fn new(opcode: u16, triggered: bool) -> Self {
Self { opcode, triggered }
}
}

#[derive(Debug)]
pub enum DebugCmd {
Pause,
Continue,
Breakpoint(u16),
Watchpoint(u16),
Instrpoint(u16),
Load(String),
ListBreakpoints,
ListWatchpoints,
Expand All @@ -43,10 +56,12 @@ pub enum DebugEvent {
Continue,
RegisterBreakpoint(u16),
RegisterWatchpoint(u16),
RegisterInstrpoint(u16),
ListBreakpoints(Vec<Breakpoint>),
ListWatchpoints(Vec<Watchpoint>),
Breakpoint(u16),
Watchpoint(u16, u16),
Instrpoint(u16),
}

impl fmt::Display for DebugEvent {
Expand All @@ -60,6 +75,9 @@ impl fmt::Display for DebugEvent {
DebugEvent::RegisterWatchpoint(addr) => {
writeln!(f, "Register watchpoint at address {:#04X}", addr)
}
DebugEvent::RegisterInstrpoint(opcode) => {
writeln!(f, "Register instrpoint with opcode {:#04X}", opcode)
}
DebugEvent::ListBreakpoints(breakpoints) => {
writeln!(f, "breakpoints:")?;
for (i, breakpoint) in breakpoints.iter().enumerate() {
Expand All @@ -86,6 +104,10 @@ impl fmt::Display for DebugEvent {
)?;
Ok(())
}
DebugEvent::Instrpoint(opcode) => {
writeln!(f, "Hit instrpoint at {:#06X}", opcode)?;
Ok(())
}
}
}
}
Expand Down
34 changes: 33 additions & 1 deletion fpt/src/debugger.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::collections::VecDeque;

use crate::debug_interface::{Breakpoint, DebugCmd, DebugEvent, Watchpoint};
use crate::debug_interface::{Breakpoint, DebugCmd, DebugEvent, Instrpoint, Watchpoint};

#[derive(Clone, PartialEq)]
pub struct Debugger {
breakpoints: Vec<Breakpoint>,
watchpoints: Vec<Watchpoint>,
instrpoints: Vec<Instrpoint>,
pub paused: bool,
dbg_events: VecDeque<DebugEvent>,
}
Expand All @@ -21,6 +22,7 @@ impl Debugger {
Self {
breakpoints: Vec::new(),
watchpoints: Vec::new(),
instrpoints: Vec::new(),
paused: false,
dbg_events: VecDeque::new(),
}
Expand All @@ -47,6 +49,13 @@ impl Debugger {
self.watchpoints.push(Watchpoint { addr: *addr });
Some(DebugEvent::RegisterWatchpoint(*addr))
}
DebugCmd::Instrpoint(instruction) => {
self.instrpoints.push(Instrpoint {
opcode: *instruction,
triggered: false,
});
Some(DebugEvent::RegisterInstrpoint(*instruction))
}
DebugCmd::ListBreakpoints => {
Some(DebugEvent::ListBreakpoints(self.breakpoints.clone()))
}
Expand All @@ -57,6 +66,29 @@ impl Debugger {
}
}

pub fn match_instrpoint(&mut self, opcode: u16) -> bool {
let instrpoint = self.instrpoints.iter_mut().find(|i| i.opcode == opcode);
let is_instrpoint = instrpoint.is_some();

let triggered = false;

if instrpoint.is_some() {
let instrpoint = instrpoint.unwrap();
if instrpoint.triggered {
instrpoint.triggered = false;
} else {
instrpoint.triggered = true;
self.paused = true;
}
}

if self.paused {
self.dbg_events.push_back(DebugEvent::Instrpoint(opcode));
}

is_instrpoint && !triggered
}

pub fn match_breakpoint(&mut self, pc: u16) -> bool {
let breakpoint = self.breakpoints.iter_mut().find(|b| b.pc == pc);

Expand Down
3 changes: 1 addition & 2 deletions fpt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

use std::collections::VecDeque;

use debug_interface::DebugEvent;
pub use debug_interface::{DebugCmd, DebugInterface};
pub use debug_interface::{DebugCmd, DebugEvent, DebugInterface};
use lr35902::LR35902;
use memory::{Bus, Buttons};
use ppu::{Frame, Ppu, DOTS_IN_ONE_FRAME};
Expand Down
5 changes: 4 additions & 1 deletion fpt/src/lr35902.rs
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,9 @@ impl LR35902 {
if self.debugger.match_breakpoint(self.pc()) {
return;
}
if self.debugger.match_instrpoint(inst.opcode) {
return;
}
self.execute(inst);
if !self.mutated_pc() {
self.set_pc(self.pc() + inst.size as u16);
Expand Down Expand Up @@ -1251,7 +1254,7 @@ impl LR35902 {
// HALT
// Take care for halt bug: https://gbdev.io/pandocs/halt.html
// https://rgbds.gbdev.io/docs/v0.6.1/gbz80.7/#HALT
//todo!("0x76 HALT")
todo!("0x76 HALT")
}
0x77 => {
// LD (HL),A
Expand Down
7 changes: 0 additions & 7 deletions fpt/src/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,6 @@ impl Timer {
let tac = self.get_tac();
let tma = self.get_tma();

if (div + 1) % 4 == 0 {
println!(
"self.div: {}, self.tima: {}, self.tac: {}, self.tma: {}",
div, tima, tac, tma
);
}

self.sys = self.sys.overflowing_add(1).0;

let enable = bw::test_bit8::<2>(tac);
Expand Down
Loading