diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index c1eaa0a..231b130 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -9,12 +9,13 @@
-
-
-
+
+
+
+
+
-
@@ -42,87 +43,88 @@
- {
- "keyToString": {
- "Cargo.Build `Run emmagui`.executor": "Run",
- "Cargo.Build `Run gemmaegui_viewer`.executor": "Run",
- "Cargo.Build `Run gemmaegui`.executor": "Run",
- "Cargo.Build `Run gemmaimgui`.executor": "Run",
- "Cargo.Build `Run trevors_chip8_toy`.executor": "Run",
- "Cargo.Build `Test chip8::computer::test::cls_test`.executor": "Run",
- "Cargo.Build `Test chip8::instructions::test::LdStVx_test`.executor": "Run",
- "Cargo.Build `Test chip8::instructions::test::random_produces_different_numbers`.executor": "Run",
- "Cargo.Build `Test chip8::instructions::test::series8xy6_corex_tests`.executor": "Run",
- "Cargo.Build `Test chip8::instructions::test::shl_vx_vy_test`.executor": "Run",
- "Cargo.Build `Test chip8::util::test::byte_to_bool_changes`.executor": "Run",
- "Cargo.Build `Test chip8::util::test::ubln`.executor": "Run",
- "Cargo.Build `Test chip8::video::test::poke_byte_test`.executor": "Run",
- "Cargo.Build `Test chip8::video::test::poke_byte`.executor": "Run",
- "Cargo.Build `Test computer::test`.executor": "Run",
- "Cargo.Build `Test instructions::test (1)`.executor": "Run",
- "Cargo.Build `Test instructions::test`.executor": "Run",
- "Cargo.Build gemma.executor": "Run",
- "Cargo.Run emmagui.executor": "Run",
- "Cargo.Run gemmaegui.executor": "Run",
- "Cargo.Run gemmaegui_viewer.executor": "Debug",
- "Cargo.Run gemmaimgui.executor": "Run",
- "Cargo.Run trevors_chip8_toy.executor": "Debug",
- "Cargo.Test chip8::computer::test::cls_test.executor": "Run",
- "Cargo.Test chip8::computer::test::decoder_test_valid_instructions.executor": "Run",
- "Cargo.Test chip8::instructions::test::LdStVx_test.executor": "Run",
- "Cargo.Test chip8::instructions::test::LdVxDt_test.executor": "Run",
- "Cargo.Test chip8::instructions::test::LdiAddr_test.executor": "Run",
- "Cargo.Test chip8::instructions::test::RndVxByte_test.executor": "Run",
- "Cargo.Test chip8::instructions::test::ShrVxVy_test.executor": "Run",
- "Cargo.Test chip8::instructions::test::SneVxVy_test.executor": "Run",
- "Cargo.Test chip8::instructions::test::decoder_test_invalid_instructions.executor": "Run",
- "Cargo.Test chip8::instructions::test::draw_nibble_vx_vy_n_test.executor": "Debug",
- "Cargo.Test chip8::instructions::test::encode_decode_test.executor": "Run",
- "Cargo.Test chip8::instructions::test::random_produces_different_numbers.executor": "Run",
- "Cargo.Test chip8::instructions::test::series4000_corex_tests.executor": "Run",
- "Cargo.Test chip8::instructions::test::series8xy4_corex_tests.executor": "Run",
- "Cargo.Test chip8::instructions::test::series8xy6_corex_tests.executor": "Run",
- "Cargo.Test chip8::instructions::test::shl_vx_vy_test.executor": "Run",
- "Cargo.Test chip8::instructions::test::subn_vx_vy_test.executor": "Run",
- "Cargo.Test chip8::util::test::bool_to_byte_changes.executor": "Run",
- "Cargo.Test chip8::util::test::byte_to_bool_changes.executor": "Run",
- "Cargo.Test chip8::util::test::ubln.executor": "Run",
- "Cargo.Test chip8::video::test::poke_byte.executor": "Run",
- "Cargo.Test chip8::video::test::poke_byte_test.executor": "Run",
- "Cargo.Test chip8::video::test::poke_sprite_test.executor": "Debug",
- "Cargo.Test computer::test.executor": "Debug",
- "Cargo.Test instructions::test (1).executor": "Debug",
- "Cargo.Test instructions::test.executor": "Debug",
- "Cargo.Test sound_timer::test.executor": "Run",
- "Cargo.Test util::test.executor": "Run",
- "Cargo.Test video::test.executor": "Coverage",
- "RunOnceActivity.ShowReadmeOnStart": "true",
- "RunOnceActivity.rust.reset.selective.auto.import": "true",
- "git-widget-placeholder": "rename__instructions",
- "last_opened_file_path": "/home/tmerritt/Projects/chip8_toy/gemmaimgui",
- "node.js.detected.package.eslint": "true",
- "node.js.selected.package.eslint": "(autodetect)",
- "nodejs_package_manager_path": "npm",
- "org.rust.cargo.project.model.PROJECT_DISCOVERY": "true",
- "org.rust.cargo.project.model.impl.CargoExternalSystemProjectAware.subscribe.first.balloon": "",
- "org.rust.first.attach.projects": "true",
- "settings.editor.selected.configurable": "language.rust.build.tool.cargo"
+
+}]]>
+
-
+
@@ -193,8 +195,8 @@
-
+
diff --git a/Cargo.lock b/Cargo.lock
index c65940c..2a6a087 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1835,6 +1835,8 @@ version = "0.1.0"
dependencies = [
"clap",
"gemma",
+ "pest",
+ "pest_derive",
]
[[package]]
@@ -3216,6 +3218,51 @@ version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+[[package]]
+name = "pest"
+version = "2.7.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442"
+dependencies = [
+ "memchr",
+ "thiserror",
+ "ucd-trie",
+]
+
+[[package]]
+name = "pest_derive"
+version = "2.7.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd"
+dependencies = [
+ "pest",
+ "pest_generator",
+]
+
+[[package]]
+name = "pest_generator"
+version = "2.7.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e"
+dependencies = [
+ "pest",
+ "pest_meta",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.79",
+]
+
+[[package]]
+name = "pest_meta"
+version = "2.7.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d"
+dependencies = [
+ "once_cell",
+ "pest",
+ "sha2",
+]
+
[[package]]
name = "pin-project"
version = "1.1.6"
@@ -3748,6 +3795,17 @@ dependencies = [
"digest",
]
+[[package]]
+name = "sha2"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
[[package]]
name = "shlex"
version = "1.3.0"
@@ -4151,6 +4209,12 @@ version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+[[package]]
+name = "ucd-trie"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
+
[[package]]
name = "uds_windows"
version = "1.1.0"
diff --git a/gemma/src/chip8/computer_manager.rs b/gemma/src/chip8/computer_manager.rs
index 120bd47..3eb7e49 100644
--- a/gemma/src/chip8/computer_manager.rs
+++ b/gemma/src/chip8/computer_manager.rs
@@ -3,6 +3,7 @@ use std::thread;
use std::thread::{sleep, JoinHandle, Thread};
use std::time::{Duration, Instant};
use crate::chip8::computer::Chip8Computer;
+use crate::chip8::cpu_states::Chip8CpuStates;
use crate::chip8::cpu_states::Chip8CpuStates::WaitingForInstruction;
pub enum ManagerDumpables {
@@ -13,10 +14,10 @@ pub enum ManagerDumpables {
pub struct Chip8ComputerManager {
- pub core_should_run: bool,
- pub one_step: bool,
- pub core_cycle_timer: bool,
- pub core_last_cycle_start: Instant,
+ core_should_run: bool,
+ one_step: bool,
+ core_cycle_timer: bool,
+ core_last_cycle_start: Instant,
computer: Chip8Computer
}
@@ -41,11 +42,10 @@ impl Chip8ComputerManager {
let core_handle = thread::spawn(move || {
loop {
let start_time = Instant::now();
- println!("Core Thread starting at {start_time:?}");
-
+ // 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");
+ // println!("Core Thread sleeping for {sleep_time}ms");
sleep(Duration::from_millis((16 - sleep_time) as u64));
}
});
@@ -53,16 +53,16 @@ impl Chip8ComputerManager {
Chip8ComputerManager::default()
}
- pub fn start(managed: &mut Chip8ComputerManager) {
- managed.core_should_run = true;
+ pub fn start(&mut self) {
+ self.core_should_run = true;
}
- pub fn stop(managed: &mut Chip8ComputerManager) {
- managed.core_should_run = false
+ pub fn stop(&mut self) {
+ self.core_should_run = false
}
- pub fn step(managed: &mut Chip8ComputerManager) {
- managed.one_step = true;
+ pub fn step(&mut self) {
+ self.one_step = true;
}
pub fn state(&mut self) -> &Chip8Computer {
@@ -70,11 +70,16 @@ impl Chip8ComputerManager {
}
pub fn tick( &mut self) {
- println!("STARTING TICK");
- if self.one_step | self.core_should_run {
- self.core_last_cycle_start = Instant::now();
- self.computer.step_system();
- println!("SYSTEM STEP");
+ // println!("STARTING TICK");
+ if self.one_step | self.core_should_run {
+ match self.computer.state {
+ WaitingForInstruction => {
+ self.core_last_cycle_start = Instant::now();
+ self.computer.step_system();
+ println!("SYSTEM STEP");
+ }
+ _ => {}
+ }
};
if self.one_step {
println!("SYSTEM HALTED AFTER 1 STEP");
@@ -86,6 +91,9 @@ impl Chip8ComputerManager {
pub fn press_key(&mut self, key_index: u8) {
self.computer.keypad.push_key(key_index);
+ if matches!(self.computer.state, Chip8CpuStates::WaitingForKey) {
+ self.computer.state = WaitingForInstruction
+ }
}
pub fn release_key(&mut self, key_index: u8) {
self.computer.keypad.release_key(key_index);
diff --git a/gemmaegui/src/bin/gemmaegui.rs b/gemmaegui/src/bin/gemmaegui.rs
index 17e4340..3241260 100644
--- a/gemmaegui/src/bin/gemmaegui.rs
+++ b/gemmaegui/src/bin/gemmaegui.rs
@@ -1,23 +1,31 @@
+use std::path::PathBuf;
use std::time::Instant;
use crate::support::gemma_egui_support::{EGuiFileList, GemmaEguiSupport};
use crate::support::gemma_egui_state::GemmaEGuiState;
use eframe::egui;
-use egui::Ui;
+use egui::{Key, Ui};
use gemma::chip8::computer::Chip8Computer;
use gemma::chip8::computer_manager::Chip8ComputerManager;
mod support;
+const LIN_KEYS: [[(Key, u8); 4]; 4] = [
+ [(Key::Num1, 0x01), (Key::Num2, 0x02), (Key::Num3, 0x03), (Key::Num4, 0x0c)],
+ [(Key::Q, 0x04), (Key::W, 0x05), (Key::E, 0x06), (Key::R, 0x0d)],
+ [(Key::A, 0x07), (Key::S, 0x08), (Key::D, 0x09), (Key::F, 0x0e)],
+ [(Key::Z, 0x0a), (Key::X, 0x00), (Key::C, 0x0b), (Key::V, 0x0F)]
+];
+
#[derive(Default)]
struct DisplayOptions {
pub video: bool,
pub registers: bool,
- pub memory: bool
+ pub memory: bool,
}
pub struct GemmaViewerState {
pub selected_file_index: i32,
pub selected_filename: String,
- pub display_options: DisplayOptions
+ pub display_options: DisplayOptions,
}
impl Default for GemmaViewerState {
@@ -25,7 +33,7 @@ impl Default for GemmaViewerState {
GemmaViewerState {
selected_file_index: -1,
selected_filename: String::new(),
- display_options: Default::default()
+ display_options: Default::default(),
}
}
}
@@ -54,28 +62,28 @@ fn main() -> eframe::Result {
computer.tick();
let local_computer = computer.state();
//if state.display_video {
- GemmaEguiSupport::video_view(local_computer, ui);
- // }
+ GemmaEguiSupport::video_view(local_computer, ui);
+ // }
ui.heading("EGUI Gemma");
- // if state.display_memory {
- GemmaEguiSupport::memory_view(&local_computer, ui);
- // }
+ // if state.display_memory {
+ GemmaEguiSupport::memory_view(&local_computer, ui);
+ // }
- // if state.display_registers {
- GemmaEguiSupport::registers_view(&local_computer, ui);
- // }
+ // if state.display_registers {
+ GemmaEguiSupport::registers_view(&local_computer, ui);
+ // }
ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {
if ui.button("Start").clicked() {
- computer.core_should_run = true;
+ computer.start();
}
if ui.button("Step").clicked() {
- computer.one_step = true;
+ computer.step();
}
if ui.button("Stop").clicked() {
- computer.core_should_run = false;
+ computer.stop();
// state.is_running = false;
}
if ui.button("Reset").clicked() {
@@ -84,17 +92,31 @@ fn main() -> eframe::Result {
}
});
- if ui.button(format!("Load {}", state.selected_filename)).clicked() {
-
- }
- // // load the bin...
- // let read_bin = std::fs::read(PathBuf::from(format!("resources/roms/{}", state.selected_rom_filename))).unwrap();
- // // ...then feed the system.
- // system.load_bytes_to_memory(0x200, &read_bin);
- // println!("Loaded {}", state.selected_rom_filename);
- // }
- // EGuiFileList::display_path(PathBuf::from("resources/roms"), &mut state.selected_rom_filename, ui);
+ if ui.button(format!("Load {}", state.selected_filename)).clicked() {
+ // println!("Should load the bin now");
+ let read_bin = std::fs::read(PathBuf::from(format!("resources/roms/{}", state.selected_filename))).unwrap();
+ computer.load_bytes_to_system_memory(read_bin);
+ };
+ EGuiFileList::display_path(PathBuf::from("resources/roms"), &mut state.selected_filename, ui);
+ let input = ctx.input(|input| {
+ // loop through the keys we are checking...
+ for row in LIN_KEYS {
+ for (keyboard_key, keypad_key) in row {
+ if input.key_pressed(keyboard_key) {
+ computer.press_key(keypad_key);
+ // println!("KEY {keypad_key:02x} DOWN");
+ } else {
+ // release it if the user just did
+ if computer.is_key_pressed(keypad_key) {
+ computer.release_key(keypad_key);
+ // println!("KEY {keypad_key:02x} up");
+ }
+ }
+ }
+ }
+ });
+ ctx.request_repaint();
});
})
}
diff --git a/gemmaimgui/src/bin/gemmaimgui.rs b/gemmaimgui/src/bin/gemmaimgui.rs
index dfa4d7a..fa918bf 100644
--- a/gemmaimgui/src/bin/gemmaimgui.rs
+++ b/gemmaimgui/src/bin/gemmaimgui.rs
@@ -45,10 +45,8 @@ fn main() {
}
// END DEBUG CODE
-
for (key_code, key_reg) in LIN_KEYS {
if down_keys[key_code as usize] {
- system.press_key(key_reg);
system.press_key(key_reg);
system.wait_for_instruction();
} else {
diff --git a/gemmautil/Cargo.toml b/gemmautil/Cargo.toml
index 54a63ff..4257587 100644
--- a/gemmautil/Cargo.toml
+++ b/gemmautil/Cargo.toml
@@ -6,3 +6,5 @@ edition = "2021"
[dependencies]
gemma = { path = "../gemma" }
clap = { version = "4.5.20", features = ["derive"] }
+pest = "2.7.14"
+pest_derive = "2.7.14"
\ No newline at end of file
diff --git a/gemmautil/src/bin/ch8asm.rs b/gemmautil/src/bin/ch8asm.rs
index 709c232..937e2b1 100644
--- a/gemmautil/src/bin/ch8asm.rs
+++ b/gemmautil/src/bin/ch8asm.rs
@@ -1,59 +1,87 @@
-use std::fs::File;
-use std::io;
-use std::io::BufRead;
-use std::path::Path;
-use clap::Parser;
-use gemma::chip8::instructions::Chip8CpuInstructions;
-
-/// Ch8Asm
-/// Converts well formed CH8ASM.
-/// no variables.
-/// no labels.
-/// nothing fun.
-
-pub struct Assembler {}
-
-impl Assembler {
-
-}
+use std::fs;
+// Ch8Asm
+// Converts well formed CH8ASM.
+// no variables.
+// no labels.
+// nothing fun.
+use pest::Parser;
+use pest_derive::Parser;
#[derive(Parser)]
-#[command(version, about, long_about = None)]
-struct AssemblerApp {
- #[arg(short)]
- input_file: Box,
-}
+#[grammar = "chip8_asm.pest"]
+pub struct Chip8AsmParser;
fn main() {
println!("Taxation is Theft");
- let result = AssemblerApp::parse();
- let mut assembled_code: Vec = vec![];
- // println!("Preparing to assemble {}", result.input_file.file_name());
+ let unparsed = fs::read_to_string("resources/test/gemma_disassembler_1_chip_logo_ch8_asm.asc").expect("Unable to read input");
- let path = Path::new(result.input_file);
+ let file = Chip8AsmParser::parse(Rule::file, &unparsed).expect("Unable to parse. Try again.")
+ .next().unwrap();
- // Open the file in read-only mode
- let file = File::open(&path)?;
-
- // Use a buffered reader for efficient reading
- let reader = io::BufReader::new(file);
-
- // Read the file line by line
- for line in reader.lines() {
- // Get the line, handling possible errors
- let line = line?;
-
- // Split the line by ';' and collect parts into a vector
- let parts: Vec<&str> = line.split(';').collect();
-
- // Print each part or process it as needed
- for part in &parts {
- println!("{}", part);
+ for record in file.into_inner() {
+ match record.as_rule() {
+ Rule::instruction => {
+ println!("INSTRUCTION = {:?}", record.into_inner().flatten())
+ }
+ _ => {
+ println!("UNHANDLED PART.");
+ }
}
}
- // read the line split by a semicolon
+}
+mod test {
+ use super::*;
+
+ #[test]
+ fn bits_all_parse() {
+ println!("PARSED: {:?}",
+ Chip8AsmParser::parse(Rule::instruction, "CLS")
+ );
+ println!("PARSED: {:?}",
+ Chip8AsmParser::parse(Rule::parameter, "0x01")
+ );
+ let parsed = Chip8AsmParser::parse(Rule::comment, "; comment").unwrap();
+ for i in parsed {
+ println!("PARSED COMMENT -> {:?}", i);
+ }
+
+ let parsed =
+ Chip8AsmParser::parse(Rule::record, "CLS ; comment").unwrap();
+ for i in parsed {
+ println!("RULE PAIR THING: {:?}", i);
+ }
+
+ let parsed = Chip8AsmParser::parse(Rule::record, "ADDI 0x01 ; comment");
+ for i in parsed {
+ println!("RULE PAIR THING: {:?}", i);
+ }
+
+
+ let parsed = Chip8AsmParser::parse(Rule::record, "ADDI ; comment");
+ for i in parsed {
+ println!("RULE PAIR THING: {:?}", i);
+ }
+
+
+ println!("PARSED: {:?}",
+ Chip8AsmParser::parse(Rule::record, "ADD 0x01 0x02 ; Comment")
+ );
+
+ println!("PARSED: {:?}",
+ Chip8AsmParser::parse(Rule::record, "ADD ADD ADD")
+ );
+
+ println!("PARSED: {:?}",
+ Chip8AsmParser::parse(Rule::record, "ADD 0x01 0x02 ; Comment")
+ );
+
+ println!("PARSED: {:?}",
+ Chip8AsmParser::parse(Rule::record, "ADD 0x01 0x02 ; Comment")
+ );
+
+ }
}
\ No newline at end of file
diff --git a/gemmautil/src/bin/ch8disasm.rs b/gemmautil/src/bin/ch8disasm.rs
index b002e3c..f6ac8eb 100644
--- a/gemmautil/src/bin/ch8disasm.rs
+++ b/gemmautil/src/bin/ch8disasm.rs
@@ -18,7 +18,41 @@ struct DisassemblerApp {
struct Disassembler {}
impl Disassembler {
pub fn disassemble(from_data: Vec) -> String {
- String::new()
+ let mut working_instruction: u16 = 0x0000;
+
+ // read the input data and loop through it byte by byte.
+ let mut output_string = String::new();
+
+ for (offset, byte) in from_data.iter().enumerate() {
+ working_instruction = (working_instruction << 8) | (*byte as u16);
+ if offset % 2 != 0 {
+ let decoded = Chip8CpuInstructions::decode(working_instruction);
+ let decoded_string = decoded.to_string();
+ let mut current_parts = String::new();
+
+ match decoded {
+ XXXXERRORINSTRUCTION => {
+ current_parts = format!("DW 0x{:04x}", working_instruction);
+ }
+ _ => {
+ current_parts = format!("{}", decoded);
+ }
+ };
+
+ let target_length: i32 = 25;
+ let spacing_length = target_length.saturating_sub(current_parts.len() as i32);
+
+ // now add the rest after the string
+ let x = spacing_length as usize;
+ current_parts = format!("{}{: {
- current_parts = format!("DW 0x{:04x}", working_instruction);
- }
- _ => {
- current_parts = format!("{}", decoded);
- }
- };
-
- let target_length: i32 = 25;
- let spacing_length = target_length.saturating_sub(current_parts.len() as i32);
-
- // now add the rest after the string
- let x = spacing_length as usize;
- current_parts = format!("{}{: {
println!("Output to console.");
- println!("OS: \n\n{}", output_string);
+ println!("OS: \n\n{}", decompiled_program);
}
Some(target) => {
println!("Output to {:?}", target);
- std::fs::write(target, output_string).unwrap();
+ std::fs::write(target, decompiled_program).unwrap();
}
}
}
diff --git a/gemmautil/src/chip8_asm.pest b/gemmautil/src/chip8_asm.pest
new file mode 100644
index 0000000..727d8de
--- /dev/null
+++ b/gemmautil/src/chip8_asm.pest
@@ -0,0 +1,7 @@
+WHITESPACE = _{ " " }
+instruction = { ASCII_ALPHA+ }
+parameter = { "0X" ~ ASCII_HEX_DIGIT+ }
+comment = { ";" ~ WHITESPACE* ~ ASCII* }
+parameters = { parameter ~ (WHITESPACE* ~ "," ~ WHITESPACE* ~ parameter)* }
+record = { instruction ~ WHITESPACE ~ parameters? ~ WHITESPACE* ~ comment? }
+file = { SOI ~ (record ~ ("\r\n" | "\n"))* ~ EOI }