move tests to unit_tests to clean up individual files
adds start of font characters
This commit is contained in:
parent
e29ac45c84
commit
1694157e27
@ -28,34 +28,3 @@ impl DelayTimer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::chip8::sound_timer::SoundTimer;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn smoke() {
|
||||
assert!(true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ticks_reduce_time() {
|
||||
let mut st = DelayTimer::new();
|
||||
st.set_timer(100);
|
||||
st.tick();
|
||||
st.tick();
|
||||
st.tick();
|
||||
assert_eq!(st.current(), 97);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn out_of_ticks_works() {
|
||||
let mut st = DelayTimer::new();
|
||||
st.set_timer(0);
|
||||
st.tick();
|
||||
st.tick();
|
||||
st.tick();
|
||||
assert_eq!(st.current(), 0);
|
||||
}
|
||||
}
|
||||
@ -735,12 +735,29 @@ impl Chip8CpuInstructions {
|
||||
let source_memory_offset = input.registers.peek_i();
|
||||
let x_offset = input.registers.peek(*x) as u16;
|
||||
let y_offset = input.registers.peek(*y) as u16;
|
||||
|
||||
for byte_index in 0..*n {
|
||||
let current_byte = input.memory.peek(byte_index as u16 + source_memory_offset);
|
||||
let x_offset: u16 = (x_offset + byte_index as u16) * 64;
|
||||
for bit_index in 0..8 {
|
||||
input.video_memory.poke(x_offset + (y_offset + bit_index as u16), (current_byte & (0x80 >> bit_index)) != 0);
|
||||
if input.video_memory.is_highres() {
|
||||
// if n == 0 we have a 16 row sprite (font maybe)
|
||||
let actual_num_loops = if *n == 0u8 {
|
||||
16
|
||||
} else {
|
||||
*n
|
||||
};
|
||||
for byte_index in 0..actual_num_loops {
|
||||
let current_byte = input.memory.peek(byte_index as u16 + source_memory_offset);
|
||||
let next_byte = input.memory.peek(byte_index as u16 + 1u16 + source_memory_offset);
|
||||
let x_offset = (x_offset + byte_index as u16) * 64;
|
||||
for bit_index in 0..8 {
|
||||
input.video_memory.poke(x_offset + (y_offset + bit_index as u16), (current_byte & (0x80 >> bit_index)) != 0);
|
||||
input.video_memory.poke(x_offset + (y_offset + bit_index as u16) + 8, (current_byte & (0x80 >> bit_index)) != 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for byte_index in 0..*n {
|
||||
let current_byte = input.memory.peek(byte_index as u16 + source_memory_offset);
|
||||
let x_offset: u16 = (x_offset + byte_index as u16) * 64;
|
||||
for bit_index in 0..8 {
|
||||
input.video_memory.poke(x_offset + (y_offset + bit_index as u16), (current_byte & (0x80 >> bit_index)) != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -921,766 +938,3 @@ impl Chip8CpuInstructions {
|
||||
Chip8CpuInstructions::XXXXERRORINSTRUCTION
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::chip8::system_memory::{*};
|
||||
use crate::constants::CHIP8_VIDEO_MEMORY;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn smoke() {
|
||||
assert!(true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn encode_decode_test() {
|
||||
assert_eq!(Chip8CpuInstructions::CLS.encode(), 0x00E0);
|
||||
assert_eq!(Chip8CpuInstructions::RET.encode(), 0x00EE);
|
||||
assert_eq!(Chip8CpuInstructions::SYS(0x123).encode(), 0x0123);
|
||||
assert_eq!(Chip8CpuInstructions::JPA(0x234).encode(), 0x1234);
|
||||
assert_eq!(Chip8CpuInstructions::CALL(0x345).encode(), 0x2345);
|
||||
assert_eq!(Chip8CpuInstructions::SEX(0x4, 0x56).encode(), 0x3456);
|
||||
assert_eq!(Chip8CpuInstructions::SNEB(0xa, 0xbc).encode(), 0x4abc);
|
||||
assert_eq!(Chip8CpuInstructions::SEY(0xa, 0xb).encode(), 0x5ab0);
|
||||
assert_eq!(Chip8CpuInstructions::LDR(0xa, 0xff).encode(), 0x6aff);
|
||||
assert_eq!(Chip8CpuInstructions::ADD(0xa, 0xbc).encode(), 0x7abc);
|
||||
assert_eq!(Chip8CpuInstructions::LDR_Y(0xa, 0xb).encode(), 0x8ab0);
|
||||
assert_eq!(Chip8CpuInstructions::OR(0xb, 0xa).encode(), 0x8ba1);
|
||||
assert_eq!(Chip8CpuInstructions::AND(0xc, 0xd).encode(), 0x8cd2);
|
||||
assert_eq!(Chip8CpuInstructions::ORY(0xd, 0xe).encode(), 0x8de3);
|
||||
assert_eq!(Chip8CpuInstructions::ADDR(0xe, 0xf).encode(), 0x8ef4);
|
||||
assert_eq!(Chip8CpuInstructions::SUB(0xf, 0x0).encode(), 0x8f05);
|
||||
assert_eq!(Chip8CpuInstructions::SHR(0x0, 0x1).encode(), 0x8016);
|
||||
assert_eq!(Chip8CpuInstructions::SUBC(0x1, 0x2).encode(), 0x8127);
|
||||
assert_eq!(Chip8CpuInstructions::SHL(0x3, 0x4).encode(), 0x834e);
|
||||
assert_eq!(Chip8CpuInstructions::SNEY(0xa, 0xb).encode(), 0x9ab0);
|
||||
assert_eq!(Chip8CpuInstructions::LDIA(0x123).encode(), 0xa123);
|
||||
assert_eq!(Chip8CpuInstructions::JPI(0x234).encode(), 0xb234);
|
||||
assert_eq!(Chip8CpuInstructions::RND(0xa, 0xca).encode(), 0xcaca);
|
||||
assert_eq!(Chip8CpuInstructions::DRW(0xa, 0xb, 0x4).encode(), 0xdab4);
|
||||
assert_eq!(Chip8CpuInstructions::SKP(0x1).encode(), 0xe19e);
|
||||
assert_eq!(Chip8CpuInstructions::SKNP(0x2).encode(), 0xe2a1);
|
||||
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::ADDI(0xd).encode(), 0xfd1e);
|
||||
assert_eq!(Chip8CpuInstructions::LDFX(0xc).encode(), 0xfc29);
|
||||
assert_eq!(Chip8CpuInstructions::BCD(0xd).encode(), 0xfd33);
|
||||
assert_eq!(Chip8CpuInstructions::LDIX(0xe).encode(), 0xfe55);
|
||||
assert_eq!(Chip8CpuInstructions::LDRI(0x3).encode(), 0xf365);
|
||||
assert_eq!(Chip8CpuInstructions::SDN(0x1).encode(), 0x00C1);
|
||||
assert_eq!(Chip8CpuInstructions::SLF.encode(), 0x00FC);
|
||||
assert_eq!(Chip8CpuInstructions::SRT.encode(), 0x00FB);
|
||||
assert_eq!(Chip8CpuInstructions::EXIT.encode(), 0x00FD);
|
||||
assert_eq!(Chip8CpuInstructions::ENA.encode(), 0x00FF);
|
||||
assert_eq!(Chip8CpuInstructions::DIS.encode(), 0x00FE);
|
||||
assert_eq!(Chip8CpuInstructions::LDF2(0).encode(), 0xF030);
|
||||
assert_eq!(Chip8CpuInstructions::STR(1).encode(), 0xF175);
|
||||
assert_eq!(Chip8CpuInstructions::LIDR(1).encode(), 0xF185);
|
||||
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xF175), Chip8CpuInstructions::STR(1)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xF185), Chip8CpuInstructions::LIDR(1)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x00C1u16), Chip8CpuInstructions::SDN(0x01)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x00FCu16), Chip8CpuInstructions::SLF));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x00FBu16), Chip8CpuInstructions::SRT));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x00FDu16), Chip8CpuInstructions::EXIT));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x00FEu16), Chip8CpuInstructions::DIS));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x00FFu16), Chip8CpuInstructions::ENA));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xF030u16), Chip8CpuInstructions::LDF2(0)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x00E0u16), Chip8CpuInstructions::CLS));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x00EEu16), Chip8CpuInstructions::RET));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x0123), Chip8CpuInstructions::SYS(0x123)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x0FFF), Chip8CpuInstructions::SYS(0xfff)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x1002), Chip8CpuInstructions::JPA(0x2)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x1FF0), Chip8CpuInstructions::JPA(0xFF0)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x2002), Chip8CpuInstructions::CALL(0x2)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x3123), Chip8CpuInstructions::SEX(0x1, 0x23)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x4abc), Chip8CpuInstructions::SNEB(0xa, 0xbc)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x5ab0), Chip8CpuInstructions::SEY(0xa, 0xb)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x6aff), Chip8CpuInstructions::LDR(0xa, 0xff)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x7abc), Chip8CpuInstructions::ADD(0xa, 0xbc)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x8ab0), Chip8CpuInstructions::LDR_Y(0xa, 0xb)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x8ba1), Chip8CpuInstructions::OR(0xb, 0xa)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x8cd2), Chip8CpuInstructions::AND(0xc, 0xd)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x8de3), Chip8CpuInstructions::ORY(0xd, 0xe)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x8ef4), Chip8CpuInstructions::ADDR(0xe, 0xf)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x8f05), Chip8CpuInstructions::SUB(0xf, 0x0)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x8016), Chip8CpuInstructions::SHR(0x0, 0x1)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x8127), Chip8CpuInstructions::SUBC(0x1, 0x2)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x834e), Chip8CpuInstructions::SHL(0x3, 0x4)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0x9ab0), Chip8CpuInstructions::SNEY(0xa, 0xb)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xa123), Chip8CpuInstructions::LDIA(0x123)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xb234), Chip8CpuInstructions::JPI(0x234)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xcaca), Chip8CpuInstructions::RND(0xa, 0xca)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xdab4), Chip8CpuInstructions::DRW(0xa, 0xb, 0x4)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xe19e), Chip8CpuInstructions::SKP(0x1)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xe2a1), Chip8CpuInstructions::SKNP(0x2)));
|
||||
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(0xfd1e), Chip8CpuInstructions::ADDI(0xd)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xfc29), Chip8CpuInstructions::LDFX(0xc)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xfd33), Chip8CpuInstructions::BCD(0xd)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xfe55), Chip8CpuInstructions::LDIX(0xe)));
|
||||
assert!(matches!(Chip8CpuInstructions::decode(0xf365), Chip8CpuInstructions::LDRI(0x3)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decoder_test_invalid_instructions() {
|
||||
let invalid_to_encode = [
|
||||
0x5ab1, 0x5abf, 0x8ab8, 0x8abd, 0x8abf,
|
||||
0x9ab1, 0x9abf, 0xea9d, 0xea9f, 0xeaa0,
|
||||
0xeaa2, 0xf006, 0xf008
|
||||
];
|
||||
|
||||
for i in invalid_to_encode {
|
||||
assert_eq!(Chip8CpuInstructions::decode(i).encode(), 0xffff);
|
||||
assert!(matches!(Chip8CpuInstructions::decode(i), Chip8CpuInstructions::XXXXERRORINSTRUCTION));
|
||||
}
|
||||
}
|
||||
|
||||
/// START OF THE EXECUTION TESTS
|
||||
#[test]
|
||||
fn sys_test() {
|
||||
// 0x0nnn Exit to System Call
|
||||
let mut x = Chip8Computer::new();
|
||||
Chip8CpuInstructions::SYS(0).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0);
|
||||
|
||||
let mut x = Chip8Computer::new();
|
||||
Chip8CpuInstructions::SYS(0xFA0).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0xFA0);
|
||||
|
||||
let mut x = Chip8Computer::new();
|
||||
Chip8CpuInstructions::SYS(0x0AF).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0x0AF);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn jpaddr_test() {
|
||||
// 0x1nnn Jump to Address
|
||||
let mut x = Chip8Computer::new();
|
||||
Chip8CpuInstructions::JPA(0).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0);
|
||||
|
||||
let mut x = Chip8Computer::new();
|
||||
Chip8CpuInstructions::JPA(0xABC).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0xABC);
|
||||
}
|
||||
|
||||
// ** test moved up so it can be used later
|
||||
#[test]
|
||||
fn ld_vx_byte_test() {
|
||||
// 0x6xkk Set Vx = kk
|
||||
let mut x = Chip8Computer::new();
|
||||
Chip8CpuInstructions::LDR(1, 0x12).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(1), 0x12);
|
||||
|
||||
let mut x = Chip8Computer::new();
|
||||
Chip8CpuInstructions::LDR(2, 0x21).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(2), 0x21);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sevxbyte_match_test() {
|
||||
// 0x3xkk Skip next instruction if Vx = kk.
|
||||
// The interpreter compares register Vx to kk,
|
||||
// and if they are equal, increments the program counter by 2.
|
||||
|
||||
// test setup: Load value 0x84 into V1
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x1, 0x84);
|
||||
Chip8CpuInstructions::SEX(1, 0x48).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0x202);
|
||||
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x1, 0x84);
|
||||
Chip8CpuInstructions::SEX(1, 0x84).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0x204);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn se_vx_vy_test() {
|
||||
// 0x4xkk Skip next instruction if Vx != kk
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x01, 0x84);
|
||||
x.registers.poke(0x2, 0x84);
|
||||
// skip, compare 0x84 to 0x84
|
||||
Chip8CpuInstructions::SEY(0x1, 0x2).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0x204);
|
||||
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x01, 0x84);
|
||||
x.registers.poke(0x2, 0x48);
|
||||
Chip8CpuInstructions::SEY(0x01, 0x02).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0x202);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ld_vx_vy_test() {
|
||||
// 0x8xy0 Set value of Vy in Vx
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x01, 0x01);
|
||||
x.registers.poke(0x02, 0x02);
|
||||
Chip8CpuInstructions::LDR_Y(0x01, 0x02).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(1), 0x02);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn or_vx_vy_test() {
|
||||
// 0x8xy1 Set Vx = Vx OR Vy
|
||||
// 0b0101 0000 (0x50)
|
||||
// | 0b0000 1010 (0x0A)
|
||||
// 0b0101 1010 (0x5A)
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x01, 0b01010000);
|
||||
x.registers.poke(0x02, 0b00001010);
|
||||
Chip8CpuInstructions::OR(1, 2).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(1), 0b01011010);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn and_vx_vy_test() {
|
||||
// 0x8xy2 Set Vx = Vx AND Vy
|
||||
// 0b1111 1100 (0xFC)
|
||||
// & 0b1100 1010 (0xCA)
|
||||
// 0b1100 1000 (0xC8)
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x01, 0xFC);
|
||||
x.registers.poke(0x02, 0xCA);
|
||||
Chip8CpuInstructions::AND(1, 2).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(1), 0xC8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn xor_vx_vy_test() {
|
||||
// 0x8xy3 Set Vx = Vx XOR Vy
|
||||
// 0b1111 1100 (0xFC)
|
||||
// ^ 0b1100 1010 (0xCA)
|
||||
// 0b0011 0110 (0x36)
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x01, 0b11111100);
|
||||
x.registers.poke(0x02, 0b11001010);
|
||||
Chip8CpuInstructions::ORY(1, 2).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(1), 0b00110110);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_vx_vy_test() {
|
||||
// 0x8xy4 Set Vx = Vx + Vy (SET VF on Carry)
|
||||
// T1 T2: Judgement Test
|
||||
// 0x01 0xFF
|
||||
// + 0x01 0x01
|
||||
// 0x02 F0 0x00 F1
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x0f, 00);
|
||||
x.registers.poke(0x01, 0x01);
|
||||
x.registers.poke(0x02, 0x01);
|
||||
Chip8CpuInstructions::ADDR(0x01, 0x02).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(0xf), 0x00);
|
||||
assert_eq!(x.registers.peek(0x01), 0x02);
|
||||
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x0f, 0x00);
|
||||
x.registers.poke(0x01, 0xff);
|
||||
x.registers.poke(0x02, 0x01);
|
||||
Chip8CpuInstructions::ADDR(1, 2).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(0xf), 1);
|
||||
assert_eq!(x.registers.peek(1), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shr_vx_vy_test() {
|
||||
/*
|
||||
Set Vx = Vx SHR 1.
|
||||
|
||||
If the least-significant bit of Vx is 1, then VF is set to 1, otherwise 0. Then Vx is divided by 2.
|
||||
*/
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x0f, 0x00);
|
||||
x.registers.poke(0x01, 0b00001000);
|
||||
x.registers.poke(0x02, 0b00000000);
|
||||
Chip8CpuInstructions::SHR(0x1, 0x2).execute(&mut x); // 0b0000 0010 (0x02) (Not Set)
|
||||
assert_eq!(x.registers.peek(1), 0b00000100);
|
||||
assert_eq!(x.registers.peek(0xf), 0);
|
||||
|
||||
x = Chip8Computer::new();
|
||||
x.registers.poke(0x0f, 0x00);
|
||||
x.registers.poke(0x01, 0b00001001);
|
||||
Chip8CpuInstructions::SHR(0x1, 0x2).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(1), 0b00000100);
|
||||
assert_eq!(x.registers.peek(0xf), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ldi_addr_test() {
|
||||
let mut x = Chip8Computer::new();
|
||||
Chip8CpuInstructions::LDIA(0x123).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_i(), 0x123);
|
||||
assert_eq!(x.registers.peek_pc(), 0x202);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn jp_v0addr_test() {
|
||||
let mut x = Chip8Computer::new();
|
||||
/// jump to I + nnn
|
||||
x.registers.poke(0x0, 0xff);
|
||||
Chip8CpuInstructions::JPI(0x100).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0x1FF);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cls_test() {
|
||||
let mut x = Chip8Computer::new();
|
||||
Chip8CpuInstructions::CLS.execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0x202);
|
||||
for i in 0..CHIP8_VIDEO_MEMORY {
|
||||
assert_eq!(x.video_memory.peek(i as u16), false);
|
||||
}
|
||||
// draw some thing to the video memory
|
||||
x.video_memory.poke(0x01, true);
|
||||
x.video_memory.poke(0x03, true);
|
||||
x.video_memory.poke(0x05, true);
|
||||
|
||||
Chip8CpuInstructions::CLS.execute(&mut x);
|
||||
|
||||
for i in 0..CHIP8_VIDEO_MEMORY {
|
||||
assert_eq!(x.video_memory.peek(i as u16), false);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn skip_next_instruction_ne_text() {
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x1, 0xf0);
|
||||
Chip8CpuInstructions::SNEB(0x1, 0x0f).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0x204);
|
||||
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x1, 0xf0);
|
||||
Chip8CpuInstructions::SNEB(0x1, 0xf0).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0x202);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn addivx_test() {
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke_i(0xabc);
|
||||
x.registers.poke(0x0, 0x10);
|
||||
Chip8CpuInstructions::ADDI(0x0).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_i(), 0xacc);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ldstvt_test() {
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x1, 0xf0);
|
||||
Chip8CpuInstructions::LDI_S(0x01).execute(&mut x);
|
||||
assert_eq!(x.sound_timer.current(), 0xf0);
|
||||
x.sound_timer.tick();
|
||||
x.sound_timer.tick();
|
||||
x.sound_timer.tick();
|
||||
assert_eq!(x.sound_timer.current(), 0xed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rnd_vx_byte_text() {
|
||||
let mut x = Chip8Computer::new();
|
||||
Chip8CpuInstructions::RND(0x1, 0x0f).execute(&mut x);
|
||||
let new_value = x.registers.peek(0x1);
|
||||
assert!(new_value < 0x10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_vx_byte_test() {
|
||||
let mut x = Chip8Computer::new();
|
||||
// set a value in the register
|
||||
x.registers.poke(0x01, 0xab);
|
||||
// add 0x10 to register
|
||||
Chip8CpuInstructions::ADD(0x1, 0x10).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(1), 0xbb);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_vx_vy_test() {
|
||||
let mut x = Chip8Computer::new();
|
||||
// load values in 2 registers
|
||||
x.registers.poke(0x1, 0x10);
|
||||
x.registers.poke(0x2, 0x08);
|
||||
Chip8CpuInstructions::SUB(0x1, 0x02).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(0xf), 1);
|
||||
assert_eq!(x.registers.peek(0x1), 0x8);
|
||||
assert_eq!(x.registers.peek_pc(), 0x202);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sne_vx_vy_test() {
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x1, 0x10);
|
||||
x.registers.poke(0x2, 0x10);
|
||||
Chip8CpuInstructions::SNEY(0x1, 0x2).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0x202);
|
||||
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x1, 0x10);
|
||||
x.registers.poke(0x2, 0x00);
|
||||
Chip8CpuInstructions::SNEY(0x01, 0x02).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0x204)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ld_dt_vx_test() {
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x1, 0x10);
|
||||
Chip8CpuInstructions::LDD(0x1).execute(&mut x);
|
||||
assert_eq!(x.delay_timer.current(), 0x10);
|
||||
for i in 0..0x20 {
|
||||
x.delay_timer.tick();
|
||||
}
|
||||
assert_eq!(x.delay_timer.current(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ld_vx_dt_test() {
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x1, 0xf0);
|
||||
Chip8CpuInstructions::LDD(0x1).execute(&mut x);
|
||||
x.delay_timer.tick();
|
||||
x.delay_timer.tick();
|
||||
x.delay_timer.tick();
|
||||
assert_eq!(x.delay_timer.current(), 0xed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subn_vx_vy_test() {
|
||||
// This instruction subtracts the value in
|
||||
// register Vx from the value in register Vy and stores the result in register Vx.
|
||||
// The subtraction is performed as follows: Vx = Vy - Vx. If Vy is less than Vx,
|
||||
// the result will wrap around (due to the 8-bit nature of the registers).
|
||||
// The carry flag (VF) is set to 1 if there is no borrow (i.e., Vy is greater
|
||||
// than or equal to Vx), and it is set to 0 if there is a borrow.
|
||||
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x1, 0xa0);
|
||||
x.registers.poke(0x2, 0xab);
|
||||
Chip8CpuInstructions::SUBC(0x1, 0x2).execute(&mut x);
|
||||
// expect the result to be 0x0b
|
||||
assert_eq!(x.registers.peek(0x1), 0x0b);
|
||||
// expect the vf register to be set to 1 as there was overflow
|
||||
assert_eq!(x.registers.peek(0xf), 0x1);
|
||||
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x01, 0xab);
|
||||
x.registers.poke(0x02, 0xa0);
|
||||
Chip8CpuInstructions::SUBC(0x1, 0x2).execute(&mut x);
|
||||
|
||||
// expect the result to be 11110101, -0xB, -11, 245, 0xF5
|
||||
assert_eq!(x.registers.peek(0x1), 0xf5);
|
||||
assert_eq!(x.registers.peek(0xf), 0x0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shl_vx_vy_test_1() {
|
||||
// 8xyE - SHL Vx {, Vy}
|
||||
// Set Vx = Vx SHL 1.
|
||||
//
|
||||
// If the most-significant bit of Vx is 1, then VF is set to 1, otherwise to 0. Then Vx is multiplied by 2.
|
||||
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x1, 0b00100000);
|
||||
Chip8CpuInstructions::SHL(0x1, 0x1).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(0x1), 0b01000000);
|
||||
assert_eq!(x.registers.peek(0xf), 0x0);
|
||||
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x1, 0b10101010);
|
||||
Chip8CpuInstructions::SHL(0x1, 0x1).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(0x1), 0b01010100);
|
||||
assert_eq!(x.registers.peek(0xf), 0x1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ld_f_vx_test() {
|
||||
// Fx29 - LD F, Vx
|
||||
// Set I = location of sprite for digit Vx.
|
||||
//
|
||||
// The value of I is set to the location for the hexadecimal sprite corresponding to the value of Vx. See section 2.4, Display, for more information on the Chip-8 hexadecimal font.
|
||||
let mut x = Chip8Computer::new();
|
||||
// target_sprite = 2
|
||||
// target_offset = 0x5
|
||||
x.registers.poke(0x1, 0x2);
|
||||
Chip8CpuInstructions::LDFX(0x1).execute(&mut x);
|
||||
|
||||
assert_eq!(x.registers.peek_i(), 10);
|
||||
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x01, 0x06);
|
||||
Chip8CpuInstructions::LDFX(0x1).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_i(), 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ld_b_vx_test() {
|
||||
// Fx33 - LD B, Vx
|
||||
// Store BCD representation of Vx in memory locations I, I+1, and I+2.
|
||||
//
|
||||
// The interpreter takes the decimal value of Vx, and places the hundreds digit
|
||||
// in memory at location in I, the tens digit at location I+1,
|
||||
// and the ones digit at location I+2.
|
||||
let mut x = Chip8Computer::new();
|
||||
|
||||
// load the value 123 (0x7b)
|
||||
x.registers.poke(0x1, 0x7b);
|
||||
x.registers.poke_i(0x500);
|
||||
Chip8CpuInstructions::BCD(0x1).execute(&mut x);
|
||||
assert_eq!(x.memory.peek(0x500), 0x1);
|
||||
assert_eq!(x.memory.peek(0x501), 0x2);
|
||||
assert_eq!(x.memory.peek(0x502), 0x3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ld_i_vx_test() {
|
||||
// Store registers V0 through Vx in memory starting at location I.
|
||||
//
|
||||
// The interpreter copies the values of registers V0 through Vx into memory,
|
||||
// starting at the address in I.
|
||||
let mut x = Chip8Computer::new();
|
||||
|
||||
// Load Registers.
|
||||
let to_load = [0xab, 0xba, 0xca, 0xca, 0xbe, 0xef];
|
||||
for (idx, val) in to_load.iter().enumerate() {
|
||||
x.registers.poke(idx as u8, *val);
|
||||
}
|
||||
x.registers.poke_i(0x500);
|
||||
|
||||
Chip8CpuInstructions::LDIX(to_load.len() as u8).execute(&mut x);
|
||||
|
||||
// Verify the values are in memory from 0x500 to 0x507
|
||||
for (idx, value) in to_load.iter().enumerate() {
|
||||
assert_eq!(x.memory.peek(0x500 + idx as u16), *value);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ld_vx_i_test() {
|
||||
// Read registers V0 through Vx from memory starting at location I.
|
||||
//
|
||||
// The interpreter reads values from memory starting at location I into registers V0 through Vx.
|
||||
|
||||
let mut x = Chip8Computer::new();
|
||||
|
||||
let base_offset = 0x500;
|
||||
let to_load = [0xab, 0xba, 0xca, 0xca, 0xbe, 0xef];
|
||||
|
||||
// start by setting values in memory
|
||||
for (idx, memory) in to_load.iter().enumerate() {
|
||||
let target_address = base_offset + idx;
|
||||
let target_value = *memory;
|
||||
x.memory.poke(target_address as u16, target_value);
|
||||
}
|
||||
// where to load from
|
||||
x.registers.poke_i(0x500);
|
||||
// how much to load
|
||||
x.registers.poke(0x6, to_load.len() as u8);
|
||||
|
||||
// then copying them values memory to registers
|
||||
Chip8CpuInstructions::LDRI(0x6).execute(&mut x);
|
||||
|
||||
// now check that we have the right values in our registers
|
||||
for (idx, value) in to_load.iter().enumerate() {
|
||||
assert_eq!(x.registers.peek(idx as u8), *value);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn Sknkpvx_test() {
|
||||
// ExA1 - SKNP Vx
|
||||
// Skip next instruction if key with the value of Vx is not pressed.
|
||||
//
|
||||
// Checks the keyboard,
|
||||
// and if the key corresponding to the value of Vx is currently in the up position,
|
||||
// PC is increased by 2.
|
||||
let mut x = Chip8Computer::new();
|
||||
x.keypad.push_key(0x5);
|
||||
x.registers.poke(0x1, 0x5);
|
||||
Chip8CpuInstructions::SKNP(0x1).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0x202);
|
||||
x.keypad.release_key(0x5);
|
||||
Chip8CpuInstructions::SKNP(0x1).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0x206);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn skpvx_test() {
|
||||
// Ex9E - SKP Vx
|
||||
// Skip next instruction if key with the value of Vx is pressed.
|
||||
//
|
||||
// Checks the keyboard, and if the key corresponding to the value of Vx is currently in the down position, PC is increased by 2.
|
||||
let mut x = Chip8Computer::new();
|
||||
x.keypad.push_key(0x5);
|
||||
x.registers.poke(0x1, 0x5);
|
||||
Chip8CpuInstructions::SKP(0x1).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0x204);
|
||||
|
||||
x.keypad.release_key(0x5);
|
||||
Chip8CpuInstructions::SKP(0x1).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0x206);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn draw_nibble_vx_vy_n_test() {
|
||||
let mut x = Chip8Computer::new();
|
||||
let x_register = 0x1;
|
||||
let y_register = 0x2;
|
||||
let x_offset = 1;
|
||||
let y_offset = 2;
|
||||
let char_offset = 0x0A;
|
||||
|
||||
// now lets set the X and Y to 1,2
|
||||
x.registers.poke(x_register, x_offset);
|
||||
x.registers.poke(y_register, y_offset);
|
||||
x.registers.poke_i(char_offset);
|
||||
// we are using 5 rows.
|
||||
Chip8CpuInstructions::DRW(x_register, y_register, 5).execute(&mut x);
|
||||
|
||||
// now check that video memory has the values at
|
||||
// 1,2->1,9
|
||||
// 2,2->2,9
|
||||
// 3,2->3,9
|
||||
// 4,2->4,9
|
||||
// 5,2->5,9
|
||||
// let byte_to_check = CHIP8FONT_0[0];
|
||||
for row_in_sprite in 0..5 {
|
||||
let row_data = CHIP8FONT_2[row_in_sprite];
|
||||
for bit_in_byte in 0..8 {
|
||||
let data_offset = (x_offset
|
||||
as u16 + row_in_sprite as u16) * 64 + (bit_in_byte + y_offset) as u16;
|
||||
let real_bit_in_byte = 7 - bit_in_byte;
|
||||
let shifted_one = 0x01 << real_bit_in_byte;
|
||||
let one_shift_set = (shifted_one & row_data) > 0;
|
||||
debug!("ROWDATA = \t\t[{row_data:08b}]\tBIT IN BYTE = \t[{bit_in_byte}]\tONE_SHIFT_SET = [{one_shift_set}]\tSHIFTED ONE = [{shifted_one:08b}]");
|
||||
debug!("DATA_OFFSET FOR SOURCE DATA {}x{} is {} / offset by {}x{} and should be {} working with byte {:08b}",
|
||||
bit_in_byte, row_in_sprite, data_offset, x_offset, y_offset, one_shift_set, row_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_test() {
|
||||
// 2nnn
|
||||
// Call a subroutine at 2nnn
|
||||
let mut x = Chip8Computer::new();
|
||||
Chip8CpuInstructions::CALL(0x124).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0x124);
|
||||
assert_eq!(x.stack.depth(), 1);
|
||||
Chip8CpuInstructions::CALL(0x564).execute(&mut x);
|
||||
assert_eq!(x.registers.peek_pc(), 0x564);
|
||||
assert_eq!(x.stack.depth(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ret_test() {
|
||||
// SETUP
|
||||
// Return from a subroutine.
|
||||
let mut x = Chip8Computer::new();
|
||||
x.stack.push(&0x132);
|
||||
x.stack.push(&0xabc);
|
||||
// EXECUTE
|
||||
Chip8CpuInstructions::RET.execute(&mut x);
|
||||
// VERIFY
|
||||
assert_eq!(x.registers.peek_pc(), 0xabc);
|
||||
assert_eq!(x.stack.depth(), 1);
|
||||
// EXECUTE
|
||||
Chip8CpuInstructions::RET.execute(&mut x);
|
||||
// VERIFY
|
||||
assert_eq!(x.registers.peek_pc(), 0x132);
|
||||
assert_eq!(x.stack.depth(), 0);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn ldvxk_test() {
|
||||
// SETUP
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x01, 0x01);
|
||||
Chip8CpuInstructions::LDRK(0x1).execute(&mut x);
|
||||
assert!(matches!(x.state, WaitingForKey));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn series8xy4_corex_tests() {
|
||||
/// 8xy4
|
||||
/// Set Vx = Vx + Vy
|
||||
/// Set VF=1 if Carry
|
||||
///
|
||||
|
||||
// 1 + 1
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x01, 0x01);
|
||||
x.registers.poke(0x02, 0x01);
|
||||
Chip8CpuInstructions::ADDR(0x01, 0x02).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(0x01), 0x02);
|
||||
assert_eq!(x.registers.peek(0x0f), 0x00);
|
||||
|
||||
// 255+1
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x01, 0xff);
|
||||
x.registers.poke(0x02, 0x01);
|
||||
Chip8CpuInstructions::ADDR(0x01, 0x02).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(0x01), 0x00);
|
||||
assert_eq!(x.registers.peek(0x0f), 0x01);
|
||||
|
||||
// 128+192
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x01, 128);
|
||||
x.registers.poke(0x02, 192);
|
||||
Chip8CpuInstructions::ADDR(0x01, 0x02).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(0x01), 64);
|
||||
assert_eq!(x.registers.peek(0x0f), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn series8xy6_corex_tests() {
|
||||
// 8xy6 - SHR Vx {, Vy}
|
||||
// Set Vx = Vx SHR 1.
|
||||
//
|
||||
// If the least-significant bit of Vx is 1, then VF is set to 1,
|
||||
// otherwise 0. Then Vx is divided by 2.
|
||||
let mut x = Chip8Computer::new();
|
||||
// 0b10101010 -> 0b01010101
|
||||
x.registers.poke(0x01, 0b10101010);
|
||||
x.registers.poke(0x0f, 0x0);
|
||||
|
||||
Chip8CpuInstructions::SHL(0x01, 0x00).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(0x01), 0b01010100);
|
||||
assert_eq!(x.registers.peek(0x0f), 1);
|
||||
|
||||
Chip8CpuInstructions::SHL(0x01, 0x00).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(0x01), 0b10101000);
|
||||
assert_eq!(x.registers.peek(0x0f), 0x00);
|
||||
|
||||
Chip8CpuInstructions::SHL(0x01, 0x00).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(0x01), 0b01010000);
|
||||
assert_eq!(x.registers.peek(0x0f), 0x01);
|
||||
|
||||
Chip8CpuInstructions::SHL(0x01, 0x00).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(0x01), 0b10100000);
|
||||
assert_eq!(x.registers.peek(0x0f), 0x00);
|
||||
|
||||
Chip8CpuInstructions::SHL(0x01, 0x00).execute(&mut x);
|
||||
assert_eq!(x.registers.peek(0x01), 0b01000000);
|
||||
assert_eq!(x.registers.peek(0x0f), 0x01);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn random_produces_different_numbers() {
|
||||
let mut x = Chip8Computer::new();
|
||||
x.registers.poke(0x01, 0x00);
|
||||
let first_number = Chip8CpuInstructions::RND(0x01, 0xff).execute(&mut x).registers.peek(0x01);
|
||||
let second_number = Chip8CpuInstructions::RND(0x01, 0xff).execute(&mut x).registers.peek(0x01);
|
||||
assert_ne!(first_number, second_number);
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,28 +60,3 @@ impl Keypad {
|
||||
!self.key_state(key)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn smoke() { assert!(true) }
|
||||
|
||||
#[test]
|
||||
fn keys_check() {
|
||||
let mut k = Keypad::new();
|
||||
|
||||
for i in 0..16 {
|
||||
assert!(!k.key_state(i));
|
||||
}
|
||||
|
||||
// press a key
|
||||
k.push_key(1);
|
||||
k.push_key(2);
|
||||
assert!(k.pressed(1));
|
||||
assert!(k.pressed(2));
|
||||
k.release_key(1);
|
||||
assert!(k.released(1));
|
||||
}
|
||||
}
|
||||
@ -2,9 +2,9 @@
|
||||
/// Privately using zero base array so -1 to shift from pub to priv.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Chip8Registers {
|
||||
registers: [u8; 16],
|
||||
i_register: u16,
|
||||
pc: u16,
|
||||
pub registers: [u8; 16],
|
||||
pub i_register: u16,
|
||||
pub pc: u16,
|
||||
}
|
||||
|
||||
impl Chip8Registers {
|
||||
@ -82,60 +82,3 @@ impl Chip8Registers {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use rand::random;
|
||||
use crate::chip8::registers::Chip8Registers;
|
||||
|
||||
#[test]
|
||||
fn smoke() { assert!(true) }
|
||||
|
||||
#[test]
|
||||
fn register_rw_test() {
|
||||
let mut x = Chip8Registers::default();
|
||||
x.poke(0x0, 0xff);
|
||||
x.poke(0x1, 0xab);
|
||||
assert_eq!(x.peek(0x0), 0xff);
|
||||
assert_eq!(x.peek(0x1), 0xab);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pc_test() {
|
||||
let mut x = Chip8Registers::default();
|
||||
x.set_pc(0x300);
|
||||
assert_eq!(x.peek_pc(), 0x300);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn invalid_register() {
|
||||
let mut x = Chip8Registers::default();
|
||||
x.poke(0x10, 0xff);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_as_string_looks_right() {
|
||||
let mut x = Chip8Registers::default();
|
||||
for i in 0..0x10 {
|
||||
x.registers[i] = i as u8;
|
||||
}
|
||||
x.pc = 0xabc;
|
||||
x.i_register = 0xcab;
|
||||
let result_string = x.format_as_string();
|
||||
assert_eq!(result_string, String::from("Vx: 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07\n 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f\nI: 0x0cab\tPC: 0x0abc"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_clears_registers() {
|
||||
let mut x = Chip8Registers::default();
|
||||
|
||||
for register in 0..0x10 {
|
||||
x.registers[register] = random::<u8>();
|
||||
}
|
||||
x.reset();
|
||||
for register in 0..0x10 {
|
||||
assert_eq!(x.registers[register], 0x00);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -37,33 +37,3 @@ impl SoundTimer {
|
||||
self.counter = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn smoke() {
|
||||
assert!(true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ticks_reduce_time() {
|
||||
let mut st = SoundTimer::new();
|
||||
st.set_timer(100);
|
||||
st.tick();
|
||||
st.tick();
|
||||
st.tick();
|
||||
assert_eq!(st.current(), 97);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn out_of_ticks_works() {
|
||||
let mut st = SoundTimer::new();
|
||||
st.set_timer(0);
|
||||
st.tick();
|
||||
st.tick();
|
||||
st.tick();
|
||||
assert_eq!(st.current(), 0);
|
||||
}
|
||||
}
|
||||
@ -39,71 +39,3 @@ impl Chip8Stack {
|
||||
self.items = vec![]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use rand::random;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn smoke() { assert!(true) }
|
||||
|
||||
#[test]
|
||||
fn push_pop_test() {
|
||||
let mut x = Chip8Stack::new();
|
||||
|
||||
// lets see if we can push and pop a bunch
|
||||
x.push(&0xabcu16);
|
||||
x.push(&0xcdeu16);
|
||||
x.pop();
|
||||
assert_eq!(x.depth(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn stack_overflow_test() {
|
||||
let mut x = Chip8Stack::new();
|
||||
for i in 0..17 {
|
||||
x.push(&i);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn stack_underflow_test() {
|
||||
let mut x = Chip8Stack::new();
|
||||
x.pop();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lots_of_subs() {
|
||||
let mut x = Chip8Stack::new();
|
||||
let stack_contents = [0x123, 0x321, 0xabc, 0xdef,
|
||||
0xbad, 0xbef, 0xfed, 0xcab,
|
||||
0xbed, 0xcad, 0xfeb, 0xcab,
|
||||
0xfff, 0x000, 0x001];
|
||||
for i in stack_contents {
|
||||
x.push(&i);
|
||||
}
|
||||
|
||||
assert_eq!(x.depth(), 15);
|
||||
|
||||
// up to 50 random loops
|
||||
let num_loops: u8 = random::<u8>() % 50;
|
||||
for i in 0..num_loops {
|
||||
let start_count = x.depth();
|
||||
let num_pop = random::<u8>() % x.depth() as u8;
|
||||
for current_pop in 0..num_pop {
|
||||
x.pop();
|
||||
}
|
||||
|
||||
let post_pop_count = x.depth();
|
||||
assert_eq!(post_pop_count as u8, start_count as u8 - num_pop);
|
||||
for current_push in 0..num_pop {
|
||||
x.push(&stack_contents[(current_push + post_pop_count as u8) as usize]);
|
||||
}
|
||||
assert_eq!(x.depth(), 15);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -86,46 +86,4 @@ impl Chip8SystemMemory {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn smoke() {
|
||||
assert!(true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn model_smoke() {
|
||||
let m = Chip8SystemMemory::default();
|
||||
for i in 0..5 {
|
||||
assert_eq!(m.peek(i), CHIP8FONT_0[i as usize]);
|
||||
}
|
||||
|
||||
assert_eq!(m.peek((CHIP8_MEMORY_SIZE - 1) as u16), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn known_data_loaded_correctly() {
|
||||
let to_load = [ 0x01, 0x02, 0x03, 0x04, 0x05 , 0x06 ];
|
||||
let mut x = Chip8SystemMemory::default();
|
||||
|
||||
for (index, value) in [1..10].iter().enumerate() {
|
||||
assert_ne!(x.peek(0), 0x01);
|
||||
x.poke(0, 0x01);
|
||||
assert_eq!(x.peek(0), 0x01);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_load_program() {
|
||||
// first line of 1-chip-logo.ch8
|
||||
let program_to_load = [0x00e0, 0x6101, 0x6008, 0xa250, 0xd01f, 0x6010, 0xa25f, 0xd01f];
|
||||
|
||||
let mut x = Chip8SystemMemory::new();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -62,59 +62,3 @@ impl InstructionUtil {
|
||||
((to_read_from & 0x0f00) >> 8) as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn smoke() {
|
||||
assert!(true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_bytes() {
|
||||
// from 0xABCD we should have AB high, CD low
|
||||
let (low, high) = InstructionUtil::split_bytes(0xabcd);
|
||||
assert_eq!(low, 0xAB);
|
||||
assert_eq!(high, 0xCD);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn join_bytes() {
|
||||
// from 0xAB low and 0xCD high we get 0xABCD
|
||||
let merged = InstructionUtil::join_bytes(0xcd, 0xab);
|
||||
assert_eq!(merged, 0xcdab);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_from_instruction() {
|
||||
// from 0xABCD
|
||||
let source = 0xABCD;
|
||||
assert_eq!(InstructionUtil::read_addr_from_instruction(source), 0xBCD);
|
||||
assert_eq!(InstructionUtil::read_nibble_from_instruction(source), 0xD);
|
||||
assert_eq!(InstructionUtil::read_x_from_instruction(source), 0xB);
|
||||
assert_eq!(InstructionUtil::read_y_from_instruction(source), 0xC);
|
||||
assert_eq!(InstructionUtil::read_byte_from_instruction(source), 0xCD);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ubln() {
|
||||
// from 0xABCD we should see B
|
||||
assert_eq!(InstructionUtil::read_upper_byte_lower_nibble(0xABCD), 0xB);
|
||||
assert_eq!(InstructionUtil::read_upper_byte_lower_nibble(0x0123), 0x1);
|
||||
assert_eq!(InstructionUtil::read_upper_byte_lower_nibble(0x0000), 0x0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn byte_to_bool_changes() {
|
||||
assert_eq!(InstructionUtil::byte_to_bools(0b00000000), [false, false, false, false, false, false, false, false]);
|
||||
assert_eq!(InstructionUtil::byte_to_bools(0b11111111), [true, true, true, true, true, true, true, true]);
|
||||
assert_eq!(InstructionUtil::byte_to_bools(0b11001100), [false, false, true, true, false, false, true, true]);
|
||||
assert_eq!(InstructionUtil::byte_to_bools(0b11110000), [false, false, false, false, true, true, true, true]);
|
||||
assert_eq!(InstructionUtil::bools_to_byte([false, false, false, false, false, false, false, false]), 0b00000000);
|
||||
assert_eq!(InstructionUtil::bools_to_byte([true, true, true, true, true, true, true, true]), 0b11111111);
|
||||
assert_eq!(InstructionUtil::bools_to_byte([false, false, true, true, false, false, true, true]), 0b11001100);
|
||||
assert_eq!(InstructionUtil::bools_to_byte([false, false, false, false, true, true, true, true]), 0b11110000);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use log::{debug};
|
||||
use crate::chip8::util::InstructionUtil;
|
||||
use crate::chip8::video::Chip8VideoModes::{HighRes, LowRes};
|
||||
use crate::constants::{CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_MEMORY, CHIP8_VIDEO_WIDTH, SCHIP_VIDE_MEMORY, SCHIP_VIDEO_HEIGHT, SCHIP_VIDEO_WIDTH};
|
||||
|
||||
@ -204,393 +205,3 @@ impl Default for Chip8Video {
|
||||
Chip8Video { memory: mem, has_frame_changed: false, current_res: Chip8VideoModes::LowRes }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::io::Read;
|
||||
use crate::constants::*;
|
||||
use super::*;
|
||||
|
||||
const TEST_OUTPUT_SAMPLE_DIR: &str = "../resources/test/";
|
||||
|
||||
fn real_build_checkboard(in_hd: bool) -> Chip8Video {
|
||||
let mut r = Chip8Video::default();
|
||||
let (width, height) = if in_hd {
|
||||
r.set_highres();
|
||||
(SCHIP_VIDEO_WIDTH, SCHIP_VIDEO_HEIGHT)
|
||||
} else {
|
||||
(CHIP8_VIDEO_WIDTH, CHIP8_VIDEO_HEIGHT)
|
||||
};
|
||||
|
||||
println!("BUILDING BOARD WITH SIZE OF {width}x{height}");
|
||||
|
||||
for row in 0..height {
|
||||
let data_offset = row * width;
|
||||
|
||||
for col in 0..width {
|
||||
// XOR row and column indices to alternate in a checkerboard pattern
|
||||
let to_poke = (row % 2) ^ (col % 2) == 1;
|
||||
let local_offset: u16 = (data_offset + col) as u16;
|
||||
|
||||
r.poke(local_offset, to_poke);
|
||||
}
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
fn build_checkboard_hd() -> Chip8Video {
|
||||
real_build_checkboard(true)
|
||||
}
|
||||
|
||||
fn build_checkerboard() -> Chip8Video {
|
||||
real_build_checkboard(false)
|
||||
}
|
||||
|
||||
fn read_test_result(suffix: &str) -> String {
|
||||
std::fs::read_to_string(TEST_OUTPUT_SAMPLE_DIR.to_owned() + suffix)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn smoke() { assert!(true) }
|
||||
|
||||
#[test]
|
||||
fn default_test() {
|
||||
let mut x = Chip8Video::default();
|
||||
|
||||
for i in 0..CHIP8_VIDEO_MEMORY {
|
||||
assert!(!x.clone().peek(i as u16));
|
||||
// then flip the value and test again.
|
||||
&x.poke(i as u16, true);
|
||||
assert!(x.clone().peek(i as u16));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_initial_memory_sd() {
|
||||
let mut x = Chip8Video::default();
|
||||
// let mut initial_memory = [false; CHIP8_VIDEO_MEMORY];
|
||||
let mut ws = String::new();
|
||||
// set our checkerboard
|
||||
for cbr in 0..32 {
|
||||
for cbc in 0..64 {
|
||||
let dof = cbr * 64 + cbc;
|
||||
if (dof as i32 % 2) == 0 {
|
||||
x.poke(dof, true);
|
||||
ws += "*";
|
||||
} else {
|
||||
ws += " ";
|
||||
}
|
||||
}
|
||||
ws += "\n";
|
||||
}
|
||||
assert_eq!(x.format_as_string(), ws);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn poke_byte_test() {
|
||||
let to_poke = 0b11001111;
|
||||
let mut x = Chip8Video::default();
|
||||
x.poke_byte(0x05, to_poke);
|
||||
let mut expected = String::new();
|
||||
expected = " ** **** \n".to_string();
|
||||
for i in 0..31 {
|
||||
expected += &*(" ".repeat(64) + "\n");
|
||||
}
|
||||
assert_eq!(x.format_as_string(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn poke_2byte_test() {
|
||||
let to_poke: [u8; 2] = [
|
||||
0b11001111,
|
||||
0b00111100
|
||||
];
|
||||
|
||||
let mut x = Chip8Video::default();
|
||||
x.poke_2byte(0x00, to_poke);
|
||||
|
||||
let mut expected = String::new();
|
||||
expected = "** **** **** ".to_string() + &*" ".repeat(64 - 16).to_string() + "\n";
|
||||
for i in 0..31 {
|
||||
expected += &*((&*" ".repeat(64)).to_string() + "\n");
|
||||
}
|
||||
|
||||
assert_eq!(expected, x.format_as_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn poke_multirow_2_byte_sprite() {
|
||||
// take 2 rows of 16bits and write them to memory
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cls_stddef() {
|
||||
let width = 64;
|
||||
let height = 32;
|
||||
let mut initial_memory = vec![];
|
||||
let mut ws = String::new();
|
||||
let mut set_x = Chip8Video::new(initial_memory.into());
|
||||
for cbr in 0..32 {
|
||||
ws += &*" ".repeat(width);
|
||||
ws += "\n";
|
||||
}
|
||||
set_x.cls();
|
||||
|
||||
assert_eq!(set_x.format_as_string(), ws);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn poke_byte_test_2() {
|
||||
let to_poke = 0b10101010;
|
||||
let mut v = Chip8Video::default();
|
||||
v.poke_byte(0x00, to_poke);
|
||||
assert!(v.clone().peek(0x00));
|
||||
assert!(!v.clone().peek(0x01));
|
||||
assert!(v.clone().peek(0x02));
|
||||
assert!(!v.clone().peek(0x03));
|
||||
assert!(v.clone().peek(0x04));
|
||||
assert!(!v.clone().peek(0x05));
|
||||
assert!(v.clone().peek(0x06));
|
||||
assert!(!v.clone().peek(0x07));
|
||||
for i in 0x8..CHIP8_VIDEO_MEMORY {
|
||||
assert!(!v.clone().peek(i as u16));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn poke_multi_line_test() {
|
||||
let mut v = Chip8Video::default();
|
||||
let to_poke = [
|
||||
0b00000000,
|
||||
0b11111111,
|
||||
0b10101010,
|
||||
0b01010101
|
||||
];
|
||||
|
||||
for (byte_in_set, byte_to_poke) in to_poke.iter().enumerate() {
|
||||
let base_offset = byte_in_set * 64;
|
||||
v.poke_byte(base_offset as u16, *byte_to_poke);
|
||||
}
|
||||
|
||||
// row 2 column 1
|
||||
{
|
||||
assert!(v.clone().peek(0x40));
|
||||
assert!(v.clone().peek(0x41));
|
||||
assert!(v.clone().peek(0x42));
|
||||
assert!(v.clone().peek(0x43));
|
||||
assert!(v.clone().peek(0x44));
|
||||
assert!(v.clone().peek(0x45));
|
||||
assert!(v.clone().peek(0x46));
|
||||
assert!(v.clone().peek(0x47));
|
||||
|
||||
// row 3 column 1
|
||||
assert!(!v.clone().peek(0xC0));
|
||||
assert!(v.clone().peek(0xC1));
|
||||
assert!(!v.clone().peek(0xC2));
|
||||
assert!(v.clone().peek(0xC3));
|
||||
assert!(!v.clone().peek(0xC4));
|
||||
assert!(v.clone().peek(0xC5));
|
||||
assert!(!v.clone().peek(0xC6));
|
||||
assert!(v.clone().peek(0xC7));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn moved_poke_test() {
|
||||
let mut v = Chip8Video::default();
|
||||
let to_poke = [
|
||||
0b00000000,
|
||||
0b11111111,
|
||||
0b10101010,
|
||||
0b01010101
|
||||
];
|
||||
|
||||
let x_offset = 20;
|
||||
let y_offset = 5;
|
||||
|
||||
|
||||
for (byte_in_set, byte_to_poke) in to_poke.iter().enumerate() {
|
||||
let base_offset = (x_offset + byte_in_set) * 64 + y_offset;
|
||||
v.poke_byte(base_offset as u16, *byte_to_poke);
|
||||
}
|
||||
|
||||
let test_offset = (x_offset * 64 + y_offset) as u16;
|
||||
assert!(!v.clone().peek(test_offset));
|
||||
assert!(!v.clone().peek(test_offset + 1));
|
||||
assert!(!v.clone().peek(test_offset + 2));
|
||||
assert!(!v.clone().peek(test_offset + 3));
|
||||
assert!(!v.clone().peek(test_offset + 4));
|
||||
assert!(!v.clone().peek(test_offset + 5));
|
||||
assert!(!v.clone().peek(test_offset + 6));
|
||||
assert!(!v.clone().peek(test_offset + 7));
|
||||
|
||||
let test_offset = test_offset + 0x40;
|
||||
assert!(v.clone().peek(test_offset));
|
||||
assert!(v.clone().peek(test_offset + 1));
|
||||
assert!(v.clone().peek(test_offset + 2));
|
||||
assert!(v.clone().peek(test_offset + 3));
|
||||
assert!(v.clone().peek(test_offset + 4));
|
||||
assert!(v.clone().peek(test_offset + 5));
|
||||
assert!(v.clone().peek(test_offset + 6));
|
||||
assert!(v.clone().peek(test_offset + 7));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_change_registered() {
|
||||
let mut v = Chip8Video::default();
|
||||
v.poke(0x01, true);
|
||||
v.poke(0x01, true);
|
||||
assert!(v.has_frame_changed);
|
||||
|
||||
v.start_frame();
|
||||
assert!(!v.has_frame_changed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_checkboard() {
|
||||
let mut v = build_checkerboard();
|
||||
assert_eq!(v.clone().format_as_string(), read_test_result("test_video_write_checkerboard.asc"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_test() {
|
||||
let mut x = Chip8Video::default();
|
||||
|
||||
for (byte_index, data_offset) in (0..=0x100).step_by(0x40).enumerate() {
|
||||
x.poke_byte(data_offset as u16, CHIP8FONT_0[byte_index]);
|
||||
}
|
||||
|
||||
assert_eq!(read_test_result("test_video_zero.asc"), x.format_as_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_sprite_test() {
|
||||
let mut x = Chip8Video::default();
|
||||
// draw a row of digits 01234567
|
||||
let to_draw = [CHIP8FONT_0, CHIP8FONT_1, CHIP8FONT_2, CHIP8FONT_3, CHIP8FONT_4, CHIP8FONT_5, CHIP8FONT_6, CHIP8FONT_7];
|
||||
for (index, sprite) in to_draw.iter().enumerate() {
|
||||
let data_base_offset = index * 0x8;
|
||||
for (index, offset) in (0..=0x100).step_by(0x40).enumerate() {
|
||||
x.poke_byte((data_base_offset + offset) as u16, sprite[index]);
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(read_test_result("test_multi_sprite.asc"), x.format_as_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_test() {
|
||||
let mut x = build_checkerboard();
|
||||
x.reset();
|
||||
assert_eq!(x.format_as_string(), read_test_result("test_reset_clears_video.asc"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collision_test() {
|
||||
// Setup: Set 0xFF to 0x00 with a new frame ready
|
||||
// Action: Run Poke to the same area
|
||||
// Test: Verify the 'changed' flag is tripped
|
||||
let mut x = Chip8Video::default();
|
||||
x.poke_byte(0x00, 0xff);
|
||||
x.tick();
|
||||
// set the cell thats already set...
|
||||
x.poke(0x00, true);
|
||||
// it becomes unset and theres a frame changed
|
||||
assert_eq!(false, x.peek(0x00));
|
||||
|
||||
assert_eq!(true, x.clone().has_frame_changed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn collision_test2() {
|
||||
let mut x = Chip8Video::default();
|
||||
x.poke_byte(0x00, 0b11110000);
|
||||
assert_eq!(true, x.has_frame_changed);
|
||||
x.tick();
|
||||
assert_eq!(false, x.has_frame_changed);
|
||||
// clear the 'has changed' flag
|
||||
|
||||
// now set a no-collision value
|
||||
x.poke_byte(0x00, 0b00001111);
|
||||
assert_eq!(true, x.has_frame_changed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn peek_out_of_bounds_doesnt_panic() {
|
||||
let x = Chip8Video::default();
|
||||
|
||||
let y = x.clone().peek(2049);
|
||||
let y = x.clone().peek(0);
|
||||
|
||||
// if we got here we didn't panic
|
||||
assert!(true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scroll_down_1_row_test() {
|
||||
let mut x = build_checkerboard();
|
||||
x.scroll_down(1);
|
||||
assert_eq!(read_test_result("test_video_scroll_down_1.asc"), x.format_as_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scroll_down_10_row_test() {
|
||||
let mut x = build_checkerboard();
|
||||
x.scroll_down(10);
|
||||
assert_eq!(read_test_result("test_video_scroll_down_10.asc"), x.format_as_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn high_res_has_right_resolution() {
|
||||
let mut x = build_checkboard_hd();
|
||||
println!("[{}]", x.format_as_string());
|
||||
assert_eq!(read_test_result("test_video_highdef.asc"), x.format_as_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scroll_down_1_row_test_schip() {
|
||||
let mut x = build_checkboard_hd();
|
||||
x.scroll_down(1);
|
||||
|
||||
println!("[{}]", x.format_as_string());
|
||||
println!("[{}]", read_test_result("test_scroll_down_1_hd.asc"));
|
||||
|
||||
assert_eq!(read_test_result("test_scroll_down_1_hd.asc"), x.format_as_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scroll_down_10_row_test_schip() {
|
||||
let mut x = build_checkboard_hd();
|
||||
x.scroll_down(10);
|
||||
assert_eq!(read_test_result("test_scroll_down_10_hd.asc"), x.format_as_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scroll_left_4_row_test_std_def() {
|
||||
let mut x = build_checkerboard();
|
||||
x.scroll_left();
|
||||
assert_eq!(read_test_result("test_scroll_left_4.asc"), x.format_as_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scroll_left_4_row_test_high_def() {
|
||||
let mut x = build_checkboard_hd();
|
||||
x.scroll_left();
|
||||
assert_eq!(read_test_result("test_scroll_left_4_hd.asc"), x.format_as_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scroll_right_4_row_test_std_def() {
|
||||
let mut x = build_checkerboard();
|
||||
x.scroll_right();
|
||||
assert_eq!(read_test_result("test_scroll_right_4.asc"), x.format_as_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scroll_right_4_row_test_high_def() {
|
||||
let mut x = build_checkboard_hd();
|
||||
x.scroll_right();
|
||||
assert_eq!(read_test_result("test_scroll_right_4_hd.asc"), x.format_as_string());
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,9 @@ pub const CHIP8_VIDEO_HEIGHT: i32 = 32i32;
|
||||
pub const CHIP8_VIDEO_MEMORY: usize = (CHIP8_VIDEO_HEIGHT * CHIP8_VIDEO_WIDTH) as usize;
|
||||
pub const CHIP8_ROM_SIZE: usize = 512;
|
||||
|
||||
pub const RESOURCES_ROOT: &str = "../resources";
|
||||
pub const TESTS_ROOT: &str = "../resources/tests/";
|
||||
|
||||
pub const CHIP8_KEYBOARD: [[u8; 4]; 4] = [
|
||||
[0x01, 0x02, 0x03, 0x0C],
|
||||
[0x04, 0x05, 0x06, 0x0D],
|
||||
@ -53,7 +56,7 @@ pub const INST_SKP: &str = "SKP";
|
||||
pub const INST_SNEB: &str = "SNEB";
|
||||
pub const INST_SNEY: &str = "SNEY";
|
||||
pub const INST_SNKP: &str = "SNKP";
|
||||
pub const INST_STR : &str = "STR";
|
||||
pub const INST_STR: &str = "STR";
|
||||
pub const INST_SUB: &str = "SUB";
|
||||
pub const INST_SUBC: &str = "SUBC";
|
||||
pub const INST_SYS: &str = "SYS";
|
||||
@ -61,8 +64,6 @@ pub const INST_DIS: &str = "DIS";
|
||||
pub const INST_ENA: &str = "ENA";
|
||||
pub const INST_ORY: &str = "ORY";
|
||||
|
||||
|
||||
|
||||
pub const CHIP8_PROGRAM_LOAD_OFFSET: i32 = 0x200;
|
||||
pub const CHIP8FONT_0: [u8; 5] = [0xF0, 0x90, 0x90, 0x90, 0xF0];
|
||||
pub const CHIP8FONT_1: [u8; 5] = [0x20, 0x60, 0x20, 0x20, 0x70];
|
||||
@ -81,47 +82,90 @@ pub const CHIP8FONT_D: [u8; 5] = [0xE0, 0x90, 0x90, 0x90, 0xE0];
|
||||
pub const CHIP8FONT_E: [u8; 5] = [0xF0, 0x80, 0xF0, 0x80, 0xF0];
|
||||
pub const CHIP8FONT_F: [u8; 5] = [0xF0, 0x80, 0xF0, 0x80, 0x80];
|
||||
|
||||
|
||||
pub const SCHIPFONT_0: [u8; 0x10] = [0xF0, 0xFC, 0xFE, 0xFF, 0xF3, 0xE1, 0xE0, 0xE0,
|
||||
0xE0, 0xE0, 0xE0, 0xF1, 0xFB, 0xFF, 0xFE, 0x7C];
|
||||
pub const SCHIPFONT_1: [u8; 0x10] = [0x18, 0x3C, 0x7E, 0xFF, 0xF7, 0xE3, 0xC1, 0xC0,
|
||||
0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0
|
||||
pub const SCHIPFONT_0: [u8; 0x20] = [
|
||||
0x00, 0x00,
|
||||
0x01, 0x80,
|
||||
0x03, 0xc0,
|
||||
0x06, 0x60,
|
||||
0x0c, 0x30,
|
||||
0x0c, 0x30,
|
||||
0x18, 0x18,
|
||||
0x18, 0x18,
|
||||
0x18, 0x18,
|
||||
0x18, 0x18,
|
||||
0x0c, 0x30,
|
||||
0x0c, 0x30,
|
||||
0x06, 0x60,
|
||||
0x03, 0xc0, // 0b0000001111000000
|
||||
0x01, 0x80, // 0b0000000110000000
|
||||
0x00, 0x00 // 0b0000000000000000
|
||||
];
|
||||
pub const SCHIPFONT_2: [u8; 0x10] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC7, 0xC3, 0xC0, 0xE0,
|
||||
0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0xFF, 0xFF
|
||||
pub const SCHIPFONT_1: [u8; 0x20] = [
|
||||
0x00, 0x00,
|
||||
0x03, 0xc0,
|
||||
0x02, 0xc0,
|
||||
0x00, 0xc0,
|
||||
0x00, 0xc0,
|
||||
0x00, 0xc0,
|
||||
0x00, 0xc0,
|
||||
0x00, 0xc0,
|
||||
0x00, 0xc0,
|
||||
0x00, 0xc0,
|
||||
0x00, 0xc0,
|
||||
0x00, 0xc0,
|
||||
0x00, 0xc0,
|
||||
0x00, 0xc0,
|
||||
0x03, 0xf0,
|
||||
0x00, 0x00
|
||||
];
|
||||
pub const SCHIPFONT_3: [u8; 0x10] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC7, 0xC3, 0xC0, 0xE0,
|
||||
0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0xFF, 0xFF];
|
||||
pub const SCHIPFONT_4: [u8; 0x10] = [0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xF7, 0xF3, 0xF1,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0];
|
||||
pub const SCHIPFONT_5: [u8; 0x10] = [0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x3F, 0x7F, 0x7F,
|
||||
0x01, 0x01, 0xC1, 0xE3, 0xFF, 0xFE, 0xFC, 0x78];
|
||||
pub const SCHIPFONT_6: [u8; 0x10] = [0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,
|
||||
pub const SCHIPFONT_2: [u8; 0x20] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC7, 0xC3, 0xC0, 0xE0,
|
||||
0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0xFF, 0xFF,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78];
|
||||
pub const SCHIPFONT_3: [u8; 0x20] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC7, 0xC3, 0xC0, 0xE0,
|
||||
0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0xFF, 0xFF,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78];
|
||||
pub const SCHIPFONT_4: [u8; 0x20] = [0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xF7, 0xF3, 0xF1,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78];
|
||||
pub const SCHIPFONT_5: [u8; 0x20] = [0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x3F, 0x7F, 0x7F,
|
||||
0x01, 0x01, 0xC1, 0xE3, 0xFF, 0xFE, 0xFC, 0x78,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78];
|
||||
pub const SCHIPFONT_6: [u8; 0x20] = [0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78
|
||||
];
|
||||
pub const SCHIPFONT_7: [u8; 0x10] = [0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0x78, 0x3C,
|
||||
0x1E, 0x0F, 0x07, 0x03, 0x01, 0x01, 0x01, 0x01
|
||||
pub const SCHIPFONT_7: [u8; 0x20] = [0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0x78, 0x3C,
|
||||
0x1E, 0x0F, 0x07, 0x03, 0x01, 0x01, 0x01, 0x01,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78
|
||||
];
|
||||
pub const SCHIPFONT_8: [u8; 0x10] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF,
|
||||
0x7E, 0xFE, 0xC3, 0xC3, 0xFF, 0xFF, 0xFE, 0x7C
|
||||
pub const SCHIPFONT_8: [u8; 0x20] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF,
|
||||
0x7E, 0xFE, 0xC3, 0xC3, 0xFF, 0xFF, 0xFE, 0x7C,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78
|
||||
];
|
||||
pub const SCHIPFONT_9: [u8; 0x10] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF,
|
||||
0xFF, 0x7F, 0x03, 0x03, 0xC7, 0xFF, 0xFE, 0x7C
|
||||
pub const SCHIPFONT_9: [u8; 0x20] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF,
|
||||
0xFF, 0x7F, 0x03, 0x03, 0xC7, 0xFF, 0xFE, 0x7C,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78
|
||||
];
|
||||
pub const SCHIPFONT_A: [u8; 0x10] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3
|
||||
pub const SCHIPFONT_A: [u8; 0x20] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78
|
||||
];
|
||||
pub const SCHIPFONT_B: [u8; 0x10] = [0xFE, 0xFF, 0xFF, 0xFF, 0xC3, 0xC3, 0xFE, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xFE
|
||||
pub const SCHIPFONT_B: [u8; 0x20] = [0xFE, 0xFF, 0xFF, 0xFF, 0xC3, 0xC3, 0xFE, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xFE,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78
|
||||
];
|
||||
pub const SCHIPFONT_C: [u8; 0x10] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0x01, 0x01,
|
||||
0x01, 0x01, 0xC3, 0xC3, 0xFF, 0xFE, 0xFC, 0x78
|
||||
pub const SCHIPFONT_C: [u8; 0x20] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0x01, 0x01,
|
||||
0x01, 0x01, 0xC3, 0xC3, 0xFF, 0xFE, 0xFC, 0x78,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78
|
||||
];
|
||||
pub const SCHIPFONT_D: [u8; 0x10] = [0xFE, 0xFF, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3,
|
||||
0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xFE, 0x7C
|
||||
pub const SCHIPFONT_D: [u8; 0x20] = [0xFE, 0xFF, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3,
|
||||
0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xFE, 0x7C, 0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78
|
||||
];
|
||||
pub const SCHIPFONT_E: [u8; 0x10] = [0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x03, 0xFF,
|
||||
0xFF, 0xFF, 0x03, 0x03, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
pub const SCHIPFONT_E: [u8; 0x20] = [0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x03, 0xFF,
|
||||
0xFF, 0xFF, 0x03, 0x03, 0xFF, 0xFF, 0xFF, 0xFF,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78
|
||||
];
|
||||
pub const SCHIPFONT_F: [u8; 0x10] = [0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x03, 0xFF,
|
||||
0xFF, 0xFF, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03];
|
||||
pub const SCHIPFONT_F: [u8; 0x20] = [0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x03, 0xFF,
|
||||
0xFF, 0xFF, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,
|
||||
0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78];
|
||||
|
||||
@ -48,11 +48,9 @@ fn level2_test() {
|
||||
let mut x = Chip8Computer::new();
|
||||
// Load the IBM rom and run it.
|
||||
// it takes 39 cycles to get to the end so lets run it 40.
|
||||
|
||||
let test_rom_to_run = load_rom("2-ibm-logo.ch8");
|
||||
x.load_bytes_to_memory(0x200, (&test_rom_to_run).into());
|
||||
|
||||
for i in 0..40 {
|
||||
for _ in 0..40 {
|
||||
x.step_system();
|
||||
}
|
||||
// ...then verify that the current video memory of the chip-8
|
||||
@ -79,12 +77,12 @@ fn level3_test() {
|
||||
fn rps_test() {
|
||||
let mut x = Chip8Computer::new();
|
||||
x.load_bytes_to_memory(0x200, &load_rom("RPS.ch8").into());
|
||||
for i in 0..0xF0 {
|
||||
for _ in 0..0xF0 {
|
||||
x.step_system();
|
||||
}
|
||||
assert_eq!(x.dump_video_to_string(), load_result("gemma_integration_rps_stage1.asc"));
|
||||
x.keypad.push_key(0x01);
|
||||
for i in 0..0x200 {
|
||||
for _ in 0..0x200 {
|
||||
x.step_system();
|
||||
}
|
||||
assert_eq!(x.dump_video_to_string(), load_result("gemma_integration_rps_stage2.asc"));
|
||||
@ -95,7 +93,7 @@ fn level4_test() {
|
||||
// flags
|
||||
let mut x = Chip8Computer::new();
|
||||
x.load_bytes_to_memory(0x200, &load_rom("4-flags.ch8").into());
|
||||
for i in 0..0x400 {
|
||||
for _ in 0..0x400 {
|
||||
x.step_system();
|
||||
}
|
||||
|
||||
|
||||
1320
gemma/tests/unit_tests.rs
Normal file
1320
gemma/tests/unit_tests.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -33,6 +33,7 @@ fn main() {
|
||||
|
||||
support::simple_init(file!(), move |_, ui| {
|
||||
let current_time = Instant::now();
|
||||
let mut num_cycles = 0;
|
||||
|
||||
// Key Checks
|
||||
let down_keys = ui.io().keys_down;
|
||||
@ -58,9 +59,10 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
system.tick();
|
||||
|
||||
|
||||
while Instant::now().duration_since(current_time).as_millis() < 16 && num_cycles < 1000 {
|
||||
system.tick();
|
||||
num_cycles += 1;
|
||||
}
|
||||
// GUI Parts
|
||||
if ui_state.show_video {
|
||||
GemmaImguiSupport::video_display(&system.state(), &ui_state, ui);
|
||||
|
||||
@ -16,7 +16,7 @@ use crate::ImGuiUiState;
|
||||
use crate::support::gui_file_list::GuiFileList;
|
||||
use super::ui_state;
|
||||
|
||||
const ROM_ROOT: &str = "/home/tmerritt/Projects/trevors_chip8_toy/resources/octoroms";
|
||||
const ROM_ROOT: &str = "/home/tmerritt/Projects/trevors_chip8_toy/resources/roms";
|
||||
|
||||
pub struct GemmaImguiSupport {}
|
||||
|
||||
@ -43,23 +43,37 @@ impl GemmaImguiSupport {
|
||||
|
||||
pub fn video_display(system_to_control: &Chip8Computer, gui_state: &ImGuiUiState, ui: &Ui) {
|
||||
// draw area size
|
||||
let (width, height) = system_to_control.video_memory.get_resolution();
|
||||
let draw_area_size = ui.io().display_size;
|
||||
// println!("DRAW_AREA_SIZE = {}x{}", draw_area_size[0], draw_area_size[1]);
|
||||
let cell_width = ((draw_area_size[0] as i32 / 64) * 6) / 10;
|
||||
let cell_height = ((draw_area_size[1] as i32 / 32) * 6) / 10;
|
||||
let cell_width = ((draw_area_size[0] as i32 / width) * 6) / 10;
|
||||
let cell_height = ((draw_area_size[1] as i32 / height) * 6) / 10;
|
||||
|
||||
ui.window(format!("Display {cell_width}x{cell_height}"))
|
||||
.size([300.0, 300.0], Condition::Once)
|
||||
.build(|| {
|
||||
let (width, height) = system_to_control.video_memory.get_resolution();
|
||||
let origin = ui.cursor_screen_pos();
|
||||
let fg = ui.get_window_draw_list();
|
||||
if (system_to_control.video_memory.is_highres()) {
|
||||
ui.text("High Def Video here");
|
||||
|
||||
for current_row in 0..=height {
|
||||
let y_offset = origin[1] as i32 + (current_row * cell_height);
|
||||
for current_column in 0..=width {
|
||||
let x_offset = origin[0] as i32 + (current_column * cell_width);
|
||||
let current_origin = [x_offset as f32, y_offset as f32];
|
||||
let current_limit = [(x_offset + cell_width) as f32, (y_offset + cell_height) as f32];
|
||||
let memory_offset = (current_row * width + current_column) as u16;
|
||||
let to_render = system_to_control.video_memory.peek(memory_offset);
|
||||
let color: ImColor32 = if to_render {
|
||||
gui_state.on_colour
|
||||
} else {
|
||||
gui_state.off_colour
|
||||
};
|
||||
fg.add_rect_filled_multicolor(current_origin, current_limit, color, color, color, color);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ui.text("StdDef video here.");
|
||||
|
||||
for current_row in 0..=height {
|
||||
let y_offset = origin[1] as i32 + (current_row * cell_height);
|
||||
for current_column in 0..=width {
|
||||
@ -88,7 +102,7 @@ impl GemmaImguiSupport {
|
||||
ui.text(format!("Step {:04x}", system_to_control.num_cycles()).as_str());
|
||||
|
||||
/* ROM Lister */
|
||||
let new_filename = GuiFileList::display_path(PathBuf::from("/home/tmerritt/Projects/trevors_chip8_toy/resources/octoroms/"), &gui_state.filename_to_load, ui);
|
||||
let new_filename = GuiFileList::display_path(PathBuf::from("/home/tmerritt/Projects/trevors_chip8_toy/resources/roms/"), &gui_state.filename_to_load, ui);
|
||||
if !new_filename.is_empty() {
|
||||
if new_filename != gui_state.filename_to_load {
|
||||
debug!("NEW FILENAME SELECTED -> {new_filename}");
|
||||
@ -98,7 +112,7 @@ impl GemmaImguiSupport {
|
||||
let mut buffer = Vec::new();
|
||||
debug!("PREPARING TO LOAD {}", gui_state.filename_to_load);
|
||||
// let mut input_file = File::open(Path::new("./1-chip8-logo.ch8")).expect("put 1-chip8-logo.ch8 in this directory");
|
||||
let mut input_file = File::open(Path::new(&("/home/tmerritt/Projects/trevors_chip8_toy/resources/octoroms/".to_string() + &gui_state.filename_to_load))).expect("put 1-chip8-logo.ch8 in this directory");
|
||||
let mut input_file = File::open(Path::new(&("/home/tmerritt/Projects/trevors_chip8_toy/resources/roms/".to_string() + &gui_state.filename_to_load))).expect("put 1-chip8-logo.ch8 in this directory");
|
||||
input_file.read_to_end(&mut buffer).expect("unable to read file");
|
||||
system_to_control.load_bytes_to_system_memory((&*buffer).into());
|
||||
}
|
||||
|
||||
83
gemmautil/src/bin/bin2hex.rs
Normal file
83
gemmautil/src/bin/bin2hex.rs
Normal file
@ -0,0 +1,83 @@
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::{BufReader, Read};
|
||||
use clap::{Arg, Command, ArgAction, ValueEnum};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CliArgs {
|
||||
input: String,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Taxation is Theft!");
|
||||
// Set up the command line arguments
|
||||
let matches = Command::new("my_program")
|
||||
.about("Processes an input file and outputs it with a specified bit width")
|
||||
.arg(
|
||||
Arg::new("input")
|
||||
.help("The input file to process")
|
||||
.required(true)
|
||||
.index(1),
|
||||
)
|
||||
|
||||
.get_matches();
|
||||
|
||||
// Parse the command-line arguments
|
||||
let args = CliArgs {
|
||||
input: matches.get_one::<String>("input").unwrap().to_string(),
|
||||
};
|
||||
|
||||
// Use the parsed arguments
|
||||
println!("Input file: {}", args.input);
|
||||
|
||||
// behave like a shift register and load each character from the file 1 by 1.
|
||||
let results = read_file_to_bools(&args.input);
|
||||
for result in results.unwrap().bytes() {
|
||||
print!("0x{:02x}, ", result.unwrap());
|
||||
}
|
||||
}
|
||||
fn read_file_to_bools(file_path: &str) -> io::Result<Vec<u8>> {
|
||||
// Open the file
|
||||
let file = File::open(file_path)?;
|
||||
let mut reader = BufReader::new(file);
|
||||
|
||||
let mut bytes = Vec::new();
|
||||
reader.read_to_end(&mut bytes)?;
|
||||
|
||||
let mut output = Vec::new();
|
||||
let mut current_byte = 0u8;
|
||||
let mut bit_index = 0;
|
||||
|
||||
for &byte in &bytes {
|
||||
// Convert ASCII character '1' or '0' to boolean, skip any other characters
|
||||
let bit = match byte {
|
||||
b'1' => true,
|
||||
b'0' => false,
|
||||
_ => continue, // Skip non-'1' or '0' characters
|
||||
};
|
||||
|
||||
// Set the appropriate bit in the current byte
|
||||
if bit {
|
||||
current_byte |= 1 << (7 - bit_index); // Set the bit at the correct position
|
||||
}
|
||||
|
||||
bit_index += 1;
|
||||
|
||||
// Once we have filled 8 bits, push the byte and reset
|
||||
if bit_index == 8 {
|
||||
output.push(current_byte);
|
||||
current_byte = 0;
|
||||
bit_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// If there are remaining bits, push the last byte (it will be partially filled)
|
||||
if bit_index > 0 {
|
||||
output.push(current_byte);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
16
resources/schip_font/0.asc
Normal file
16
resources/schip_font/0.asc
Normal file
@ -0,0 +1,16 @@
|
||||
0000000000000000
|
||||
0000000110000000
|
||||
0000001111000000
|
||||
0000011001100000
|
||||
0000110000110000
|
||||
0000110000110000
|
||||
0001100000011000
|
||||
0001100000011000
|
||||
0001100000011000
|
||||
0001100000011000
|
||||
0000110000110000
|
||||
0000110000110000
|
||||
0000011001100000
|
||||
0000001111000000
|
||||
0000000110000000
|
||||
0000000000000000
|
||||
16
resources/schip_font/1.asc
Normal file
16
resources/schip_font/1.asc
Normal file
@ -0,0 +1,16 @@
|
||||
0000000000000000
|
||||
0000001111000000
|
||||
0000001011000000
|
||||
0000000011000000
|
||||
0000000011000000
|
||||
0000000011000000
|
||||
0000000011000000
|
||||
0000000011000000
|
||||
0000000011000000
|
||||
0000000011000000
|
||||
0000000011000000
|
||||
0000000011000000
|
||||
0000000011000000
|
||||
0000000011000000
|
||||
0000001111110000
|
||||
0000000000000000
|
||||
16
resources/schip_font/2.asc
Normal file
16
resources/schip_font/2.asc
Normal file
@ -0,0 +1,16 @@
|
||||
0000000000000000
|
||||
0000011111000000
|
||||
0000100000100000
|
||||
0001000000010000
|
||||
0000000000100000
|
||||
0000000001000000
|
||||
0000000010000000
|
||||
0000000100000000
|
||||
0000001000000000
|
||||
0000010000000000
|
||||
0000100000000000
|
||||
0000100000000000
|
||||
0000100000000000
|
||||
0000100000000000
|
||||
0000111111110000
|
||||
0000000000000000
|
||||
16
resources/schip_font/3.asc
Normal file
16
resources/schip_font/3.asc
Normal file
@ -0,0 +1,16 @@
|
||||
0000000000000000
|
||||
0000011111000000
|
||||
0000100000100000
|
||||
0001000000010000
|
||||
0001000000010000
|
||||
0000000000010000
|
||||
0000000000010000
|
||||
0000011111100000
|
||||
0000000000010000
|
||||
0000000000010000
|
||||
0000000000010000
|
||||
0000100000010000
|
||||
0000100000100000
|
||||
0000011111000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
16
resources/schip_font/4.asc
Normal file
16
resources/schip_font/4.asc
Normal file
@ -0,0 +1,16 @@
|
||||
0000000000000000
|
||||
0001000000100000
|
||||
0001000000100000
|
||||
0001000000100000
|
||||
0001000000100000
|
||||
0001000000100000
|
||||
0001000000100000
|
||||
0001111111100000
|
||||
0000000000100000
|
||||
0000000000100000
|
||||
0000000000100000
|
||||
0000000000100000
|
||||
0000000000100000
|
||||
0000000000100000
|
||||
0000000000100000
|
||||
0000000000000000
|
||||
16
resources/schip_font/5.asc
Normal file
16
resources/schip_font/5.asc
Normal file
@ -0,0 +1,16 @@
|
||||
0000000000000000
|
||||
0011111111111100
|
||||
0010000000000000
|
||||
0010000000000000
|
||||
0010000000000000
|
||||
0010000000000000
|
||||
0010000000000000
|
||||
0010111111000000
|
||||
0011000000100000
|
||||
0000000000010000
|
||||
0000000000010000
|
||||
0000000000010000
|
||||
0001000000100000
|
||||
0001111111000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
16
resources/schip_font/6.asc
Normal file
16
resources/schip_font/6.asc
Normal file
@ -0,0 +1,16 @@
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000011111111100
|
||||
0000100000000000
|
||||
0001000000000000
|
||||
0010000000000000
|
||||
0010000000000000
|
||||
0010000000000000
|
||||
0010111111000000
|
||||
0011000000100000
|
||||
0010000000010000
|
||||
0010000000010000
|
||||
0010000000010000
|
||||
0011000000100000
|
||||
0001111111000000
|
||||
0000000000000000
|
||||
16
resources/schip_font/7.asc
Normal file
16
resources/schip_font/7.asc
Normal file
@ -0,0 +1,16 @@
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
16
resources/schip_font/8.asc
Normal file
16
resources/schip_font/8.asc
Normal file
@ -0,0 +1,16 @@
|
||||
0000000000000000
|
||||
0000000110000000
|
||||
0000001001000000
|
||||
0000010000100000
|
||||
0000001001000000
|
||||
0000000110000000
|
||||
0000011110000000
|
||||
0001100001100000
|
||||
0011000000110000
|
||||
0011000000110000
|
||||
0011000000110000
|
||||
0001100001100000
|
||||
0000110011000000
|
||||
0000011110000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
16
resources/schip_font/9.asc
Normal file
16
resources/schip_font/9.asc
Normal file
@ -0,0 +1,16 @@
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
16
resources/schip_font/A.asc
Normal file
16
resources/schip_font/A.asc
Normal file
@ -0,0 +1,16 @@
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
16
resources/schip_font/B.asc
Normal file
16
resources/schip_font/B.asc
Normal file
@ -0,0 +1,16 @@
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
16
resources/schip_font/C.asc
Normal file
16
resources/schip_font/C.asc
Normal file
@ -0,0 +1,16 @@
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
16
resources/schip_font/D.asc
Normal file
16
resources/schip_font/D.asc
Normal file
@ -0,0 +1,16 @@
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
0000000000000000
|
||||
16
resources/schip_font/E.asc
Normal file
16
resources/schip_font/E.asc
Normal file
@ -0,0 +1,16 @@
|
||||
0000000000000000
|
||||
0111111111111000
|
||||
0100000000001000
|
||||
0100000000001000
|
||||
0100000000000000
|
||||
0100000000000000
|
||||
0111111111000000
|
||||
0100000000000000
|
||||
0100000000000000
|
||||
0100000000000000
|
||||
0100000000000000
|
||||
0100000000000000
|
||||
0100000000000000
|
||||
0100000000001000
|
||||
0111111111111000
|
||||
0000000000000000
|
||||
16
resources/schip_font/F.asc
Normal file
16
resources/schip_font/F.asc
Normal file
@ -0,0 +1,16 @@
|
||||
0000000000000000
|
||||
0111111111111000
|
||||
0100000000001000
|
||||
0100000000001000
|
||||
0100000000000000
|
||||
0100000000000000
|
||||
0111111111000000
|
||||
0100000000000000
|
||||
0100000000000000
|
||||
0100000000000000
|
||||
0100000000000000
|
||||
0100000000000000
|
||||
0100000000000000
|
||||
0100000000000000
|
||||
0100000000000000
|
||||
0000000000000000
|
||||
Loading…
x
Reference in New Issue
Block a user