diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 7580cc3..15ec57c 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -9,10 +9,8 @@
-
-
-
+
@@ -58,8 +56,10 @@
"Cargo.Build `Test chip8::video::test::poke_byte`.executor": "Run",
"Cargo.Build `Test chip8::video::test::scroll_down_1_row_test`.executor": "Run",
"Cargo.Build `Test computer::test`.executor": "Run",
+ "Cargo.Build `Test computer_dump_registers_to_string`.executor": "Run",
"Cargo.Build `Test instructions::test (1)`.executor": "Run",
"Cargo.Build `Test instructions::test`.executor": "Run",
+ "Cargo.Build `Test instructions_name_tests`.executor": "Run",
"Cargo.Build `Test video::test`.executor": "Run",
"Cargo.Build gemma.executor": "Run",
"Cargo.Run emmagui.executor": "Run",
@@ -95,8 +95,11 @@
"Cargo.Test chip8::video::test::scroll_down_1_row_test.executor": "Run",
"Cargo.Test chip8::video::test::write_checkboard.executor": "Run",
"Cargo.Test computer::test.executor": "Debug",
+ "Cargo.Test computer_dump_registers_to_string.executor": "Run",
+ "Cargo.Test encode_decode_name_test.executor": "Debug",
"Cargo.Test instructions::test (1).executor": "Debug",
"Cargo.Test instructions::test.executor": "Debug",
+ "Cargo.Test instructions_name_tests.executor": "Run",
"Cargo.Test sound_timer::test.executor": "Run",
"Cargo.Test util::test.executor": "Run",
"Cargo.Test video::test.executor": "Debug",
@@ -123,11 +126,29 @@
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -145,8 +166,8 @@
-
-
+
+
@@ -162,25 +183,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -215,11 +219,11 @@
+
+
+
-
-
-
-
+
@@ -259,6 +263,7 @@
+
@@ -268,17 +273,6 @@
-
-
-
-
- file://$PROJECT_DIR$/emma/src/chip8/system_memory.rs
- 46
-
-
-
-
-
diff --git a/Cargo.lock b/Cargo.lock
index 2a6a087..bb4c37b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -743,6 +743,15 @@ dependencies = [
"wayland-client 0.31.6",
]
+[[package]]
+name = "catppuccin-egui"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a2413b3bbc4e1b627b453d9147c156076b74f78e102e90797463bab0486eee6"
+dependencies = [
+ "egui 0.29.1",
+]
+
[[package]]
name = "cc"
version = "1.1.30"
@@ -1785,6 +1794,7 @@ dependencies = [
name = "gemmaegui"
version = "0.1.0"
dependencies = [
+ "catppuccin-egui",
"eframe",
"egui 0.29.1",
"gemma",
@@ -1795,6 +1805,7 @@ name = "gemmaimgui"
version = "0.1.0"
dependencies = [
"chrono",
+ "clap",
"copypasta",
"dimensioned",
"gemma",
diff --git a/coverage/tarpaulin-report.html b/coverage/tarpaulin-report.html
new file mode 100644
index 0000000..29b0636
--- /dev/null
+++ b/coverage/tarpaulin-report.html
@@ -0,0 +1,671 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/gemma/src/chip8/computer.rs b/gemma/src/chip8/computer.rs
index 3ee4de5..509dc7a 100644
--- a/gemma/src/chip8/computer.rs
+++ b/gemma/src/chip8/computer.rs
@@ -1,6 +1,7 @@
use log::{debug};
use crate::chip8::delay_timer::DelayTimer;
use crate::chip8::keypad::Keypad;
+use crate::chip8::quirk_modes::QuirkMode;
use crate::chip8::registers::Chip8Registers;
use crate::chip8::sound_timer::SoundTimer;
use crate::chip8::stack::Chip8Stack;
@@ -19,7 +20,8 @@ pub struct Chip8Computer {
pub video_memory: Chip8Video,
pub state: Chip8CpuStates,
pub keypad: Keypad,
- pub stack: Chip8Stack
+ pub stack: Chip8Stack,
+ pub quirk_mode: QuirkMode
}
impl Default for Chip8Computer {
fn default() -> Self {
@@ -32,7 +34,8 @@ impl Default for Chip8Computer {
delay_timer: DelayTimer::new(),
state: Chip8CpuStates::default(),
keypad: Keypad::default(),
- stack: Chip8Stack::default()
+ stack: Chip8Stack::default(),
+ quirk_mode: QuirkMode::default()
}
}
}
@@ -45,6 +48,8 @@ impl Chip8Computer {
self.delay_timer.reset();
self.sound_timer.reset();
self.stack.reset();
+ self.memory.reset();
+ self.quirk_mode = QuirkMode::Chip8;
}
pub fn dump_keypad_to_string(&self) -> String {
diff --git a/gemma/src/chip8/computer_manager.rs b/gemma/src/chip8/computer_manager.rs
index 9cba622..fb8d558 100644
--- a/gemma/src/chip8/computer_manager.rs
+++ b/gemma/src/chip8/computer_manager.rs
@@ -23,7 +23,7 @@ impl Default for Chip8ComputerManager {
fn default() -> Self {
Chip8ComputerManager {
core_should_run: false,
- one_step: true,
+ one_step: false,
core_cycle_timer: false,
core_last_cycle_start: Instant::now() ,
computer: Chip8Computer::new()
@@ -32,18 +32,16 @@ impl Default for Chip8ComputerManager {
}
impl Chip8ComputerManager {
-
pub fn reset(&mut self) {
+ self.one_step = false;
+ self.core_should_run = false;
self.computer.reset();
}
pub fn new() -> Chip8ComputerManager {
let core_handle = thread::spawn(move || {
loop {
let start_time = Instant::now();
- // println!("Core Thread starting at {start_time:?}");
-
let sleep_time = Instant::now().duration_since(start_time).as_millis();
- // println!("Core Thread sleeping for {sleep_time}ms");
sleep(Duration::from_millis((16 - sleep_time) as u64));
}
});
@@ -67,13 +65,15 @@ impl Chip8ComputerManager {
&self.computer
}
- pub fn tick( &mut self) {
+ pub fn tick( &mut self) -> bool {
// println!("STARTING TICK");
+ let mut did_tick: bool = false;
if self.one_step | self.core_should_run {
match self.computer.state {
WaitingForInstruction => {
self.core_last_cycle_start = Instant::now();
self.computer.step_system();
+ did_tick = true
// println!("SYSTEM STEP");
}
_ => {}
@@ -84,7 +84,9 @@ impl Chip8ComputerManager {
// stop the CPU for the next cycle, we are only
// wanting one step.
self.one_step = false;
+ did_tick = true;
}
+ did_tick
}
pub fn press_key(&mut self, key_index: u8) {
diff --git a/gemma/src/chip8/delay_timer.rs b/gemma/src/chip8/delay_timer.rs
index f289675..4ce2b44 100644
--- a/gemma/src/chip8/delay_timer.rs
+++ b/gemma/src/chip8/delay_timer.rs
@@ -1,10 +1,10 @@
#[derive(Clone, Copy)]
pub struct DelayTimer {
- counter: i32
+ counter: u8
}
impl DelayTimer {
- pub fn current(&self) -> i32 {
+ pub fn current(&self) -> u8 {
self.counter
}
@@ -18,8 +18,8 @@ impl DelayTimer {
self.counter = 0xff;
}
- pub fn set_timer(&mut self, new_value: i32) {
- self.counter = new_value
+ pub fn set_timer(&mut self, new_value: u8) {
+ self.counter = new_value as u8
}
pub fn tick(&mut self) {
diff --git a/gemma/src/chip8/instructions.rs b/gemma/src/chip8/instructions.rs
index 171b657..1bf7297 100644
--- a/gemma/src/chip8/instructions.rs
+++ b/gemma/src/chip8/instructions.rs
@@ -2,11 +2,12 @@ use std::arch::x86_64::_mm_xor_pd;
use std::fmt::{Debug, Display, Formatter};
use std::ops::{BitAnd, Deref, Shr};
use std::time::Instant;
+use chrono::ParseMonthError;
use log::debug;
use rand::{random, Rng};
use crate::chip8::computer::{Chip8Computer};
use crate::chip8::cpu_states::Chip8CpuStates::WaitingForKey;
-use crate::chip8::instructions::Chip8CpuInstructions::XXXXERRORINSTRUCTION;
+use crate::chip8::instructions::Chip8CpuInstructions::*;
use crate::chip8::util::InstructionUtil;
use crate::constants::{*};
@@ -188,7 +189,7 @@ pub enum Chip8CpuInstructions {
/// Set sound timer = Vx.
///
/// ST is set equal to the value of Vx.
- LDI_S(u8),
+ LDIS(u8),
/// Fx1E - ADD I, Vx
/// Set I = I + Vx.
///
@@ -280,7 +281,7 @@ impl Chip8CpuInstructions {
Chip8CpuInstructions::LDIA(_) => INST_LDIA,
Chip8CpuInstructions::LDIX(_) => INST_LDIX,
Chip8CpuInstructions::LIDR(_) => INST_LIDR,
- Chip8CpuInstructions::LDI_S(_) => INST_LIDS,
+ Chip8CpuInstructions::LDIS(_) => INST_LDIS,
Chip8CpuInstructions::LDR(_, _) => INST_LDR,
Chip8CpuInstructions::LDRD(_) => INST_LDRD,
Chip8CpuInstructions::LDRI(_) => INST_LDRI,
@@ -327,6 +328,7 @@ impl Chip8CpuInstructions {
Chip8CpuInstructions::ADD(x, byte) => {
format!("0x{x:02x}, 0x{byte:02x}")
}
+ // Reg, Reg
Chip8CpuInstructions::SEY(x, y) |
Chip8CpuInstructions::LDR_Y(x, y) |
Chip8CpuInstructions::OR(x, y) |
@@ -338,50 +340,162 @@ impl Chip8CpuInstructions {
Chip8CpuInstructions::SUBC(x, y) |
Chip8CpuInstructions::SHL(x, y) |
Chip8CpuInstructions::SNEY(x, y) => {
- format!("0x{x:02x}, 0x{y:02x}")
+ format!("0x{x:01x}, 0x{y:01x}")
}
+ // Reg, Reg, Nibble
Chip8CpuInstructions::DRW(x, y, nibble) => {
format!("0x{x:02x}, 0x{y:02x}, 0x{nibble:02x}")
}
+ // Registers. 0-F
Chip8CpuInstructions::LDD(x) |
- Chip8CpuInstructions::LDI_S(x) |
+ Chip8CpuInstructions::LDIS(x) |
Chip8CpuInstructions::ADDI(x) |
Chip8CpuInstructions::LDFX(x) |
Chip8CpuInstructions::BCD(x) |
Chip8CpuInstructions::LDIX(x) |
- Chip8CpuInstructions::SKP(x) |
Chip8CpuInstructions::LDRD(x) |
Chip8CpuInstructions::LDRK(x) |
Chip8CpuInstructions::LDRI(x) |
Chip8CpuInstructions::LDF2(x) |
Chip8CpuInstructions::STR(x) |
Chip8CpuInstructions::LIDR(x) |
+ Chip8CpuInstructions::SDN(x) |
+ Chip8CpuInstructions::SKNP(x) |
Chip8CpuInstructions::SKP(x) => {
format!("0x{x:02x}")
}
- _ => { String::new() }
+ Chip8CpuInstructions::EXIT |
+ Chip8CpuInstructions::ENA |
+ Chip8CpuInstructions::DIS |
+ Chip8CpuInstructions::SLF |
+ Chip8CpuInstructions::XXXXERRORINSTRUCTION |
+ Chip8CpuInstructions::SRT |
+ Chip8CpuInstructions::CLS |
+ Chip8CpuInstructions::RET => {
+ String::new()
+ }
}
}
}
impl Display for Chip8CpuInstructions {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
- write!(f, "{} {}", self.name(), self.operands())
+ let ops = self.operands();
+ let space = if ops.is_empty() { "" } else { " " };
+ write!(f, "{}{}{}", self.name(), space, ops)
}
}
impl Chip8CpuInstructions {
pub fn from_str(input: &str) -> Chip8CpuInstructions {
- let parts = input.split(" ");
- println!("THERE ARE {} PARTS", parts.count());
- XXXXERRORINSTRUCTION
- //
- // match input.to_uppercase().as_str() {
- // INST_ADDI => Chip8CpuInstructions::ADDI(parts.nth(1)),
- // INST_ADD => Chip8CpuInstructions::ADD(parts[1], parts[2]),
- // INST_ADDR => Chip8CpuInstructions::ADDR(parts[1], parts[2]),
- // _ => XXXXERRORINSTRUCTION
- // }
+ let mut parts = input.split(" ");
+ // print!("THERE ARE {} PARTS", parts.clone().count());
+ let first_part = parts.next().unwrap_or("");
+ // take the next value...
+ // ...strip off the extra...
+ // ...convert it to an integer from base 16
+ let param1 = u16::from_str_radix(parts.next().unwrap_or("0").trim_start_matches("0x").trim_end_matches(","), 16).unwrap_or(0);
+ let param2 = u16::from_str_radix(parts.next().unwrap_or("0").trim_start_matches("0x").trim_end_matches(","), 16).unwrap_or(0);
+ let param3 = u16::from_str_radix(parts.next().unwrap_or("0").trim_start_matches("0x").trim_end_matches(","), 16).unwrap_or(0);
+ // println!("\tFirst part is {:?} / {:?} / {:?} / {:?}", first_part, param1 ,param2 ,param3);
+ match first_part {
+ INST_CLS => {
+ CLS
+ }
+ INST_DRW => {
+ DRW(param1 as u8, param2 as u8, param3 as u8)
+ }
+ INST_ADD => {
+ ADD(param1 as u8, param2 as u8)
+ }
+ INST_CALL => {
+ CALL(param1)
+ }
+ INST_SYS => {
+ SYS(param1)
+ }
+ INST_RET => {
+ RET
+ }
+ INST_JPA => {
+ JPA(param1)
+ }
+ INST_JPI => {
+ JPI(param1)
+ }
+ INST_SEX => {
+ SEX(param1 as u8, param2 as u8)
+ }
+ INST_SNEB => {
+ SNEB(param1 as u8, param2 as u8)
+ }
+ INST_SDN => {
+ SDN(param1 as u8)
+ }
+ INST_SRT => {
+ SRT
+ }
+ INST_SLF => {
+ SLF
+ }
+ INST_EXIT => {
+ EXIT
+ }
+ INST_DIS => {
+ DIS
+ }
+ INST_ENA => {
+ ENA
+ }
+ INST_SEY => {
+ SEY(param1 as u8, param2 as u8)
+ }
+ INST_LDRY => {
+ LDR_Y(param1 as u8, param2 as u8)
+ }
+ INST_LDR => {
+ LDR(param1 as u8, param2 as u8)
+ }
+ INST_OR => {
+ OR(param1 as u8, param2 as u8)
+ }
+ INST_AND => {
+ AND(param1 as u8, param2 as u8)
+ }
+ INST_ORY => {
+ ORY(param1 as u8, param2 as u8)
+ }
+ INST_ADDR => {
+ ADDR(param1 as u8, param2 as u8)
+ }
+ INST_SUB => {
+ SUB(param1 as u8, param2 as u8)
+ }
+ INST_SHR => {
+ SHR(param1 as u8, param2 as u8)
+ }
+ INST_SHL => {
+ SHL(param1 as u8, param2 as u8)
+ }
+ INST_SUBC => {
+ SUBC(param1 as u8, param2 as u8)
+ }
+ INST_SNEY => {
+ SNEY(param1 as u8, param2 as u8)
+ }
+ INST_LDIA => {
+ LDIA(param1)
+ }
+ INST_RND => {
+ RND(param1 as u8, param2 as u8)
+ }
+ INST_DRW => {
+ DRW(param1 as u8, param2 as u8, param3 as u8)
+ }
+ _ => {
+ XXXXERRORINSTRUCTION
+ }
+ }
}
pub fn encode(&self) -> u16 {
@@ -417,7 +531,7 @@ impl Chip8CpuInstructions {
Chip8CpuInstructions::LDRD(x_register) => 0xF007 | ((*x_register as u16) << 8),
Chip8CpuInstructions::LDRK(x_register) => 0xF00A | ((*x_register as u16) << 8),
Chip8CpuInstructions::LDD(x_register) => 0xF015 | ((*x_register as u16) << 8),
- Chip8CpuInstructions::LDI_S(x_register) => 0xF018 | ((*x_register as u16) << 8),
+ Chip8CpuInstructions::LDIS(x_register) => 0xF018 | ((*x_register as u16) << 8),
Chip8CpuInstructions::ADDI(x_register) => 0xF01E | ((*x_register as u16) << 8),
Chip8CpuInstructions::LDFX(x_register) => 0xF029 | ((*x_register as u16) << 8),
Chip8CpuInstructions::BCD(x_register) => 0xF033 | ((*x_register as u16) << 8),
@@ -488,7 +602,7 @@ impl Chip8CpuInstructions {
0x07 => Chip8CpuInstructions::LDRD(ubln),
0x0A => Chip8CpuInstructions::LDRK(ubln),
0x15 => Chip8CpuInstructions::LDD(ubln),
- 0x18 => Chip8CpuInstructions::LDI_S(ubln),
+ 0x18 => Chip8CpuInstructions::LDIS(ubln),
0x1E => Chip8CpuInstructions::ADDI(ubln),
0x29 => Chip8CpuInstructions::LDFX(ubln),
0x30 => Chip8CpuInstructions::LDF2(ubln),
@@ -816,9 +930,9 @@ impl Chip8CpuInstructions {
//
// DT is set equal to the value of Vx.
let new_time = input.registers.peek(*source_register as u8);
- input.delay_timer.set_timer(new_time as i32);
+ input.delay_timer.set_timer(new_time);
}
- Chip8CpuInstructions::LDI_S(new_time) => {
+ Chip8CpuInstructions::LDIS(new_time) => {
let new_value = input.registers.peek(*new_time as u8);
input.sound_timer.set_timer(new_value as i32);
}
diff --git a/gemma/src/chip8/keypad.rs b/gemma/src/chip8/keypad.rs
index 039b1f7..05bacf5 100644
--- a/gemma/src/chip8/keypad.rs
+++ b/gemma/src/chip8/keypad.rs
@@ -11,15 +11,17 @@ impl Keypad {
// draw a 4x4 grid showing the keys with * filling the cells that are depressed
for row in CHIP8_KEYBOARD.iter() {
for (index, key) in row.iter().enumerate() {
- let is_lit = if self.keys[*key as usize] { "*".to_string() } else { char::from_digit(*key as u32, 16).unwrap_or(' ').to_string() };
- match index {
- 3 => {
- // last in col
- return_value += format!("|{}|\n", is_lit).as_str();
- }
- _=> {
- return_value += format!("|{}", is_lit).as_str();
- }
+ let is_lit = if self.keys[*key as usize] {
+ "*".to_string()
+ } else {
+ char::from_digit(*key as u32, 16).unwrap_or(' ').to_string()
+ };
+
+ if index == 3 {
+ return_value += format!("|{}|\n", is_lit).as_str();
+
+ } else {
+ return_value += format!("|{}", is_lit).as_str();
}
}
}
diff --git a/gemma/src/chip8/quirk_modes.rs b/gemma/src/chip8/quirk_modes.rs
new file mode 100644
index 0000000..17c443d
--- /dev/null
+++ b/gemma/src/chip8/quirk_modes.rs
@@ -0,0 +1,8 @@
+#[derive(Default, Clone)]
+pub enum QuirkMode {
+ #[default]
+ Chip8,
+ SChipLegacy,
+ XOChip,
+ SChipModern
+}
diff --git a/gemma/src/chip8/system_memory.rs b/gemma/src/chip8/system_memory.rs
index cbed98d..d009a6a 100644
--- a/gemma/src/chip8/system_memory.rs
+++ b/gemma/src/chip8/system_memory.rs
@@ -20,6 +20,12 @@ impl Default for Chip8SystemMemory {
}
}
impl Chip8SystemMemory {
+
+ pub fn reset(&mut self){
+ self.memory = [0x00; CHIP8_MEMORY_SIZE as usize];
+ self.load_fonts_to_memory();
+ self.load_schip_fonts_to_memory();
+ }
pub fn new() -> Self {
Chip8SystemMemory {
diff --git a/gemma/src/chip8/video.rs b/gemma/src/chip8/video.rs
index 57e35c0..a8941d0 100644
--- a/gemma/src/chip8/video.rs
+++ b/gemma/src/chip8/video.rs
@@ -136,10 +136,9 @@ impl Chip8Video {
(CHIP8_VIDEO_WIDTH, CHIP8_VIDEO_HEIGHT)
}
}
-
fn get_memory_size(&self) -> i32 {
- let w = self.get_resolution();
- w.1 * w.0
+ let (width, height) = self.get_resolution();
+ width * height
}
pub fn tick(&mut self) {
diff --git a/gemma/src/constants.rs b/gemma/src/constants.rs
index dbeb3f3..21452b5 100644
--- a/gemma/src/constants.rs
+++ b/gemma/src/constants.rs
@@ -36,7 +36,7 @@ pub const INST_LDF2: &str = "LDF2";
pub const INST_LDIA: &str = "LDIA";
pub const INST_LDIX: &str = "LDIX";
pub const INST_LIDR: &str = "LIDR";
-pub const INST_LIDS: &str = "LIDS";
+pub const INST_LDIS: &str = "LIDS";
pub const INST_LDR: &str = "LDR";
pub const INST_LDRD: &str = "LDRD";
pub const INST_LDRI: &str = "LDRI";
diff --git a/gemma/src/lib.rs b/gemma/src/lib.rs
index b95b90c..1f26cfb 100644
--- a/gemma/src/lib.rs
+++ b/gemma/src/lib.rs
@@ -11,8 +11,8 @@ pub mod chip8 {
pub mod registers;
pub mod stack;
-
pub mod computer_manager;
+ pub mod quirk_modes;
}
pub mod constants;
\ No newline at end of file
diff --git a/gemma/tests/unit_tests.rs b/gemma/tests/unit_tests.rs
index 402c34d..eae71dc 100644
--- a/gemma/tests/unit_tests.rs
+++ b/gemma/tests/unit_tests.rs
@@ -1,8 +1,10 @@
+use std::collections::{BTreeMap, BTreeSet};
use log::debug;
use rand::random;
use gemma::chip8::computer::Chip8Computer;
use gemma::chip8::delay_timer::DelayTimer;
use gemma::chip8::instructions::Chip8CpuInstructions;
+use gemma::chip8::instructions::Chip8CpuInstructions::JPA;
use gemma::chip8::keypad::Keypad;
use gemma::chip8::registers::Chip8Registers;
use gemma::chip8::sound_timer::SoundTimer;
@@ -11,7 +13,7 @@ use gemma::chip8::util::InstructionUtil;
use gemma::chip8::video::Chip8Video;
use gemma::constants::*;
-const TEST_OUTPUT_SAMPLE_DIR: &str = "/home/tmerritt/Projects/trevors_chip8_toy/resources/test/";
+const TEST_OUTPUT_SAMPLE_DIR: &str = "/home/tmerritt/Projects/chip8_toy/resources/test/";
fn read_test_result(suffix: &str) -> String {
std::fs::read_to_string(TEST_OUTPUT_SAMPLE_DIR.to_owned() + suffix)
@@ -54,7 +56,7 @@ fn encode_decode_test() {
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::LDIS(0xb).encode(), 0xfb18);
assert_eq!(Chip8CpuInstructions::ADDI(0xd).encode(), 0xfd1e);
assert_eq!(Chip8CpuInstructions::LDFX(0xc).encode(), 0xfc29);
assert_eq!(Chip8CpuInstructions::BCD(0xd).encode(), 0xfd33);
@@ -110,7 +112,7 @@ fn encode_decode_test() {
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(0xfb18), Chip8CpuInstructions::LDIS(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)));
@@ -334,7 +336,7 @@ fn addivx_test() {
fn ldstvt_test() {
let mut x = Chip8Computer::new();
x.registers.poke(0x1, 0xf0);
- Chip8CpuInstructions::LDI_S(0x01).execute(&mut x);
+ Chip8CpuInstructions::LDIS(0x01).execute(&mut x);
assert_eq!(x.sound_timer.current(), 0xf0);
x.sound_timer.tick();
x.sound_timer.tick();
@@ -565,7 +567,6 @@ fn subn_vx_vy_test() {
assert_eq!(x.registers.peek_pc(), 0x206);
}
-#[test]
fn draw_nibble_vx_vy_n_test_hd() {
let mut x = Chip8Computer::new();
@@ -770,6 +771,15 @@ fn keypad_keys_check() {
assert!(k.released(1));
}
+
+#[test]
+fn keypad_string_format_test() {
+ let mut k = Keypad::new();
+
+
+ assert_eq!(k.format_as_string(), read_test_result("gemma_keypad_string_result.asc"));
+}
+
#[test]
fn register_rw_test() {
let mut x = Chip8Registers::default();
@@ -853,7 +863,7 @@ fn stack_push_pop_test() {
#[should_panic]
fn stack_overflow_test() {
let mut x = Chip8Stack::new();
- for i in 0..17 {
+ for i in 0..17 {
x.push(&i);
}
}
@@ -894,7 +904,6 @@ fn stack_lots_of_subs() {
}
assert_eq!(x.depth(), 15);
}
-
}
@@ -945,7 +954,6 @@ fn instruction_byte_to_bool_changes() {
}
-
fn real_build_checkboard(in_hd: bool) -> Chip8Video {
let mut r = Chip8Video::default();
let (width, height) = if in_hd {
@@ -1318,3 +1326,320 @@ fn video_scroll_right_4_row_test_high_def() {
x.scroll_right();
assert_eq!(read_test_result("test_scroll_right_4_hd.asc"), x.format_as_string());
}
+
+struct InstructionTest {
+ name: String,
+ instruction: Chip8CpuInstructions,
+ asm: String,
+ encoded: u16,
+}
+
+#[test]
+fn instructions_name_tests() {
+ assert_eq!(Chip8CpuInstructions::SYS(0x0000).name(), INST_SYS);
+ assert_eq!(Chip8CpuInstructions::ADD(0x0, 0x1).name(), INST_ADD);
+ assert_eq!(Chip8CpuInstructions::ADDI(0x0).name(), INST_ADDI);
+ assert_eq!(Chip8CpuInstructions::ADDR(0x01, 0x02).name(), INST_ADDR);
+ assert_eq!(Chip8CpuInstructions::AND(0x01, 0x02).name(), INST_AND);
+
+ let it = vec![
+ InstructionTest {
+ name: INST_SYS.to_string(),
+ instruction: Chip8CpuInstructions::SYS(0x123),
+ asm: "SYS 0x0123".to_string(),
+ encoded: 0x0123
+ },
+ InstructionTest {
+ name: INST_CLS.to_string(),
+ instruction: Chip8CpuInstructions::CLS,
+ asm: "CLS".to_string(),
+ encoded: 0x00E0
+ },
+ InstructionTest {
+ name: INST_RET.to_string(),
+ instruction: Chip8CpuInstructions::RET,
+ asm: "RET".to_string(),
+ encoded: 0x00ee
+ },
+ InstructionTest {
+ name: INST_JPA.to_string(),
+ instruction: JPA(0x234),
+ asm: "JPA 0x0234".to_string(),
+ encoded: 0xb234
+ },
+ InstructionTest {
+ name: INST_CALL.to_string(),
+ instruction: Chip8CpuInstructions::CALL(0x123),
+ asm: "CALL 0x0123".to_string(),
+ encoded: 0x2123,
+ },
+ InstructionTest {
+ name: INST_DRW.to_string(),
+ instruction: Chip8CpuInstructions::DRW(0x01, 0x02, 0x03),
+ asm: "DRW 0x01, 0x02, 0x03".to_string(),
+ encoded: 0xd123
+ },
+ InstructionTest {
+ name: INST_JPI.to_string(),
+ instruction: Chip8CpuInstructions::JPI(0x321),
+ asm: "JPI 0x0321".to_string(),
+ encoded: 0xb321
+ },
+ InstructionTest {
+ name: INST_SDN.to_string(),
+ instruction: Chip8CpuInstructions::SDN(0x01),
+ asm: "SDN 0x01".to_string(),
+ encoded: 0x00c1
+ },
+ InstructionTest {
+ name: INST_SRT.to_string(),
+ instruction: Chip8CpuInstructions::SRT,
+ asm: "SRT".to_string(),
+ encoded: 0x00FB
+ },
+ InstructionTest {
+ name: INST_SLF.to_string(),
+ instruction: Chip8CpuInstructions::SLF,
+ asm: "SLF".to_string(),
+ encoded: 0x00FC,
+ },
+ InstructionTest {
+ name: INST_EXIT.to_string(),
+ instruction: Chip8CpuInstructions::EXIT,
+ asm: "EXIT".to_string(),
+ encoded: 0x00FD,
+ },
+ InstructionTest {
+ name: INST_DIS.to_string(),
+ instruction: Chip8CpuInstructions::DIS,
+ asm: "DIS".to_string(),
+ encoded: 0x00FE,
+ },
+ InstructionTest {
+ name: INST_ENA.to_string(),
+ instruction: Chip8CpuInstructions::ENA,
+ asm: "ENA".to_string(),
+ encoded: 0x00FF,
+ },
+ InstructionTest {
+ name: INST_SEX.to_string(),
+ instruction: Chip8CpuInstructions::SEX(0x01, 0xfa),
+ asm: "SEX 0x01, 0xfa".to_string(),
+ encoded: 0x32fa,
+ },
+ InstructionTest {
+ name: INST_SNEB.to_string(),
+ instruction: Chip8CpuInstructions::SNEB(0x01, 0xab),
+ asm: "SNEB 0x01, 0xab".to_string(),
+ encoded: 0x41ab,
+ },
+ InstructionTest {
+ name: INST_SEY.to_string(),
+ instruction: Chip8CpuInstructions::SEY(0x1, 0x2),
+ asm: "SEY 0x1, 0x2".to_string(),
+ encoded: 0x5120
+ },
+ InstructionTest {
+ name: INST_LDR.to_string(),
+ instruction: Chip8CpuInstructions::LDR(0xa, 0xbe),
+ asm: "LDR 0x0a, 0xbe".to_string(),
+ encoded: 0x6abe,
+ },
+ InstructionTest {
+ name: INST_ADD.to_string(),
+ instruction: Chip8CpuInstructions::ADD(0x01, 0xab),
+ asm: "ADD 0x01, 0xab".to_string(),
+ encoded: 0x71ab
+ },
+ InstructionTest {
+ name: INST_LDRY.to_string(),
+ instruction: Chip8CpuInstructions::LDR_Y(0x1, 0x2),
+ asm: "LDRY 0x1, 0x2".to_string(),
+ encoded: 0x8120,
+ },
+ InstructionTest {
+ name: INST_OR.to_string(),
+ instruction: Chip8CpuInstructions::OR(0x1, 0x2),
+ asm: "OR 0x1, 0x2".to_string(),
+ encoded: 0x8121
+ },
+ InstructionTest {
+ name: INST_AND.to_string(),
+ instruction: Chip8CpuInstructions::AND(0xb, 0xc),
+ asm: "AND 0xb, 0xc".to_string(),
+ encoded: 0x8bc2,
+ },
+ InstructionTest {
+ name: INST_ORY.to_string(),
+ instruction: Chip8CpuInstructions::ORY(0xa, 0x3),
+ asm: "ORY 0xa, 0x3".to_string(),
+ encoded: 0x8a33
+ },
+ InstructionTest {
+ name: INST_ADDR.to_string(),
+ instruction: Chip8CpuInstructions::ADDR(0x1, 0x2),
+ asm: "ADDR 0x1, 0x2".to_string(),
+ encoded: 0x8124
+ },
+ InstructionTest {
+ name: INST_SUB.to_string(),
+ instruction: Chip8CpuInstructions::SUB(0x4, 0x5),
+ asm: "SUB 0x4, 0x5".to_string(),
+ encoded: 0x8455
+ },
+ InstructionTest {
+ name: INST_SHR.to_string(),
+ instruction: Chip8CpuInstructions::SHR(0x01, 0x1),
+ asm: "SHR 0x1, 0x1".to_string(),
+ encoded: 0x8116,
+ },
+ InstructionTest {
+ name: INST_SUBC.to_string(),
+ instruction: Chip8CpuInstructions::SUBC(0xf, 0xa),
+ asm: "SUBC 0xf, 0xa".to_string(),
+ encoded: 0x8fa7,
+ },
+ InstructionTest {
+ name: INST_SHL.to_string(),
+ instruction: Chip8CpuInstructions::SHL(0x1, 0x4),
+ asm: "SHL 0x1, 0x4".to_string(),
+ encoded: 0x814e,
+ },
+ InstructionTest {
+ name: INST_SNEY.to_string(),
+ instruction: Chip8CpuInstructions::SNEY(0x4, 0x5),
+ asm: "SNEY 0x4, 0x5".to_string(),
+ encoded: 0x9450,
+ },
+ InstructionTest {
+ name: INST_LDIA.to_string(),
+ instruction: Chip8CpuInstructions::LDIA(0xbee),
+ asm: "LDIA 0x0bee".to_string(),
+ encoded: 0x9bee
+ },
+ InstructionTest {
+ name: INST_JPI.to_string(),
+ instruction: Chip8CpuInstructions::JPI(0xfee),
+ asm: "JPI 0x0fee".to_string(),
+ encoded: 0xbfee
+ },
+ InstructionTest {
+ name: INST_RND.to_string(),
+ instruction: Chip8CpuInstructions::RND(0x1, 0xae),
+ asm: "RND 0x01, 0xae".to_string(),
+ encoded: 0xc1ae,
+ },
+ InstructionTest {
+ name: INST_DRW.to_string(),
+ instruction: Chip8CpuInstructions::DRW(0x1, 0x2, 0xf),
+ asm: "DRW 0x01, 0x02, 0x0f".to_string(),
+ encoded: 0xd12f
+ }
+ /*
+ 0xE09E..=0xEFA1 => match last_byte {
+ 0x9E => Chip8CpuInstructions::SKP(ubln),
+ 0xA1 => Chip8CpuInstructions::SKNP(ubln),
+ 0xF007..=0xFF65 => match last_byte {
+ 0x07 => Chip8CpuInstructions::LDRD(ubln),
+ 0x0A => Chip8CpuInstructions::LDRK(ubln),
+ 0x15 => Chip8CpuInstructions::LDD(ubln),
+ 0x18 => Chip8CpuInstructions::LDIS(ubln),
+ 0x1E => Chip8CpuInstructions::ADDI(ubln),
+ 0x29 => Chip8CpuInstructions::LDFX(ubln),
+ 0x30 => Chip8CpuInstructions::LDF2(ubln),
+ 0x33 => Chip8CpuInstructions::BCD(ubln),
+ 0x55 => Chip8CpuInstructions::LDIX(ubln),
+ 0x65 => Chip8CpuInstructions::LDRI(ubln),
+ 0x75 => Chip8CpuInstructions::STR(ubln),
+ 0x85 => Chip8CpuInstructions::LIDR(ubln),
+
+ */
+ ];
+
+ for current in it {
+ assert_eq!(current.instruction.name(), current.name);
+ let i = current.instruction;
+ assert!(matches!(Chip8CpuInstructions::decode(current.encoded), i));
+ assert_eq!(i.to_string(), current.asm);
+ let asm = Chip8CpuInstructions::from_str(¤t.asm);
+ assert_eq!(i.to_string(), asm.to_string());
+ }
+}
+
+#[test]
+fn instructions_operands_tests() {
+ assert_eq!(Chip8CpuInstructions::SYS(0x000).operands(), "0x0000");
+ assert_eq!(Chip8CpuInstructions::JPI(0x123).operands(), "0x0123");
+ assert_eq!(Chip8CpuInstructions::JPA(0x234).operands(), "0x0234");
+ assert_eq!(Chip8CpuInstructions::LDIA(0x345).operands(), "0x0345");
+ assert_eq!(Chip8CpuInstructions::CALL(0x456).operands(), "0x0456");
+}
+
+#[test]
+fn instruction_ena_dis_tests() {
+ let mut x = Chip8Computer::new();
+ assert!(!x.video_memory.is_highres());
+ Chip8CpuInstructions::ENA.execute(&mut x);
+ assert!(x.video_memory.is_highres());
+ Chip8CpuInstructions::ENA.execute(&mut x);
+ assert!(x.video_memory.is_highres());
+ Chip8CpuInstructions::DIS.execute(&mut x);
+ assert!(!x.video_memory.is_highres());
+}
+
+#[test]
+fn instruction_test_scrolling_lowres() {
+ let mut x = Chip8Computer::new();
+ x.video_memory = build_checkerboard();
+ Chip8CpuInstructions::SRT.execute(&mut x);
+
+ assert_eq!(read_test_result("test_scroll_right_4.asc"), x.dump_video_to_string());
+
+ x = Chip8Computer::new();
+ x.video_memory = build_checkerboard();
+ Chip8CpuInstructions::SLF.execute(&mut x);
+
+ assert_eq!(read_test_result("test_scroll_left_4.asc"), x.dump_video_to_string());
+
+ x = Chip8Computer::new();
+ x.video_memory = build_checkerboard();
+ Chip8CpuInstructions::SDN(0x01).execute(&mut x);
+ assert_eq!(read_test_result("test_video_scroll_down_1.asc"), x.dump_video_to_string());
+
+ x = Chip8Computer::new();
+ x.video_memory = build_checkerboard();
+ Chip8CpuInstructions::SDN(0xA).execute(&mut x);
+ assert_eq!(read_test_result("test_video_scroll_down_10.asc"), x.dump_video_to_string());
+}
+
+#[test]
+fn computer_dump_keypad_to_string() {
+
+}
+
+#[test]
+fn computer_dump_registers_to_string() {
+ let mut x = Chip8Computer::new();
+ let values_to_set = [0x0b, 0xad, 0xbe, 0xef,
+ 0xca, 0xb0,
+ 0x7a, 0xc0, 0xca, 0x70,
+ 0xba, 0xdb, 0xed, 0x00,
+ 0x00, 0x00
+ ];
+ let expected_value = "Vx: 0x0b 0xad 0xbe 0xef 0xca 0xb0 0x7a 0xc0\n 0xca 0x70 0xba 0xdb 0xed 0x00 0x00 0x00\nI: 0x0000\tPC: 0x0200";
+
+ for i in 0..16 {
+ x.registers.poke(i, values_to_set[i as usize]);
+ }
+
+ // now verify.
+ assert_eq!(expected_value, x.dump_registers_to_string());
+}
+
+//#[test]
+fn quirks_chip8_vf_reset_tests() {
+ // vF reset - The AND, OR and XOR opcodes (8xy1, 8xy2 and 8xy3) reset the flags
+ // register to zero. Test will show ERR1 if the AND and OR tests don't behave
+ // the same and ERR2 if the AND and XOR tests don't behave the same.
+ let mut x = Chip8Computer::new();
+}
\ No newline at end of file
diff --git a/gemmaegui/Cargo.toml b/gemmaegui/Cargo.toml
index 57c7aba..f0c8646 100644
--- a/gemmaegui/Cargo.toml
+++ b/gemmaegui/Cargo.toml
@@ -7,3 +7,4 @@ edition = "2021"
gemma = { path = "../gemma" }
egui.workspace = true
eframe.workspace = true
+catppuccin-egui = { version = "5.3.0", default-features = false, features = ["egui29"] }
diff --git a/gemmaegui/src/bin/gemmaegui.rs b/gemmaegui/src/bin/gemmaegui.rs
index 3241260..f5bc9f2 100644
--- a/gemmaegui/src/bin/gemmaegui.rs
+++ b/gemmaegui/src/bin/gemmaegui.rs
@@ -58,8 +58,10 @@ fn main() -> eframe::Result {
};
eframe::run_simple_native("EGUI Gemma", options, move |ctx, _frame| {
+ catppuccin_egui::set_theme(&ctx, catppuccin_egui::MOCHA);
egui::CentralPanel::default().show(ctx, |ui| {
- computer.tick();
+ let frame_start_time = Instant::now();
+
let local_computer = computer.state();
//if state.display_video {
GemmaEguiSupport::video_view(local_computer, ui);
@@ -116,6 +118,13 @@ fn main() -> eframe::Result {
}
});
+ // run our target number of ticks in the amount of available time.
+ let time_consumed = Instant::now().duration_since(frame_start_time).as_millis();
+ let mut num_ticks = 0;
+ while num_ticks < 1000 {
+ computer.tick();
+ num_ticks += 1;
+ }
ctx.request_repaint();
});
})
diff --git a/gemmaegui/src/bin/gemmaegui_viewer.rs b/gemmaegui/src/bin/gemmaegui_viewer.rs
deleted file mode 100644
index 587cf17..0000000
--- a/gemmaegui/src/bin/gemmaegui_viewer.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-use egui::Ui;
-use gemma::chip8::instructions::Chip8CpuInstructions;
-
-/// GemmaEGui - Viewer
-///
-///
-/// This program lets a user open a CH8 file and it will be decoded
-/// as Chip-8 Instructions.
-/// Colour variants for instructions show colours for
-/// -> Jumps
-/// -> Load
-/// -> Store
-/// -> Timers
-/// -> Math (Add, Sub)
-/// -> Logic
-/// -> Video
-
-fn display_instruction(offset: i32, to_display: &Chip8CpuInstructions, ui: &mut Ui) {
- ui.label(format!("{offset:04x} {}", to_display.name()));
- ui.label(format!("{}", to_display.operands()));
- ui.end_row();
-}
-
-fn display_instructions(base_offset: i32, instructions: Vec, ui: &mut Ui) {
- egui::Grid::new("my_grid")
- .min_col_width(200.0)
- .show(ui, |ui| {
- for (index, instruction) in instructions.iter().enumerate() {
- display_instruction(base_offset + index as i32, instruction, ui);
- }
- });
-}
-
-fn main() -> eframe::Result {
- let mut edit_space: String = String::new();
-
- let options = eframe::NativeOptions {
- viewport: egui::ViewportBuilder::default().with_inner_size([640.0, 480.0]),
- ..Default::default()
- };
-
- eframe::run_simple_native("Gemma - Chip8 Machine Code Viewer", options, move |ctx, frame| {
- egui::CentralPanel::default().show(ctx, |ui| {
- ui.label("Taxation is Theft");
- // file picker
- ui.vertical_centered(|ui| {
- if ui.button("Load File").clicked() {
- println!("Clicked load file");
- }
- });
- ui.label("File Picker Herre");
- ui.label("display of file here");
-
- ui.vertical(|ui| {
- display_instruction(0x010, &Chip8CpuInstructions::ADDI(0x01), ui);
- display_instruction(0x012, &Chip8CpuInstructions::RND(0x01, 0x02), ui);
- });
- ui.text_edit_multiline(&mut edit_space);
- });
- })
-}
\ No newline at end of file
diff --git a/gemmaimgui/Cargo.toml b/gemmaimgui/Cargo.toml
index 719d87c..f6dd850 100644
--- a/gemmaimgui/Cargo.toml
+++ b/gemmaimgui/Cargo.toml
@@ -17,3 +17,4 @@ image = { version = "0.23" }
imgui = { version = "0.12.0" }
winit = { version = "0.27", features = ["x11", "mint"]}
copypasta = { version = "0.8" }
+clap = { version = "4.5.20", features = ["derive"] }
\ No newline at end of file
diff --git a/gemmaimgui/src/bin/gemmaimgui.rs b/gemmaimgui/src/bin/gemmaimgui.rs
index 5ead06c..1d3f7cf 100644
--- a/gemmaimgui/src/bin/gemmaimgui.rs
+++ b/gemmaimgui/src/bin/gemmaimgui.rs
@@ -12,6 +12,10 @@ use gemma::chip8::computer_manager::Chip8ComputerManager;
use gemma::chip8::cpu_states::Chip8CpuStates::WaitingForInstruction;
use gemma::chip8::system_memory::Chip8SystemMemory;
use support::{emmagui_support::GemmaImguiSupport, ui_state::ImGuiUiState};
+use clap::{Parser, Subcommand};
+use gemma::chip8::quirk_modes::QuirkMode;
+use gemma::chip8::quirk_modes::QuirkMode::Chip8;
+
mod support;
@@ -28,8 +32,10 @@ const LIN_KEYS: [(u16, u8); 0x10] = [(537, 0x01),(538, 0x02),(539, 0x03),(540, 0
fn main() {
pretty_env_logger::init();
+
let mut system = Chip8ComputerManager::default();
let mut ui_state = ImGuiUiState::default();
+ let target_ips = ui_state.target_ips;
support::simple_init(file!(), move |_, ui| {
let current_time = Instant::now();
@@ -59,9 +65,16 @@ fn main() {
}
}
- while Instant::now().duration_since(current_time).as_millis() < 16 && num_cycles < 1000 {
- system.tick();
- num_cycles += 1;
+ let target_ms = ui_state.frame_time;
+ let loop_start_time = Instant::now();
+ while Instant::now().duration_since(current_time).as_millis() < target_ms as u128 && num_cycles < target_ips {
+ if system.tick() {
+ num_cycles += 1;
+ }
+ }
+ let cycles_time = Instant::now().duration_since(loop_start_time);
+ if num_cycles > 0 {
+ println!("Ran for {}ms and executed {}/{} cycles.", cycles_time.as_millis(), num_cycles, target_ips);
}
// GUI Parts
if ui_state.show_video {
diff --git a/gemmaimgui/src/bin/support/emmagui_support.rs b/gemmaimgui/src/bin/support/emmagui_support.rs
index 5c342bd..1a03a04 100644
--- a/gemmaimgui/src/bin/support/emmagui_support.rs
+++ b/gemmaimgui/src/bin/support/emmagui_support.rs
@@ -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/roms";
+const ROM_ROOT: &str = "/home/tmerritt/Projects/chip8_toy/resources/roms";
pub struct GemmaImguiSupport {}
@@ -25,37 +25,39 @@ const CELL_HEIGHT: i32 = 5i32;
impl GemmaImguiSupport {
pub fn keypad_display(system_to_display: &Chip8Computer, ui: &Ui) {
- ui.text("Keypad");
-
- for row in CHIP8_KEYBOARD {
- for key in row {
- let label = if system_to_display.keypad.pressed(key) {
- format!("*{:1x}*", key)
- } else {
- format!("{:1x}", key)
- };
- ui.text(format!("{}", label));
- ui.same_line();
- }
- ui.text("");
- }
+ ui.window(format!("Keypad"))
+ .size([100.0, 100.0], Condition::FirstUseEver)
+ .build(|| {
+ for row in CHIP8_KEYBOARD {
+ for key in row {
+ let label = if system_to_display.keypad.pressed(key) {
+ format!("*{:1x}*", key)
+ } else {
+ format!("{:1x}", key)
+ };
+ ui.text(format!("{}", label));
+ ui.same_line();
+ }
+ ui.text("");
+ }
+ });
}
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]);
+ // println!("DRAW_AREA_SIZE = {}x{}", draw_area_size[0], draw_area_size[1]);
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 origin = ui.cursor_screen_pos();
+ let origin = ui.cursor_pos();
let fg = ui.get_window_draw_list();
- if (system_to_control.video_memory.is_highres()) {
- ui.text("High Def Video here");
+ 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 {
@@ -73,10 +75,9 @@ impl GemmaImguiSupport {
}
}
} else {
- ui.text("StdDef video here.");
- for current_row in 0..=height {
+ for current_row in 0..height {
let y_offset = origin[1] as i32 + (current_row * cell_height);
- for current_column in 0..=width {
+ 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];
@@ -94,7 +95,7 @@ impl GemmaImguiSupport {
});
}
pub fn system_controls(system_to_control: &mut Chip8ComputerManager, gui_state: &mut ImGuiUiState, ui: &Ui) {
- // let mut state: Chip8Computer = system_to_control;
+ // let mut state: Chip8Computer = system_to_control;
ui.window("!!!! CONTROLS !!!!")
.size([345.0, 200.0], Condition::FirstUseEver)
.build(|| {
@@ -102,7 +103,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/roms/"), &gui_state.filename_to_load, ui);
+ let new_filename = GuiFileList::display_path(PathBuf::from(ROM_ROOT), &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}");
@@ -112,19 +113,21 @@ 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/roms/".to_string() + &gui_state.filename_to_load))).expect("put 1-chip8-logo.ch8 in this directory");
+ let mut input_file = File::open(Path::new(&(ROM_ROOT.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());
}
}
ui.separator();
- if ui.button("Step") {
- system_to_control.step();
-
- };
- ui.same_line();
- if ui.button("Run") {
- system_to_control.start();
+ // if the system has no program loaded hide the buttons.
+ if system_to_control.state().memory.peek(0x200) != 0x00 {
+ if ui.button("Step") {
+ system_to_control.step();
+ };
+ ui.same_line();
+ if ui.button("Run") {
+ system_to_control.start();
+ }
}
ui.same_line();
if ui.button("Stop") {
@@ -183,55 +186,53 @@ impl GemmaImguiSupport {
ui.window("System Memory")
.size([400.0, 300.0], Condition::FirstUseEver)
.build(|| {
- let mut current_x_hover: i32 = 0;
- let mut current_y_hover: i32 = 0;
- // display a block of data
- for current_row in 0..rows {
- ui.text(format!("{:02x}", current_row * cols));
- ui.same_line();
- for current_column in 0..cols {
- let data_offset = current_row * cols + current_column;
- let formatted_text = format!("{:02x}", bytes.peek(data_offset as u16));
- let text_location = ui.cursor_screen_pos();
- let text_size = ui.calc_text_size(formatted_text.clone());
- let bounding_box = imgui::sys::ImVec2 {
- x: text_location[0] + text_size[0],
- y: text_location[1] + text_size[1],
- };
+ let mut current_x_hover: i32 = 0;
+ let mut current_y_hover: i32 = 0;
+ // display a block of data
+ for current_row in 0..rows {
+ ui.text(format!("{:02x}", current_row * cols));
+ ui.same_line();
+ for current_column in 0..cols {
+ let data_offset = current_row * cols + current_column;
+ let formatted_text = format!("{:02x}", bytes.peek(data_offset as u16));
+ let text_location = ui.cursor_screen_pos();
+ let text_size = ui.calc_text_size(formatted_text.clone());
+ let bounding_box = imgui::sys::ImVec2 {
+ x: text_location[0] + text_size[0],
+ y: text_location[1] + text_size[1],
+ };
- let hovering = ui.is_mouse_hovering_rect(text_location, [bounding_box.x, bounding_box.y]);
- let is_active = data_offset == active as i32;
+ let hovering = ui.is_mouse_hovering_rect(text_location, [bounding_box.x, bounding_box.y]);
+ let is_active = data_offset == active as i32;
- ui.text_colored(if hovering {
- [0., 1., 1., 1.]
- } else if is_active {
- [1., 0., 1., 1.]
- } else {
- [1., 1., 0., 1.]
- }, formatted_text.clone());
+ ui.text_colored(if hovering {
+ [0., 1., 1., 1.]
+ } else if is_active {
+ [1., 0., 1., 1.]
+ } else {
+ [1., 1., 0., 1.]
+ }, formatted_text.clone());
+ // if we are hovering show that at the bottom...
+ if hovering {
+ // Optionally change the text color to indicate it's interactable
+ current_x_hover = current_column;
+ current_y_hover = current_row;
- // if we are hovering show that at the bottom...
- if hovering {
- // Optionally change the text color to indicate it's interactable
- current_x_hover = current_column;
- current_y_hover = current_row;
+ // Check if the left mouse button is clicked while hovering over the text
+ if ui.is_mouse_clicked(imgui::MouseButton::Left) {
+ debug!("Offset: [{}] [0x{:02x}] Value: [{}]", data_offset, data_offset, formatted_text.clone());
+ // Perform any action here, e.g., call a function, trigger an event, etc.
+ }
+ }
- // Check if the left mouse button is clicked while hovering over the text
- if ui.is_mouse_clicked(imgui::MouseButton::Left) {
- debug!("Offset: [{}] [0x{:02x}] Value: [{}]", data_offset, data_offset, formatted_text.clone());
- // Perform any action here, e.g., call a function, trigger an event, etc.
+ // are we on the same line?
+ if current_column != (cols - 1) {
+ ui.same_line();
}
}
-
- // are we on the same line?
- if current_column != (cols - 1) {
- ui.same_line();
- }
}
- }
- ui.text(format!("Offset 0x{:03x}", current_x_hover * cols + current_y_hover));
+ ui.text(format!("Offset 0x{:03x}", current_x_hover * cols + current_y_hover));
});
}
-
}
\ No newline at end of file
diff --git a/gemmaimgui/src/bin/support/ui_state.rs b/gemmaimgui/src/bin/support/ui_state.rs
index f0e317a..8ef7af3 100644
--- a/gemmaimgui/src/bin/support/ui_state.rs
+++ b/gemmaimgui/src/bin/support/ui_state.rs
@@ -10,8 +10,9 @@ pub struct ImGuiUiState {
pub on_colour: ImColor32,
pub off_colour: ImColor32,
pub is_running: bool,
- pub frame_time: f32,
- pub last_frame_instant: Instant
+ pub frame_time: u32,
+ pub last_frame_instant: Instant,
+ pub target_ips: i32
}
impl Clone for ImGuiUiState {
@@ -26,7 +27,8 @@ impl Clone for ImGuiUiState {
off_colour: self.off_colour,
is_running: self.is_running,
frame_time: self.frame_time,
- last_frame_instant: self.last_frame_instant
+ last_frame_instant: self.last_frame_instant,
+ target_ips: self.target_ips
}
}
}
@@ -42,8 +44,9 @@ impl Default for ImGuiUiState {
on_colour: ImColor32::from_rgb(0xff, 0xff, 0x00),
off_colour: ImColor32::from_rgb(0x00, 0xff, 0xff),
is_running: false,
- frame_time: 1.0,
- last_frame_instant: Instant::now()
+ frame_time: 16,
+ last_frame_instant: Instant::now(),
+ target_ips: 20
}
}
}
diff --git a/resources/octoroms/caveexplorer.ch8 b/resources/octoroms/caveexplorer.ch8
new file mode 100644
index 0000000..c70de42
Binary files /dev/null and b/resources/octoroms/caveexplorer.ch8 differ
diff --git a/resources/roms/chipwar.ch8 b/resources/roms/chipwar.ch8
new file mode 100644
index 0000000..e043ab1
Binary files /dev/null and b/resources/roms/chipwar.ch8 differ
diff --git a/resources/roms/deep8.ch8 b/resources/roms/deep8.ch8
new file mode 100644
index 0000000..14eea8b
Binary files /dev/null and b/resources/roms/deep8.ch8 differ
diff --git a/resources/test/gemma_keypad_string_result.asc b/resources/test/gemma_keypad_string_result.asc
new file mode 100644
index 0000000..643a5a4
--- /dev/null
+++ b/resources/test/gemma_keypad_string_result.asc
@@ -0,0 +1,4 @@
+|1|2|3|c|
+|4|5|6|d|
+|7|8|9|e|
+|a|0|b|f|