Skip to content

Commit 79686df

Browse files
committed
basic emulator testing framework
1 parent d49df68 commit 79686df

File tree

4 files changed

+96
-10
lines changed

4 files changed

+96
-10
lines changed

tests/src/labels.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,29 @@ fn labels() -> &'static HashMap<String, u16> {
2020
})
2121
}
2222

23+
fn addrs() -> &'static HashMap<u16, String> {
24+
static LABELS: OnceLock<HashMap<u16, String>> = OnceLock::new();
25+
LABELS.get_or_init(|| {
26+
let text = include_str!("../../tetris.lbl");
27+
let mut labels: HashMap<u16, String> = HashMap::new();
28+
29+
for line in text.lines() {
30+
let parts: Vec<&str> = line.split_whitespace().collect();
31+
if parts.len() >= 2 {
32+
if let Ok(hex_value) = u16::from_str_radix(parts[1], 16) {
33+
labels.insert(hex_value, parts[2].to_string());
34+
}
35+
}
36+
}
37+
38+
labels
39+
})
40+
}
41+
2342
pub fn get(label: &str) -> u16 {
2443
*labels().get(label).expect(&format!("label {} not found", label))
2544
}
45+
46+
pub fn from_addr(addr: u16) -> Option<&'static String> {
47+
addrs().get(&addr)
48+
}

tests/src/main.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
1-
use rusticnes_core::nes::NesState;
2-
use rusticnes_core::cartridge;
3-
41
mod labels;
2+
mod util;
53

6-
fn main() {
7-
let rom = include_bytes!("../../tetris.nes");
8-
let mut emu = NesState::new(Box::new(cartridge::mapper_from_file(rom)).unwrap());
9-
10-
emu.registers.pc = labels::get(".addPushDownPoints");
4+
// tests
5+
mod pushdown;
116

12-
// set pc
13-
// set stackpointer to something absurd
7+
fn main() {
8+
pushdown::test();
149
}

tests/src/pushdown.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// reference implementation - tested against the original game
2+
fn pushdown(pushdown: u8, score: u16) -> u16 {
3+
let ones = score % 10;
4+
let hundredths = score % 100;
5+
let mut newscore = ones as u8 + (pushdown - 1);
6+
if newscore & 0xF > 9 {
7+
newscore += 6;
8+
}
9+
10+
let low = (newscore & 0xF) as u16;
11+
let high = ((newscore & 0xF0) / 16 * 10) as u16;
12+
13+
let mut newscore = high + (hundredths - ones);
14+
let nextscore = newscore + low;
15+
16+
if nextscore <= 100 {
17+
newscore = nextscore;
18+
}
19+
20+
newscore + (score-hundredths) - score
21+
}
22+
23+
use crate::{ labels, util };
24+
25+
pub fn test() {
26+
let mut emu = util::emulator(None);
27+
28+
emu.registers.pc = labels::get(".addPushDownPoints");
29+
30+
util::run_to_return(&mut emu);
31+
}

tests/src/util.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use rusticnes_core::nes::NesState;
2+
use rusticnes_core::{ cartridge, opcodes, opcode_info };
3+
use crate::labels;
4+
5+
pub fn emulator(rom: Option<&[u8]>) -> NesState {
6+
let rom = rom.unwrap_or(include_bytes!("../../tetris.nes"));
7+
let mut emu = NesState::new(Box::new(cartridge::mapper_from_file(rom)).unwrap());
8+
9+
emu.power_on();
10+
11+
emu
12+
}
13+
14+
pub fn run_to_return(emu: &mut NesState) {
15+
opcodes::push(emu, 0);
16+
opcodes::push(emu, 0);
17+
18+
loop {
19+
print_step(emu);
20+
21+
if emu.registers.pc < 3 {
22+
break;
23+
}
24+
}
25+
}
26+
27+
pub fn print_step(emu: &mut NesState) {
28+
if let Some(label) = labels::from_addr(emu.registers.pc) {
29+
println!("{}:", label);
30+
}
31+
32+
print!("{:x} ", emu.registers.pc);
33+
34+
emu.step();
35+
36+
println!("{}", opcode_info::disassemble_instruction(emu.cpu.opcode, 0, 0).0);
37+
}

0 commit comments

Comments
 (0)