more test suite evolution
This commit is contained in:
parent
24ea413848
commit
9d3fabe0c3
@ -17,36 +17,98 @@ kk or byte - An 8-bit value, the lowest 8 bits of the instruction
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Chip8CpuInstructions {
|
pub enum Chip8CpuInstructions {
|
||||||
SysAddr(i16), // 0x0nnn Exit to System Call
|
/// 0nnn
|
||||||
CLS, // * 0x00E0 Clear Screen
|
/// Exit to System Call at nnn
|
||||||
RET, // 0x00EE Return from Subroutine
|
SysAddr(i16),
|
||||||
JpAddr(i16), // 0x1nnn Jump to Address
|
/// Clear Screen
|
||||||
CallAddr(i16), // 0x2nnn Call Subroutine
|
CLS,
|
||||||
SeVxByte(i16, i16), // 0x3xkk Skip next instruction if Vx = kk.
|
/// Return from Subroutine
|
||||||
SneVxByte(i16, i16), // 0x4xkk Skip next instruction if Vx != kk
|
RET,
|
||||||
SeVxVy(u16, u16), // 0x5xy0 Skip next instruction if Vx == Vy
|
/// 1nnn
|
||||||
LdVxByte(u16, u16), // * 0x6xkk Set Vx = kk
|
/// Jump to Address nnn
|
||||||
AddVxByte(u16, u16), // 0x7xkk Set Vx = Vx + kk
|
JpAddr(i16),
|
||||||
LdVxVy(u16, u16), // 0x8xy0 Set value of Vy in Vx
|
/// 2nnn
|
||||||
OrVxVy(u16, u16), // 0x8xy1 Set Vx = Vx OR Vy
|
/// Call Subroutine at nnn
|
||||||
AndVxVy(u16, u16), // 0x8xy2 Set Vx = Vx AND Vy
|
CallAddr(i16),
|
||||||
XorVxVy(u16, u16), // 0x8xy3 Set Vx = Vx XOR Vy
|
/// 0x3xkk
|
||||||
AddVxVy(u16, u16), // 0x8xy4 Set Vx = Vx + Vy (SET VF on Carry)
|
/// Skip next instruction if Vx == kk
|
||||||
SubVxVy(u16, u16), // 0x8xy5 Set Vx = Vx - Vy (Set VF NOT Borrow)
|
SeVxByte(i16, i16),
|
||||||
ShrVxVy(u16, u16), // 0x8xy6 Set Vx = Vx SHR 1 (Shift Rotated Right 1)
|
/// 4xkk
|
||||||
SubnVxVy(u16, u16), // 0x8xy7 Set Vx = Vy - Vx (Set VF NOT Borrow)
|
/// Skip next instruction if Vx != kk
|
||||||
ShlVxVy(u16, u16), // 0x8xyE Shift Left
|
SneVxByte(i16, i16),
|
||||||
SneVxVy(u16, u16), // 0x9xy0 Skip next instruction if Vx != Vy
|
/// 5xy0
|
||||||
LdIAddr(u16), // * 0xAnnn VI = nnn
|
/// Skip next instruction if Vx == Vy
|
||||||
JpV0Addr(u16), // 0xBnnn Jump to nnn+V0
|
SeVxVy(u16, u16),
|
||||||
RndVxByte(u16, u16), // 0xCxkk Vx = random byte AND kk
|
/// 6xkk
|
||||||
DrawVxVyNibble(u16, u16, u16), // * 0xDxyn Display N byte sprite starting at Vx to Vy
|
/// Set Vx = kk
|
||||||
SkpVx(u16), // 0xE09E Skip next instruction if key in Vx pressed
|
LdVxByte(u16, u16),
|
||||||
SnkpVx(u16), // 0xE0A1 Skip next instruction if key in Vx NOT pressed
|
/// 7xkk
|
||||||
LdVxDt(u16), // 0xFx07 Set Vx = Delay timer
|
/// Set Vx = Vx + kk
|
||||||
LdVxK(u16), // 0xFx0A Wait for key, put in Vx
|
AddVxByte(u16, u16),
|
||||||
|
/// 8xy0
|
||||||
|
/// Set Vx = Vy
|
||||||
|
LdVxVy(u16, u16),
|
||||||
|
/// 8xy1
|
||||||
|
/// Set Vx = Vx OR Vy
|
||||||
|
OrVxVy(u16, u16),
|
||||||
|
/// 8xy2
|
||||||
|
/// Set Vx = Vx AND Vy
|
||||||
|
AndVxVy(u16, u16),
|
||||||
|
/// 8xy3
|
||||||
|
/// Set Vx = Vx XOR Vy
|
||||||
|
XorVxVy(u16, u16),
|
||||||
|
/// 8xy4
|
||||||
|
/// Set Vx = Vx + Vy
|
||||||
|
/// Set VF=1 if Carry
|
||||||
|
AddVxVy(u16, u16),
|
||||||
|
/// 8xy5
|
||||||
|
/// Set Vx = Vx - Vy
|
||||||
|
/// Set VF=1 if No Borrow
|
||||||
|
SubVxVy(u16, u16),
|
||||||
|
/// 8xy6
|
||||||
|
/// Set Vx = Vx SHR 1
|
||||||
|
ShrVxVy(u16, u16),
|
||||||
|
/// 8xy7
|
||||||
|
/// Set Vx = Vy - Vx
|
||||||
|
/// Set VF=1 if No Borrow
|
||||||
|
SubnVxVy(u16, u16),
|
||||||
|
/// 8xye
|
||||||
|
/// Set Vx = Vx SHL 1
|
||||||
|
ShlVxVy(u16, u16),
|
||||||
|
/// 9xy0
|
||||||
|
/// Skip next instruction if Vx != Vy
|
||||||
|
SneVxVy(u16, u16),
|
||||||
|
/// Annn
|
||||||
|
/// Load I register with NNN
|
||||||
|
LdIAddr(u16),
|
||||||
|
/// Bnnn
|
||||||
|
/// Jump to nnn+V0
|
||||||
|
JpV0Addr(u16),
|
||||||
|
/// Cxkk
|
||||||
|
/// Set Vx = Random u8 AND kk
|
||||||
|
RndVxByte(u16, u16),
|
||||||
|
/// Dxyn
|
||||||
|
/// Display N byte tall sprite starting at Vx, Vy
|
||||||
|
DrawVxVyNibble(u16, u16, u16),
|
||||||
|
/// Ex9E
|
||||||
|
/// Skip next instruction of key in Vx pressed
|
||||||
|
SkpVx(u16),
|
||||||
|
/// ExA1
|
||||||
|
/// Skip Next If Key Not Pressed
|
||||||
|
SnkpVx(u16),
|
||||||
|
/// Fx07
|
||||||
|
/// Set Vx = Dt
|
||||||
|
LdVxDt(u16),
|
||||||
|
/// Fx0A
|
||||||
|
/// Wait for Key to be pressed and store
|
||||||
|
/// in Vx
|
||||||
|
LdVxK(u16),
|
||||||
|
/// Fx15
|
||||||
|
/// Load Value in Delay Timer to Vx
|
||||||
LdDtVx(u16), // 0xFx15 Set Delay Timer
|
LdDtVx(u16), // 0xFx15 Set Delay Timer
|
||||||
LdStVx(u16), // 0xFx18 Set Sount Timer
|
/// Fx18
|
||||||
|
/// Set Dt = Vx
|
||||||
|
LdStVx(u16),
|
||||||
AddIVx(u16), // 0xFx1E I = I + Vx
|
AddIVx(u16), // 0xFx1E I = I + Vx
|
||||||
LdFVx(u16), // 0xFx29 Set I = Location of sprite for Digit Vx
|
LdFVx(u16), // 0xFx29 Set I = Location of sprite for Digit Vx
|
||||||
LdBVx(u16), // 0xFx33 Store BCD of Vx in I, I+1, I+2
|
LdBVx(u16), // 0xFx33 Store BCD of Vx in I, I+1, I+2
|
||||||
@ -163,7 +225,7 @@ impl Chip8CpuInstructions {
|
|||||||
Chip8CpuInstructions::LdVxI(x_register) => {
|
Chip8CpuInstructions::LdVxI(x_register) => {
|
||||||
0xf065u16 | x_register << 8
|
0xf065u16 | x_register << 8
|
||||||
}
|
}
|
||||||
_ => {
|
XXXXERRORINSTRUCTION => {
|
||||||
0xffff
|
0xffff
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -393,9 +455,7 @@ impl Chip8CpuInstructions {
|
|||||||
}
|
}
|
||||||
// 0x4xkk Skip next instruction if Vx != kk
|
// 0x4xkk Skip next instruction if Vx != kk
|
||||||
Chip8CpuInstructions::SneVxByte(x, byte) => {
|
Chip8CpuInstructions::SneVxByte(x, byte) => {
|
||||||
let lhs = input.registers.peek(*x as u8);
|
if input.registers.peek(*x as u8) != *byte as u8 {
|
||||||
let rhs = byte.to_be_bytes()[0];
|
|
||||||
if lhs == rhs {
|
|
||||||
input.registers.advance_pc();
|
input.registers.advance_pc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -410,7 +470,8 @@ impl Chip8CpuInstructions {
|
|||||||
}
|
}
|
||||||
// 0x6xkk Set Vx = kk
|
// 0x6xkk Set Vx = kk
|
||||||
Chip8CpuInstructions::LdVxByte(register, byte) => {
|
Chip8CpuInstructions::LdVxByte(register, byte) => {
|
||||||
input.registers.poke(*register as u8, *byte as u8);
|
let byte_value = *byte as u8;
|
||||||
|
input.registers.poke(*register as u8, byte_value);
|
||||||
}
|
}
|
||||||
// 0x7xkk Set Vx = Vx + kk
|
// 0x7xkk Set Vx = Vx + kk
|
||||||
Chip8CpuInstructions::AddVxByte(vx_register, byte) => {
|
Chip8CpuInstructions::AddVxByte(vx_register, byte) => {
|
||||||
@ -565,9 +626,14 @@ impl Chip8CpuInstructions {
|
|||||||
// ExA1 - SKNP Vx
|
// ExA1 - SKNP Vx
|
||||||
// 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.
|
|
||||||
let key_to_check = input.registers.peek(*x as u8);
|
// Checks the keyboard,
|
||||||
let is_pressed = input.keypad.pressed(*x as u8);
|
// and if the key corresponding to the value of Vx is currently in the up position,
|
||||||
|
// PC is increased by 2.
|
||||||
|
let target_key = input.registers.peek(*x as u8);
|
||||||
|
println!("TESTING REGISTER {x} -> READ {target_key}");
|
||||||
|
let is_pressed = input.keypad.pressed(target_key);
|
||||||
|
println!("KEY STATE = {is_pressed}");
|
||||||
if is_pressed {
|
if is_pressed {
|
||||||
input.registers.advance_pc();
|
input.registers.advance_pc();
|
||||||
}
|
}
|
||||||
@ -577,8 +643,8 @@ impl Chip8CpuInstructions {
|
|||||||
// Set Vx = delay timer value.
|
// Set Vx = delay timer value.
|
||||||
//
|
//
|
||||||
// The value of DT is placed into Vx.
|
// The value of DT is placed into Vx.
|
||||||
let value_to_set = input.registers.peek(*x as u8);
|
let value_to_set = input.delay_timer.current();
|
||||||
input.delay_timer.set_timer(value_to_set as i32);
|
input.registers.poke(*x as u8, value_to_set as u8);
|
||||||
}
|
}
|
||||||
Chip8CpuInstructions::LdVxK(x) => {
|
Chip8CpuInstructions::LdVxK(x) => {
|
||||||
// Fx0A - LD Vx, K
|
// Fx0A - LD Vx, K
|
||||||
@ -595,7 +661,8 @@ impl Chip8CpuInstructions {
|
|||||||
input.delay_timer.set_timer(new_time as i32);
|
input.delay_timer.set_timer(new_time as i32);
|
||||||
}
|
}
|
||||||
Chip8CpuInstructions::LdStVx(new_time) => {
|
Chip8CpuInstructions::LdStVx(new_time) => {
|
||||||
input.sound_timer.set_timer(*new_time as i32);
|
let new_value = input.registers.peek(*new_time as u8);
|
||||||
|
input.sound_timer.set_timer(new_value as i32);
|
||||||
}
|
}
|
||||||
Chip8CpuInstructions::AddIVx(x) => {
|
Chip8CpuInstructions::AddIVx(x) => {
|
||||||
// Fx1E - ADD I, Vx
|
// Fx1E - ADD I, Vx
|
||||||
@ -646,6 +713,7 @@ impl Chip8CpuInstructions {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use ratatui::crossterm::execute;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -756,19 +824,6 @@ mod test {
|
|||||||
assert_eq!(x.registers.peek_pc(), 0x0AF);
|
assert_eq!(x.registers.peek_pc(), 0x0AF);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cls_test() {
|
|
||||||
// * 0x00E0 Clear Screen
|
|
||||||
// todo: Need to write this
|
|
||||||
let mut x = Chip8Computer::new();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ret_test() {
|
|
||||||
// 0x00EE Return from Subroutine
|
|
||||||
// todo: no stack yet.
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn jpaddr_test() {
|
fn jpaddr_test() {
|
||||||
// 0x1nnn Jump to Address
|
// 0x1nnn Jump to Address
|
||||||
@ -779,11 +834,6 @@ mod test {
|
|||||||
assert_eq!(x.registers.peek_pc(), 0xABC);
|
assert_eq!(x.registers.peek_pc(), 0xABC);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calladdr_test() {
|
|
||||||
// 0x2nnn Call Subroutine
|
|
||||||
// todo: no stack
|
|
||||||
}
|
|
||||||
|
|
||||||
// ** test moved up so it can be used later
|
// ** test moved up so it can be used later
|
||||||
#[test]
|
#[test]
|
||||||
fn LdVxByte_test() {
|
fn LdVxByte_test() {
|
||||||
@ -857,17 +907,6 @@ mod test {
|
|||||||
assert_eq!(x.registers.peek_pc(), 0x20C);
|
assert_eq!(x.registers.peek_pc(), 0x20C);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn AddVxByte_test() {
|
|
||||||
// 0x7xkk Set Vx = Vx + kk
|
|
||||||
let mut x = Chip8Computer::new();
|
|
||||||
Chip8CpuInstructions::LdVxByte(0x01, 0x01).execute(&mut x);
|
|
||||||
Chip8CpuInstructions::LdVxByte(0x02, 0x02).execute(&mut x);
|
|
||||||
assert_eq!(x.registers.peek_pc(), 0x204);
|
|
||||||
Chip8CpuInstructions::AddVxVy(0x01, 0x02).execute(&mut x);
|
|
||||||
assert_eq!(x.registers.peek(1), 0x03);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn LdVxVy_test() {
|
fn LdVxVy_test() {
|
||||||
// 0x8xy0 Set value of Vy in Vx
|
// 0x8xy0 Set value of Vy in Vx
|
||||||
@ -950,24 +989,6 @@ mod test {
|
|||||||
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]
|
|
||||||
fn SubVxVy_test() {
|
|
||||||
todo: this test sucks. dont have the borrow concept in here.
|
|
||||||
Set Vx = Vx - Vy, set VF = NOT borrow.
|
|
||||||
If Vx > Vy, then VF is set to 1, otherwise 0.
|
|
||||||
Then Vy is subtracted from Vx, and the results stored in Vx.
|
|
||||||
let mut x = Chip8Computer::new();
|
|
||||||
Chip8CpuInstructions::LdVxByte(1, 0x10).execute(&mut x);
|
|
||||||
Chip8CpuInstructions::LdVxByte(2, 0x01).execute(&mut x);
|
|
||||||
Chip8CpuInstructions::LdVxByte(0xf, 0x00).execute(&mut x);
|
|
||||||
Chip8CpuInstructions::SubVxVy(0x1, 0x2).execute(&mut x);
|
|
||||||
|
|
||||||
assert_eq!(x.registers.peek_pc(), 0x208);
|
|
||||||
assert_eq!(x.registers.peek(1), 0xF);
|
|
||||||
assert_eq!(x.registers.peek(0x10), 0);
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ShrVxVy_test() {
|
fn ShrVxVy_test() {
|
||||||
@ -985,82 +1006,38 @@ mod test {
|
|||||||
assert_eq!(x.registers.peek(0xf), 0);
|
assert_eq!(x.registers.peek(0xf), 0);
|
||||||
assert_eq!(x.registers.peek_pc(), 0x208);
|
assert_eq!(x.registers.peek_pc(), 0x208);
|
||||||
|
|
||||||
let mut x = Chip8Computer::new();
|
x = Chip8Computer::new();
|
||||||
Chip8CpuInstructions::LdVxByte(0xf, 0x00).execute(&mut x);
|
Chip8CpuInstructions::LdVxByte(0xf, 0x00).execute(&mut x);
|
||||||
Chip8CpuInstructions::LdVxByte(0x1, 0b00001001).execute(&mut x); // 0b0000 1001 (0x09)
|
Chip8CpuInstructions::LdVxByte(0x1, 0b00001001).execute(&mut x); // 0b0000 1001 (0x09)
|
||||||
Chip8CpuInstructions::ShrVxVy(0x1, 0x2).execute(&mut x); // 0b0000 0100 (0x02) (Set)
|
Chip8CpuInstructions::ShrVxVy(0x1, 0x2).execute(&mut x); // 0b0000 0010 (0x02) (Set)
|
||||||
Chip8CpuInstructions::ShrVxVy(0x1, 0x1).execute(&mut x);
|
assert_eq!(x.registers.peek(1), 0x04);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn SneVxVy_test() {
|
|
||||||
// 9xy0 - SNE Vx, Vy
|
|
||||||
// Skip next instruction if Vx != Vy.
|
|
||||||
//
|
|
||||||
// The values of Vx and Vy are compared, and if they are not equal, the program counter is increased by 2.
|
|
||||||
let mut x = Chip8Computer::new();
|
|
||||||
Chip8CpuInstructions::LdVxByte(0x01, 0xab).execute(&mut x);
|
|
||||||
Chip8CpuInstructions::LdVxByte(0x02, 0xba).execute(&mut x);
|
|
||||||
// they are not the same. we should skip.
|
|
||||||
assert_eq!(x.registers.peek_pc(), 0x204);
|
|
||||||
Chip8CpuInstructions::SneVxVy(0x01, 0x02).execute(&mut x);
|
|
||||||
assert_eq!(x.registers.peek_pc(), 0x208);
|
|
||||||
|
|
||||||
Chip8CpuInstructions::LdVxByte(0x02, 0xab).execute(&mut x);
|
|
||||||
Chip8CpuInstructions::SneVxVy(0x01, 0x02).execute(&mut x);
|
|
||||||
assert_eq!(x.registers.peek_pc(), 0x20C);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn LdiAddr_test() {
|
fn LdiAddr_test() {
|
||||||
// Annn - LD I, addr
|
|
||||||
// Set I = nnn.
|
|
||||||
//
|
|
||||||
// The value of register I is set to nnn.
|
|
||||||
let mut x = Chip8Computer::new();
|
let mut x = Chip8Computer::new();
|
||||||
|
Chip8CpuInstructions::LdIAddr(0x123).execute(&mut x);
|
||||||
let value_for_memory = 0xbe;
|
assert_eq!(x.registers.peek_i(), 0x123);
|
||||||
// load the value into V0
|
assert_eq!(x.registers.peek_pc(), 0x202);
|
||||||
Chip8CpuInstructions::LdIAddr(0xfab).execute(&mut x);
|
|
||||||
assert_eq!(x.registers.peek_i(), 0xfab);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn JpV0Addr_test() {
|
|
||||||
// Bnnn - JP V0, addr
|
|
||||||
// Jump to location nnn + V0.
|
|
||||||
//
|
|
||||||
// The program counter is set to nnn plus the value of V0.
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn RndVxByte_test() {
|
fn JpV0Addr_test() {
|
||||||
let mut x = Chip8Computer::new();
|
let mut x = Chip8Computer::new();
|
||||||
|
/// jump to I + nnn
|
||||||
// generate random number masked by 0xF0;
|
Chip8CpuInstructions::LdVxByte(0x0, 0xFF).execute(&mut x);
|
||||||
let mask = 0xF0u8;
|
Chip8CpuInstructions::JpV0Addr(0x100).execute(&mut x);
|
||||||
Chip8CpuInstructions::RndVxByte(0x0, mask as u16).execute(&mut x);
|
assert_eq!(x.registers.peek_pc(), 0x1FF);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
// #[test]
|
||||||
fn DrawVxVyNibble_test() {}
|
|
||||||
|
|
||||||
fn SkpVx_test() {
|
|
||||||
// skip if key pressed
|
|
||||||
}
|
|
||||||
|
|
||||||
fn SnKpVx_test() {
|
fn SnKpVx_test() {
|
||||||
// skip key not pressed
|
// skip key not pressed
|
||||||
|
let mut x = Chip8Computer::new();
|
||||||
|
x.keypad.push_key(2);
|
||||||
|
Chip8CpuInstructions::LdVxByte(0x1, 0x02);
|
||||||
|
Chip8CpuInstructions::SnkpVx(2).execute(&mut x);
|
||||||
|
assert_eq!(x.registers.peek_pc(), 0x204);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1069,72 +1046,84 @@ mod test {
|
|||||||
let mut x = Chip8Computer::new();
|
let mut x = Chip8Computer::new();
|
||||||
|
|
||||||
// set the value we want in the timer to V0...
|
// set the value we want in the timer to V0...
|
||||||
Chip8CpuInstructions::LdVxByte(0x0, 0x10).execute(&mut x);
|
Chip8CpuInstructions::LdVxByte(0x1, 0x10).execute(&mut x);
|
||||||
|
Chip8CpuInstructions::LdDtVx(0x1).execute(&mut x);
|
||||||
// ...then tell the CPU to use that value for the timer.
|
// ...then tell the CPU to use that value for the timer.
|
||||||
Chip8CpuInstructions::LdVxDt(0x0).execute(&mut x);
|
Chip8CpuInstructions::LdVxDt(0x1).execute(&mut x);
|
||||||
x.delay_timer.tick();
|
|
||||||
x.delay_timer.tick();
|
|
||||||
x.delay_timer.tick();
|
|
||||||
assert_eq!(x.delay_timer.current(), 0xd);
|
|
||||||
for i in 0..0x10 {
|
|
||||||
x.delay_timer.tick();
|
|
||||||
}
|
|
||||||
assert_eq!(x.delay_timer.current(), 0x00);
|
|
||||||
x.delay_timer.tick();
|
|
||||||
assert_eq!(x.delay_timer.current(), 0x00);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn LdVxK_test() {
|
let new_reg_value = x.registers.peek(0x1);
|
||||||
// Wait for a key press, store the value of the key in Vx.
|
assert_eq!(new_reg_value, 0x1);
|
||||||
// All execution stops until a key is pressed, then the value of that key is stored in Vx.
|
}
|
||||||
|
#[test]
|
||||||
|
fn cls_test() {
|
||||||
|
let mut x = Chip8Computer::new();
|
||||||
|
Chip8CpuInstructions::CLS.execute(&mut x);
|
||||||
|
assert_eq!(x.registers.peek_pc(), 0x202);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn LdStVx_test() {
|
fn skip_next_instruction_ne_text() {
|
||||||
// sound timer setting
|
|
||||||
let mut x = Chip8Computer::new();
|
let mut x = Chip8Computer::new();
|
||||||
Chip8CpuInstructions::LdVxByte(0x1, 0x10).execute(&mut x);
|
Chip8CpuInstructions::LdVxByte(0x1, 0xf0).execute(&mut x);
|
||||||
Chip8CpuInstructions::LdStVx(0x10).execute(&mut x);
|
// 202
|
||||||
|
Chip8CpuInstructions::SneVxByte(0x1, 0x0f).execute(&mut x);
|
||||||
// tick from 0x8 to 0x1
|
// 204+2
|
||||||
for i in 0..6 { x.sound_timer.tick(); }
|
assert_eq!(x.registers.peek_pc(), 0x206);
|
||||||
|
Chip8CpuInstructions::SneVxByte(0x1, 0xf0).execute(&mut x);
|
||||||
assert_eq!(x.sound_timer.current(), 0xA);
|
// 208
|
||||||
|
assert_eq!(x.registers.peek_pc(), 0x208);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn LdIVx_test() {
|
#[test]
|
||||||
// Store registers V0 through Vx in memory starting at location I.
|
fn lddtvx_test() {
|
||||||
//
|
let mut x = Chip8Computer::new();
|
||||||
// The interpreter copies the values of registers V0 through Vx
|
Chip8CpuInstructions::LdDtVx(0x10).execute(&mut x);
|
||||||
// into memory, starting at the address in I.
|
assert_eq!(x.delay_timer.current(), 0x10);
|
||||||
|
x.delay_timer.tick();
|
||||||
|
x.delay_timer.tick();
|
||||||
|
assert_eq!(x.delay_timer.current(), 0x0E);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn LdVxI_test() {}
|
#[test]
|
||||||
// Read registers V0 through Vx from memory starting at location I.
|
fn addivx_test() {
|
||||||
//
|
let mut x = Chip8Computer::new();
|
||||||
// The interpreter reads values from memory starting at location I into registers V0 through Vx.
|
Chip8CpuInstructions::LdIAddr(0xabc).execute(&mut x);
|
||||||
|
Chip8CpuInstructions::LdVxByte(0x0, 0x10).execute(&mut x);
|
||||||
|
Chip8CpuInstructions::AddIVx(0x0).execute(&mut x);
|
||||||
|
assert_eq!(x.registers.peek_i(), 0xacc);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ldstvt_test() {
|
||||||
|
let mut x = Chip8Computer::new();
|
||||||
|
Chip8CpuInstructions::LdVxByte(0x01, 0xf0).execute(&mut x);
|
||||||
|
Chip8CpuInstructions::LdStVx(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::RndVxByte(0x1, 0x0f).execute(&mut x);
|
||||||
|
let new_value = x.registers.peek(0x1);
|
||||||
|
assert!(new_value < 0x10);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
#[test]
|
#[test]
|
||||||
fn LdDtVx_test() {
|
fn skp_vx_test() {
|
||||||
|
|
||||||
// delay timer setting
|
|
||||||
let mut x = Chip8Computer::new();
|
let mut x = Chip8Computer::new();
|
||||||
|
x.keypad.push_key(0x1);
|
||||||
// lets set our delay timer...
|
Chip8CpuInstructions::LdVxByte(0x1, 0x1).execute(&mut x);
|
||||||
Chip8CpuInstructions::LdVxByte(0x0, 0x80).execute(&mut x);
|
Chip8CpuInstructions::SkpVx(0x1).execute(&mut x);
|
||||||
Chip8CpuInstructions::LdDtVx(0x0).execute(&mut x);
|
assert_eq!(x.registers.peek_pc(), 0x208);
|
||||||
|
x.keypad.release_key(0x1);
|
||||||
// now that we have our timer set to 0x80 we should tick it 0x10 times
|
Chip8CpuInstructions::SkpVx(0x1).execute(&mut x);
|
||||||
// so we are then down to 0x70
|
assert_eq!(x.registers.peek_pc(), 0x20A);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ impl SoundTimer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn set_timer(&mut self, new_value: i32) {
|
pub fn set_timer(&mut self, new_value: i32) {
|
||||||
|
println!("SETTING SOUND TIMER TO {new_value}");
|
||||||
self.counter = new_value
|
self.counter = new_value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,24 +10,12 @@ pub struct Chip8Video {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Chip8Video {
|
impl Chip8Video {
|
||||||
pub fn as_64bit(&self) -> Vec<u64> {
|
|
||||||
let mut to_return = vec![];
|
|
||||||
|
|
||||||
for row_in_video in 0..32 {
|
pub fn cls(&mut self) {
|
||||||
let mut working_row = 0u64;
|
for i in 0..CHIP8_VIDEO_MEMORY {
|
||||||
for bit_in_video in 0..64 {
|
self.memory[i] = false;
|
||||||
let data_offset = row_in_video * 64 + bit_in_video;
|
|
||||||
let to_convert = self.memory[data_offset];
|
|
||||||
let shifted_bit = if to_convert {
|
|
||||||
1 << bit_in_video
|
|
||||||
} else { 0 };
|
|
||||||
working_row = working_row | shifted_bit;
|
|
||||||
}
|
}
|
||||||
to_return.push(working_row);
|
|
||||||
}
|
}
|
||||||
to_return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn new(initial_configuration: [bool; CHIP8_VIDEO_MEMORY]) -> Self {
|
pub fn new(initial_configuration: [bool; CHIP8_VIDEO_MEMORY]) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -172,22 +160,22 @@ mod test {
|
|||||||
}
|
}
|
||||||
assert_eq!(x.format_as_string(), expected);
|
assert_eq!(x.format_as_string(), expected);
|
||||||
}
|
}
|
||||||
|
fn cls() {
|
||||||
#[test]
|
let mut initial_memory = [false; CHIP8_VIDEO_MEMORY];
|
||||||
fn poke_sprite() {
|
let mut ws = String::new();
|
||||||
let mut expected = String::new();
|
// set our checkerboard
|
||||||
let to_poke = [
|
for cbr in 0..32 {
|
||||||
0b11001100,
|
for cbc in 0..64 {
|
||||||
0b00110011,
|
let dof = cbr * 64 + cbc;
|
||||||
0b11001100,
|
if (dof as i32 % 2) == 0 {
|
||||||
0b00110011
|
initial_memory[dof] = true;
|
||||||
];
|
}
|
||||||
|
ws += " ";
|
||||||
// Position at 4,10
|
}
|
||||||
// 5,10
|
ws += "\n";
|
||||||
// 6,10
|
}
|
||||||
// 7,10
|
let mut set_x = Chip8Video::new(initial_memory);
|
||||||
let start_address = (4 * 64) + 10;
|
set_x.cls();
|
||||||
|
assert_eq!(set_x.format_as_string(), ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user