more fixed tests and covered text.

This commit is contained in:
Trevor Merritt 2024-09-28 08:55:35 -04:00
parent fc62512edd
commit 731f20d894
4 changed files with 178 additions and 95 deletions

View File

@ -1,3 +1,4 @@
use std::ops::{Shl, Shr};
use imgui::ColorPicker3; use imgui::ColorPicker3;
use log::debug; use log::debug;
use rand::random; use rand::random;
@ -53,6 +54,7 @@ pub enum Chip8CpuInstructions {
LdVxI(u16), // 0xFx65 Load V0 to Vx in memory starting at I LdVxI(u16), // 0xFx65 Load V0 to Vx in memory starting at I
XXXXERRORINSTRUCTION, XXXXERRORINSTRUCTION,
} }
impl Chip8CpuInstructions { impl Chip8CpuInstructions {
pub fn encode(&self) -> u16 { pub fn encode(&self) -> u16 {
match self { match self {
@ -172,7 +174,7 @@ impl Chip8CpuInstructions {
let addr_param = InstructionUtil::read_addr_from_instruction(input); let addr_param = InstructionUtil::read_addr_from_instruction(input);
let byte_param = InstructionUtil::read_byte_from_instruction(input); let byte_param = InstructionUtil::read_byte_from_instruction(input);
let nibble_param = InstructionUtil::read_nibble_from_instruction(input); let nibble_param = InstructionUtil::read_nibble_from_instruction(input);
let ubln = u16::rotate_right(InstructionUtil::read_upper_byte_lower_nibble(input), 8); let ubln = InstructionUtil::read_upper_byte_lower_nibble(input);
let last_byte = input & 0xFF; let last_byte = input & 0xFF;
match input { match input {
@ -303,6 +305,8 @@ impl Chip8CpuInstructions {
0xE09E..=0xEFA1 => { 0xE09E..=0xEFA1 => {
match last_byte { match last_byte {
0x9E => { 0x9E => {
println!("DECODING {:4x}", input);
println!("UBLN: {:4x}", ubln);
Chip8CpuInstructions::SkpVx(ubln) Chip8CpuInstructions::SkpVx(ubln)
} }
0xA1 => { 0xA1 => {
@ -314,7 +318,7 @@ impl Chip8CpuInstructions {
} }
} }
0xF007..=0xFF65 => { 0xF007..=0xFF65 => {
// println!("COMPARING LAST BYTE FROM TODECODE: {:2x} to {:4x} with {:2x}", last_byte, input, ubln); // println!("COMPARING LAST BYTE FROM TODECODE: {:2x} to {:4x} with {:2x}", last_byte, input, ubln);
match last_byte { match last_byte {
0x07 => { 0x07 => {
Chip8CpuInstructions::LdVxDt(ubln) Chip8CpuInstructions::LdVxDt(ubln)
@ -360,7 +364,7 @@ impl Chip8CpuInstructions {
let _ = match self { let _ = match self {
// 0x0nnn Exit to System Call // 0x0nnn Exit to System Call
Chip8CpuInstructions::SysAddr(new_address) => { Chip8CpuInstructions::SysAddr(new_address) => {
// println!("SYS TO [{new_address}]"); // println!("SYS TO [{new_address}]");
input.registers.poke_pc(*new_address as u16); input.registers.poke_pc(*new_address as u16);
} }
// * 0x00E0 Clear Screen // * 0x00E0 Clear Screen
@ -396,10 +400,10 @@ impl Chip8CpuInstructions {
} }
} }
// 0x5xy0 Skip next instruction if Vx == Vy // 0x5xy0 Skip next instruction if Vx == Vy
Chip8CpuInstructions::SeVxVy(x,y) => { Chip8CpuInstructions::SeVxVy(x, y) => {
let lhs = input.registers.peek(*x as u8); let lhs = input.registers.peek(*x as u8);
let rhs = input.registers.peek(*y as u8); let rhs = input.registers.peek(*y as u8);
// println!("COMPARING [{lhs}] to [{rhs}]"); // println!("COMPARING [{lhs}] to [{rhs}]");
if lhs == rhs { if lhs == rhs {
input.registers.advance_pc(); input.registers.advance_pc();
} }
@ -408,7 +412,7 @@ impl Chip8CpuInstructions {
Chip8CpuInstructions::LdVxByte(register, byte) => { Chip8CpuInstructions::LdVxByte(register, byte) => {
let start_value = input.registers.peek(*register as u8); let start_value = input.registers.peek(*register as u8);
let byte_value = *byte as u8; let byte_value = *byte as u8;
// println!("SETTING REGISTER [{register}] FROM [{start_value}] to [{byte_value}] by loading."); // println!("SETTING REGISTER [{register}] FROM [{start_value}] to [{byte_value}] by loading.");
input.registers.poke(*register as u8, byte_value); input.registers.poke(*register as u8, byte_value);
} }
// 0x7xkk Set Vx = Vx + kk // 0x7xkk Set Vx = Vx + kk
@ -452,7 +456,7 @@ impl Chip8CpuInstructions {
} }
input.registers.poke(*x as u8, working as u8); input.registers.poke(*x as u8, working as u8);
} }
Chip8CpuInstructions::SubVxVy(x,y) => { Chip8CpuInstructions::SubVxVy(x, y) => {
// 8xy5 - SUB Vx, Vy // 8xy5 - SUB Vx, Vy
// Set Vx = Vx - Vy, set VF = NOT borrow. // Set Vx = Vx - Vy, set VF = NOT borrow.
// //
@ -470,9 +474,9 @@ impl Chip8CpuInstructions {
if 0xb1 & initial_value == 1 { if 0xb1 & initial_value == 1 {
input.registers.poke(0xf, 1); input.registers.poke(0xf, 1);
} }
input.registers.poke(*x as u8, initial_value.rotate_left(1)); input.registers.poke(*x as u8, initial_value.shr(1));
} }
Chip8CpuInstructions::SubnVxVy(x,y) => { Chip8CpuInstructions::SubnVxVy(x, y) => {
// 8xy7 - SUBN Vx, Vy // 8xy7 - SUBN Vx, Vy
// Set Vx = Vy - Vx, set VF = NOT borrow. // Set Vx = Vy - Vx, set VF = NOT borrow.
// //
@ -494,7 +498,7 @@ impl Chip8CpuInstructions {
if 0x80 & initial_value == 0x80 { if 0x80 & initial_value == 0x80 {
input.registers.poke(0xf, 1); input.registers.poke(0xf, 1);
} }
input.registers.poke(*x as u8, initial_value.rotate_left(1)); input.registers.poke(*x as u8, initial_value.shl(1));
} }
Chip8CpuInstructions::SneVxVy(vx_register, vy_register) => { Chip8CpuInstructions::SneVxVy(vx_register, vy_register) => {
// 9xy0 - SNE Vx, Vy // 9xy0 - SNE Vx, Vy
@ -528,9 +532,10 @@ impl Chip8CpuInstructions {
// Cxkk - RND Vx, byte // Cxkk - RND Vx, byte
// Set Vx = random byte AND kk. // Set Vx = random byte AND kk.
// //
// The interpreter generates a random number from 0 to 255, which is then ANDed with the value kk. The results are stored in Vx. See instruction 8xy2 for more information on AND. // The interpreter generates a random number from 0 to 255,
// which is then ANDed with the value kk.
let new_value: u8 = random() ; // The results are stored in Vx.
let new_value: u8 = random();
input.registers.poke(*x as u8, (new_value & *byte as u8)) input.registers.poke(*x as u8, (new_value & *byte as u8))
} }
Chip8CpuInstructions::DrawVxVyNibble(x, y, n) => { Chip8CpuInstructions::DrawVxVyNibble(x, y, n) => {
@ -548,8 +553,8 @@ impl Chip8CpuInstructions {
let start_position = input.registers.peek_i(); let start_position = input.registers.peek_i();
let num_bytes_to_read = *n; let num_bytes_to_read = *n;
for i in start_position..start_position + num_bytes_to_read { for i in start_position..start_position + num_bytes_to_read {
// let current_byte = input.memory[i as usize]; // let current_byte = input.memory[i as usize];
// println!("READ BYTE [{current_byte:8b}"); // println!("READ BYTE [{current_byte:8b}");
} }
let mut did_change: bool = false; let mut did_change: bool = false;
@ -572,8 +577,6 @@ impl Chip8CpuInstructions {
// //
// Checks the keyboard, and if the key corresponding to the value of Vx is currently in the down position, PC is increased by 2. // 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 key_to_check = input.registers.peek(*x as u8); let key_to_check = input.registers.peek(*x as u8);
} }
Chip8CpuInstructions::SnkpVx(x) => { Chip8CpuInstructions::SnkpVx(x) => {
@ -581,8 +584,6 @@ impl Chip8CpuInstructions {
// Skip next instruction if key with the value of Vx is not pressed. // 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. // Checks the keyboard, and if the key corresponding to the value of Vx is currently in the up position, PC is increased by 2.
} }
Chip8CpuInstructions::LdVxDt(x) => { Chip8CpuInstructions::LdVxDt(x) => {
// Fx07 - LD Vx, DT // Fx07 - LD Vx, DT
@ -598,15 +599,17 @@ impl Chip8CpuInstructions {
// //
// All execution stops until a key is pressed, then the value of that key is stored in Vx. // All execution stops until a key is pressed, then the value of that key is stored in Vx.
} }
Chip8CpuInstructions::LdDtVx(new_time) => { Chip8CpuInstructions::LdDtVx(source_register) => {
// Fx15 - LD DT, Vx // Fx15 - LD DT, Vx
// Set delay timer = Vx. // Set delay timer = Vx.
// //
// DT is set equal to the value of Vx. // DT is set equal to the value of Vx.
println!("SETTING DELAY TIMER TO [{}]", *new_time); let new_time = input.registers.peek(*source_register as u8);
input.delay_timer.set_timer(*new_time as i32); println!("SETTING DELAY TIMER TO [{}]", new_time);
input.delay_timer.set_timer(new_time as i32);
} }
Chip8CpuInstructions::LdStVx(new_time) => { Chip8CpuInstructions::LdStVx(new_time) => {
println!("SETTING SOUND TIMER TO [0x{:2x}]", *new_time);
input.sound_timer.set_timer(*new_time as i32); input.sound_timer.set_timer(*new_time as i32);
} }
Chip8CpuInstructions::AddIVx(x) => { Chip8CpuInstructions::AddIVx(x) => {
@ -623,14 +626,12 @@ impl Chip8CpuInstructions {
// Set I = location of sprite for digit 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. // 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.
} }
Chip8CpuInstructions::LdBVx(x) => { Chip8CpuInstructions::LdBVx(x) => {
// Fx33 - LD B, Vx // Fx33 - LD B, Vx
// Store BCD representation of Vx in memory locations I, I+1, and I+2. // 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. // 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.
} }
Chip8CpuInstructions::LdIVx(x) => { Chip8CpuInstructions::LdIVx(x) => {
// Store registers V0 through Vx in memory starting at location I. // Store registers V0 through Vx in memory starting at location I.
@ -704,8 +705,8 @@ mod test {
assert_eq!(Chip8CpuInstructions::LdBVx(0xd).encode(), 0xfd33); assert_eq!(Chip8CpuInstructions::LdBVx(0xd).encode(), 0xfd33);
assert_eq!(Chip8CpuInstructions::LdIVx(0xe).encode(), 0xfe55); assert_eq!(Chip8CpuInstructions::LdIVx(0xe).encode(), 0xfe55);
assert_eq!(Chip8CpuInstructions::LdVxI(0x3).encode(), 0xf365); assert_eq!(Chip8CpuInstructions::LdVxI(0x3).encode(), 0xf365);
assert!(matches!( Chip8CpuInstructions::decode(0x00E0u16), Chip8CpuInstructions::CLS)); assert!(matches!(Chip8CpuInstructions::decode(0x00E0u16), Chip8CpuInstructions::CLS));
assert!(matches!( Chip8CpuInstructions::decode(0x00EEu16), Chip8CpuInstructions::RET)); assert!(matches!(Chip8CpuInstructions::decode(0x00EEu16), Chip8CpuInstructions::RET));
assert!(matches!(Chip8CpuInstructions::decode(0x0123), Chip8CpuInstructions::SysAddr(0x123))); assert!(matches!(Chip8CpuInstructions::decode(0x0123), Chip8CpuInstructions::SysAddr(0x123)));
assert!(matches!(Chip8CpuInstructions::decode(0x0FFF), Chip8CpuInstructions::SysAddr(0xfff))); assert!(matches!(Chip8CpuInstructions::decode(0x0FFF), Chip8CpuInstructions::SysAddr(0xfff)));
assert!(matches!(Chip8CpuInstructions::decode(0x1002), Chip8CpuInstructions::JpAddr(0x2))); assert!(matches!(Chip8CpuInstructions::decode(0x1002), Chip8CpuInstructions::JpAddr(0x2)));
@ -741,6 +742,7 @@ mod test {
assert!(matches!(Chip8CpuInstructions::decode(0xfd33), Chip8CpuInstructions::LdBVx(0xd))); assert!(matches!(Chip8CpuInstructions::decode(0xfd33), Chip8CpuInstructions::LdBVx(0xd)));
assert!(matches!(Chip8CpuInstructions::decode(0xfe55), Chip8CpuInstructions::LdIVx(0xe))); assert!(matches!(Chip8CpuInstructions::decode(0xfe55), Chip8CpuInstructions::LdIVx(0xe)));
assert!(matches!(Chip8CpuInstructions::decode(0xf365), Chip8CpuInstructions::LdVxI(0x3))); assert!(matches!(Chip8CpuInstructions::decode(0xf365), Chip8CpuInstructions::LdVxI(0x3)));
} }
/// START OF THE EXECUTION TESTS /// START OF THE EXECUTION TESTS
@ -755,9 +757,13 @@ mod test {
Chip8CpuInstructions::SysAddr(0x0AF).execute(&mut x); Chip8CpuInstructions::SysAddr(0x0AF).execute(&mut x);
assert_eq!(x.registers.peek_pc(), 0x0AF); assert_eq!(x.registers.peek_pc(), 0x0AF);
} }
fn cls_test() { fn cls_test() {
// * 0x00E0 Clear Screen // * 0x00E0 Clear Screen
// todo: Need to write this // todo: Need to write this
let mut x = Chip8Computer::new();
} }
fn ret_test() { fn ret_test() {
@ -875,7 +881,6 @@ mod test {
Chip8CpuInstructions::LdVxVy(0x01, 0x02).execute(&mut x); Chip8CpuInstructions::LdVxVy(0x01, 0x02).execute(&mut x);
assert_eq!(x.registers.peek(1), 0x02); assert_eq!(x.registers.peek(1), 0x02);
assert_eq!(x.registers.peek_pc(), 0x206); assert_eq!(x.registers.peek_pc(), 0x206);
} }
#[test] #[test]
@ -887,7 +892,7 @@ mod test {
let mut x = Chip8Computer::new(); let mut x = Chip8Computer::new();
Chip8CpuInstructions::LdVxByte(1, 0x50).execute(&mut x); Chip8CpuInstructions::LdVxByte(1, 0x50).execute(&mut x);
Chip8CpuInstructions::LdVxByte(2, 0x0A).execute(&mut x); Chip8CpuInstructions::LdVxByte(2, 0x0A).execute(&mut x);
Chip8CpuInstructions::OrVxVy(1,2).execute(&mut x); Chip8CpuInstructions::OrVxVy(1, 2).execute(&mut x);
assert_eq!(x.registers.peek(1), 0x5A); assert_eq!(x.registers.peek(1), 0x5A);
assert_eq!(x.registers.peek_pc(), 0x206); assert_eq!(x.registers.peek_pc(), 0x206);
} }
@ -901,7 +906,7 @@ mod test {
let mut x = Chip8Computer::new(); let mut x = Chip8Computer::new();
Chip8CpuInstructions::LdVxByte(1, 0xFC).execute(&mut x); Chip8CpuInstructions::LdVxByte(1, 0xFC).execute(&mut x);
Chip8CpuInstructions::LdVxByte(2, 0xCA).execute(&mut x); Chip8CpuInstructions::LdVxByte(2, 0xCA).execute(&mut x);
Chip8CpuInstructions::AndVxVy(1,2).execute(&mut x); Chip8CpuInstructions::AndVxVy(1, 2).execute(&mut x);
assert_eq!(x.registers.peek(1), 0xC8); assert_eq!(x.registers.peek(1), 0xC8);
assert_eq!(x.registers.peek_pc(), 0x206); assert_eq!(x.registers.peek_pc(), 0x206);
} }
@ -915,7 +920,7 @@ mod test {
let mut x = Chip8Computer::new(); let mut x = Chip8Computer::new();
Chip8CpuInstructions::LdVxByte(1, 0xFC).execute(&mut x); Chip8CpuInstructions::LdVxByte(1, 0xFC).execute(&mut x);
Chip8CpuInstructions::LdVxByte(2, 0xCA).execute(&mut x); Chip8CpuInstructions::LdVxByte(2, 0xCA).execute(&mut x);
Chip8CpuInstructions::XorVxVy(1,2).execute(&mut x); Chip8CpuInstructions::XorVxVy(1, 2).execute(&mut x);
assert_eq!(x.registers.peek(1), 0x36); assert_eq!(x.registers.peek(1), 0x36);
assert_eq!(x.registers.peek_pc(), 0x206); assert_eq!(x.registers.peek_pc(), 0x206);
} }
@ -941,69 +946,90 @@ mod test {
Chip8CpuInstructions::LdVxByte(0xf, 0x00).execute(&mut x); Chip8CpuInstructions::LdVxByte(0xf, 0x00).execute(&mut x);
Chip8CpuInstructions::LdVxByte(0x1, 0xff).execute(&mut x); Chip8CpuInstructions::LdVxByte(0x1, 0xff).execute(&mut x);
Chip8CpuInstructions::LdVxByte(0x2, 0x01).execute(&mut x); Chip8CpuInstructions::LdVxByte(0x2, 0x01).execute(&mut x);
Chip8CpuInstructions::AddVxVy(1,2).execute(&mut x); Chip8CpuInstructions::AddVxVy(1, 2).execute(&mut x);
// T2 // T2
assert_eq!(x.registers.peek(0xf), 1); assert_eq!(x.registers.peek(0xf), 1);
assert_eq!(x.registers.peek(1), 0); assert_eq!(x.registers.peek(1), 0);
assert_eq!(x.registers.peek_pc(), 0x208) assert_eq!(x.registers.peek_pc(), 0x208)
} }
/* #[test] /* #[test]
fn SubVxVy_test() { fn SubVxVy_test() {
todo: this test sucks. dont have the borrow concept in here. todo: this test sucks. dont have the borrow concept in here.
Set Vx = Vx - Vy, set VF = NOT borrow. Set Vx = Vx - Vy, set VF = NOT borrow.
If Vx > Vy, then VF is set to 1, otherwise 0. If Vx > Vy, then VF is set to 1, otherwise 0.
Then Vy is subtracted from Vx, and the results stored in Vx. Then Vy is subtracted from Vx, and the results stored in Vx.
let mut x = Chip8Computer::new(); let mut x = Chip8Computer::new();
Chip8CpuInstructions::LdVxByte(1, 0x10).execute(&mut x); Chip8CpuInstructions::LdVxByte(1, 0x10).execute(&mut x);
Chip8CpuInstructions::LdVxByte(2, 0x01).execute(&mut x); Chip8CpuInstructions::LdVxByte(2, 0x01).execute(&mut x);
Chip8CpuInstructions::LdVxByte(0xf, 0x00).execute(&mut x); Chip8CpuInstructions::LdVxByte(0xf, 0x00).execute(&mut x);
Chip8CpuInstructions::SubVxVy(0x1, 0x2).execute(&mut x); Chip8CpuInstructions::SubVxVy(0x1, 0x2).execute(&mut x);
assert_eq!(x.registers.peek_pc(), 0x208); assert_eq!(x.registers.peek_pc(), 0x208);
assert_eq!(x.registers.peek(1), 0xF); assert_eq!(x.registers.peek(1), 0xF);
assert_eq!(x.registers.peek(0x10), 0); assert_eq!(x.registers.peek(0x10), 0);
} }
*/ */
#[test]
fn ShrVxVy_test() { fn ShrVxVy_test() {
/* /*
Set Vx = Vx SHR 1. 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. If the least-significant bit of Vx is 1, then VF is set to 1, otherwise 0. Then Vx is divided by 2.
*/ */
let x = Chip8Computer::new(); let mut x = Chip8Computer::new();
Chip8CpuInstructions::LdVxByte(0xf, 0x00); Chip8CpuInstructions::LdVxByte(0xf, 0x00).execute(&mut x);
Chip8CpuInstructions::LdVxByte(0x1, 0x08); // 0b0000 1000 (0x08) Chip8CpuInstructions::LdVxByte(0x1, 0x08).execute(&mut x); // 0b0000 1000 (0x08)
Chip8CpuInstructions::LdVxByte(0x2, 0x2); Chip8CpuInstructions::LdVxByte(0x2, 0x2).execute(&mut x);
Chip8CpuInstructions::ShrVxVy(0x1, 0x2); // 0b0000 0010 (0x02) (Not Set) Chip8CpuInstructions::ShrVxVy(0x1, 0x2).execute(&mut x); // 0b0000 0010 (0x02) (Not Set)
assert_eq!(x.registers.peek(1), 0x02); assert_eq!(x.registers.peek(1), 0x04);
assert_eq!(x.registers.peek(0xf), 0); assert_eq!(x.registers.peek(0xf), 0);
assert_eq!(x.registers.peek_pc(), 0x206); assert_eq!(x.registers.peek_pc(), 0x208);
let x = Chip8Computer::new(); let mut x = Chip8Computer::new();
Chip8CpuInstructions::LdVxByte(0xf, 0x00); Chip8CpuInstructions::LdVxByte(0xf, 0x00).execute(&mut x);
Chip8CpuInstructions::LdVxByte(0x1, 0x09); // 0b0000 1001 (0x09) Chip8CpuInstructions::LdVxByte(0x1, 0b00001001).execute(&mut x); // 0b0000 1001 (0x09)
Chip8CpuInstructions::LdVxByte(0x2, 0x2); Chip8CpuInstructions::ShrVxVy(0x1, 0x2).execute(&mut x); // 0b0000 0100 (0x02) (Set)
Chip8CpuInstructions::ShrVxVy(0x1, 0x2); // 0b0000 0010 (0x02) (Set) Chip8CpuInstructions::ShrVxVy(0x1, 0x1).execute(&mut x);
assert_eq!(x.registers.peek(1), 0x02); assert_eq!(x.registers.peek(0x1), 0b00000010);
assert_eq!(x.registers.peek(0xf), 1); assert_eq!(x.registers.peek(0xf), 0x1);
assert_eq!(x.registers.peek_pc(), 0x206); assert_eq!(x.registers.peek_pc(), 0x208);
} }
fn SneVxVy_test() {} fn SneVxVy_test() {}
fn LdiAddr_test() {} fn LdiAddr_test() {}
fn JpV0Addr_test() {} fn JpV0Addr_test() {}
fn RndVxByte_test() {}
#[test]
fn RndVxByte_test() {
let mut x = Chip8Computer::new();
// generate random number masked by 0xF0;
let mask = 0xF0u8;
Chip8CpuInstructions::RndVxByte(0x0, mask as u16).execute(&mut x);
let register_value = x.registers.peek(0x0);
assert!(register_value < mask);
// generate random number masked by 0x0F;
let mask2 = 0x0Fu8;
Chip8CpuInstructions::RndVxByte(0x1, mask2 as u16).execute(&mut x);
let register_value = x.registers.peek(0x1);
assert!(register_value < mask);
}
fn DrawVxVyNibble_test() {} fn DrawVxVyNibble_test() {}
fn SkpVx_test() { fn SkpVx_test() {
// skip if key pressed // skip if key pressed
} }
fn SnKpVx_test() { fn SnKpVx_test() {
// skip key not pressed // skip key not pressed
} }
#[test] #[test]
fn LdVxDt_test() { fn LdVxDt_test() {
// delay timer reading // delay timer reading
@ -1028,33 +1054,54 @@ mod test {
fn LdVxK_test() { fn LdVxK_test() {
// Wait for a key press, store the value of the key in Vx. // Wait for a key press, store the value of the key in Vx.
// All execution stops until a key is pressed, then the value of that key is stored in Vx. // All execution stops until a key is pressed, then the value of that key is stored in Vx.
} }
#[test]
fn LdStVx_test() { fn LdStVx_test() {
// sound timer setting // sound timer setting
}
fn LdIVx_test() {}
fn LdVxI_test() {}
/*
#[test]
fn LdDtVx_test() {
// delay timer setting
let mut x = Chip8Computer::new(); let mut x = Chip8Computer::new();
Chip8CpuInstructions::LdVxByte(0x1, 0x10).execute(&mut x);
Chip8CpuInstructions::LdStVx(0x10).execute(&mut x);
// lets set our delay timer... // tick from 0x8 to 0x1
Chip8CpuInstructions::LdVxByte(0x0, 0x80).execute(&mut x); for i in 0..6 { x.sound_timer.tick(); }
Chip8CpuInstructions::LdDtVx(0x0).execute(&mut x);
// now that we have our timer set to 0x80 we should tick it 0x10 times assert_eq!(x.sound_timer.current(), 0xA);
// so we are then down to 0x70
for i in 0..0x10 {
x.delay_timer.tick();
}
// Then tell the CPU to copy that timer over into our V0
Chip8CpuInstructions::LdVxK(0x0).execute(&mut x);
let register_value = x.registers.peek(0);
// assert_eq!(register_value, 0x70);
} }
*/
fn LdIVx_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.
}
fn LdVxI_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.
/*
#[test]
fn LdDtVx_test() {
// delay timer setting
let mut x = Chip8Computer::new();
// lets set our delay timer...
Chip8CpuInstructions::LdVxByte(0x0, 0x80).execute(&mut x);
Chip8CpuInstructions::LdDtVx(0x0).execute(&mut x);
// now that we have our timer set to 0x80 we should tick it 0x10 times
// so we are then down to 0x70
for i in 0..0x10 {
x.delay_timer.tick();
}
// Then tell the CPU to copy that timer over into our V0
Chip8CpuInstructions::LdVxK(0x0).execute(&mut x);
let register_value = x.registers.peek(0);
// assert_eq!(register_value, 0x70);
}
*/
} }

View File

@ -56,4 +56,7 @@ impl Chip8Registers {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
#[test]
fn smoke() { assert!(true) }
} }

View File

@ -19,6 +19,7 @@ impl SoundTimer {
} }
pub fn tick(&mut self) { pub fn tick(&mut self) {
println!("TICKING SOUND FROM {} to {}", self.counter, self.counter - 1);
if self.counter > 0 { if self.counter > 0 {
self.counter -= 1; self.counter -= 1;
/* /*

View File

@ -1,6 +1,25 @@
pub struct InstructionUtil {} pub struct InstructionUtil {}
impl InstructionUtil { impl InstructionUtil {
pub fn byte_to_bools(to_convert: u8) -> [bool; 8] {
let mut return_values = [false; 8];
for i in 0..8 {
let new_value = to_convert >> i & 0x1 == 1;
return_values[i as usize] = new_value;
}
return_values
}
pub fn bools_to_byte(to_convert: [bool; 8]) -> u8 {
let mut return_value = 0u8;
for i in 0..to_convert.len() {
let new_bit = 0x1 << i;
if to_convert[i] {
return_value = return_value | new_bit
}
}
return_value
}
pub fn split_bytes(to_split: u16) -> (u8, u8) { pub fn split_bytes(to_split: u16) -> (u8, u8) {
let high = to_split.rotate_left(8) as u8; let high = to_split.rotate_left(8) as u8;
@ -10,7 +29,7 @@ impl InstructionUtil {
} }
pub fn join_bytes(high: u8, low: u8) -> u16 { pub fn join_bytes(high: u8, low: u8) -> u16 {
let result = (high as u16 )<< 8 | low as u16; let result = (high as u16) << 8 | low as u16;
result result
} }
@ -40,11 +59,10 @@ impl InstructionUtil {
} }
pub fn read_upper_byte_lower_nibble(to_read_from: u16) -> u16 { pub fn read_upper_byte_lower_nibble(to_read_from: u16) -> u16 {
to_read_from & 0x0f00 (to_read_from & 0x0f00) >> 8
} }
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
@ -65,7 +83,7 @@ mod test {
#[test] #[test]
fn join_bytes() { fn join_bytes() {
// from 0xAB low and 0xCD high we get 0xABCD // from 0xAB low and 0xCD high we get 0xABCD
let merged = InstructionUtil::join_bytes( 0xcd, 0xab); let merged = InstructionUtil::join_bytes(0xcd, 0xab);
assert_eq!(merged, 0xcdab); assert_eq!(merged, 0xcdab);
} }
@ -83,6 +101,20 @@ mod test {
#[test] #[test]
fn ubln() { fn ubln() {
// from 0xABCD we should see B // from 0xABCD we should see B
assert_eq!(InstructionUtil::read_upper_byte_lower_nibble(0xABCD), 0xB << 8); 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);
}
}