add chatgpt driven changes to video rendering
This commit is contained in:
parent
448aeab154
commit
939fd83e80
@ -11,6 +11,7 @@ use super::{
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Chip8Computer {
|
||||
pub num_cycles: i32,
|
||||
pub memory: Chip8SystemMemory,
|
||||
pub registers: Chip8Registers,
|
||||
pub sound_timer: SoundTimer,
|
||||
@ -23,6 +24,7 @@ pub struct Chip8Computer {
|
||||
impl Default for Chip8Computer {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
num_cycles: 0,
|
||||
memory: Chip8SystemMemory::default(),
|
||||
video_memory: Chip8Video::default(),
|
||||
registers: Chip8Registers::default(),
|
||||
@ -36,10 +38,12 @@ impl Default for Chip8Computer {
|
||||
}
|
||||
|
||||
impl Chip8Computer {
|
||||
pub fn reset(&mut self) -> Self{
|
||||
let mut working = Chip8Computer::new();
|
||||
working.video_memory.reset();
|
||||
working
|
||||
pub fn reset(&mut self) {
|
||||
self.video_memory.reset();
|
||||
self.num_cycles = 0;
|
||||
self.registers.reset();
|
||||
self.delay_timer.reset();
|
||||
self.sound_timer.reset();
|
||||
}
|
||||
|
||||
pub fn dump_keypad_to_string(&self) -> String {
|
||||
|
||||
@ -13,6 +13,11 @@ impl DelayTimer {
|
||||
counter: 0xff
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.counter = 0xff;
|
||||
}
|
||||
|
||||
pub fn set_timer(&mut self, new_value: i32) {
|
||||
self.counter = new_value
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use std::ops::{BitAnd, Shr};
|
||||
use log::debug;
|
||||
use rand::random;
|
||||
use rand::{random, Rng};
|
||||
use crate::chip8::computer::{Chip8Computer};
|
||||
use crate::chip8::cpu_states::Chip8CpuStates::WaitingForKey;
|
||||
use crate::chip8::instructions::Chip8CpuInstructions::XXXXERRORINSTRUCTION;
|
||||
@ -240,7 +240,7 @@ impl Chip8CpuInstructions {
|
||||
|
||||
match input {
|
||||
0x00E0 => {
|
||||
// 00E0 - CLS
|
||||
// 00E0 - f
|
||||
// Clear the display.
|
||||
Chip8CpuInstructions::CLS
|
||||
}
|
||||
@ -428,9 +428,7 @@ impl Chip8CpuInstructions {
|
||||
}
|
||||
// * 0x00E0 Clear Screen
|
||||
Chip8CpuInstructions::CLS => {
|
||||
for i in 0..(64 * 32) {
|
||||
input.video_memory.poke(i, false);
|
||||
}
|
||||
input.video_memory.cls();
|
||||
}
|
||||
// 0x00EE Return from Subroutine
|
||||
Chip8CpuInstructions::RET => {
|
||||
@ -653,7 +651,8 @@ impl Chip8CpuInstructions {
|
||||
// The interpreter generates a random number from 0 to 255,
|
||||
// which is then ANDed with the value kk.
|
||||
// The results are stored in Vx.
|
||||
let new_value: u8 = random();
|
||||
let mut rng = rand::thread_rng();
|
||||
let new_value: u8 = rng.random();
|
||||
let and_value: u8 = *byte;
|
||||
let result = new_value & and_value;
|
||||
debug!("RANDOM: [{new_value:02x}] AND: [{and_value:02x} Result: [{result:02x}]");
|
||||
@ -664,7 +663,6 @@ impl Chip8CpuInstructions {
|
||||
|
||||
// The interpreter reads n bytes from memory, starting at the address stored in I.
|
||||
|
||||
|
||||
// These bytes are then displayed as sprites on screen at coordinates (Vx, Vy).
|
||||
// Sprites are XORed onto the existing screen.
|
||||
// If this causes any pixels to be erased, VF is set to 1,
|
||||
@ -676,7 +674,6 @@ impl Chip8CpuInstructions {
|
||||
let x_offset = input.registers.peek(*x as u8);
|
||||
let y_offset = input.registers.peek(*y as u8);
|
||||
|
||||
|
||||
// let target_memory_offset = x_offset as u16 * 64 + y_offset as u16;
|
||||
|
||||
let num_bytes_to_read = *n;
|
||||
@ -837,6 +834,7 @@ impl Chip8CpuInstructions {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::chip8::system_memory::{CHIP8FONT_0, CHIP8FONT_1, CHIP8FONT_2, CHIP8FONT_9};
|
||||
use crate::constants::CHIP8_VIDEO_MEMORY;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
@ -1129,6 +1127,19 @@ mod 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]
|
||||
|
||||
@ -24,6 +24,12 @@ impl Default for Chip8Registers {
|
||||
}
|
||||
|
||||
impl Chip8Registers {
|
||||
pub fn reset(&mut self) {
|
||||
self.registers = [0x00; 16];
|
||||
self.i_register = 0x00;
|
||||
self.pc = 0x200;
|
||||
}
|
||||
|
||||
pub fn poke_pc(&mut self, new_pc: u16) {
|
||||
self.pc = new_pc
|
||||
}
|
||||
@ -79,6 +85,7 @@ impl Chip8Registers {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use rand::random;
|
||||
use crate::chip8::registers::Chip8Registers;
|
||||
|
||||
#[test]
|
||||
@ -118,4 +125,17 @@ mod test {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -32,6 +32,10 @@ impl SoundTimer {
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.counter = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@ -31,11 +31,7 @@ impl Chip8Video {
|
||||
}
|
||||
|
||||
pub fn peek(self, address: u16) -> bool {
|
||||
let effective_address = if address >= 2048 {
|
||||
address - 2048
|
||||
} else {
|
||||
address
|
||||
};
|
||||
let effective_address = address % 2048;
|
||||
self.memory[effective_address as usize]
|
||||
}
|
||||
|
||||
@ -43,24 +39,50 @@ impl Chip8Video {
|
||||
// println!("OFFSET: {address} - POKING {new_value}");
|
||||
|
||||
// Loop the address
|
||||
let effective_address = if address >= 2048 {
|
||||
address - 2048
|
||||
} else {
|
||||
address
|
||||
};
|
||||
let effective_address = address % 2048;
|
||||
|
||||
let old_value = self.memory[effective_address as usize];
|
||||
let xored_value = new_value ^ old_value; // XOR of the video
|
||||
let value_changed = old_value != xored_value; // From True to False is a change.
|
||||
|
||||
self.has_frame_changed = if xored_value && value_changed { false } else { true };
|
||||
if value_changed {
|
||||
self.has_frame_changed = true;
|
||||
}
|
||||
self.has_frame_changed = true
|
||||
};
|
||||
|
||||
self.memory[effective_address as usize] = xored_value;
|
||||
}
|
||||
|
||||
/*
|
||||
CHATGPT
|
||||
pub fn poke_byte(&mut self, first_address: u16, to_write: u8) {
|
||||
let effective_address = first_address as usize % CHIP8_VIDEO_MEMORY;
|
||||
|
||||
// Loop through each bit of the byte
|
||||
for i in 0..8 {
|
||||
let is_set = (to_write & (0x80 >> i)) != 0;
|
||||
let address = effective_address + i;
|
||||
|
||||
if address < CHIP8_VIDEO_MEMORY {
|
||||
self.poke(address as u16, is_set);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
pub fn poke_byte(&mut self, first_address: u16, to_write: u8) {
|
||||
for i in (0..8).rev() {
|
||||
let shifted = ((1 << i) & to_write) >> i;
|
||||
//
|
||||
let target_address = first_address + (7 - i);
|
||||
let is_set = (to_write & (1 << i)) != 0;
|
||||
self.poke(target_address, is_set);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
MINE
|
||||
pub fn poke_byte(&mut self, first_address: u16, to_write: u8) {
|
||||
for i in (0..8).rev() {
|
||||
let shifted = ((1 << i) & to_write) >> i;
|
||||
@ -71,13 +93,16 @@ impl Chip8Video {
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
pub fn poke_sprite(&mut self, first_address: u16, to_write: Vec<u8>) -> Self {
|
||||
let sprite_length = to_write.len();
|
||||
|
||||
for (index, byte) in to_write.iter().enumerate() {
|
||||
let real_address = index * 64;
|
||||
self.poke_byte(real_address as u16, *byte);
|
||||
}
|
||||
};
|
||||
self.to_owned()
|
||||
}
|
||||
|
||||
@ -111,7 +136,7 @@ impl Default for Chip8Video {
|
||||
let new_struct = Chip8Video { memory: [false; CHIP8_VIDEO_MEMORY], has_frame_changed: false };
|
||||
println!("NEW DEFAULT MEMORY : {}", new_struct.format_as_string());
|
||||
|
||||
new_struct
|
||||
new_struct.clone()
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,10 +171,10 @@ mod test {
|
||||
let mut x = Chip8Video::default();
|
||||
|
||||
for i in 0..CHIP8_VIDEO_MEMORY {
|
||||
assert!(!x.peek(i as u16));
|
||||
assert!(!x.clone().peek(i as u16));
|
||||
// then flip the value and test again.
|
||||
&x.poke(i as u16, true);
|
||||
assert!(x.peek(i as u16));
|
||||
assert!(x.clone().peek(i as u16));
|
||||
}
|
||||
}
|
||||
|
||||
@ -271,24 +296,24 @@ mod test {
|
||||
|
||||
// row 2 column 1
|
||||
{
|
||||
assert!(v.peek(0x40));
|
||||
assert!(v.peek(0x41));
|
||||
assert!(v.peek(0x42));
|
||||
assert!(v.peek(0x43));
|
||||
assert!(v.peek(0x44));
|
||||
assert!(v.peek(0x45));
|
||||
assert!(v.peek(0x46));
|
||||
assert!(v.peek(0x47));
|
||||
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.peek(0xC0));
|
||||
assert!(v.peek(0xC1));
|
||||
assert!(!v.peek(0xC2));
|
||||
assert!(v.peek(0xC3));
|
||||
assert!(!v.peek(0xC4));
|
||||
assert!(v.peek(0xC5));
|
||||
assert!(!v.peek(0xC6));
|
||||
assert!(v.peek(0xC7));
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,23 +338,23 @@ mod test {
|
||||
|
||||
let test_offset = (x_offset * 64 + y_offset) as u16;
|
||||
assert!(!v.peek(test_offset));
|
||||
assert!(!v.peek(test_offset + 1));
|
||||
assert!(!v.peek(test_offset + 2));
|
||||
assert!(!v.peek(test_offset + 3));
|
||||
assert!(!v.peek(test_offset + 4));
|
||||
assert!(!v.peek(test_offset + 5));
|
||||
assert!(!v.peek(test_offset + 6));
|
||||
assert!(!v.peek(test_offset + 7));
|
||||
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.peek(test_offset));
|
||||
assert!(v.peek(test_offset + 1));
|
||||
assert!(v.peek(test_offset + 2));
|
||||
assert!(v.peek(test_offset + 3));
|
||||
assert!(v.peek(test_offset + 4));
|
||||
assert!(v.peek(test_offset + 5));
|
||||
assert!(v.peek(test_offset + 6));
|
||||
assert!(v.peek(test_offset + 7));
|
||||
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]
|
||||
@ -458,8 +483,8 @@ mod test {
|
||||
fn peek_out_of_bounds_doesnt_panic() {
|
||||
let x = Chip8Video::default();
|
||||
|
||||
let y = x.peek(2049);
|
||||
let y = x.peek(0);
|
||||
let y = x.clone().peek(2049);
|
||||
let y = x.clone().peek(0);
|
||||
|
||||
// if we got here we didn't panic
|
||||
assert!(true);
|
||||
|
||||
@ -34,6 +34,9 @@ fn main() -> eframe::Result {
|
||||
if state.display_registers {
|
||||
GemmaEguiSupport::registers_view(&computer, ui);
|
||||
}
|
||||
if state.is_running {
|
||||
computer.step_system();
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
@ -4,7 +4,8 @@ pub struct GemmaEGuiState {
|
||||
pub display_memory: bool,
|
||||
pub display_registers: bool,
|
||||
pub memory_view_min: i32,
|
||||
pub memory_view_max: i32
|
||||
pub memory_view_max: i32,
|
||||
pub is_running: bool
|
||||
}
|
||||
|
||||
impl Default for GemmaEGuiState {
|
||||
@ -14,7 +15,8 @@ impl Default for GemmaEGuiState {
|
||||
display_memory: true,
|
||||
display_registers: true,
|
||||
memory_view_min: 0x00,
|
||||
memory_view_max: 0x100
|
||||
memory_view_max: 0x100,
|
||||
is_running: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,16 +19,18 @@ impl EGuiFileList {
|
||||
let mut working_filename = selected_filename.clone();
|
||||
ui.label(format!("Displaying {}", root.to_str().unwrap_or("Unable to Load Path")));
|
||||
|
||||
egui::ComboBox::from_label(format!(
|
||||
"Currently selected string: {}",
|
||||
selected_filename
|
||||
))
|
||||
ComboBox::from_label("Choose an option")
|
||||
.selected_text(selected_filename.clone())
|
||||
.show_ui(ui, |ui| {
|
||||
for option in read_dir(root.as_path()).unwrap() {
|
||||
ui.label(format!("{:?}", option.unwrap().file_name()));
|
||||
// Add each option to the ComboBox
|
||||
let mut label = option.unwrap().file_name();
|
||||
ui.selectable_value(selected_filename, selected_filename.clone(), label.into_string().unwrap());
|
||||
}
|
||||
});
|
||||
|
||||
// Display the selected option
|
||||
ui.label(format!("Selected value: {}", selected_filename));
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,6 +41,7 @@ impl GemmaEguiSupport {
|
||||
ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {
|
||||
if ui.button("Start").clicked() {
|
||||
println!("Start");
|
||||
state.is_running = true;
|
||||
|
||||
}
|
||||
if ui.button("Step").clicked() {
|
||||
@ -47,6 +50,7 @@ impl GemmaEguiSupport {
|
||||
|
||||
if ui.button("Stop").clicked() {
|
||||
println!("STOP");
|
||||
state.is_running = false;
|
||||
}
|
||||
if ui.button("Reset").clicked() {
|
||||
system.reset();
|
||||
@ -60,6 +64,8 @@ impl GemmaEguiSupport {
|
||||
// ...then feed the system.
|
||||
system.load_bytes_to_memory(0x200, &read_bin);
|
||||
}
|
||||
let mut target = String::new();
|
||||
EGuiFileList::display_path(PathBuf::from("resources/roms"), &mut target, ui);
|
||||
});
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user