WIP
richer test suite Updates imgui to have target ips and limits correctly. Initial IPS = 1000, plan to expose to user More tests for encode/decode of instructions Adding text to instruction parsing
This commit is contained in:
+333
-8
@@ -1,8 +1,10 @@
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use log::debug;
|
||||
use rand::random;
|
||||
use gemma::chip8::computer::Chip8Computer;
|
||||
use gemma::chip8::delay_timer::DelayTimer;
|
||||
use gemma::chip8::instructions::Chip8CpuInstructions;
|
||||
use gemma::chip8::instructions::Chip8CpuInstructions::JPA;
|
||||
use gemma::chip8::keypad::Keypad;
|
||||
use gemma::chip8::registers::Chip8Registers;
|
||||
use gemma::chip8::sound_timer::SoundTimer;
|
||||
@@ -11,7 +13,7 @@ use gemma::chip8::util::InstructionUtil;
|
||||
use gemma::chip8::video::Chip8Video;
|
||||
use gemma::constants::*;
|
||||
|
||||
const TEST_OUTPUT_SAMPLE_DIR: &str = "/home/tmerritt/Projects/trevors_chip8_toy/resources/test/";
|
||||
const TEST_OUTPUT_SAMPLE_DIR: &str = "/home/tmerritt/Projects/chip8_toy/resources/test/";
|
||||
|
||||
fn read_test_result(suffix: &str) -> String {
|
||||
std::fs::read_to_string(TEST_OUTPUT_SAMPLE_DIR.to_owned() + suffix)
|
||||
@@ -54,7 +56,7 @@ fn encode_decode_test() {
|
||||
assert_eq!(Chip8CpuInstructions::LDRD(0x1).encode(), 0xf107);
|
||||
assert_eq!(Chip8CpuInstructions::LDRK(0x4).encode(), 0xf40a);
|
||||
assert_eq!(Chip8CpuInstructions::LDD(0x6).encode(), 0xf615);
|
||||
assert_eq!(Chip8CpuInstructions::LDI_S(0xb).encode(), 0xfb18);
|
||||
assert_eq!(Chip8CpuInstructions::LDIS(0xb).encode(), 0xfb18);
|
||||
assert_eq!(Chip8CpuInstructions::ADDI(0xd).encode(), 0xfd1e);
|
||||
assert_eq!(Chip8CpuInstructions::LDFX(0xc).encode(), 0xfc29);
|
||||
assert_eq!(Chip8CpuInstructions::BCD(0xd).encode(), 0xfd33);
|
||||
@@ -110,7 +112,7 @@ fn encode_decode_test() {
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xf107), Chip8CpuInstructions::LDRD(0x1)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xf40a), Chip8CpuInstructions::LDRK(0x4)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xf615), Chip8CpuInstructions::LDD(0x6)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xfb18), Chip8CpuInstructions::LDI_S(0xb)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xfb18), Chip8CpuInstructions::LDIS(0xb)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xfd1e), Chip8CpuInstructions::ADDI(0xd)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xfc29), Chip8CpuInstructions::LDFX(0xc)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xfd33), Chip8CpuInstructions::BCD(0xd)));
|
||||
@@ -334,7 +336,7 @@ fn addivx_test() {
|
||||
fn ldstvt_test() {
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x1, 0xf0);
|
||||
Chip8CpuInstructions::LDI_S(0x01).execute(&mut x);
|
||||
Chip8CpuInstructions::LDIS(0x01).execute(&mut x);
|
||||
assert_eq!(x.sound_timer.current(), 0xf0);
|
||||
x.sound_timer.tick();
|
||||
x.sound_timer.tick();
|
||||
@@ -565,7 +567,6 @@ fn subn_vx_vy_test() {
|
||||
assert_eq!(x.registers.peek_pc(), 0x206);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn draw_nibble_vx_vy_n_test_hd() {
|
||||
let mut x = Chip8Computer::new();
|
||||
|
||||
@@ -770,6 +771,15 @@ fn keypad_keys_check() {
|
||||
assert!(k.released(1));
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn keypad_string_format_test() {
|
||||
let mut k = Keypad::new();
|
||||
|
||||
|
||||
assert_eq!(k.format_as_string(), read_test_result("gemma_keypad_string_result.asc"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn register_rw_test() {
|
||||
let mut x = Chip8Registers::default();
|
||||
@@ -853,7 +863,7 @@ fn stack_push_pop_test() {
|
||||
#[should_panic]
|
||||
fn stack_overflow_test() {
|
||||
let mut x = Chip8Stack::new();
|
||||
for i in 0..17 {
|
||||
for i in 0..17 {
|
||||
x.push(&i);
|
||||
}
|
||||
}
|
||||
@@ -894,7 +904,6 @@ fn stack_lots_of_subs() {
|
||||
}
|
||||
assert_eq!(x.depth(), 15);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -945,7 +954,6 @@ fn instruction_byte_to_bool_changes() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn real_build_checkboard(in_hd: bool) -> Chip8Video {
|
||||
let mut r = Chip8Video::default();
|
||||
let (width, height) = if in_hd {
|
||||
@@ -1318,3 +1326,320 @@ fn video_scroll_right_4_row_test_high_def() {
|
||||
x.scroll_right();
|
||||
assert_eq!(read_test_result("test_scroll_right_4_hd.asc"), x.format_as_string());
|
||||
}
|
||||
|
||||
struct InstructionTest {
|
||||
name: String,
|
||||
instruction: Chip8CpuInstructions,
|
||||
asm: String,
|
||||
encoded: u16,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instructions_name_tests() {
|
||||
assert_eq!(Chip8CpuInstructions::SYS(0x0000).name(), INST_SYS);
|
||||
assert_eq!(Chip8CpuInstructions::ADD(0x0, 0x1).name(), INST_ADD);
|
||||
assert_eq!(Chip8CpuInstructions::ADDI(0x0).name(), INST_ADDI);
|
||||
assert_eq!(Chip8CpuInstructions::ADDR(0x01, 0x02).name(), INST_ADDR);
|
||||
assert_eq!(Chip8CpuInstructions::AND(0x01, 0x02).name(), INST_AND);
|
||||
|
||||
let it = vec![
|
||||
InstructionTest {
|
||||
name: INST_SYS.to_string(),
|
||||
instruction: Chip8CpuInstructions::SYS(0x123),
|
||||
asm: "SYS 0x0123".to_string(),
|
||||
encoded: 0x0123
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_CLS.to_string(),
|
||||
instruction: Chip8CpuInstructions::CLS,
|
||||
asm: "CLS".to_string(),
|
||||
encoded: 0x00E0
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_RET.to_string(),
|
||||
instruction: Chip8CpuInstructions::RET,
|
||||
asm: "RET".to_string(),
|
||||
encoded: 0x00ee
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_JPA.to_string(),
|
||||
instruction: JPA(0x234),
|
||||
asm: "JPA 0x0234".to_string(),
|
||||
encoded: 0xb234
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_CALL.to_string(),
|
||||
instruction: Chip8CpuInstructions::CALL(0x123),
|
||||
asm: "CALL 0x0123".to_string(),
|
||||
encoded: 0x2123,
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_DRW.to_string(),
|
||||
instruction: Chip8CpuInstructions::DRW(0x01, 0x02, 0x03),
|
||||
asm: "DRW 0x01, 0x02, 0x03".to_string(),
|
||||
encoded: 0xd123
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_JPI.to_string(),
|
||||
instruction: Chip8CpuInstructions::JPI(0x321),
|
||||
asm: "JPI 0x0321".to_string(),
|
||||
encoded: 0xb321
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_SDN.to_string(),
|
||||
instruction: Chip8CpuInstructions::SDN(0x01),
|
||||
asm: "SDN 0x01".to_string(),
|
||||
encoded: 0x00c1
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_SRT.to_string(),
|
||||
instruction: Chip8CpuInstructions::SRT,
|
||||
asm: "SRT".to_string(),
|
||||
encoded: 0x00FB
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_SLF.to_string(),
|
||||
instruction: Chip8CpuInstructions::SLF,
|
||||
asm: "SLF".to_string(),
|
||||
encoded: 0x00FC,
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_EXIT.to_string(),
|
||||
instruction: Chip8CpuInstructions::EXIT,
|
||||
asm: "EXIT".to_string(),
|
||||
encoded: 0x00FD,
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_DIS.to_string(),
|
||||
instruction: Chip8CpuInstructions::DIS,
|
||||
asm: "DIS".to_string(),
|
||||
encoded: 0x00FE,
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_ENA.to_string(),
|
||||
instruction: Chip8CpuInstructions::ENA,
|
||||
asm: "ENA".to_string(),
|
||||
encoded: 0x00FF,
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_SEX.to_string(),
|
||||
instruction: Chip8CpuInstructions::SEX(0x01, 0xfa),
|
||||
asm: "SEX 0x01, 0xfa".to_string(),
|
||||
encoded: 0x32fa,
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_SNEB.to_string(),
|
||||
instruction: Chip8CpuInstructions::SNEB(0x01, 0xab),
|
||||
asm: "SNEB 0x01, 0xab".to_string(),
|
||||
encoded: 0x41ab,
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_SEY.to_string(),
|
||||
instruction: Chip8CpuInstructions::SEY(0x1, 0x2),
|
||||
asm: "SEY 0x1, 0x2".to_string(),
|
||||
encoded: 0x5120
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_LDR.to_string(),
|
||||
instruction: Chip8CpuInstructions::LDR(0xa, 0xbe),
|
||||
asm: "LDR 0x0a, 0xbe".to_string(),
|
||||
encoded: 0x6abe,
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_ADD.to_string(),
|
||||
instruction: Chip8CpuInstructions::ADD(0x01, 0xab),
|
||||
asm: "ADD 0x01, 0xab".to_string(),
|
||||
encoded: 0x71ab
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_LDRY.to_string(),
|
||||
instruction: Chip8CpuInstructions::LDR_Y(0x1, 0x2),
|
||||
asm: "LDRY 0x1, 0x2".to_string(),
|
||||
encoded: 0x8120,
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_OR.to_string(),
|
||||
instruction: Chip8CpuInstructions::OR(0x1, 0x2),
|
||||
asm: "OR 0x1, 0x2".to_string(),
|
||||
encoded: 0x8121
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_AND.to_string(),
|
||||
instruction: Chip8CpuInstructions::AND(0xb, 0xc),
|
||||
asm: "AND 0xb, 0xc".to_string(),
|
||||
encoded: 0x8bc2,
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_ORY.to_string(),
|
||||
instruction: Chip8CpuInstructions::ORY(0xa, 0x3),
|
||||
asm: "ORY 0xa, 0x3".to_string(),
|
||||
encoded: 0x8a33
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_ADDR.to_string(),
|
||||
instruction: Chip8CpuInstructions::ADDR(0x1, 0x2),
|
||||
asm: "ADDR 0x1, 0x2".to_string(),
|
||||
encoded: 0x8124
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_SUB.to_string(),
|
||||
instruction: Chip8CpuInstructions::SUB(0x4, 0x5),
|
||||
asm: "SUB 0x4, 0x5".to_string(),
|
||||
encoded: 0x8455
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_SHR.to_string(),
|
||||
instruction: Chip8CpuInstructions::SHR(0x01, 0x1),
|
||||
asm: "SHR 0x1, 0x1".to_string(),
|
||||
encoded: 0x8116,
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_SUBC.to_string(),
|
||||
instruction: Chip8CpuInstructions::SUBC(0xf, 0xa),
|
||||
asm: "SUBC 0xf, 0xa".to_string(),
|
||||
encoded: 0x8fa7,
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_SHL.to_string(),
|
||||
instruction: Chip8CpuInstructions::SHL(0x1, 0x4),
|
||||
asm: "SHL 0x1, 0x4".to_string(),
|
||||
encoded: 0x814e,
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_SNEY.to_string(),
|
||||
instruction: Chip8CpuInstructions::SNEY(0x4, 0x5),
|
||||
asm: "SNEY 0x4, 0x5".to_string(),
|
||||
encoded: 0x9450,
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_LDIA.to_string(),
|
||||
instruction: Chip8CpuInstructions::LDIA(0xbee),
|
||||
asm: "LDIA 0x0bee".to_string(),
|
||||
encoded: 0x9bee
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_JPI.to_string(),
|
||||
instruction: Chip8CpuInstructions::JPI(0xfee),
|
||||
asm: "JPI 0x0fee".to_string(),
|
||||
encoded: 0xbfee
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_RND.to_string(),
|
||||
instruction: Chip8CpuInstructions::RND(0x1, 0xae),
|
||||
asm: "RND 0x01, 0xae".to_string(),
|
||||
encoded: 0xc1ae,
|
||||
},
|
||||
InstructionTest {
|
||||
name: INST_DRW.to_string(),
|
||||
instruction: Chip8CpuInstructions::DRW(0x1, 0x2, 0xf),
|
||||
asm: "DRW 0x01, 0x02, 0x0f".to_string(),
|
||||
encoded: 0xd12f
|
||||
}
|
||||
/*
|
||||
0xE09E..=0xEFA1 => match last_byte {
|
||||
0x9E => Chip8CpuInstructions::SKP(ubln),
|
||||
0xA1 => Chip8CpuInstructions::SKNP(ubln),
|
||||
0xF007..=0xFF65 => match last_byte {
|
||||
0x07 => Chip8CpuInstructions::LDRD(ubln),
|
||||
0x0A => Chip8CpuInstructions::LDRK(ubln),
|
||||
0x15 => Chip8CpuInstructions::LDD(ubln),
|
||||
0x18 => Chip8CpuInstructions::LDIS(ubln),
|
||||
0x1E => Chip8CpuInstructions::ADDI(ubln),
|
||||
0x29 => Chip8CpuInstructions::LDFX(ubln),
|
||||
0x30 => Chip8CpuInstructions::LDF2(ubln),
|
||||
0x33 => Chip8CpuInstructions::BCD(ubln),
|
||||
0x55 => Chip8CpuInstructions::LDIX(ubln),
|
||||
0x65 => Chip8CpuInstructions::LDRI(ubln),
|
||||
0x75 => Chip8CpuInstructions::STR(ubln),
|
||||
0x85 => Chip8CpuInstructions::LIDR(ubln),
|
||||
|
||||
*/
|
||||
];
|
||||
|
||||
for current in it {
|
||||
assert_eq!(current.instruction.name(), current.name);
|
||||
let i = current.instruction;
|
||||
assert!(matches!(Chip8CpuInstructions::decode(current.encoded), i));
|
||||
assert_eq!(i.to_string(), current.asm);
|
||||
let asm = Chip8CpuInstructions::from_str(¤t.asm);
|
||||
assert_eq!(i.to_string(), asm.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instructions_operands_tests() {
|
||||
assert_eq!(Chip8CpuInstructions::SYS(0x000).operands(), "0x0000");
|
||||
assert_eq!(Chip8CpuInstructions::JPI(0x123).operands(), "0x0123");
|
||||
assert_eq!(Chip8CpuInstructions::JPA(0x234).operands(), "0x0234");
|
||||
assert_eq!(Chip8CpuInstructions::LDIA(0x345).operands(), "0x0345");
|
||||
assert_eq!(Chip8CpuInstructions::CALL(0x456).operands(), "0x0456");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_ena_dis_tests() {
|
||||
let mut x = Chip8Computer::new();
|
||||
assert!(!x.video_memory.is_highres());
|
||||
Chip8CpuInstructions::ENA.execute(&mut x);
|
||||
assert!(x.video_memory.is_highres());
|
||||
Chip8CpuInstructions::ENA.execute(&mut x);
|
||||
assert!(x.video_memory.is_highres());
|
||||
Chip8CpuInstructions::DIS.execute(&mut x);
|
||||
assert!(!x.video_memory.is_highres());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_test_scrolling_lowres() {
|
||||
let mut x = Chip8Computer::new();
|
||||
x.video_memory = build_checkerboard();
|
||||
Chip8CpuInstructions::SRT.execute(&mut x);
|
||||
|
||||
assert_eq!(read_test_result("test_scroll_right_4.asc"), x.dump_video_to_string());
|
||||
|
||||
x = Chip8Computer::new();
|
||||
x.video_memory = build_checkerboard();
|
||||
Chip8CpuInstructions::SLF.execute(&mut x);
|
||||
|
||||
assert_eq!(read_test_result("test_scroll_left_4.asc"), x.dump_video_to_string());
|
||||
|
||||
x = Chip8Computer::new();
|
||||
x.video_memory = build_checkerboard();
|
||||
Chip8CpuInstructions::SDN(0x01).execute(&mut x);
|
||||
assert_eq!(read_test_result("test_video_scroll_down_1.asc"), x.dump_video_to_string());
|
||||
|
||||
x = Chip8Computer::new();
|
||||
x.video_memory = build_checkerboard();
|
||||
Chip8CpuInstructions::SDN(0xA).execute(&mut x);
|
||||
assert_eq!(read_test_result("test_video_scroll_down_10.asc"), x.dump_video_to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn computer_dump_keypad_to_string() {
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn computer_dump_registers_to_string() {
|
||||
let mut x = Chip8Computer::new();
|
||||
let values_to_set = [0x0b, 0xad, 0xbe, 0xef,
|
||||
0xca, 0xb0,
|
||||
0x7a, 0xc0, 0xca, 0x70,
|
||||
0xba, 0xdb, 0xed, 0x00,
|
||||
0x00, 0x00
|
||||
];
|
||||
let expected_value = "Vx: 0x0b 0xad 0xbe 0xef 0xca 0xb0 0x7a 0xc0\n 0xca 0x70 0xba 0xdb 0xed 0x00 0x00 0x00\nI: 0x0000\tPC: 0x0200";
|
||||
|
||||
for i in 0..16 {
|
||||
x.registers.poke(i, values_to_set[i as usize]);
|
||||
}
|
||||
|
||||
// now verify.
|
||||
assert_eq!(expected_value, x.dump_registers_to_string());
|
||||
}
|
||||
|
||||
//#[test]
|
||||
fn quirks_chip8_vf_reset_tests() {
|
||||
// vF reset - The AND, OR and XOR opcodes (8xy1, 8xy2 and 8xy3) reset the flags
|
||||
// register to zero. Test will show ERR1 if the AND and OR tests don't behave
|
||||
// the same and ERR2 if the AND and XOR tests don't behave the same.
|
||||
let mut x = Chip8Computer::new();
|
||||
}
|
||||
Reference in New Issue
Block a user