more test etc.
video needs stuff bad
This commit is contained in:
parent
731f20d894
commit
24ea413848
1243
Cargo.lock
generated
1243
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,3 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = ["chip8_toy","chip8_core", "emma"]
|
members = ["emma"]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
@ -1,5 +1,5 @@
|
|||||||
use std::io::{stdout, Result};
|
use std::io::{stdout, Result};
|
||||||
|
/*
|
||||||
use emmaemu::{chip8::{computer::Chip8Computer, video::Chip8Video}, constants::{CHIP8_MEMORY_SIZE, CHIP8_REGISTER_COUNT, CHIP8_ROM_SIZE, CHIP8_VIDEO_MEMORY}};
|
use emmaemu::{chip8::{computer::Chip8Computer, video::Chip8Video}, constants::{CHIP8_MEMORY_SIZE, CHIP8_REGISTER_COUNT, CHIP8_ROM_SIZE, CHIP8_VIDEO_MEMORY}};
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
backend::CrosstermBackend,
|
backend::CrosstermBackend,
|
||||||
@ -162,3 +162,7 @@ mod test {
|
|||||||
assert_eq!(Chip8Video::new(grid_data).format_as_string(), expected_data);
|
assert_eq!(Chip8Video::new(grid_data).format_as_string(), expected_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
fn main() {
|
||||||
|
println!("Taxation is theft");
|
||||||
|
}
|
||||||
@ -53,8 +53,8 @@ impl EmmaGui {
|
|||||||
let mut buffer = Vec::new();
|
let mut buffer = Vec::new();
|
||||||
|
|
||||||
println!("PREPARING TO LOAD 1-chip8-logo.ch8");
|
println!("PREPARING TO LOAD 1-chip8-logo.ch8");
|
||||||
// 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("./1-chip8-logo.ch8")).expect("put 1-chip8-logo.ch8 in this directory");
|
||||||
let mut input_file = File::open(Path::new("./coraxhard.ch8")).expect("put 1-chip8-logo.ch8 in this directory");
|
// let mut input_file = File::open(Path::new("./coraxhard.ch8")).expect("put 1-chip8-logo.ch8 in this directory");
|
||||||
input_file.read_to_end(&mut buffer).expect("unable to read file");
|
input_file.read_to_end(&mut buffer).expect("unable to read file");
|
||||||
system_to_control.load_bytes_to_memory(0x200, buffer.into());
|
system_to_control.load_bytes_to_memory(0x200, buffer.into());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -99,34 +99,6 @@ mod test {
|
|||||||
assert!(true)
|
assert!(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn decoder_test_invalid_instructions() {
|
|
||||||
// 'bad' instructions that should be dropped...
|
|
||||||
|
|
||||||
// 5xy0 is the only valid 5 series.
|
|
||||||
assert!(matches!(Chip8CpuInstructions::decode(0x5ab1), Chip8CpuInstructions::XXXXERRORINSTRUCTION));
|
|
||||||
assert!(matches!(Chip8CpuInstructions::decode(0x5abf), Chip8CpuInstructions::XXXXERRORINSTRUCTION));
|
|
||||||
|
|
||||||
// 8__8 -> 8__D and 8__F are invalid
|
|
||||||
assert!(matches!(Chip8CpuInstructions::decode(0x8ab8), Chip8CpuInstructions::XXXXERRORINSTRUCTION));
|
|
||||||
assert!(matches!(Chip8CpuInstructions::decode(0x8abd), Chip8CpuInstructions::XXXXERRORINSTRUCTION));
|
|
||||||
assert!(matches!(Chip8CpuInstructions::decode(0x8abf), Chip8CpuInstructions::XXXXERRORINSTRUCTION));
|
|
||||||
|
|
||||||
// 9__1 -> 9__F are invalid
|
|
||||||
assert!(matches!(Chip8CpuInstructions::decode(0x9ab1), Chip8CpuInstructions::XXXXERRORINSTRUCTION));
|
|
||||||
assert!(matches!(Chip8CpuInstructions::decode(0x9abf), Chip8CpuInstructions::XXXXERRORINSTRUCTION));
|
|
||||||
|
|
||||||
// Only valid E suffixes are 9E and A1
|
|
||||||
assert!(matches!(Chip8CpuInstructions::decode(0xea9d), Chip8CpuInstructions::XXXXERRORINSTRUCTION));
|
|
||||||
assert!(matches!(Chip8CpuInstructions::decode(0xea9f), Chip8CpuInstructions::XXXXERRORINSTRUCTION));
|
|
||||||
assert!(matches!(Chip8CpuInstructions::decode(0xeaa0), Chip8CpuInstructions::XXXXERRORINSTRUCTION));
|
|
||||||
assert!(matches!(Chip8CpuInstructions::decode(0xeaa2), Chip8CpuInstructions::XXXXERRORINSTRUCTION));
|
|
||||||
|
|
||||||
// oh god f is a mess.
|
|
||||||
assert!(matches!(Chip8CpuInstructions::decode(0xf006), Chip8CpuInstructions::XXXXERRORINSTRUCTION));
|
|
||||||
assert!(matches!(Chip8CpuInstructions::decode(0xf008), Chip8CpuInstructions::XXXXERRORINSTRUCTION));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn new_with_program() {
|
fn new_with_program() {
|
||||||
|
|||||||
@ -410,17 +410,11 @@ impl Chip8CpuInstructions {
|
|||||||
}
|
}
|
||||||
// 0x6xkk Set Vx = kk
|
// 0x6xkk Set Vx = kk
|
||||||
Chip8CpuInstructions::LdVxByte(register, byte) => {
|
Chip8CpuInstructions::LdVxByte(register, byte) => {
|
||||||
let start_value = input.registers.peek(*register as u8);
|
input.registers.poke(*register as u8, *byte as u8);
|
||||||
let byte_value = *byte as u8;
|
|
||||||
// println!("SETTING REGISTER [{register}] FROM [{start_value}] to [{byte_value}] by loading.");
|
|
||||||
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) => {
|
||||||
let to_add = *byte as u8;
|
input.registers.poke(*vx_register as u8, (input.registers.peek(*vx_register as u8) + *byte as u8));
|
||||||
let old_value = input.registers.peek(*vx_register as u8);
|
|
||||||
println!("Adding [{old_value}] from register [{vx_register}] to [{to_add}] ");
|
|
||||||
input.registers.poke(*vx_register as u8, (old_value + to_add));
|
|
||||||
}
|
}
|
||||||
// 0x8xy0 Set value of Vy in Vx
|
// 0x8xy0 Set value of Vy in Vx
|
||||||
Chip8CpuInstructions::LdVxVy(x, y) => {
|
Chip8CpuInstructions::LdVxVy(x, y) => {
|
||||||
@ -428,28 +422,20 @@ impl Chip8CpuInstructions {
|
|||||||
}
|
}
|
||||||
// 0x8xy1 Set Vx = Vx OR Vy
|
// 0x8xy1 Set Vx = Vx OR Vy
|
||||||
Chip8CpuInstructions::OrVxVy(x, y) => {
|
Chip8CpuInstructions::OrVxVy(x, y) => {
|
||||||
let lhs = input.registers.peek(*x as u8);
|
input.registers.poke(*x as u8, input.registers.peek(*x as u8) | input.registers.peek(*y as u8));
|
||||||
let rhs = input.registers.peek(*y as u8);
|
|
||||||
input.registers.poke(*x as u8, lhs | rhs);
|
|
||||||
}
|
}
|
||||||
// 0x8xy2 Set Vx = Vx AND Vy
|
// 0x8xy2 Set Vx = Vx AND Vy
|
||||||
Chip8CpuInstructions::AndVxVy(x, y) => {
|
Chip8CpuInstructions::AndVxVy(x, y) => {
|
||||||
let lhs = input.registers.peek(*x as u8);
|
input.registers.poke(*x as u8, input.registers.peek(*x as u8) & input.registers.peek(*y as u8));
|
||||||
let rhs = input.registers.peek(*y as u8);
|
|
||||||
|
|
||||||
input.registers.poke(*x as u8, lhs & rhs);
|
|
||||||
}
|
}
|
||||||
// 0x8xy3 Set Vx = Vx XOR Vy
|
// 0x8xy3 Set Vx = Vx XOR Vy
|
||||||
Chip8CpuInstructions::XorVxVy(x, y) => {
|
Chip8CpuInstructions::XorVxVy(x, y) => {
|
||||||
let lhs = input.registers.peek(*x as u8);
|
input.registers.poke(*x as u8, input.registers.peek(*x as u8) ^ input.registers.peek(*y as u8));
|
||||||
let rhs = input.registers.peek(*y as u8);
|
|
||||||
input.registers.poke(*x as u8, lhs ^ rhs);
|
|
||||||
}
|
}
|
||||||
// 0x8xy4 Set Vx = Vx + Vy (SET VF on Carry)
|
// 0x8xy4 Set Vx = Vx + Vy (SET VF on Carry)
|
||||||
Chip8CpuInstructions::AddVxVy(x, y) => {
|
Chip8CpuInstructions::AddVxVy(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);
|
||||||
|
|
||||||
let working = (lhs as i16 + rhs as i16) as i16;
|
let working = (lhs as i16 + rhs as i16) as i16;
|
||||||
if working > 255 {
|
if working > 255 {
|
||||||
input.registers.poke(0xf, 0x01);
|
input.registers.poke(0xf, 0x01);
|
||||||
@ -461,9 +447,7 @@ impl Chip8CpuInstructions {
|
|||||||
// 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. Then Vy is subtracted from Vx, and the results stored in Vx.
|
// If Vx > Vy, then VF is set to 1, otherwise 0. Then Vy is subtracted from Vx, and the results stored in Vx.
|
||||||
let lhs = input.registers.peek(*x as u8);
|
input.registers.poke(*x as u8, input.registers.peek(*x as u8) - input.registers.peek(*y as u8));
|
||||||
let rhs = input.registers.peek(*y as u8);
|
|
||||||
input.registers.poke(*x as u8, lhs - rhs);
|
|
||||||
}
|
}
|
||||||
Chip8CpuInstructions::ShrVxVy(x, y) => {
|
Chip8CpuInstructions::ShrVxVy(x, y) => {
|
||||||
// 8xy6 - SHR Vx {, Vy}
|
// 8xy6 - SHR Vx {, Vy}
|
||||||
@ -493,7 +477,6 @@ impl Chip8CpuInstructions {
|
|||||||
// Set Vx = Vx SHL 1.
|
// 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.
|
// 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 initial_value = input.registers.peek(*x as u8);
|
let initial_value = input.registers.peek(*x as u8);
|
||||||
if 0x80 & initial_value == 0x80 {
|
if 0x80 & initial_value == 0x80 {
|
||||||
input.registers.poke(0xf, 1);
|
input.registers.poke(0xf, 1);
|
||||||
@ -517,6 +500,7 @@ impl Chip8CpuInstructions {
|
|||||||
// Set I = nnn.
|
// Set I = nnn.
|
||||||
//
|
//
|
||||||
// The value of register I is set to nnn.
|
// The value of register I is set to nnn.
|
||||||
|
println!("SETTING I to {new_index}");
|
||||||
input.registers.poke_i(*new_index);
|
input.registers.poke_i(*new_index);
|
||||||
}
|
}
|
||||||
// 0xBnnn Jump to nnn+V0
|
// 0xBnnn Jump to nnn+V0
|
||||||
@ -525,8 +509,7 @@ impl Chip8CpuInstructions {
|
|||||||
// Jump to location nnn + V0.
|
// Jump to location nnn + V0.
|
||||||
//
|
//
|
||||||
// The program counter is set to nnn plus the value of V0.
|
// The program counter is set to nnn plus the value of V0.
|
||||||
let x_reg = input.registers.peek(0);
|
input.registers.poke_pc(input.registers.peek(0) as u16 + addr);
|
||||||
input.registers.poke_pc(x_reg as u16 + addr);
|
|
||||||
}
|
}
|
||||||
Chip8CpuInstructions::RndVxByte(x, byte) => {
|
Chip8CpuInstructions::RndVxByte(x, byte) => {
|
||||||
// Cxkk - RND Vx, byte
|
// Cxkk - RND Vx, byte
|
||||||
@ -579,11 +562,15 @@ impl Chip8CpuInstructions {
|
|||||||
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) => {
|
||||||
|
|
||||||
// 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.
|
// 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);
|
||||||
|
let is_pressed = input.keypad.pressed(*x as u8);
|
||||||
|
if is_pressed {
|
||||||
|
input.registers.advance_pc();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Chip8CpuInstructions::LdVxDt(x) => {
|
Chip8CpuInstructions::LdVxDt(x) => {
|
||||||
// Fx07 - LD Vx, DT
|
// Fx07 - LD Vx, DT
|
||||||
@ -605,11 +592,9 @@ impl Chip8CpuInstructions {
|
|||||||
//
|
//
|
||||||
// DT is set equal to the value of Vx.
|
// DT is set equal to the value of Vx.
|
||||||
let new_time = input.registers.peek(*source_register as u8);
|
let new_time = input.registers.peek(*source_register as u8);
|
||||||
println!("SETTING DELAY TIMER TO [{}]", new_time);
|
|
||||||
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) => {
|
||||||
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) => {
|
||||||
@ -742,7 +727,20 @@ 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)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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
|
/// START OF THE EXECUTION TESTS
|
||||||
@ -997,11 +995,46 @@ mod test {
|
|||||||
assert_eq!(x.registers.peek_pc(), 0x208);
|
assert_eq!(x.registers.peek_pc(), 0x208);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn SneVxVy_test() {}
|
#[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);
|
||||||
|
|
||||||
fn LdiAddr_test() {}
|
Chip8CpuInstructions::LdVxByte(0x02, 0xab).execute(&mut x);
|
||||||
|
Chip8CpuInstructions::SneVxVy(0x01, 0x02).execute(&mut x);
|
||||||
|
assert_eq!(x.registers.peek_pc(), 0x20C);
|
||||||
|
}
|
||||||
|
|
||||||
fn JpV0Addr_test() {}
|
#[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 value_for_memory = 0xbe;
|
||||||
|
// load the value into V0
|
||||||
|
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 RndVxByte_test() {
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use log::debug;
|
||||||
|
|
||||||
/// Registers. numbered 1-16 publicly.
|
/// Registers. numbered 1-16 publicly.
|
||||||
/// Privately using zero base array so -1 to shift from pub to priv.
|
/// Privately using zero base array so -1 to shift from pub to priv.
|
||||||
@ -33,6 +34,7 @@ impl Chip8Registers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn poke_i(&mut self, new_value: u16) {
|
pub fn poke_i(&mut self, new_value: u16) {
|
||||||
|
println!("REGISTER: Setting I to {new_value}");
|
||||||
self.i_register = new_value;
|
self.i_register = new_value;
|
||||||
}
|
}
|
||||||
pub fn peek(&self, register_number: u8) -> u8 {
|
pub fn peek(&self, register_number: u8) -> u8 {
|
||||||
|
|||||||
@ -5,6 +5,7 @@ use beep::beep;
|
|||||||
pub struct SoundTimer {
|
pub struct SoundTimer {
|
||||||
counter: i32
|
counter: i32
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SoundTimer {
|
impl SoundTimer {
|
||||||
pub fn current(&self) -> i32 {
|
pub fn current(&self) -> i32 {
|
||||||
self.counter
|
self.counter
|
||||||
@ -33,7 +34,6 @@ impl SoundTimer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@ -42,20 +42,6 @@ impl Default for Chip8SystemMemory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Widget for Chip8SystemMemory {
|
|
||||||
fn render(self, area: ratatui::prelude::Rect, buf: &mut ratatui::prelude::Buffer)
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
// build the text version of the system memory...
|
|
||||||
// ...and stuff it in the display.
|
|
||||||
let style = Style::new();
|
|
||||||
let string = String::new();
|
|
||||||
buf.set_string(0, 0, string, style)
|
|
||||||
}
|
|
||||||
// Display the system memory as a widget
|
|
||||||
}
|
|
||||||
|
|
||||||
const cell_width: i32 = 5i32;
|
const cell_width: i32 = 5i32;
|
||||||
const cell_height: i32 = 5i32;
|
const cell_height: i32 = 5i32;
|
||||||
|
|
||||||
@ -71,8 +57,6 @@ impl Chip8SystemMemory {
|
|||||||
self.memory[address as usize] = value;
|
self.memory[address as usize] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub fn load_program(&mut self, program_to_load: Box<Vec<u8>>) {
|
pub fn load_program(&mut self, program_to_load: Box<Vec<u8>>) {
|
||||||
for load_index in 0..program_to_load.len() {
|
for load_index in 0..program_to_load.len() {
|
||||||
self.poke((load_index + 0x200) as u16, program_to_load[load_index]);
|
self.poke((load_index + 0x200) as u16, program_to_load[load_index]);
|
||||||
|
|||||||
@ -4,13 +4,31 @@ use ratatui::{layout::Rect, style::Style, widgets::Widget};
|
|||||||
use crate::chip8::computer::Chip8Computer;
|
use crate::chip8::computer::Chip8Computer;
|
||||||
use crate::constants::CHIP8_VIDEO_MEMORY;
|
use crate::constants::CHIP8_VIDEO_MEMORY;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Chip8Video {
|
pub struct Chip8Video {
|
||||||
memory: [bool; CHIP8_VIDEO_MEMORY]
|
memory: [bool; CHIP8_VIDEO_MEMORY]
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Chip8Video {
|
impl Chip8Video {
|
||||||
|
pub fn as_64bit(&self) -> Vec<u64> {
|
||||||
|
let mut to_return = vec![];
|
||||||
|
|
||||||
|
for row_in_video in 0..32 {
|
||||||
|
let mut working_row = 0u64;
|
||||||
|
for bit_in_video in 0..64 {
|
||||||
|
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 {
|
||||||
memory: initial_configuration
|
memory: initial_configuration
|
||||||
@ -26,6 +44,19 @@ impl Chip8Video {
|
|||||||
self.to_owned()
|
self.to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn poke_byte(&mut self, first_address: u16, to_write: u8) -> Self {
|
||||||
|
println!("PREPARING TO POKE {to_write:b} to {first_address:4x}");
|
||||||
|
for i in (0..8).rev() {
|
||||||
|
let shifted = ((1 << i) & to_write) >> i;
|
||||||
|
//
|
||||||
|
let target_address = first_address + (7 - i);
|
||||||
|
let is_set = shifted == 1;
|
||||||
|
println!("POKE {} with {} / {shifted:8b}", target_address, is_set);
|
||||||
|
self.poke(target_address, is_set);
|
||||||
|
}
|
||||||
|
self.to_owned()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn format_as_string(self) -> String {
|
pub fn format_as_string(self) -> String {
|
||||||
let mut output = String::new();
|
let mut output = String::new();
|
||||||
for row in 0..32 {
|
for row in 0..32 {
|
||||||
@ -110,14 +141,15 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn set_initial_memory() {
|
fn set_initial_memory() {
|
||||||
let mut initial_memory = [false; CHIP8_VIDEO_MEMORY];
|
let mut x = Chip8Video::default();
|
||||||
|
// let mut initial_memory = [false; CHIP8_VIDEO_MEMORY];
|
||||||
let mut ws = String::new();
|
let mut ws = String::new();
|
||||||
// set our checkerboard
|
// set our checkerboard
|
||||||
for cbr in 0..32 {
|
for cbr in 0..32 {
|
||||||
for cbc in 0..64 {
|
for cbc in 0..64 {
|
||||||
let dof = cbr * 64 + cbc;
|
let dof = cbr * 64 + cbc;
|
||||||
if (dof as i32 % 2) == 0 {
|
if (dof as i32 % 2) == 0 {
|
||||||
initial_memory[dof] = true;
|
x.poke(dof, true);
|
||||||
ws += "*";
|
ws += "*";
|
||||||
} else {
|
} else {
|
||||||
ws += " ";
|
ws += " ";
|
||||||
@ -125,36 +157,37 @@ mod test {
|
|||||||
}
|
}
|
||||||
ws += "\n";
|
ws += "\n";
|
||||||
}
|
}
|
||||||
let set_x = Chip8Video::new(initial_memory);
|
assert_eq!(x.format_as_string(), ws);
|
||||||
assert_eq!(set_x.format_as_string(), ws);
|
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
#[test]
|
#[test]
|
||||||
fn set_sprite_test() {
|
fn poke_byte() {
|
||||||
|
let to_poke = 0b11001111;
|
||||||
let mut x = Chip8Video::default();
|
let mut x = Chip8Video::default();
|
||||||
let sprite = vec![0b00110011,
|
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_sprite() {
|
||||||
|
let mut expected = String::new();
|
||||||
|
let to_poke = [
|
||||||
0b11001100,
|
0b11001100,
|
||||||
0b01010101,
|
0b00110011,
|
||||||
0b10101010];
|
0b11001100,
|
||||||
|
0b00110011
|
||||||
|
];
|
||||||
|
|
||||||
x.write_sprite(sprite.clone(), (0,0));
|
// Position at 4,10
|
||||||
|
// 5,10
|
||||||
for sprite_row in 0..sprite.len() {
|
// 6,10
|
||||||
for bit_in_row in 0..8 {
|
// 7,10
|
||||||
let data_offset = sprite_row * 8 + bit_in_row;
|
let start_address = (4 * 64) + 10;
|
||||||
let test_bit = 1 << bit_in_row;
|
|
||||||
// now we have a 1 in the 'right' place
|
|
||||||
let test_value = test_bit & sprite[sprite_row];
|
|
||||||
// if we found a bit where we looked
|
|
||||||
if test_bit == test_value {
|
|
||||||
assert!(x.peek(data_offset as u16));
|
|
||||||
} else {
|
|
||||||
// no bit. expect false.
|
|
||||||
assert!(!x.peek(data_offset as u16));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user