WIP
richer test suite Updates imgui to have target ips and limits correctly. Initial IPS = 1000, plan to expose to user More tests for encode/decode of instructions Adding text to instruction parsing
This commit is contained in:
parent
1694157e27
commit
b492eb5f49
74
.idea/workspace.xml
generated
74
.idea/workspace.xml
generated
@ -9,10 +9,8 @@
|
|||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="9bcba7c5-ac1d-4216-959a-63faee7047bc" name="Changes" comment="">
|
<list default="true" id="9bcba7c5-ac1d-4216-959a-63faee7047bc" name="Changes" comment="">
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/gemma/src/chip8/computer.rs" beforeDir="false" afterPath="$PROJECT_DIR$/gemma/src/chip8/computer.rs" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/gemma/src/chip8/instructions.rs" beforeDir="false" afterPath="$PROJECT_DIR$/gemma/src/chip8/instructions.rs" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/gemma/src/chip8/instructions.rs" beforeDir="false" afterPath="$PROJECT_DIR$/gemma/src/chip8/instructions.rs" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/gemma/src/chip8/stack.rs" beforeDir="false" afterPath="$PROJECT_DIR$/gemma/src/chip8/stack.rs" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/gemma/tests/unit_tests.rs" beforeDir="false" afterPath="$PROJECT_DIR$/gemma/tests/unit_tests.rs" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/gemma/src/chip8/video.rs" beforeDir="false" afterPath="$PROJECT_DIR$/gemma/src/chip8/video.rs" afterDir="false" />
|
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
@ -58,8 +56,10 @@
|
|||||||
"Cargo.Build `Test chip8::video::test::poke_byte`.executor": "Run",
|
"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 chip8::video::test::scroll_down_1_row_test`.executor": "Run",
|
||||||
"Cargo.Build `Test computer::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 (1)`.executor": "Run",
|
||||||
"Cargo.Build `Test instructions::test`.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 `Test video::test`.executor": "Run",
|
||||||
"Cargo.Build gemma.executor": "Run",
|
"Cargo.Build gemma.executor": "Run",
|
||||||
"Cargo.Run emmagui.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::scroll_down_1_row_test.executor": "Run",
|
||||||
"Cargo.Test chip8::video::test::write_checkboard.executor": "Run",
|
"Cargo.Test chip8::video::test::write_checkboard.executor": "Run",
|
||||||
"Cargo.Test computer::test.executor": "Debug",
|
"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 (1).executor": "Debug",
|
||||||
"Cargo.Test instructions::test.executor": "Debug",
|
"Cargo.Test instructions::test.executor": "Debug",
|
||||||
|
"Cargo.Test instructions_name_tests.executor": "Run",
|
||||||
"Cargo.Test sound_timer::test.executor": "Run",
|
"Cargo.Test sound_timer::test.executor": "Run",
|
||||||
"Cargo.Test util::test.executor": "Run",
|
"Cargo.Test util::test.executor": "Run",
|
||||||
"Cargo.Test video::test.executor": "Debug",
|
"Cargo.Test video::test.executor": "Debug",
|
||||||
@ -123,11 +126,29 @@
|
|||||||
<recent name="$PROJECT_DIR$/gemmaimgui" />
|
<recent name="$PROJECT_DIR$/gemmaimgui" />
|
||||||
</key>
|
</key>
|
||||||
<key name="MoveFile.RECENT_KEYS">
|
<key name="MoveFile.RECENT_KEYS">
|
||||||
|
<recent name="$PROJECT_DIR$/resources/octoroms" />
|
||||||
<recent name="$PROJECT_DIR$/gemmautil/src" />
|
<recent name="$PROJECT_DIR$/gemmautil/src" />
|
||||||
<recent name="$PROJECT_DIR$/gemmaimgui/src/bin" />
|
<recent name="$PROJECT_DIR$/gemmaimgui/src/bin" />
|
||||||
</key>
|
</key>
|
||||||
</component>
|
</component>
|
||||||
<component name="RunManager" selected="Cargo.Run gemmaimgui">
|
<component name="RunManager" selected="Cargo.Test instructions_name_tests">
|
||||||
|
<configuration name="Run gemmaegui" type="CargoCommandRunConfiguration" factoryName="Cargo Command" temporary="true">
|
||||||
|
<option name="command" value="run --package gemmaegui --bin gemmaegui" />
|
||||||
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||||
|
<envs />
|
||||||
|
<option name="emulateTerminal" value="true" />
|
||||||
|
<option name="channel" value="DEFAULT" />
|
||||||
|
<option name="requiredFeatures" value="true" />
|
||||||
|
<option name="allFeatures" value="false" />
|
||||||
|
<option name="withSudo" value="false" />
|
||||||
|
<option name="buildTarget" value="REMOTE" />
|
||||||
|
<option name="backtrace" value="SHORT" />
|
||||||
|
<option name="isRedirectInput" value="false" />
|
||||||
|
<option name="redirectInputPath" value="" />
|
||||||
|
<method v="2">
|
||||||
|
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
<configuration name="Run gemmaimgui" type="CargoCommandRunConfiguration" factoryName="Cargo Command" temporary="true">
|
<configuration name="Run gemmaimgui" type="CargoCommandRunConfiguration" factoryName="Cargo Command" temporary="true">
|
||||||
<option name="command" value="run --package gemmaimgui --bin gemmaimgui" />
|
<option name="command" value="run --package gemmaimgui --bin gemmaimgui" />
|
||||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||||
@ -145,8 +166,8 @@
|
|||||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
</configuration>
|
</configuration>
|
||||||
<configuration name="Test chip8::video::test::high_res_has_right_resolution" type="CargoCommandRunConfiguration" factoryName="Cargo Command" temporary="true">
|
<configuration name="Test computer_dump_registers_to_string" type="CargoCommandRunConfiguration" factoryName="Cargo Command" temporary="true">
|
||||||
<option name="command" value="test --package gemma --lib chip8::video::test::high_res_has_right_resolution -- --exact" />
|
<option name="command" value="test --package gemma --test unit_tests computer_dump_registers_to_string -- --exact" />
|
||||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||||
<envs />
|
<envs />
|
||||||
<option name="emulateTerminal" value="true" />
|
<option name="emulateTerminal" value="true" />
|
||||||
@ -162,25 +183,8 @@
|
|||||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
</configuration>
|
</configuration>
|
||||||
<configuration name="Test chip8::video::test::scroll_down_10_row_test" type="CargoCommandRunConfiguration" factoryName="Cargo Command" temporary="true">
|
<configuration name="Test instructions_name_tests" type="CargoCommandRunConfiguration" factoryName="Cargo Command" temporary="true">
|
||||||
<option name="command" value="test --package gemma --lib chip8::video::test::scroll_down_10_row_test -- --exact" />
|
<option name="command" value="test --package gemma --test unit_tests instructions_name_tests -- --exact" />
|
||||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
|
||||||
<envs />
|
|
||||||
<option name="emulateTerminal" value="true" />
|
|
||||||
<option name="channel" value="DEFAULT" />
|
|
||||||
<option name="requiredFeatures" value="true" />
|
|
||||||
<option name="allFeatures" value="false" />
|
|
||||||
<option name="withSudo" value="false" />
|
|
||||||
<option name="buildTarget" value="REMOTE" />
|
|
||||||
<option name="backtrace" value="SHORT" />
|
|
||||||
<option name="isRedirectInput" value="false" />
|
|
||||||
<option name="redirectInputPath" value="" />
|
|
||||||
<method v="2">
|
|
||||||
<option name="CARGO.BUILD_TASK_PROVIDER" enabled="true" />
|
|
||||||
</method>
|
|
||||||
</configuration>
|
|
||||||
<configuration name="Test chip8::video::test::scroll_down_1_row_test" type="CargoCommandRunConfiguration" factoryName="Cargo Command" temporary="true">
|
|
||||||
<option name="command" value="test --package gemma --lib chip8::video::test::scroll_down_1_row_test -- --exact" />
|
|
||||||
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
<option name="workingDirectory" value="file://$PROJECT_DIR$" />
|
||||||
<envs />
|
<envs />
|
||||||
<option name="emulateTerminal" value="true" />
|
<option name="emulateTerminal" value="true" />
|
||||||
@ -215,11 +219,11 @@
|
|||||||
</configuration>
|
</configuration>
|
||||||
<recent_temporary>
|
<recent_temporary>
|
||||||
<list>
|
<list>
|
||||||
|
<item itemvalue="Cargo.Test instructions_name_tests" />
|
||||||
|
<item itemvalue="Cargo.Run gemmaegui" />
|
||||||
|
<item itemvalue="Cargo.Run gemmaegui" />
|
||||||
<item itemvalue="Cargo.Run gemmaimgui" />
|
<item itemvalue="Cargo.Run gemmaimgui" />
|
||||||
<item itemvalue="Cargo.Test video::test" />
|
<item itemvalue="Cargo.Test computer_dump_registers_to_string" />
|
||||||
<item itemvalue="Cargo.Test chip8::video::test::high_res_has_right_resolution" />
|
|
||||||
<item itemvalue="Cargo.Test chip8::video::test::scroll_down_10_row_test" />
|
|
||||||
<item itemvalue="Cargo.Test chip8::video::test::scroll_down_1_row_test" />
|
|
||||||
</list>
|
</list>
|
||||||
</recent_temporary>
|
</recent_temporary>
|
||||||
</component>
|
</component>
|
||||||
@ -259,6 +263,7 @@
|
|||||||
<workItem from="1729375372050" duration="3579000" />
|
<workItem from="1729375372050" duration="3579000" />
|
||||||
<workItem from="1729797802231" duration="9220000" />
|
<workItem from="1729797802231" duration="9220000" />
|
||||||
<workItem from="1729992186995" duration="4226000" />
|
<workItem from="1729992186995" duration="4226000" />
|
||||||
|
<workItem from="1730115460078" duration="30915000" />
|
||||||
</task>
|
</task>
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
@ -268,17 +273,6 @@
|
|||||||
<component name="UnknownFeatures">
|
<component name="UnknownFeatures">
|
||||||
<option featureType="com.intellij.fileTypeFactory" implementationName="*.asc" />
|
<option featureType="com.intellij.fileTypeFactory" implementationName="*.asc" />
|
||||||
</component>
|
</component>
|
||||||
<component name="XDebuggerManager">
|
|
||||||
<breakpoint-manager>
|
|
||||||
<breakpoints>
|
|
||||||
<line-breakpoint enabled="true" type="com.jetbrains.cidr.execution.debugger.OCBreakpointType">
|
|
||||||
<url>file://$PROJECT_DIR$/emma/src/chip8/system_memory.rs</url>
|
|
||||||
<line>46</line>
|
|
||||||
<option name="timeStamp" value="2" />
|
|
||||||
</line-breakpoint>
|
|
||||||
</breakpoints>
|
|
||||||
</breakpoint-manager>
|
|
||||||
</component>
|
|
||||||
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
||||||
<SUITE FILE_PATH="coverage/trevors_chip8_toy$Test_video__test.info" NAME="Test video::test Coverage Results" MODIFIED="1728072993962" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="RsCoverageRunner" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" CONTEXT_FILE_PATH="$PROJECT_DIR$" />
|
<SUITE FILE_PATH="coverage/trevors_chip8_toy$Test_video__test.info" NAME="Test video::test Coverage Results" MODIFIED="1728072993962" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="RsCoverageRunner" COVERAGE_BY_TEST_ENABLED="false" COVERAGE_TRACING_ENABLED="false" CONTEXT_FILE_PATH="$PROJECT_DIR$" />
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
11
Cargo.lock
generated
11
Cargo.lock
generated
@ -743,6 +743,15 @@ dependencies = [
|
|||||||
"wayland-client 0.31.6",
|
"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]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.1.30"
|
version = "1.1.30"
|
||||||
@ -1785,6 +1794,7 @@ dependencies = [
|
|||||||
name = "gemmaegui"
|
name = "gemmaegui"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"catppuccin-egui",
|
||||||
"eframe",
|
"eframe",
|
||||||
"egui 0.29.1",
|
"egui 0.29.1",
|
||||||
"gemma",
|
"gemma",
|
||||||
@ -1795,6 +1805,7 @@ name = "gemmaimgui"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"clap",
|
||||||
"copypasta",
|
"copypasta",
|
||||||
"dimensioned",
|
"dimensioned",
|
||||||
"gemma",
|
"gemma",
|
||||||
|
|||||||
671
coverage/tarpaulin-report.html
Normal file
671
coverage/tarpaulin-report.html
Normal file
File diff suppressed because one or more lines are too long
@ -1,6 +1,7 @@
|
|||||||
use log::{debug};
|
use log::{debug};
|
||||||
use crate::chip8::delay_timer::DelayTimer;
|
use crate::chip8::delay_timer::DelayTimer;
|
||||||
use crate::chip8::keypad::Keypad;
|
use crate::chip8::keypad::Keypad;
|
||||||
|
use crate::chip8::quirk_modes::QuirkMode;
|
||||||
use crate::chip8::registers::Chip8Registers;
|
use crate::chip8::registers::Chip8Registers;
|
||||||
use crate::chip8::sound_timer::SoundTimer;
|
use crate::chip8::sound_timer::SoundTimer;
|
||||||
use crate::chip8::stack::Chip8Stack;
|
use crate::chip8::stack::Chip8Stack;
|
||||||
@ -19,7 +20,8 @@ pub struct Chip8Computer {
|
|||||||
pub video_memory: Chip8Video,
|
pub video_memory: Chip8Video,
|
||||||
pub state: Chip8CpuStates,
|
pub state: Chip8CpuStates,
|
||||||
pub keypad: Keypad,
|
pub keypad: Keypad,
|
||||||
pub stack: Chip8Stack
|
pub stack: Chip8Stack,
|
||||||
|
pub quirk_mode: QuirkMode
|
||||||
}
|
}
|
||||||
impl Default for Chip8Computer {
|
impl Default for Chip8Computer {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
@ -32,7 +34,8 @@ impl Default for Chip8Computer {
|
|||||||
delay_timer: DelayTimer::new(),
|
delay_timer: DelayTimer::new(),
|
||||||
state: Chip8CpuStates::default(),
|
state: Chip8CpuStates::default(),
|
||||||
keypad: Keypad::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.delay_timer.reset();
|
||||||
self.sound_timer.reset();
|
self.sound_timer.reset();
|
||||||
self.stack.reset();
|
self.stack.reset();
|
||||||
|
self.memory.reset();
|
||||||
|
self.quirk_mode = QuirkMode::Chip8;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump_keypad_to_string(&self) -> String {
|
pub fn dump_keypad_to_string(&self) -> String {
|
||||||
|
|||||||
@ -23,7 +23,7 @@ impl Default for Chip8ComputerManager {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Chip8ComputerManager {
|
Chip8ComputerManager {
|
||||||
core_should_run: false,
|
core_should_run: false,
|
||||||
one_step: true,
|
one_step: false,
|
||||||
core_cycle_timer: false,
|
core_cycle_timer: false,
|
||||||
core_last_cycle_start: Instant::now() ,
|
core_last_cycle_start: Instant::now() ,
|
||||||
computer: Chip8Computer::new()
|
computer: Chip8Computer::new()
|
||||||
@ -32,18 +32,16 @@ impl Default for Chip8ComputerManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Chip8ComputerManager {
|
impl Chip8ComputerManager {
|
||||||
|
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
|
self.one_step = false;
|
||||||
|
self.core_should_run = false;
|
||||||
self.computer.reset();
|
self.computer.reset();
|
||||||
}
|
}
|
||||||
pub fn new() -> Chip8ComputerManager {
|
pub fn new() -> Chip8ComputerManager {
|
||||||
let core_handle = thread::spawn(move || {
|
let core_handle = thread::spawn(move || {
|
||||||
loop {
|
loop {
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
// println!("Core Thread starting at {start_time:?}");
|
|
||||||
|
|
||||||
let sleep_time = Instant::now().duration_since(start_time).as_millis();
|
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));
|
sleep(Duration::from_millis((16 - sleep_time) as u64));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -67,13 +65,15 @@ impl Chip8ComputerManager {
|
|||||||
&self.computer
|
&self.computer
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick( &mut self) {
|
pub fn tick( &mut self) -> bool {
|
||||||
// println!("STARTING TICK");
|
// println!("STARTING TICK");
|
||||||
|
let mut did_tick: bool = false;
|
||||||
if self.one_step | self.core_should_run {
|
if self.one_step | self.core_should_run {
|
||||||
match self.computer.state {
|
match self.computer.state {
|
||||||
WaitingForInstruction => {
|
WaitingForInstruction => {
|
||||||
self.core_last_cycle_start = Instant::now();
|
self.core_last_cycle_start = Instant::now();
|
||||||
self.computer.step_system();
|
self.computer.step_system();
|
||||||
|
did_tick = true
|
||||||
// println!("SYSTEM STEP");
|
// println!("SYSTEM STEP");
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -84,7 +84,9 @@ impl Chip8ComputerManager {
|
|||||||
// stop the CPU for the next cycle, we are only
|
// stop the CPU for the next cycle, we are only
|
||||||
// wanting one step.
|
// wanting one step.
|
||||||
self.one_step = false;
|
self.one_step = false;
|
||||||
|
did_tick = true;
|
||||||
}
|
}
|
||||||
|
did_tick
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn press_key(&mut self, key_index: u8) {
|
pub fn press_key(&mut self, key_index: u8) {
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct DelayTimer {
|
pub struct DelayTimer {
|
||||||
counter: i32
|
counter: u8
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DelayTimer {
|
impl DelayTimer {
|
||||||
pub fn current(&self) -> i32 {
|
pub fn current(&self) -> u8 {
|
||||||
self.counter
|
self.counter
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,8 +18,8 @@ impl DelayTimer {
|
|||||||
self.counter = 0xff;
|
self.counter = 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_timer(&mut self, new_value: i32) {
|
pub fn set_timer(&mut self, new_value: u8) {
|
||||||
self.counter = new_value
|
self.counter = new_value as u8
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self) {
|
pub fn tick(&mut self) {
|
||||||
|
|||||||
@ -2,11 +2,12 @@ use std::arch::x86_64::_mm_xor_pd;
|
|||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
use std::ops::{BitAnd, Deref, Shr};
|
use std::ops::{BitAnd, Deref, Shr};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
use chrono::ParseMonthError;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use rand::{random, Rng};
|
use rand::{random, Rng};
|
||||||
use crate::chip8::computer::{Chip8Computer};
|
use crate::chip8::computer::{Chip8Computer};
|
||||||
use crate::chip8::cpu_states::Chip8CpuStates::WaitingForKey;
|
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::chip8::util::InstructionUtil;
|
||||||
use crate::constants::{*};
|
use crate::constants::{*};
|
||||||
|
|
||||||
@ -188,7 +189,7 @@ pub enum Chip8CpuInstructions {
|
|||||||
/// Set sound timer = Vx.
|
/// Set sound timer = Vx.
|
||||||
///
|
///
|
||||||
/// ST is set equal to the value of Vx.
|
/// ST is set equal to the value of Vx.
|
||||||
LDI_S(u8),
|
LDIS(u8),
|
||||||
/// Fx1E - ADD I, Vx
|
/// Fx1E - ADD I, Vx
|
||||||
/// Set I = I + Vx.
|
/// Set I = I + Vx.
|
||||||
///
|
///
|
||||||
@ -280,7 +281,7 @@ impl Chip8CpuInstructions {
|
|||||||
Chip8CpuInstructions::LDIA(_) => INST_LDIA,
|
Chip8CpuInstructions::LDIA(_) => INST_LDIA,
|
||||||
Chip8CpuInstructions::LDIX(_) => INST_LDIX,
|
Chip8CpuInstructions::LDIX(_) => INST_LDIX,
|
||||||
Chip8CpuInstructions::LIDR(_) => INST_LIDR,
|
Chip8CpuInstructions::LIDR(_) => INST_LIDR,
|
||||||
Chip8CpuInstructions::LDI_S(_) => INST_LIDS,
|
Chip8CpuInstructions::LDIS(_) => INST_LDIS,
|
||||||
Chip8CpuInstructions::LDR(_, _) => INST_LDR,
|
Chip8CpuInstructions::LDR(_, _) => INST_LDR,
|
||||||
Chip8CpuInstructions::LDRD(_) => INST_LDRD,
|
Chip8CpuInstructions::LDRD(_) => INST_LDRD,
|
||||||
Chip8CpuInstructions::LDRI(_) => INST_LDRI,
|
Chip8CpuInstructions::LDRI(_) => INST_LDRI,
|
||||||
@ -327,6 +328,7 @@ impl Chip8CpuInstructions {
|
|||||||
Chip8CpuInstructions::ADD(x, byte) => {
|
Chip8CpuInstructions::ADD(x, byte) => {
|
||||||
format!("0x{x:02x}, 0x{byte:02x}")
|
format!("0x{x:02x}, 0x{byte:02x}")
|
||||||
}
|
}
|
||||||
|
// Reg, Reg
|
||||||
Chip8CpuInstructions::SEY(x, y) |
|
Chip8CpuInstructions::SEY(x, y) |
|
||||||
Chip8CpuInstructions::LDR_Y(x, y) |
|
Chip8CpuInstructions::LDR_Y(x, y) |
|
||||||
Chip8CpuInstructions::OR(x, y) |
|
Chip8CpuInstructions::OR(x, y) |
|
||||||
@ -338,50 +340,162 @@ impl Chip8CpuInstructions {
|
|||||||
Chip8CpuInstructions::SUBC(x, y) |
|
Chip8CpuInstructions::SUBC(x, y) |
|
||||||
Chip8CpuInstructions::SHL(x, y) |
|
Chip8CpuInstructions::SHL(x, y) |
|
||||||
Chip8CpuInstructions::SNEY(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) => {
|
Chip8CpuInstructions::DRW(x, y, nibble) => {
|
||||||
format!("0x{x:02x}, 0x{y:02x}, 0x{nibble:02x}")
|
format!("0x{x:02x}, 0x{y:02x}, 0x{nibble:02x}")
|
||||||
}
|
}
|
||||||
|
// Registers. 0-F
|
||||||
Chip8CpuInstructions::LDD(x) |
|
Chip8CpuInstructions::LDD(x) |
|
||||||
Chip8CpuInstructions::LDI_S(x) |
|
Chip8CpuInstructions::LDIS(x) |
|
||||||
Chip8CpuInstructions::ADDI(x) |
|
Chip8CpuInstructions::ADDI(x) |
|
||||||
Chip8CpuInstructions::LDFX(x) |
|
Chip8CpuInstructions::LDFX(x) |
|
||||||
Chip8CpuInstructions::BCD(x) |
|
Chip8CpuInstructions::BCD(x) |
|
||||||
Chip8CpuInstructions::LDIX(x) |
|
Chip8CpuInstructions::LDIX(x) |
|
||||||
Chip8CpuInstructions::SKP(x) |
|
|
||||||
Chip8CpuInstructions::LDRD(x) |
|
Chip8CpuInstructions::LDRD(x) |
|
||||||
Chip8CpuInstructions::LDRK(x) |
|
Chip8CpuInstructions::LDRK(x) |
|
||||||
Chip8CpuInstructions::LDRI(x) |
|
Chip8CpuInstructions::LDRI(x) |
|
||||||
Chip8CpuInstructions::LDF2(x) |
|
Chip8CpuInstructions::LDF2(x) |
|
||||||
Chip8CpuInstructions::STR(x) |
|
Chip8CpuInstructions::STR(x) |
|
||||||
Chip8CpuInstructions::LIDR(x) |
|
Chip8CpuInstructions::LIDR(x) |
|
||||||
|
Chip8CpuInstructions::SDN(x) |
|
||||||
|
Chip8CpuInstructions::SKNP(x) |
|
||||||
Chip8CpuInstructions::SKP(x) => {
|
Chip8CpuInstructions::SKP(x) => {
|
||||||
format!("0x{x:02x}")
|
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 {
|
impl Display for Chip8CpuInstructions {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
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 {
|
impl Chip8CpuInstructions {
|
||||||
pub fn from_str(input: &str) -> Chip8CpuInstructions {
|
pub fn from_str(input: &str) -> Chip8CpuInstructions {
|
||||||
let parts = input.split(" ");
|
let mut parts = input.split(" ");
|
||||||
println!("THERE ARE {} PARTS", parts.count());
|
// print!("THERE ARE {} PARTS", parts.clone().count());
|
||||||
XXXXERRORINSTRUCTION
|
let first_part = parts.next().unwrap_or("");
|
||||||
//
|
// take the next value...
|
||||||
// match input.to_uppercase().as_str() {
|
// ...strip off the extra...
|
||||||
// INST_ADDI => Chip8CpuInstructions::ADDI(parts.nth(1)),
|
// ...convert it to an integer from base 16
|
||||||
// INST_ADD => Chip8CpuInstructions::ADD(parts[1], parts[2]),
|
let param1 = u16::from_str_radix(parts.next().unwrap_or("0").trim_start_matches("0x").trim_end_matches(","), 16).unwrap_or(0);
|
||||||
// INST_ADDR => Chip8CpuInstructions::ADDR(parts[1], parts[2]),
|
let param2 = u16::from_str_radix(parts.next().unwrap_or("0").trim_start_matches("0x").trim_end_matches(","), 16).unwrap_or(0);
|
||||||
// _ => XXXXERRORINSTRUCTION
|
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 {
|
pub fn encode(&self) -> u16 {
|
||||||
@ -417,7 +531,7 @@ impl Chip8CpuInstructions {
|
|||||||
Chip8CpuInstructions::LDRD(x_register) => 0xF007 | ((*x_register as u16) << 8),
|
Chip8CpuInstructions::LDRD(x_register) => 0xF007 | ((*x_register as u16) << 8),
|
||||||
Chip8CpuInstructions::LDRK(x_register) => 0xF00A | ((*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::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::ADDI(x_register) => 0xF01E | ((*x_register as u16) << 8),
|
||||||
Chip8CpuInstructions::LDFX(x_register) => 0xF029 | ((*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),
|
Chip8CpuInstructions::BCD(x_register) => 0xF033 | ((*x_register as u16) << 8),
|
||||||
@ -488,7 +602,7 @@ impl Chip8CpuInstructions {
|
|||||||
0x07 => Chip8CpuInstructions::LDRD(ubln),
|
0x07 => Chip8CpuInstructions::LDRD(ubln),
|
||||||
0x0A => Chip8CpuInstructions::LDRK(ubln),
|
0x0A => Chip8CpuInstructions::LDRK(ubln),
|
||||||
0x15 => Chip8CpuInstructions::LDD(ubln),
|
0x15 => Chip8CpuInstructions::LDD(ubln),
|
||||||
0x18 => Chip8CpuInstructions::LDI_S(ubln),
|
0x18 => Chip8CpuInstructions::LDIS(ubln),
|
||||||
0x1E => Chip8CpuInstructions::ADDI(ubln),
|
0x1E => Chip8CpuInstructions::ADDI(ubln),
|
||||||
0x29 => Chip8CpuInstructions::LDFX(ubln),
|
0x29 => Chip8CpuInstructions::LDFX(ubln),
|
||||||
0x30 => Chip8CpuInstructions::LDF2(ubln),
|
0x30 => Chip8CpuInstructions::LDF2(ubln),
|
||||||
@ -816,9 +930,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);
|
||||||
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);
|
let new_value = input.registers.peek(*new_time as u8);
|
||||||
input.sound_timer.set_timer(new_value as i32);
|
input.sound_timer.set_timer(new_value as i32);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,15 +11,17 @@ impl Keypad {
|
|||||||
// draw a 4x4 grid showing the keys with * filling the cells that are depressed
|
// draw a 4x4 grid showing the keys with * filling the cells that are depressed
|
||||||
for row in CHIP8_KEYBOARD.iter() {
|
for row in CHIP8_KEYBOARD.iter() {
|
||||||
for (index, key) in row.iter().enumerate() {
|
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() };
|
let is_lit = if self.keys[*key as usize] {
|
||||||
match index {
|
"*".to_string()
|
||||||
3 => {
|
} else {
|
||||||
// last in col
|
char::from_digit(*key as u32, 16).unwrap_or(' ').to_string()
|
||||||
return_value += format!("|{}|\n", is_lit).as_str();
|
};
|
||||||
}
|
|
||||||
_=> {
|
if index == 3 {
|
||||||
return_value += format!("|{}", is_lit).as_str();
|
return_value += format!("|{}|\n", is_lit).as_str();
|
||||||
}
|
|
||||||
|
} else {
|
||||||
|
return_value += format!("|{}", is_lit).as_str();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
gemma/src/chip8/quirk_modes.rs
Normal file
8
gemma/src/chip8/quirk_modes.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub enum QuirkMode {
|
||||||
|
#[default]
|
||||||
|
Chip8,
|
||||||
|
SChipLegacy,
|
||||||
|
XOChip,
|
||||||
|
SChipModern
|
||||||
|
}
|
||||||
@ -20,6 +20,12 @@ impl Default for Chip8SystemMemory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl 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 {
|
pub fn new() -> Self {
|
||||||
Chip8SystemMemory {
|
Chip8SystemMemory {
|
||||||
|
|||||||
@ -136,10 +136,9 @@ impl Chip8Video {
|
|||||||
(CHIP8_VIDEO_WIDTH, CHIP8_VIDEO_HEIGHT)
|
(CHIP8_VIDEO_WIDTH, CHIP8_VIDEO_HEIGHT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_memory_size(&self) -> i32 {
|
fn get_memory_size(&self) -> i32 {
|
||||||
let w = self.get_resolution();
|
let (width, height) = self.get_resolution();
|
||||||
w.1 * w.0
|
width * height
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self) {
|
pub fn tick(&mut self) {
|
||||||
|
|||||||
@ -36,7 +36,7 @@ pub const INST_LDF2: &str = "LDF2";
|
|||||||
pub const INST_LDIA: &str = "LDIA";
|
pub const INST_LDIA: &str = "LDIA";
|
||||||
pub const INST_LDIX: &str = "LDIX";
|
pub const INST_LDIX: &str = "LDIX";
|
||||||
pub const INST_LIDR: &str = "LIDR";
|
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_LDR: &str = "LDR";
|
||||||
pub const INST_LDRD: &str = "LDRD";
|
pub const INST_LDRD: &str = "LDRD";
|
||||||
pub const INST_LDRI: &str = "LDRI";
|
pub const INST_LDRI: &str = "LDRI";
|
||||||
|
|||||||
@ -11,8 +11,8 @@ pub mod chip8 {
|
|||||||
pub mod registers;
|
pub mod registers;
|
||||||
|
|
||||||
pub mod stack;
|
pub mod stack;
|
||||||
|
|
||||||
pub mod computer_manager;
|
pub mod computer_manager;
|
||||||
|
pub mod quirk_modes;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
@ -1,8 +1,10 @@
|
|||||||
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use rand::random;
|
use rand::random;
|
||||||
use gemma::chip8::computer::Chip8Computer;
|
use gemma::chip8::computer::Chip8Computer;
|
||||||
use gemma::chip8::delay_timer::DelayTimer;
|
use gemma::chip8::delay_timer::DelayTimer;
|
||||||
use gemma::chip8::instructions::Chip8CpuInstructions;
|
use gemma::chip8::instructions::Chip8CpuInstructions;
|
||||||
|
use gemma::chip8::instructions::Chip8CpuInstructions::JPA;
|
||||||
use gemma::chip8::keypad::Keypad;
|
use gemma::chip8::keypad::Keypad;
|
||||||
use gemma::chip8::registers::Chip8Registers;
|
use gemma::chip8::registers::Chip8Registers;
|
||||||
use gemma::chip8::sound_timer::SoundTimer;
|
use gemma::chip8::sound_timer::SoundTimer;
|
||||||
@ -11,7 +13,7 @@ use gemma::chip8::util::InstructionUtil;
|
|||||||
use gemma::chip8::video::Chip8Video;
|
use gemma::chip8::video::Chip8Video;
|
||||||
use gemma::constants::*;
|
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 {
|
fn read_test_result(suffix: &str) -> String {
|
||||||
std::fs::read_to_string(TEST_OUTPUT_SAMPLE_DIR.to_owned() + suffix)
|
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::LDRD(0x1).encode(), 0xf107);
|
||||||
assert_eq!(Chip8CpuInstructions::LDRK(0x4).encode(), 0xf40a);
|
assert_eq!(Chip8CpuInstructions::LDRK(0x4).encode(), 0xf40a);
|
||||||
assert_eq!(Chip8CpuInstructions::LDD(0x6).encode(), 0xf615);
|
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::ADDI(0xd).encode(), 0xfd1e);
|
||||||
assert_eq!(Chip8CpuInstructions::LDFX(0xc).encode(), 0xfc29);
|
assert_eq!(Chip8CpuInstructions::LDFX(0xc).encode(), 0xfc29);
|
||||||
assert_eq!(Chip8CpuInstructions::BCD(0xd).encode(), 0xfd33);
|
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(0xf107), Chip8CpuInstructions::LDRD(0x1)));
|
||||||
assert!(matches!(Chip8CpuInstructions::decode(0xf40a), Chip8CpuInstructions::LDRK(0x4)));
|
assert!(matches!(Chip8CpuInstructions::decode(0xf40a), Chip8CpuInstructions::LDRK(0x4)));
|
||||||
assert!(matches!(Chip8CpuInstructions::decode(0xf615), Chip8CpuInstructions::LDD(0x6)));
|
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(0xfd1e), Chip8CpuInstructions::ADDI(0xd)));
|
||||||
assert!(matches!(Chip8CpuInstructions::decode(0xfc29), Chip8CpuInstructions::LDFX(0xc)));
|
assert!(matches!(Chip8CpuInstructions::decode(0xfc29), Chip8CpuInstructions::LDFX(0xc)));
|
||||||
assert!(matches!(Chip8CpuInstructions::decode(0xfd33), Chip8CpuInstructions::BCD(0xd)));
|
assert!(matches!(Chip8CpuInstructions::decode(0xfd33), Chip8CpuInstructions::BCD(0xd)));
|
||||||
@ -334,7 +336,7 @@ fn addivx_test() {
|
|||||||
fn ldstvt_test() {
|
fn ldstvt_test() {
|
||||||
let mut x = Chip8Computer::new();
|
let mut x = Chip8Computer::new();
|
||||||
x.registers.poke(0x1, 0xf0);
|
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);
|
assert_eq!(x.sound_timer.current(), 0xf0);
|
||||||
x.sound_timer.tick();
|
x.sound_timer.tick();
|
||||||
x.sound_timer.tick();
|
x.sound_timer.tick();
|
||||||
@ -565,7 +567,6 @@ fn subn_vx_vy_test() {
|
|||||||
assert_eq!(x.registers.peek_pc(), 0x206);
|
assert_eq!(x.registers.peek_pc(), 0x206);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn draw_nibble_vx_vy_n_test_hd() {
|
fn draw_nibble_vx_vy_n_test_hd() {
|
||||||
let mut x = Chip8Computer::new();
|
let mut x = Chip8Computer::new();
|
||||||
|
|
||||||
@ -770,6 +771,15 @@ fn keypad_keys_check() {
|
|||||||
assert!(k.released(1));
|
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]
|
#[test]
|
||||||
fn register_rw_test() {
|
fn register_rw_test() {
|
||||||
let mut x = Chip8Registers::default();
|
let mut x = Chip8Registers::default();
|
||||||
@ -853,7 +863,7 @@ fn stack_push_pop_test() {
|
|||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn stack_overflow_test() {
|
fn stack_overflow_test() {
|
||||||
let mut x = Chip8Stack::new();
|
let mut x = Chip8Stack::new();
|
||||||
for i in 0..17 {
|
for i in 0..17 {
|
||||||
x.push(&i);
|
x.push(&i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -894,7 +904,6 @@ fn stack_lots_of_subs() {
|
|||||||
}
|
}
|
||||||
assert_eq!(x.depth(), 15);
|
assert_eq!(x.depth(), 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -945,7 +954,6 @@ fn instruction_byte_to_bool_changes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn real_build_checkboard(in_hd: bool) -> Chip8Video {
|
fn real_build_checkboard(in_hd: bool) -> Chip8Video {
|
||||||
let mut r = Chip8Video::default();
|
let mut r = Chip8Video::default();
|
||||||
let (width, height) = if in_hd {
|
let (width, height) = if in_hd {
|
||||||
@ -1318,3 +1326,320 @@ fn video_scroll_right_4_row_test_high_def() {
|
|||||||
x.scroll_right();
|
x.scroll_right();
|
||||||
assert_eq!(read_test_result("test_scroll_right_4_hd.asc"), x.format_as_string());
|
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();
|
||||||
|
}
|
||||||
@ -7,3 +7,4 @@ edition = "2021"
|
|||||||
gemma = { path = "../gemma" }
|
gemma = { path = "../gemma" }
|
||||||
egui.workspace = true
|
egui.workspace = true
|
||||||
eframe.workspace = true
|
eframe.workspace = true
|
||||||
|
catppuccin-egui = { version = "5.3.0", default-features = false, features = ["egui29"] }
|
||||||
|
|||||||
@ -58,8 +58,10 @@ fn main() -> eframe::Result {
|
|||||||
};
|
};
|
||||||
|
|
||||||
eframe::run_simple_native("EGUI Gemma", options, move |ctx, _frame| {
|
eframe::run_simple_native("EGUI Gemma", options, move |ctx, _frame| {
|
||||||
|
catppuccin_egui::set_theme(&ctx, catppuccin_egui::MOCHA);
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
computer.tick();
|
let frame_start_time = Instant::now();
|
||||||
|
|
||||||
let local_computer = computer.state();
|
let local_computer = computer.state();
|
||||||
//if state.display_video {
|
//if state.display_video {
|
||||||
GemmaEguiSupport::video_view(local_computer, ui);
|
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();
|
ctx.request_repaint();
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|||||||
@ -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<Chip8CpuInstructions>, 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);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@ -17,3 +17,4 @@ image = { version = "0.23" }
|
|||||||
imgui = { version = "0.12.0" }
|
imgui = { version = "0.12.0" }
|
||||||
winit = { version = "0.27", features = ["x11", "mint"]}
|
winit = { version = "0.27", features = ["x11", "mint"]}
|
||||||
copypasta = { version = "0.8" }
|
copypasta = { version = "0.8" }
|
||||||
|
clap = { version = "4.5.20", features = ["derive"] }
|
||||||
@ -12,6 +12,10 @@ use gemma::chip8::computer_manager::Chip8ComputerManager;
|
|||||||
use gemma::chip8::cpu_states::Chip8CpuStates::WaitingForInstruction;
|
use gemma::chip8::cpu_states::Chip8CpuStates::WaitingForInstruction;
|
||||||
use gemma::chip8::system_memory::Chip8SystemMemory;
|
use gemma::chip8::system_memory::Chip8SystemMemory;
|
||||||
use support::{emmagui_support::GemmaImguiSupport, ui_state::ImGuiUiState};
|
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;
|
mod support;
|
||||||
|
|
||||||
@ -28,8 +32,10 @@ const LIN_KEYS: [(u16, u8); 0x10] = [(537, 0x01),(538, 0x02),(539, 0x03),(540, 0
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
pretty_env_logger::init();
|
pretty_env_logger::init();
|
||||||
|
|
||||||
let mut system = Chip8ComputerManager::default();
|
let mut system = Chip8ComputerManager::default();
|
||||||
let mut ui_state = ImGuiUiState::default();
|
let mut ui_state = ImGuiUiState::default();
|
||||||
|
let target_ips = ui_state.target_ips;
|
||||||
|
|
||||||
support::simple_init(file!(), move |_, ui| {
|
support::simple_init(file!(), move |_, ui| {
|
||||||
let current_time = Instant::now();
|
let current_time = Instant::now();
|
||||||
@ -59,9 +65,16 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while Instant::now().duration_since(current_time).as_millis() < 16 && num_cycles < 1000 {
|
let target_ms = ui_state.frame_time;
|
||||||
system.tick();
|
let loop_start_time = Instant::now();
|
||||||
num_cycles += 1;
|
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
|
// GUI Parts
|
||||||
if ui_state.show_video {
|
if ui_state.show_video {
|
||||||
|
|||||||
@ -16,7 +16,7 @@ use crate::ImGuiUiState;
|
|||||||
use crate::support::gui_file_list::GuiFileList;
|
use crate::support::gui_file_list::GuiFileList;
|
||||||
use super::ui_state;
|
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 {}
|
pub struct GemmaImguiSupport {}
|
||||||
|
|
||||||
@ -25,37 +25,39 @@ const CELL_HEIGHT: i32 = 5i32;
|
|||||||
|
|
||||||
impl GemmaImguiSupport {
|
impl GemmaImguiSupport {
|
||||||
pub fn keypad_display(system_to_display: &Chip8Computer, ui: &Ui) {
|
pub fn keypad_display(system_to_display: &Chip8Computer, ui: &Ui) {
|
||||||
ui.text("Keypad");
|
ui.window(format!("Keypad"))
|
||||||
|
.size([100.0, 100.0], Condition::FirstUseEver)
|
||||||
for row in CHIP8_KEYBOARD {
|
.build(|| {
|
||||||
for key in row {
|
for row in CHIP8_KEYBOARD {
|
||||||
let label = if system_to_display.keypad.pressed(key) {
|
for key in row {
|
||||||
format!("*{:1x}*", key)
|
let label = if system_to_display.keypad.pressed(key) {
|
||||||
} else {
|
format!("*{:1x}*", key)
|
||||||
format!("{:1x}", key)
|
} else {
|
||||||
};
|
format!("{:1x}", key)
|
||||||
ui.text(format!("{}", label));
|
};
|
||||||
ui.same_line();
|
ui.text(format!("{}", label));
|
||||||
}
|
ui.same_line();
|
||||||
ui.text("");
|
}
|
||||||
}
|
ui.text("");
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn video_display(system_to_control: &Chip8Computer, gui_state: &ImGuiUiState, ui: &Ui) {
|
pub fn video_display(system_to_control: &Chip8Computer, gui_state: &ImGuiUiState, ui: &Ui) {
|
||||||
// draw area size
|
// draw area size
|
||||||
let (width, height) = system_to_control.video_memory.get_resolution();
|
let (width, height) = system_to_control.video_memory.get_resolution();
|
||||||
let draw_area_size = ui.io().display_size;
|
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_width = ((draw_area_size[0] as i32 / width) * 6) / 10;
|
||||||
let cell_height = ((draw_area_size[1] as i32 / height) * 6) / 10;
|
let cell_height = ((draw_area_size[1] as i32 / height) * 6) / 10;
|
||||||
|
|
||||||
ui.window(format!("Display {cell_width}x{cell_height}"))
|
ui.window(format!("Display {cell_width}x{cell_height}"))
|
||||||
.size([300.0, 300.0], Condition::Once)
|
.size([300.0, 300.0], Condition::Once)
|
||||||
.build(|| {
|
.build(|| {
|
||||||
let origin = ui.cursor_screen_pos();
|
let origin = ui.cursor_pos();
|
||||||
let fg = ui.get_window_draw_list();
|
let fg = ui.get_window_draw_list();
|
||||||
if (system_to_control.video_memory.is_highres()) {
|
if system_to_control.video_memory.is_highres() {
|
||||||
ui.text("High Def Video here");
|
// ui.text("High Def 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);
|
let y_offset = origin[1] as i32 + (current_row * cell_height);
|
||||||
for current_column in 0..=width {
|
for current_column in 0..=width {
|
||||||
@ -73,10 +75,9 @@ impl GemmaImguiSupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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);
|
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 x_offset = origin[0] as i32 + (current_column * cell_width);
|
||||||
let current_origin = [x_offset as f32, y_offset as f32];
|
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];
|
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) {
|
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 !!!!")
|
ui.window("!!!! CONTROLS !!!!")
|
||||||
.size([345.0, 200.0], Condition::FirstUseEver)
|
.size([345.0, 200.0], Condition::FirstUseEver)
|
||||||
.build(|| {
|
.build(|| {
|
||||||
@ -102,7 +103,7 @@ impl GemmaImguiSupport {
|
|||||||
ui.text(format!("Step {:04x}", system_to_control.num_cycles()).as_str());
|
ui.text(format!("Step {:04x}", system_to_control.num_cycles()).as_str());
|
||||||
|
|
||||||
/* ROM Lister */
|
/* 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.is_empty() {
|
||||||
if new_filename != gui_state.filename_to_load {
|
if new_filename != gui_state.filename_to_load {
|
||||||
debug!("NEW FILENAME SELECTED -> {new_filename}");
|
debug!("NEW FILENAME SELECTED -> {new_filename}");
|
||||||
@ -112,19 +113,21 @@ impl GemmaImguiSupport {
|
|||||||
let mut buffer = Vec::new();
|
let mut buffer = Vec::new();
|
||||||
debug!("PREPARING TO LOAD {}", gui_state.filename_to_load);
|
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("./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");
|
input_file.read_to_end(&mut buffer).expect("unable to read file");
|
||||||
system_to_control.load_bytes_to_system_memory((&*buffer).into());
|
system_to_control.load_bytes_to_system_memory((&*buffer).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ui.separator();
|
ui.separator();
|
||||||
if ui.button("Step") {
|
// if the system has no program loaded hide the buttons.
|
||||||
system_to_control.step();
|
if system_to_control.state().memory.peek(0x200) != 0x00 {
|
||||||
|
if ui.button("Step") {
|
||||||
};
|
system_to_control.step();
|
||||||
ui.same_line();
|
};
|
||||||
if ui.button("Run") {
|
ui.same_line();
|
||||||
system_to_control.start();
|
if ui.button("Run") {
|
||||||
|
system_to_control.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ui.same_line();
|
ui.same_line();
|
||||||
if ui.button("Stop") {
|
if ui.button("Stop") {
|
||||||
@ -183,55 +186,53 @@ impl GemmaImguiSupport {
|
|||||||
ui.window("System Memory")
|
ui.window("System Memory")
|
||||||
.size([400.0, 300.0], Condition::FirstUseEver)
|
.size([400.0, 300.0], Condition::FirstUseEver)
|
||||||
.build(|| {
|
.build(|| {
|
||||||
let mut current_x_hover: i32 = 0;
|
let mut current_x_hover: i32 = 0;
|
||||||
let mut current_y_hover: i32 = 0;
|
let mut current_y_hover: i32 = 0;
|
||||||
// display a block of data
|
// display a block of data
|
||||||
for current_row in 0..rows {
|
for current_row in 0..rows {
|
||||||
ui.text(format!("{:02x}", current_row * cols));
|
ui.text(format!("{:02x}", current_row * cols));
|
||||||
ui.same_line();
|
ui.same_line();
|
||||||
for current_column in 0..cols {
|
for current_column in 0..cols {
|
||||||
let data_offset = current_row * cols + current_column;
|
let data_offset = current_row * cols + current_column;
|
||||||
let formatted_text = format!("{:02x}", bytes.peek(data_offset as u16));
|
let formatted_text = format!("{:02x}", bytes.peek(data_offset as u16));
|
||||||
let text_location = ui.cursor_screen_pos();
|
let text_location = ui.cursor_screen_pos();
|
||||||
let text_size = ui.calc_text_size(formatted_text.clone());
|
let text_size = ui.calc_text_size(formatted_text.clone());
|
||||||
let bounding_box = imgui::sys::ImVec2 {
|
let bounding_box = imgui::sys::ImVec2 {
|
||||||
x: text_location[0] + text_size[0],
|
x: text_location[0] + text_size[0],
|
||||||
y: text_location[1] + text_size[1],
|
y: text_location[1] + text_size[1],
|
||||||
};
|
};
|
||||||
|
|
||||||
let hovering = ui.is_mouse_hovering_rect(text_location, [bounding_box.x, bounding_box.y]);
|
let hovering = ui.is_mouse_hovering_rect(text_location, [bounding_box.x, bounding_box.y]);
|
||||||
let is_active = data_offset == active as i32;
|
let is_active = data_offset == active as i32;
|
||||||
|
|
||||||
ui.text_colored(if hovering {
|
ui.text_colored(if hovering {
|
||||||
[0., 1., 1., 1.]
|
[0., 1., 1., 1.]
|
||||||
} else if is_active {
|
} else if is_active {
|
||||||
[1., 0., 1., 1.]
|
[1., 0., 1., 1.]
|
||||||
} else {
|
} else {
|
||||||
[1., 1., 0., 1.]
|
[1., 1., 0., 1.]
|
||||||
}, formatted_text.clone());
|
}, 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...
|
// Check if the left mouse button is clicked while hovering over the text
|
||||||
if hovering {
|
if ui.is_mouse_clicked(imgui::MouseButton::Left) {
|
||||||
// Optionally change the text color to indicate it's interactable
|
debug!("Offset: [{}] [0x{:02x}] Value: [{}]", data_offset, data_offset, formatted_text.clone());
|
||||||
current_x_hover = current_column;
|
// Perform any action here, e.g., call a function, trigger an event, etc.
|
||||||
current_y_hover = current_row;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the left mouse button is clicked while hovering over the text
|
// are we on the same line?
|
||||||
if ui.is_mouse_clicked(imgui::MouseButton::Left) {
|
if current_column != (cols - 1) {
|
||||||
debug!("Offset: [{}] [0x{:02x}] Value: [{}]", data_offset, data_offset, formatted_text.clone());
|
ui.same_line();
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
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));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -10,8 +10,9 @@ pub struct ImGuiUiState {
|
|||||||
pub on_colour: ImColor32,
|
pub on_colour: ImColor32,
|
||||||
pub off_colour: ImColor32,
|
pub off_colour: ImColor32,
|
||||||
pub is_running: bool,
|
pub is_running: bool,
|
||||||
pub frame_time: f32,
|
pub frame_time: u32,
|
||||||
pub last_frame_instant: Instant
|
pub last_frame_instant: Instant,
|
||||||
|
pub target_ips: i32
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for ImGuiUiState {
|
impl Clone for ImGuiUiState {
|
||||||
@ -26,7 +27,8 @@ impl Clone for ImGuiUiState {
|
|||||||
off_colour: self.off_colour,
|
off_colour: self.off_colour,
|
||||||
is_running: self.is_running,
|
is_running: self.is_running,
|
||||||
frame_time: self.frame_time,
|
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),
|
on_colour: ImColor32::from_rgb(0xff, 0xff, 0x00),
|
||||||
off_colour: ImColor32::from_rgb(0x00, 0xff, 0xff),
|
off_colour: ImColor32::from_rgb(0x00, 0xff, 0xff),
|
||||||
is_running: false,
|
is_running: false,
|
||||||
frame_time: 1.0,
|
frame_time: 16,
|
||||||
last_frame_instant: Instant::now()
|
last_frame_instant: Instant::now(),
|
||||||
|
target_ips: 20
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
resources/octoroms/caveexplorer.ch8
Normal file
BIN
resources/octoroms/caveexplorer.ch8
Normal file
Binary file not shown.
BIN
resources/roms/chipwar.ch8
Normal file
BIN
resources/roms/chipwar.ch8
Normal file
Binary file not shown.
BIN
resources/roms/deep8.ch8
Normal file
BIN
resources/roms/deep8.ch8
Normal file
Binary file not shown.
4
resources/test/gemma_keypad_string_result.asc
Normal file
4
resources/test/gemma_keypad_string_result.asc
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|1|2|3|c|
|
||||||
|
|4|5|6|d|
|
||||||
|
|7|8|9|e|
|
||||||
|
|a|0|b|f|
|
||||||
Loading…
x
Reference in New Issue
Block a user