diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..4644b2a
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/trevors_chip8_toy.iml b/.idea/trevors_chip8_toy.iml
new file mode 100644
index 0000000..be4ef30
--- /dev/null
+++ b/.idea/trevors_chip8_toy.iml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 5de9cc2..cbc123c 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -7,43 +7,32 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
@@ -61,95 +50,34 @@
-
+
- {
- "associatedIndex": 8
-}
-
+
+
- {
- "keyToString": {
- "Cargo.Build `Run gemmaimgui default roms`.executor": "Run",
- "Cargo.Build `Run gemmatelnetd`.executor": "Run",
- "Cargo.Build `Run tct`.executor": "Run",
- "Cargo.Build `Test byte_to_bools_valid`.executor": "Run",
- "Cargo.Build `Test join_bytes`.executor": "Run",
- "Cargo.Build `Test read_bits_from_instruction`.executor": "Run",
- "Cargo.Build `Test registers_equality`.executor": "Run",
- "Cargo.Build `Test round_trip`.executor": "Run",
- "Cargo.Build `Test start`.executor": "Run",
- "Cargo.Build `Test state_tests`.executor": "Run",
- "Cargo.Build `Test test_serialization_round_trip`.executor": "Run",
- "Cargo.Build `debug testcompression`.executor": "Run",
- "Cargo.Run ch8asm.executor": "Run",
- "Cargo.Run gemmaegui.executor": "Run",
- "Cargo.Run gemmaimgui default roms.executor": "Debug",
- "Cargo.Run gemmaimgui.executor": "Debug",
- "Cargo.Run gemmatelnetd.executor": "Debug",
- "Cargo.Run keyboard.executor": "Run",
- "Cargo.Run tct.executor": "Run",
- "Cargo.Run testcompression.executor": "Run",
- "Cargo.Test assmber_tests.executor": "Run",
- "Cargo.Test bools_to_byte.executor": "Debug",
- "Cargo.Test byte_to_bools_valid.executor": "Run",
- "Cargo.Test computer_001_system_zero_state.executor": "Run",
- "Cargo.Test computer_tests.executor": "Run",
- "Cargo.Test default_test.executor": "Run",
- "Cargo.Test join_bytes.executor": "Run",
- "Cargo.Test join_bytes_swap_endian.executor": "Run",
- "Cargo.Test load_rom_allows_starting.executor": "Run",
- "Cargo.Test quirks_mode_test.executor": "Run",
- "Cargo.Test read_address_from_instruction.executor": "Run",
- "Cargo.Test read_bits_from_instruction.executor": "Run",
- "Cargo.Test read_x_from_instruction.executor": "Run",
- "Cargo.Test read_y_from_instruction.executor": "Run",
- "Cargo.Test registers_equality.executor": "Run",
- "Cargo.Test reset_clears_run_state.executor": "Run",
- "Cargo.Test reset_clears_video.executor": "Run",
- "Cargo.Test round_trip.executor": "Run",
- "Cargo.Test smoke.executor": "Run",
- "Cargo.Test split_bytes.executor": "Run",
- "Cargo.Test split_bytes_swap_endian.executor": "Run",
- "Cargo.Test start.executor": "Run",
- "Cargo.Test state_tests.executor": "Run",
- "Cargo.Test status_of_manager.executor": "Run",
- "Cargo.Test swap_endian.executor": "Run",
- "Cargo.Test system_memory_load_program.executor": "Run",
- "Cargo.Test test_serialization_round_trip.executor": "Run",
- "Cargo.Test util_tests.executor": "Run",
- "Cargo.debug testcompression.executor": "Debug",
- "RunOnceActivity.ShowReadmeOnStart": "true",
- "RunOnceActivity.rust.reset.selective.auto.import": "true",
- "git-widget-placeholder": "add__telnet__interface",
- "last_opened_file_path": "/home/tmerritt/Projects/trevors_chip8_toy",
- "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": "",
- "settings.editor.selected.configurable": "inlay.hints"
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+}]]>
+
+
+
@@ -165,8 +93,8 @@
-
-
+
+
@@ -182,8 +110,8 @@
-
-
+
+
@@ -199,8 +127,8 @@
-
-
+
+
@@ -216,8 +144,8 @@
-
-
+
+
@@ -233,8 +161,8 @@
-
-
+
+
@@ -250,8 +178,8 @@
-
-
+
+
@@ -267,8 +195,8 @@
-
-
+
+
@@ -284,8 +212,8 @@
-
-
+
+
@@ -301,124 +229,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -428,93 +242,16 @@
-
- 1730734609486
+
+ 1748624969802
- 1730734609486
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ 1748624969802
+
-
-
- 1748539601919
-
-
-
- 1748539601919
-
-
-
- 1748539623332
-
-
-
- 1748539623332
-
-
-
- 1748539630427
-
-
-
- 1748539630427
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/gemma/src/chip8/computer.rs b/gemma/src/chip8/computer.rs
index 5b80282..2d2ba25 100644
--- a/gemma/src/chip8/computer.rs
+++ b/gemma/src/chip8/computer.rs
@@ -75,6 +75,10 @@ impl Chip8Computer {
self.clone().video_memory.format_as_string()
}
+ pub fn dump_state_to_json(&self) -> String {
+ serde_json::to_string(self).unwrap()
+ }
+
pub fn new() -> Self {
Chip8Computer::default()
}
diff --git a/gemma/src/chip8/instructions.rs b/gemma/src/chip8/instructions.rs
index 8dfeec8..97eb654 100644
--- a/gemma/src/chip8/instructions.rs
+++ b/gemma/src/chip8/instructions.rs
@@ -410,8 +410,10 @@ impl Display for Chip8CpuInstructions {
impl Chip8CpuInstructions {
pub fn from_str(input: &str) -> Chip8CpuInstructions {
+
+ // split the instruction into its parts...
let mut parts = input.split(" ");
- // print!("THERE ARE {} PARTS", parts.clone().count());
+
let first_part = parts.next().unwrap_or("").to_ascii_uppercase();
// take the next value...
// ...strip off the extra...
@@ -450,6 +452,7 @@ impl Chip8CpuInstructions {
"\tFirst part is {:?} / {:?} / {:?} / {:?}",
first_part, param1, param2, param3
);
+ println!("MATCHING [[{}]]", first_part);
match first_part.as_str() {
INST_ADDI => ADDI(param1 as u8),
INST_ADD => ADD(param1 as u8, param2 as u8),
diff --git a/gemma/src/chip8/keypad.rs b/gemma/src/chip8/keypad.rs
index 1a032a6..0661b38 100644
--- a/gemma/src/chip8/keypad.rs
+++ b/gemma/src/chip8/keypad.rs
@@ -26,7 +26,7 @@ impl Keypad {
}
}
}
-
+ println!("PREPARE TO RETURN {}", return_value);
return_value
}
}
diff --git a/gemma/src/chip8/util.rs b/gemma/src/chip8/util.rs
index 6779588..dc4abc3 100644
--- a/gemma/src/chip8/util.rs
+++ b/gemma/src/chip8/util.rs
@@ -119,3 +119,4 @@ impl InstructionUtil {
working & working_mask as u16
}
}
+
diff --git a/gemma/tests/computer_manager.rs b/gemma/tests/computer_manager.rs
new file mode 100644
index 0000000..f53e130
--- /dev/null
+++ b/gemma/tests/computer_manager.rs
@@ -0,0 +1,127 @@
+mod test_utils;
+use std::path::Path;
+use gemma::chip8::computer::Chip8Computer;
+use gemma::chip8::computer_manager::Chip8ComputerManager;
+use gemma::chip8::quirk_modes::QuirkMode;
+use gemma::chip8::quirk_modes::QuirkMode::{Chip8, SChipModern, XOChip};
+use gemma::constants::TEST_ROM_ROOT;
+use crate::test_utils::load_compressed_result;
+
+/// Tests the ComputerManager structure
+
+#[test]
+fn smoke() {
+ assert!(true)
+}
+
+
+#[test]
+fn default_test() {
+ let new_manager = Chip8ComputerManager::default();
+
+ assert_eq!(new_manager.core_should_run, false);
+ assert_eq!(new_manager.num_cycles(), 0);
+ assert_eq!(new_manager.quirks_mode(), Chip8);
+}
+
+#[test]
+fn quirks_mode_test() {
+ let mut new_manager = Chip8ComputerManager::default();
+
+ assert_eq!(new_manager.quirks_mode(), Chip8);
+
+ new_manager.reset(QuirkMode::XOChip);
+
+ assert_eq!(new_manager.quirks_mode(), XOChip);
+
+ new_manager.reset(QuirkMode::SChipModern);
+
+ assert_eq!(new_manager.quirks_mode(), SChipModern);
+
+ new_manager.reset(Chip8);
+
+ assert_eq!(new_manager.quirks_mode(), Chip8);
+}
+
+#[test]
+fn load_rom_allows_starting() {
+ let mut new_manager = Chip8ComputerManager::default();
+ assert!(!new_manager.core_should_run);
+ let p = TEST_ROM_ROOT.to_string() + "/1-chip8-logo.ch8";
+ let full_path = Path::new(p.as_str());
+ new_manager.load_new_program_from_disk_to_system_memory(full_path);
+ assert!(new_manager.core_should_run)
+}
+
+#[test]
+fn reset_clears_run_state() {
+ let mut new_manager = Chip8ComputerManager::default();
+ let p = format!(
+ "{}/../resources/test/roms/1-chip8-logo.ch8",
+ std::env::current_dir().unwrap().display()
+ );
+ new_manager.load_new_program_from_disk_to_system_memory(Path::new(p.as_str()));
+ new_manager.reset(QuirkMode::Chip8);
+ assert!(!new_manager.core_should_run);
+}
+
+#[test]
+fn tick_when_ready() {
+ let mut new_manager = Chip8ComputerManager::default();
+ new_manager.load_new_program_from_disk_to_system_memory(Path::new(
+ format!(
+ "{}/../resources/test/roms/1-chip8-logo.ch8",
+ std::env::current_dir().unwrap().display()
+ )
+ .as_str(),
+ ));
+ assert!(new_manager.core_should_run);
+}
+
+
+#[test]
+fn start_stop_computer() {
+ let mut computer = Chip8ComputerManager::new();
+
+ assert_eq!(computer.core_should_run, false);
+ computer.start();
+ assert_eq!(computer.core_should_run, true);
+ computer.step();
+ assert_eq!(computer.core_should_run, true);
+ computer.stop();
+ assert_eq!(computer.core_should_run, false);
+ computer.reset(Chip8);
+ assert_eq!(computer.core_should_run, false);
+}
+
+
+#[test]
+fn state_default_matches() {
+ let computer = Chip8Computer::default();
+ let mut manager = Chip8ComputerManager::default();
+ assert_eq!(computer, *manager.state());
+}
+
+#[test]
+fn keys_test_manager() {
+ let mut manager = Chip8ComputerManager::default();
+
+ for i in 0..16 {
+ assert_eq!(manager.is_key_pressed(i), false);
+ }
+
+ // press key 5
+ manager.press_key(5);
+ assert_eq!(manager.is_key_pressed(5), true);
+ manager.release_key(5);
+ assert_eq!(manager.is_key_pressed(5), false);
+}
+
+#[test]
+#[ignore]
+fn status_of_manager() {
+ let mut manager = Chip8ComputerManager::default();
+ println!("MANAGER STATUS [{}]", manager.status_as_string());
+ let expected_state = load_compressed_result("test_manager_status");
+ assert_eq!(expected_state, manager.status_as_string());
+}
diff --git a/gemma/tests/computer_tests.rs b/gemma/tests/computer_tests.rs
index affa132..7376932 100644
--- a/gemma/tests/computer_tests.rs
+++ b/gemma/tests/computer_tests.rs
@@ -13,6 +13,7 @@ use std::path::Path;
fn smoke() {
assert!(true)
}
+
#[test]
fn reset_clears_video() {
let mut x = Chip8Computer::new();
@@ -131,98 +132,14 @@ fn level4_test() {
);
}
-#[test]
-fn registers_equality() {
- let data_set: Vec<(Chip8Registers, Chip8Registers, bool)> = vec![
- (Chip8Registers::default(), Chip8Registers::default(), true),
- (
- Chip8Registers {
- registers: [
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00,
- ],
- i_register: 0,
- pc: 0,
- },
- Chip8Registers {
- registers: [
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00,
- ],
- i_register: 0,
- pc: 0,
- },
- false,
- ),
- ];
-
- for (first, second, matches) in data_set.iter() {
- assert_eq!(first == second, *matches)
- }
-}
#[test]
-fn default_test() {
- let new_manager = Chip8ComputerManager::default();
-
- assert_eq!(new_manager.core_should_run, false);
- assert_eq!(new_manager.num_cycles(), 0);
- assert_eq!(new_manager.quirks_mode(), Chip8);
+fn partial_eq_chip8computer() {
+ let x = Chip8Computer::new();
+ let y = Chip8Computer::new();
+ assert_eq!(x, y)
}
-#[test]
-fn quirks_mode_test() {
- let mut new_manager = Chip8ComputerManager::default();
-
- assert_eq!(new_manager.quirks_mode(), Chip8);
-
- new_manager.reset(QuirkMode::XOChip);
-
- assert_eq!(new_manager.quirks_mode(), XOChip);
-
- new_manager.reset(QuirkMode::SChipModern);
-
- assert_eq!(new_manager.quirks_mode(), SChipModern);
-
- new_manager.reset(Chip8);
-
- assert_eq!(new_manager.quirks_mode(), Chip8);
-}
-
-#[test]
-fn load_rom_allows_starting() {
- let mut new_manager = Chip8ComputerManager::default();
- assert!(!new_manager.core_should_run);
- let p = TEST_ROM_ROOT.to_string() + "/1-chip8-logo.ch8";
- let full_path = Path::new(p.as_str());
- new_manager.load_new_program_from_disk_to_system_memory(full_path);
- assert!(new_manager.core_should_run)
-}
-
-#[test]
-fn reset_clears_run_state() {
- let mut new_manager = Chip8ComputerManager::default();
- let p = format!(
- "{}/../resources/test/roms/1-chip8-logo.ch8",
- std::env::current_dir().unwrap().display()
- );
- new_manager.load_new_program_from_disk_to_system_memory(Path::new(p.as_str()));
- new_manager.reset(QuirkMode::Chip8);
- assert!(!new_manager.core_should_run);
-}
-
-#[test]
-fn tick_when_ready() {
- let mut new_manager = Chip8ComputerManager::default();
- new_manager.load_new_program_from_disk_to_system_memory(Path::new(
- format!(
- "{}/../resources/test/roms/1-chip8-logo.ch8",
- std::env::current_dir().unwrap().display()
- )
- .as_str(),
- ));
- assert!(new_manager.core_should_run);
-}
#[test]
fn tick_when_not_ready() {}
diff --git a/gemma/tests/delay_timer.rs b/gemma/tests/delay_timer.rs
new file mode 100644
index 0000000..0991fd2
--- /dev/null
+++ b/gemma/tests/delay_timer.rs
@@ -0,0 +1,27 @@
+use gemma::chip8::delay_timer::DelayTimer;
+
+#[test]
+fn delay_timer_default() {
+ let x = DelayTimer::default();
+ assert_eq!(x.current(), 0xff);
+}
+
+#[test]
+fn delay_timer_ticks_reduce_time() {
+ let mut st = DelayTimer::new();
+ st.set_timer(100);
+ st.tick();
+ st.tick();
+ st.tick();
+ assert_eq!(st.current(), 97);
+}
+
+#[test]
+fn delay_timer_out_of_ticks_works() {
+ let mut st = DelayTimer::new();
+ st.set_timer(0);
+ st.tick();
+ st.tick();
+ st.tick();
+ assert_eq!(st.current(), 0);
+}
diff --git a/gemma/tests/instructions.rs b/gemma/tests/instructions.rs
new file mode 100644
index 0000000..72fe2ae
--- /dev/null
+++ b/gemma/tests/instructions.rs
@@ -0,0 +1,619 @@
+mod test_utils;
+use log::debug;
+use gemma::chip8::computer::Chip8Computer;
+use gemma::chip8::instructions::Chip8CpuInstructions;
+use gemma::constants::{CHIP8FONT_2, CHIP8_VIDEO_MEMORY};
+use crate::test_utils::read_compressed_test_result;
+
+
+
+/// START OF THE EXECUTION TESTS
+#[test]
+fn instruction_tests() {
+ // 0x0nnn Exit to System Call
+ let mut x = Chip8Computer::new();
+ Chip8CpuInstructions::SYS(0).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0);
+
+ let mut x = Chip8Computer::new();
+ Chip8CpuInstructions::SYS(0xFA0).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0xFA0);
+
+ let mut x = Chip8Computer::new();
+ Chip8CpuInstructions::SYS(0x0AF).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0x0AF);
+
+ // 0x1nnn Jump to Address
+ let mut x = Chip8Computer::new();
+ Chip8CpuInstructions::JPA(0).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0);
+
+ let mut x = Chip8Computer::new();
+ Chip8CpuInstructions::JPA(0xABC).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0xABC);
+
+ // 0x6xkk Set Vx = kk
+ let mut x = Chip8Computer::new();
+ Chip8CpuInstructions::LDR(1, 0x12).execute(&mut x);
+ assert_eq!(x.registers.peek(1), 0x12);
+
+ let mut x = Chip8Computer::new();
+ Chip8CpuInstructions::LDR(2, 0x21).execute(&mut x);
+ assert_eq!(x.registers.peek(2), 0x21);
+
+ // 0x3xkk Skip next instruction if Vx = kk.
+ // The interpreter compares register Vx to kk,
+ // and if they are equal, increments the program counter by 2.
+
+ // test setup: Load value 0x84 into V1
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x1, 0x84);
+ Chip8CpuInstructions::SEX(1, 0x48).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0x202);
+
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x1, 0x84);
+ Chip8CpuInstructions::SEX(1, 0x84).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0x204);
+
+ // 0x4xkk Skip next instruction if Vx != kk
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x01, 0x84);
+ x.registers.poke(0x2, 0x84);
+ // skip, compare 0x84 to 0x84
+ Chip8CpuInstructions::SEY(0x1, 0x2).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0x204);
+
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x01, 0x84);
+ x.registers.poke(0x2, 0x48);
+ Chip8CpuInstructions::SEY(0x01, 0x02).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0x202);
+
+ // 0x8xy0 Set value of Vy in Vx
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x01, 0x01);
+ x.registers.poke(0x02, 0x02);
+ Chip8CpuInstructions::LDRY(0x01, 0x02).execute(&mut x);
+ assert_eq!(x.registers.peek(1), 0x02);
+
+ // 0x8xy1 Set Vx = Vx OR Vy
+ // 0b0101 0000 (0x50)
+ // | 0b0000 1010 (0x0A)
+ // 0b0101 1010 (0x5A)
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x01, 0b01010000);
+ x.registers.poke(0x02, 0b00001010);
+ Chip8CpuInstructions::OR(1, 2).execute(&mut x);
+ assert_eq!(x.registers.peek(1), 0b01011010);
+
+ // 0x8xy2 Set Vx = Vx AND Vy
+ // 0b1111 1100 (0xFC)
+ // & 0b1100 1010 (0xCA)
+ // 0b1100 1000 (0xC8)
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x01, 0xFC);
+ x.registers.poke(0x02, 0xCA);
+ Chip8CpuInstructions::AND(1, 2).execute(&mut x);
+ assert_eq!(x.registers.peek(1), 0xC8);
+
+ // 0x8xy3 Set Vx = Vx XOR Vy
+ // 0b1111 1100 (0xFC)
+ // ^ 0b1100 1010 (0xCA)
+ // 0b0011 0110 (0x36)
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x01, 0b11111100);
+ x.registers.poke(0x02, 0b11001010);
+ Chip8CpuInstructions::ORY(1, 2).execute(&mut x);
+ assert_eq!(x.registers.peek(1), 0b00110110);
+
+ // 0x8xy4 Set Vx = Vx + Vy (SET VF on Carry)
+ // T1 T2: Judgement Test
+ // 0x01 0xFF
+ // + 0x01 0x01
+ // 0x02 F0 0x00 F1
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x0f, 00);
+ x.registers.poke(0x01, 0x01);
+ x.registers.poke(0x02, 0x01);
+ Chip8CpuInstructions::ADDR(0x01, 0x02).execute(&mut x);
+ assert_eq!(x.registers.peek(0xf), 0x00);
+ assert_eq!(x.registers.peek(0x01), 0x02);
+
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x0f, 0x00);
+ x.registers.poke(0x01, 0xff);
+ x.registers.poke(0x02, 0x01);
+ Chip8CpuInstructions::ADDR(1, 2).execute(&mut x);
+ assert_eq!(x.registers.peek(0xf), 1);
+ assert_eq!(x.registers.peek(1), 0);
+
+ /*
+ Set Vx = Vx SHR 1.
+
+ If the least-significant bit of Vx is 1, then VF is set to 1, otherwise 0. Then Vx is divided by 2.
+ */
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x0f, 0x00);
+ x.registers.poke(0x01, 0b00001000);
+ x.registers.poke(0x02, 0b00000000);
+ Chip8CpuInstructions::SHR(0x1, 0x2).execute(&mut x); // 0b0000 0010 (0x02) (Not Set)
+ assert_eq!(x.registers.peek(1), 0b00000100);
+ assert_eq!(x.registers.peek(0xf), 0);
+
+ x = Chip8Computer::new();
+ x.registers.poke(0x0f, 0x00);
+ x.registers.poke(0x01, 0b00001001);
+ Chip8CpuInstructions::SHR(0x1, 0x2).execute(&mut x);
+ assert_eq!(x.registers.peek(1), 0b00000100);
+ assert_eq!(x.registers.peek(0xf), 1);
+
+ let mut x = Chip8Computer::new();
+ Chip8CpuInstructions::LDIA(0x123).execute(&mut x);
+ assert_eq!(x.registers.peek_i(), 0x123);
+ assert_eq!(x.registers.peek_pc(), 0x202);
+}
+
+#[test]
+fn jp_v0addr_test() {
+ let mut x = Chip8Computer::new();
+ /// jump to I + nnn
+ x.registers.poke(0x0, 0xff);
+ Chip8CpuInstructions::JPI(0x100).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0x1FF);
+}
+
+#[test]
+fn cls_test() {
+ let mut x = Chip8Computer::new();
+ Chip8CpuInstructions::CLS.execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0x202);
+ for i in 0..CHIP8_VIDEO_MEMORY {
+ assert!(!x.video_memory.peek(i as u16));
+ }
+ // draw some thing to the video memory
+ x.video_memory.poke(0x01, true);
+ x.video_memory.poke(0x03, true);
+ x.video_memory.poke(0x05, true);
+
+ Chip8CpuInstructions::CLS.execute(&mut x);
+
+ for i in 0..CHIP8_VIDEO_MEMORY {
+ assert!(!x.video_memory.peek(i as u16));
+ }
+}
+
+#[test]
+fn skip_next_instruction_ne_text() {
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x1, 0xf0);
+ Chip8CpuInstructions::SNEB(0x1, 0x0f).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0x204);
+
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x1, 0xf0);
+ Chip8CpuInstructions::SNEB(0x1, 0xf0).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0x202);
+}
+
+#[test]
+fn addivx_test() {
+ let mut x = Chip8Computer::new();
+ x.registers.poke_i(0xabc);
+ x.registers.poke(0x0, 0x10);
+ Chip8CpuInstructions::ADDI(0x0).execute(&mut x);
+ assert_eq!(x.registers.peek_i(), 0xacc);
+}
+
+#[test]
+fn ldstvt_test() {
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x1, 0xf0);
+ Chip8CpuInstructions::LDIS(0x01).execute(&mut x);
+ assert_eq!(x.sound_timer.current(), 0xf0);
+ x.sound_timer.tick();
+ x.sound_timer.tick();
+ x.sound_timer.tick();
+ assert_eq!(x.sound_timer.current(), 0xed);
+}
+
+#[test]
+fn rnd_vx_byte_text() {
+ let mut x = Chip8Computer::new();
+ Chip8CpuInstructions::RND(0x1, 0x0f).execute(&mut x);
+ let new_value = x.registers.peek(0x1);
+ assert!(new_value < 0x10);
+}
+
+#[test]
+fn add_vx_byte_test() {
+ let mut x = Chip8Computer::new();
+ // set a value in the register
+ x.registers.poke(0x01, 0xab);
+ // add 0x10 to register
+ Chip8CpuInstructions::ADD(0x1, 0x10).execute(&mut x);
+ assert_eq!(x.registers.peek(1), 0xbb);
+}
+
+#[test]
+fn sub_vx_vy_test() {
+ let mut x = Chip8Computer::new();
+ // load values in 2 registers
+ x.registers.poke(0x1, 0x10);
+ x.registers.poke(0x2, 0x08);
+ Chip8CpuInstructions::SUB(0x1, 0x02).execute(&mut x);
+ assert_eq!(x.registers.peek(0xf), 1);
+ assert_eq!(x.registers.peek(0x1), 0x8);
+ assert_eq!(x.registers.peek_pc(), 0x202);
+}
+
+#[test]
+fn sne_vx_vy_test() {
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x1, 0x10);
+ x.registers.poke(0x2, 0x10);
+ Chip8CpuInstructions::SNEY(0x1, 0x2).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0x202);
+
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x1, 0x10);
+ x.registers.poke(0x2, 0x00);
+ Chip8CpuInstructions::SNEY(0x01, 0x02).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0x204)
+}
+
+#[test]
+fn ld_dt_vx_test() {
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x1, 0x10);
+ Chip8CpuInstructions::LDD(0x1).execute(&mut x);
+ assert_eq!(x.delay_timer.current(), 0x10);
+ for _ in 0..0x20 {
+ x.delay_timer.tick();
+ }
+ assert_eq!(x.delay_timer.current(), 0);
+}
+
+
+#[test]
+fn ld_vx_dt_test() {
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x1, 0xf0);
+ Chip8CpuInstructions::LDD(0x1).execute(&mut x);
+ x.delay_timer.tick();
+ x.delay_timer.tick();
+ x.delay_timer.tick();
+ assert_eq!(x.delay_timer.current(), 0xed);
+}
+
+#[test]
+fn subn_vx_vy_test() {
+ // This instruction subtracts the value in
+ // register Vx from the value in register Vy and stores the result in register Vx.
+ // The subtraction is performed as follows: Vx = Vy - Vx. If Vy is less than Vx,
+ // the result will wrap around (due to the 8-bit nature of the registers).
+ // The carry flag (VF) is set to 1 if there is no borrow (i.e., Vy is greater
+ // than or equal to Vx), and it is set to 0 if there is a borrow.
+
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x1, 0xa0);
+ x.registers.poke(0x2, 0xab);
+ Chip8CpuInstructions::SUBC(0x1, 0x2).execute(&mut x);
+ // expect the result to be 0x0b
+ assert_eq!(x.registers.peek(0x1), 0x0b);
+ // expect the vf register to be set to 1 as there was overflow
+ assert_eq!(x.registers.peek(0xf), 0x1);
+
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x01, 0xab);
+ x.registers.poke(0x02, 0xa0);
+ Chip8CpuInstructions::SUBC(0x1, 0x2).execute(&mut x);
+
+ // expect the result to be 11110101, -0xB, -11, 245, 0xF5
+ assert_eq!(x.registers.peek(0x1), 0xf5);
+ assert_eq!(x.registers.peek(0xf), 0x0);
+
+ // 8xyE - SHL Vx {, Vy}
+ // Set Vx = Vx SHL 1.
+ //
+ // If the most-significant bit of Vx is 1, then VF is set to 1, otherwise to 0. Then Vx is multiplied by 2.
+
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x1, 0b00100000);
+ Chip8CpuInstructions::SHL(0x1, 0x1).execute(&mut x);
+ assert_eq!(x.registers.peek(0x1), 0b01000000);
+ assert_eq!(x.registers.peek(0xf), 0x0);
+
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x1, 0b10101010);
+ Chip8CpuInstructions::SHL(0x1, 0x1).execute(&mut x);
+ assert_eq!(x.registers.peek(0x1), 0b01010100);
+ assert_eq!(x.registers.peek(0xf), 0x1);
+
+ // Fx29 - LD F, Vx
+ // Set I = location of sprite for digit Vx.
+ //
+ // The value of I is set to the location for the hexadecimal sprite corresponding to the value of Vx. See section 2.4, Display, for more information on the Chip-8 hexadecimal font.
+ let mut x = Chip8Computer::new();
+ // target_sprite = 2
+ // target_offset = 0x5
+ x.registers.poke(0x1, 0x2);
+ Chip8CpuInstructions::LDFX(0x1).execute(&mut x);
+
+ assert_eq!(x.registers.peek_i(), 10);
+
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x01, 0x06);
+ Chip8CpuInstructions::LDFX(0x1).execute(&mut x);
+ assert_eq!(x.registers.peek_i(), 30);
+
+ // Fx33 - LD B, Vx
+ // Store BCD representation of Vx in memory locations I, I+1, and I+2.
+ //
+ // The interpreter takes the decimal value of Vx, and places the hundreds digit
+ // in memory at location in I, the tens digit at location I+1,
+ // and the ones digit at location I+2.
+ let mut x = Chip8Computer::new();
+
+ // load the value 123 (0x7b)
+ x.registers.poke(0x1, 0x7b);
+ x.registers.poke_i(0x500);
+ Chip8CpuInstructions::BCD(0x1).execute(&mut x);
+ assert_eq!(x.memory.peek(0x500), 0x1);
+ assert_eq!(x.memory.peek(0x501), 0x2);
+ assert_eq!(x.memory.peek(0x502), 0x3);
+
+ // Store registers V0 through Vx in memory starting at location I.
+ //
+ // The interpreter copies the values of registers V0 through Vx into memory,
+ // starting at the address in I.
+ let mut x = Chip8Computer::new();
+
+ // Load Registers.
+ let to_load = [0xab, 0xba, 0xca, 0xca, 0xbe, 0xef];
+ for (idx, val) in to_load.iter().enumerate() {
+ x.registers.poke(idx as u8, *val);
+ }
+ x.registers.poke_i(0x500);
+
+ Chip8CpuInstructions::LDIX(to_load.len() as u8).execute(&mut x);
+
+ // Verify the values are in memory from 0x500 to 0x507
+ for (idx, value) in to_load.iter().enumerate() {
+ assert_eq!(x.memory.peek(0x500 + idx as u16), *value);
+ }
+
+ // Read registers V0 through Vx from memory starting at location I.
+ //
+ // The interpreter reads values from memory starting at location I into registers V0 through Vx.
+
+ let mut x = Chip8Computer::new();
+
+ let base_offset = 0x500;
+ let to_load = [0xab, 0xba, 0xca, 0xca, 0xbe, 0xef];
+
+ // start by setting values in memory
+ for (idx, memory) in to_load.iter().enumerate() {
+ let target_address = base_offset + idx;
+ let target_value = *memory;
+ x.memory.poke(target_address as u16, target_value);
+ }
+ // where to load from
+ x.registers.poke_i(0x500);
+ // how much to load
+ x.registers.poke(0x6, to_load.len() as u8);
+
+ // then copying them values memory to registers
+ Chip8CpuInstructions::LDRI(0x6).execute(&mut x);
+
+ // now check that we have the right values in our registers
+ for (idx, value) in to_load.iter().enumerate() {
+ assert_eq!(x.registers.peek(idx as u8), *value);
+ }
+
+ // ExA1 - SKNP Vx
+ // Skip next instruction if key with the value of Vx is not pressed.
+ //
+ // Checks the keyboard,
+ // and if the key corresponding to the value of Vx is currently in the up position,
+ // PC is increased by 2.
+ let mut x = Chip8Computer::new();
+ x.keypad.push_key(0x5);
+ x.registers.poke(0x1, 0x5);
+ Chip8CpuInstructions::SKNP(0x1).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0x202);
+ x.keypad.release_key(0x5);
+ Chip8CpuInstructions::SKNP(0x1).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0x206);
+
+ // Ex9E - SKP Vx
+ // Skip next instruction if key with the value of Vx is pressed.
+ //
+ // Checks the keyboard, and if the key corresponding to the value of Vx is currently in the down position, PC is increased by 2.
+ let mut x = Chip8Computer::new();
+ x.keypad.push_key(0x5);
+ x.registers.poke(0x1, 0x5);
+ Chip8CpuInstructions::SKP(0x1).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0x204);
+
+ x.keypad.release_key(0x5);
+ Chip8CpuInstructions::SKP(0x1).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0x206);
+}
+
+#[test]
+#[ignore]
+fn draw_nibble_vx_vy_n_test_hd() {
+ let mut x = Chip8Computer::new();
+
+ let x_register = 0x01;
+ let x_offset = 0x03;
+ let y_register = 0x02;
+ let y_offset = 0x04;
+ let char_offset = 0x100;
+ x.registers.poke(x_register, x_offset);
+ x.registers.poke(y_register, y_offset);
+ x.video_memory.set_highres();
+ x.registers.poke_i(char_offset);
+ Chip8CpuInstructions::DRW(x_register, y_register, 0).execute(&mut x);
+
+ println!("[[{}]]", x.video_memory.format_as_string());
+
+ assert_eq!(read_compressed_test_result(""), x.video_memory.format_as_string());
+}
+
+#[test]
+fn draw_nibble_vx_vy_n_test_sd() {
+ let mut x = Chip8Computer::new();
+ let x_register = 0x1;
+ let y_register = 0x2;
+ let x_offset = 1;
+ let y_offset = 2;
+ let char_offset = 0x0A;
+
+ // now lets set the X and Y to 1,2
+ x.registers.poke(x_register, x_offset);
+ x.registers.poke(y_register, y_offset);
+ x.registers.poke_i(char_offset);
+ // we are using 5 rows.
+ Chip8CpuInstructions::DRW(x_register, y_register, 5).execute(&mut x);
+
+ // now check that video memory has the values at
+ // 1,2->1,9
+ // 2,2->2,9
+ // 3,2->3,9
+ // 4,2->4,9
+ // 5,2->5,9
+ // let byte_to_check = CHIP8FONT_0[0];
+ for row_in_sprite in 0..5 {
+ let row_data = CHIP8FONT_2[row_in_sprite];
+ for bit_in_byte in 0..8 {
+ let data_offset =
+ (x_offset as u16 + row_in_sprite as u16) * 64 + (bit_in_byte + y_offset) as u16;
+ let real_bit_in_byte = 7 - bit_in_byte;
+ let shifted_one = 0x01 << real_bit_in_byte;
+ let one_shift_set = (shifted_one & row_data) > 0;
+ debug!("ROWDATA = \t\t[{row_data:08b}]\tBIT IN BYTE = \t[{bit_in_byte}]\tONE_SHIFT_SET = [{one_shift_set}]\tSHIFTED ONE = [{shifted_one:08b}]");
+ debug!("DATA_OFFSET FOR SOURCE DATA {}x{} is {} / offset by {}x{} and should be {} working with byte {:08b}",
+ bit_in_byte, row_in_sprite, data_offset, x_offset, y_offset, one_shift_set, row_data);
+ }
+ }
+}
+
+#[test]
+fn sub_test() {
+ // 2nnn
+ // Call a subroutine at 2nnn
+ let mut x = Chip8Computer::new();
+ Chip8CpuInstructions::CALL(0x124).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0x124);
+ assert_eq!(x.stack.depth(), 1);
+ Chip8CpuInstructions::CALL(0x564).execute(&mut x);
+ assert_eq!(x.registers.peek_pc(), 0x564);
+ assert_eq!(x.stack.depth(), 2);
+
+ // SETUP
+ // Return from a subroutine.
+ let mut x = Chip8Computer::new();
+ x.stack.push(&0x132);
+ x.stack.push(&0xabc);
+ // EXECUTE
+ Chip8CpuInstructions::RET.execute(&mut x);
+ // VERIFY
+ assert_eq!(x.registers.peek_pc(), 0xabc);
+ assert_eq!(x.stack.depth(), 1);
+ // EXECUTE
+ Chip8CpuInstructions::RET.execute(&mut x);
+ // VERIFY
+ assert_eq!(x.registers.peek_pc(), 0x132);
+ assert_eq!(x.stack.depth(), 0);
+}
+
+#[test]
+fn ldvxk_test() {
+ // SETUP
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x01, 0x01);
+ Chip8CpuInstructions::LDRK(0x1).execute(&mut x);
+ assert!(matches!(
+ x.state,
+ gemma::chip8::cpu_states::Chip8CpuStates::WaitingForKey
+ ));
+}
+
+#[test]
+fn series8xy4_corex_tests() {
+ /// 8xy4
+ /// Set Vx = Vx + Vy
+ /// Set VF=1 if Carry
+ ///
+ // 1 + 1
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x01, 0x01);
+ x.registers.poke(0x02, 0x01);
+ Chip8CpuInstructions::ADDR(0x01, 0x02).execute(&mut x);
+ assert_eq!(x.registers.peek(0x01), 0x02);
+ assert_eq!(x.registers.peek(0x0f), 0x00);
+
+ // 255+1
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x01, 0xff);
+ x.registers.poke(0x02, 0x01);
+ Chip8CpuInstructions::ADDR(0x01, 0x02).execute(&mut x);
+ assert_eq!(x.registers.peek(0x01), 0x00);
+ assert_eq!(x.registers.peek(0x0f), 0x01);
+
+ // 128+192
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x01, 128);
+ x.registers.poke(0x02, 192);
+ Chip8CpuInstructions::ADDR(0x01, 0x02).execute(&mut x);
+ assert_eq!(x.registers.peek(0x01), 64);
+ assert_eq!(x.registers.peek(0x0f), 1);
+
+ // 8xy6 - SHR Vx {, Vy}
+ // Set Vx = Vx SHR 1.
+ //
+ // If the least-significant bit of Vx is 1, then VF is set to 1,
+ // otherwise 0. Then Vx is divided by 2.
+ let mut x = Chip8Computer::new();
+ // 0b10101010 -> 0b01010101
+ x.registers.poke(0x01, 0b10101010);
+ x.registers.poke(0x0f, 0x0);
+
+ Chip8CpuInstructions::SHL(0x01, 0x00).execute(&mut x);
+ assert_eq!(x.registers.peek(0x01), 0b01010100);
+ assert_eq!(x.registers.peek(0x0f), 1);
+
+ Chip8CpuInstructions::SHL(0x01, 0x00).execute(&mut x);
+ assert_eq!(x.registers.peek(0x01), 0b10101000);
+ assert_eq!(x.registers.peek(0x0f), 0x00);
+
+ Chip8CpuInstructions::SHL(0x01, 0x00).execute(&mut x);
+ assert_eq!(x.registers.peek(0x01), 0b01010000);
+ assert_eq!(x.registers.peek(0x0f), 0x01);
+
+ Chip8CpuInstructions::SHL(0x01, 0x00).execute(&mut x);
+ assert_eq!(x.registers.peek(0x01), 0b10100000);
+ assert_eq!(x.registers.peek(0x0f), 0x00);
+
+ Chip8CpuInstructions::SHL(0x01, 0x00).execute(&mut x);
+ assert_eq!(x.registers.peek(0x01), 0b01000000);
+ assert_eq!(x.registers.peek(0x0f), 0x01);
+}
+
+#[test]
+fn random_produces_different_numbers() {
+ let mut x = Chip8Computer::new();
+ x.registers.poke(0x01, 0x00);
+ let first_number = Chip8CpuInstructions::RND(0x01, 0xff)
+ .execute(&mut x)
+ .registers
+ .peek(0x01);
+ let second_number = Chip8CpuInstructions::RND(0x01, 0xff)
+ .execute(&mut x)
+ .registers
+ .peek(0x01);
+ assert_ne!(first_number, second_number);
+}
+
diff --git a/gemma/tests/keypad.rs b/gemma/tests/keypad.rs
new file mode 100644
index 0000000..a3a2f59
--- /dev/null
+++ b/gemma/tests/keypad.rs
@@ -0,0 +1,36 @@
+mod test_utils;
+use gemma::chip8::keypad::Keypad;
+use crate::test_utils::read_compressed_test_result;
+
+#[test]
+fn keypad_keys_check() {
+ let mut k = Keypad::new();
+
+ for i in 0..16 {
+ assert!(!k.key_state(i));
+ }
+
+ // press a key
+ k.push_key(1);
+ k.push_key(2);
+ assert!(k.pressed(1));
+ assert!(k.pressed(2));
+ k.release_key(1);
+ assert!(k.released(1));
+}
+
+#[test]
+fn keypad_string_format_test() {
+ let k = Keypad::new();
+
+ let expected_result = read_compressed_test_result("gemma_keypad_string_result");
+ let actual_result = k.format_as_string();
+
+
+ println!("EXPECTING [{}]", expected_result);
+ println!("GOT [{}]", actual_result);
+ assert_eq!(
+ k.format_as_string(),
+ read_compressed_test_result("gemma_keypad_string_result")
+ );
+}
diff --git a/gemma/tests/registers.rs b/gemma/tests/registers.rs
new file mode 100644
index 0000000..f8264db
--- /dev/null
+++ b/gemma/tests/registers.rs
@@ -0,0 +1,68 @@
+use rand::random;
+use gemma::chip8::registers::Chip8Registers;
+
+#[test]
+fn register_rw_test() {
+ let mut x = Chip8Registers::default();
+ x.poke(0x0, 0xff);
+ x.poke(0x1, 0xab);
+ assert_eq!(x.peek(0x0), 0xff);
+ assert_eq!(x.peek(0x1), 0xab);
+}
+
+#[test]
+fn pc_test() {
+ let mut x = Chip8Registers::default();
+ x.set_pc(0x300);
+ assert_eq!(x.peek_pc(), 0x300);
+}
+
+#[test]
+#[should_panic]
+fn invalid_register() {
+ let mut x = Chip8Registers::default();
+ x.poke(0x10, 0xff);
+}
+
+#[test]
+fn reset_clears_registers() {
+ let mut x = Chip8Registers::default();
+
+ for register in 0..0x10 {
+ x.poke(register, random::());
+ }
+ x.reset();
+ for register in 0..0x10 {
+ assert_eq!(x.peek(register), 0x00);
+ }
+}
+
+#[test]
+fn registers_equality() {
+ let data_set: Vec<(Chip8Registers, Chip8Registers, bool)> = vec![
+ (Chip8Registers::default(), Chip8Registers::default(), true),
+ (
+ Chip8Registers {
+ registers: [
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00,
+ ],
+ i_register: 0,
+ pc: 0,
+ },
+ Chip8Registers {
+ registers: [
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00,
+ ],
+ i_register: 0,
+ pc: 0,
+ },
+ false,
+ ),
+ ];
+
+ for (first, second, matches) in data_set.iter() {
+ assert_eq!(first == second, *matches)
+ }
+}
diff --git a/gemma/tests/sound_timer.rs b/gemma/tests/sound_timer.rs
new file mode 100644
index 0000000..5b9429d
--- /dev/null
+++ b/gemma/tests/sound_timer.rs
@@ -0,0 +1,31 @@
+use gemma::chip8::sound_timer::SoundTimer;
+
+/// Tests for The Sound Timer
+///
+///
+
+#[test]
+fn sound_timer_default() {
+ let x = SoundTimer::default();
+ assert_eq!(x.current(), 0);
+}
+
+#[test]
+fn sound_timer_ticks_reduce_time() {
+ let mut st = SoundTimer::new();
+ st.set_timer(100);
+ st.tick();
+ st.tick();
+ st.tick();
+ assert_eq!(st.current(), 97);
+}
+
+#[test]
+fn sound_timer_out_of_ticks_works() {
+ let mut st = SoundTimer::new();
+ st.set_timer(0);
+ st.tick();
+ st.tick();
+ st.tick();
+ assert_eq!(st.current(), 0);
+}
diff --git a/gemma/tests/stack.rs b/gemma/tests/stack.rs
new file mode 100644
index 0000000..8506624
--- /dev/null
+++ b/gemma/tests/stack.rs
@@ -0,0 +1,49 @@
+use rand::random;
+use gemma::chip8::stack::Chip8Stack;
+
+#[test]
+#[should_panic]
+fn stack_overflow_test() {
+ let mut x = Chip8Stack::new();
+ for i in 0..17 {
+ x.push(&i);
+ }
+}
+
+#[test]
+#[should_panic]
+fn stack_underflow_test() {
+ let mut x = Chip8Stack::new();
+ x.pop();
+}
+
+#[test]
+fn stack_lots_of_subs() {
+ let mut x = Chip8Stack::new();
+ let stack_contents = [
+ 0x123, 0x321, 0xabc, 0xdef, 0xbad, 0xbef, 0xfed, 0xcab, 0xbed, 0xcad, 0xfeb, 0xcab, 0xfff,
+ 0x000, 0x001,
+ ];
+ for i in stack_contents {
+ x.push(&i);
+ }
+
+ assert_eq!(x.depth(), 15);
+
+ // up to 50 random loops
+ let num_loops: u8 = random::() % 50;
+ for i in 0..num_loops {
+ let start_count = x.depth();
+ let num_pop = random::() % x.depth() as u8;
+ for current_pop in 0..num_pop {
+ x.pop();
+ }
+
+ let post_pop_count = x.depth();
+ assert_eq!(post_pop_count as u8, start_count as u8 - num_pop);
+ for current_push in 0..num_pop {
+ x.push(&stack_contents[(current_push + post_pop_count as u8) as usize]);
+ }
+ assert_eq!(x.depth(), 15);
+ }
+}
diff --git a/gemma/tests/state_tests.rs b/gemma/tests/state_tests.rs
index fd86ef0..cd62c3c 100644
--- a/gemma/tests/state_tests.rs
+++ b/gemma/tests/state_tests.rs
@@ -1,14 +1,20 @@
mod test_utils;
-use crate::test_utils::read_test_result;
use gemma::chip8::computer::Chip8Computer;
use std::fs;
use std::io::prelude::*;
+use crate::test_utils::load_compressed_result;
+
+
+#[test]
+fn smoke() {
+ assert!(true)
+}
#[test]
#[ignore]
fn serialization_round_trip() {
let original_computer = Chip8Computer::new();
- let expected_json = read_test_result("smoke_001_round_trip_serialize_deserialize.json");
+ let expected_json = load_compressed_result("smoke_001_round_trip_serialize_deserialize");
// Serialize the Chip8Computer instance
let serialized = serde_json::to_string(&original_computer).expect("Serialization failed");
diff --git a/gemma/tests/system_memory.rs b/gemma/tests/system_memory.rs
new file mode 100644
index 0000000..585d698
--- /dev/null
+++ b/gemma/tests/system_memory.rs
@@ -0,0 +1,23 @@
+use std::fs::File;
+use std::io::Read;
+use gemma::chip8::system_memory::Chip8SystemMemory;
+use gemma::constants::TEST_ROM_ROOT;
+
+#[test]
+fn system_memory_load_program() {
+ let mut m = Chip8SystemMemory::new();
+ let mut program_to_load = vec![];
+ let file_to_load = format!("{}/2-ibm-logo.ch8", TEST_ROM_ROOT);
+ println!(
+ "Attempt to load {} from {}",
+ file_to_load,
+ std::env::current_dir().unwrap().display()
+ );
+ let mut file_to_load_from = File::open(file_to_load).expect("Unable to load sample rom");
+ file_to_load_from
+ .read_to_end(&mut program_to_load)
+ .expect("Unable to read sample rom");
+ m.load_program(program_to_load.clone().into());
+ let expected_at_200 = program_to_load[0];
+ assert_eq!(m.peek(0x200), expected_at_200);
+}
diff --git a/gemma/tests/test_utils.rs b/gemma/tests/test_utils.rs
index a460429..9e83748 100644
--- a/gemma/tests/test_utils.rs
+++ b/gemma/tests/test_utils.rs
@@ -6,6 +6,12 @@ use std::io::{Read, Write};
use tempfile::tempfile;
const TEST_OUTPUT_SAMPLE_DIR: &str = "../resources/test/";
+
+#[test]
+fn smoke() {
+ assert!(true)
+}
+
pub fn compress_string(input: &str) -> Vec {
let mut encoder = DeflateEncoder::new(Vec::new(), Compression::default());
encoder
@@ -13,7 +19,6 @@ pub fn compress_string(input: &str) -> Vec {
.expect("Failed to write data");
encoder.finish().expect("Failed to finish compression")
}
-
pub fn decompress_to_string(compressed_data: &[u8]) -> Result {
let mut decoder = DeflateDecoder::new(compressed_data);
let mut decompressed = String::new();
@@ -43,29 +48,11 @@ pub fn read_compressed_test_result(suffix: &str) -> String {
pub fn load_compressed_result(suffix: &str) -> String {
read_compressed_test_result(suffix)
}
-pub fn read_test_result(suffix: &str) -> String {
- panic!("THIS SHOULD BE COMPRESSED.");
- // let full_path = TEST_OUTPUT_SAMPLE_DIR.to_owned() + suffix;
- // println!("READING TEST RESULTS FROM {}", full_path);
- // std::fs::read_to_string(full_path).unwrap()
-}
pub fn load_rom(to_load: &str) -> Vec {
std::fs::read(format!("../resources/roms/{}.ch8", to_load)).unwrap()
}
-fn load_result(to_load: &str) -> String {
- panic!("THIS SHOULD BE COMPRESSED.");
- // let full_path = format!(
- // "{}/../resources/test/state/{}",
- // std::env::current_dir().unwrap().display(),
- // to_load
- // );
- // println!("CURRENT DIR: {:?}", std::env::current_dir());
- // println!("Loading state => (([{}]))", full_path);
- // std::fs::read_to_string(full_path).unwrap()
-}
-
#[cfg(test)]
mod tests {
use super::*;
@@ -96,4 +83,6 @@ mod tests {
//
// ...verify its the same.
}
+
+
}
diff --git a/gemma/tests/unit_tests.rs b/gemma/tests/unit_tests.rs
index 09e15a0..56de8cc 100644
--- a/gemma/tests/unit_tests.rs
+++ b/gemma/tests/unit_tests.rs
@@ -1,4 +1,4 @@
-use crate::test_utils::{load_compressed_result, read_test_result};
+use crate::test_utils::load_compressed_result;
use gemma::chip8::computer::Chip8Computer;
use gemma::chip8::computer_manager::Chip8ComputerManager;
use gemma::chip8::cpu_states::Chip8CpuStates::WaitingForInstruction;
@@ -48,683 +48,6 @@ fn decoder_test_invalid_instructions() {
}
}
-/// START OF THE EXECUTION TESTS
-#[test]
-fn instruction_tests() {
- // 0x0nnn Exit to System Call
- let mut x = Chip8Computer::new();
- Chip8CpuInstructions::SYS(0).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0);
-
- let mut x = Chip8Computer::new();
- Chip8CpuInstructions::SYS(0xFA0).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0xFA0);
-
- let mut x = Chip8Computer::new();
- Chip8CpuInstructions::SYS(0x0AF).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0x0AF);
-
- // 0x1nnn Jump to Address
- let mut x = Chip8Computer::new();
- Chip8CpuInstructions::JPA(0).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0);
-
- let mut x = Chip8Computer::new();
- Chip8CpuInstructions::JPA(0xABC).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0xABC);
-
- // 0x6xkk Set Vx = kk
- let mut x = Chip8Computer::new();
- Chip8CpuInstructions::LDR(1, 0x12).execute(&mut x);
- assert_eq!(x.registers.peek(1), 0x12);
-
- let mut x = Chip8Computer::new();
- Chip8CpuInstructions::LDR(2, 0x21).execute(&mut x);
- assert_eq!(x.registers.peek(2), 0x21);
-
- // 0x3xkk Skip next instruction if Vx = kk.
- // The interpreter compares register Vx to kk,
- // and if they are equal, increments the program counter by 2.
-
- // test setup: Load value 0x84 into V1
- let mut x = Chip8Computer::new();
- x.registers.poke(0x1, 0x84);
- Chip8CpuInstructions::SEX(1, 0x48).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0x202);
-
- let mut x = Chip8Computer::new();
- x.registers.poke(0x1, 0x84);
- Chip8CpuInstructions::SEX(1, 0x84).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0x204);
-
- // 0x4xkk Skip next instruction if Vx != kk
- let mut x = Chip8Computer::new();
- x.registers.poke(0x01, 0x84);
- x.registers.poke(0x2, 0x84);
- // skip, compare 0x84 to 0x84
- Chip8CpuInstructions::SEY(0x1, 0x2).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0x204);
-
- let mut x = Chip8Computer::new();
- x.registers.poke(0x01, 0x84);
- x.registers.poke(0x2, 0x48);
- Chip8CpuInstructions::SEY(0x01, 0x02).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0x202);
-
- // 0x8xy0 Set value of Vy in Vx
- let mut x = Chip8Computer::new();
- x.registers.poke(0x01, 0x01);
- x.registers.poke(0x02, 0x02);
- Chip8CpuInstructions::LDRY(0x01, 0x02).execute(&mut x);
- assert_eq!(x.registers.peek(1), 0x02);
-
- // 0x8xy1 Set Vx = Vx OR Vy
- // 0b0101 0000 (0x50)
- // | 0b0000 1010 (0x0A)
- // 0b0101 1010 (0x5A)
- let mut x = Chip8Computer::new();
- x.registers.poke(0x01, 0b01010000);
- x.registers.poke(0x02, 0b00001010);
- Chip8CpuInstructions::OR(1, 2).execute(&mut x);
- assert_eq!(x.registers.peek(1), 0b01011010);
-
- // 0x8xy2 Set Vx = Vx AND Vy
- // 0b1111 1100 (0xFC)
- // & 0b1100 1010 (0xCA)
- // 0b1100 1000 (0xC8)
- let mut x = Chip8Computer::new();
- x.registers.poke(0x01, 0xFC);
- x.registers.poke(0x02, 0xCA);
- Chip8CpuInstructions::AND(1, 2).execute(&mut x);
- assert_eq!(x.registers.peek(1), 0xC8);
-
- // 0x8xy3 Set Vx = Vx XOR Vy
- // 0b1111 1100 (0xFC)
- // ^ 0b1100 1010 (0xCA)
- // 0b0011 0110 (0x36)
- let mut x = Chip8Computer::new();
- x.registers.poke(0x01, 0b11111100);
- x.registers.poke(0x02, 0b11001010);
- Chip8CpuInstructions::ORY(1, 2).execute(&mut x);
- assert_eq!(x.registers.peek(1), 0b00110110);
-
- // 0x8xy4 Set Vx = Vx + Vy (SET VF on Carry)
- // T1 T2: Judgement Test
- // 0x01 0xFF
- // + 0x01 0x01
- // 0x02 F0 0x00 F1
- let mut x = Chip8Computer::new();
- x.registers.poke(0x0f, 00);
- x.registers.poke(0x01, 0x01);
- x.registers.poke(0x02, 0x01);
- Chip8CpuInstructions::ADDR(0x01, 0x02).execute(&mut x);
- assert_eq!(x.registers.peek(0xf), 0x00);
- assert_eq!(x.registers.peek(0x01), 0x02);
-
- let mut x = Chip8Computer::new();
- x.registers.poke(0x0f, 0x00);
- x.registers.poke(0x01, 0xff);
- x.registers.poke(0x02, 0x01);
- Chip8CpuInstructions::ADDR(1, 2).execute(&mut x);
- assert_eq!(x.registers.peek(0xf), 1);
- assert_eq!(x.registers.peek(1), 0);
-
- /*
- Set Vx = Vx SHR 1.
-
- If the least-significant bit of Vx is 1, then VF is set to 1, otherwise 0. Then Vx is divided by 2.
- */
- let mut x = Chip8Computer::new();
- x.registers.poke(0x0f, 0x00);
- x.registers.poke(0x01, 0b00001000);
- x.registers.poke(0x02, 0b00000000);
- Chip8CpuInstructions::SHR(0x1, 0x2).execute(&mut x); // 0b0000 0010 (0x02) (Not Set)
- assert_eq!(x.registers.peek(1), 0b00000100);
- assert_eq!(x.registers.peek(0xf), 0);
-
- x = Chip8Computer::new();
- x.registers.poke(0x0f, 0x00);
- x.registers.poke(0x01, 0b00001001);
- Chip8CpuInstructions::SHR(0x1, 0x2).execute(&mut x);
- assert_eq!(x.registers.peek(1), 0b00000100);
- assert_eq!(x.registers.peek(0xf), 1);
-
- let mut x = Chip8Computer::new();
- Chip8CpuInstructions::LDIA(0x123).execute(&mut x);
- assert_eq!(x.registers.peek_i(), 0x123);
- assert_eq!(x.registers.peek_pc(), 0x202);
-}
-
-#[test]
-fn jp_v0addr_test() {
- let mut x = Chip8Computer::new();
- /// jump to I + nnn
- x.registers.poke(0x0, 0xff);
- Chip8CpuInstructions::JPI(0x100).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0x1FF);
-}
-
-#[test]
-fn cls_test() {
- let mut x = Chip8Computer::new();
- Chip8CpuInstructions::CLS.execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0x202);
- for i in 0..CHIP8_VIDEO_MEMORY {
- assert!(!x.video_memory.peek(i as u16));
- }
- // draw some thing to the video memory
- x.video_memory.poke(0x01, true);
- x.video_memory.poke(0x03, true);
- x.video_memory.poke(0x05, true);
-
- Chip8CpuInstructions::CLS.execute(&mut x);
-
- for i in 0..CHIP8_VIDEO_MEMORY {
- assert!(!x.video_memory.peek(i as u16));
- }
-}
-
-#[test]
-fn skip_next_instruction_ne_text() {
- let mut x = Chip8Computer::new();
- x.registers.poke(0x1, 0xf0);
- Chip8CpuInstructions::SNEB(0x1, 0x0f).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0x204);
-
- let mut x = Chip8Computer::new();
- x.registers.poke(0x1, 0xf0);
- Chip8CpuInstructions::SNEB(0x1, 0xf0).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0x202);
-}
-
-#[test]
-fn addivx_test() {
- let mut x = Chip8Computer::new();
- x.registers.poke_i(0xabc);
- x.registers.poke(0x0, 0x10);
- Chip8CpuInstructions::ADDI(0x0).execute(&mut x);
- assert_eq!(x.registers.peek_i(), 0xacc);
-}
-
-#[test]
-fn ldstvt_test() {
- let mut x = Chip8Computer::new();
- x.registers.poke(0x1, 0xf0);
- Chip8CpuInstructions::LDIS(0x01).execute(&mut x);
- assert_eq!(x.sound_timer.current(), 0xf0);
- x.sound_timer.tick();
- x.sound_timer.tick();
- x.sound_timer.tick();
- assert_eq!(x.sound_timer.current(), 0xed);
-}
-
-#[test]
-fn rnd_vx_byte_text() {
- let mut x = Chip8Computer::new();
- Chip8CpuInstructions::RND(0x1, 0x0f).execute(&mut x);
- let new_value = x.registers.peek(0x1);
- assert!(new_value < 0x10);
-}
-
-#[test]
-fn add_vx_byte_test() {
- let mut x = Chip8Computer::new();
- // set a value in the register
- x.registers.poke(0x01, 0xab);
- // add 0x10 to register
- Chip8CpuInstructions::ADD(0x1, 0x10).execute(&mut x);
- assert_eq!(x.registers.peek(1), 0xbb);
-}
-
-#[test]
-fn sub_vx_vy_test() {
- let mut x = Chip8Computer::new();
- // load values in 2 registers
- x.registers.poke(0x1, 0x10);
- x.registers.poke(0x2, 0x08);
- Chip8CpuInstructions::SUB(0x1, 0x02).execute(&mut x);
- assert_eq!(x.registers.peek(0xf), 1);
- assert_eq!(x.registers.peek(0x1), 0x8);
- assert_eq!(x.registers.peek_pc(), 0x202);
-}
-
-#[test]
-fn sne_vx_vy_test() {
- let mut x = Chip8Computer::new();
- x.registers.poke(0x1, 0x10);
- x.registers.poke(0x2, 0x10);
- Chip8CpuInstructions::SNEY(0x1, 0x2).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0x202);
-
- let mut x = Chip8Computer::new();
- x.registers.poke(0x1, 0x10);
- x.registers.poke(0x2, 0x00);
- Chip8CpuInstructions::SNEY(0x01, 0x02).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0x204)
-}
-
-#[test]
-fn ld_dt_vx_test() {
- let mut x = Chip8Computer::new();
- x.registers.poke(0x1, 0x10);
- Chip8CpuInstructions::LDD(0x1).execute(&mut x);
- assert_eq!(x.delay_timer.current(), 0x10);
- for _ in 0..0x20 {
- x.delay_timer.tick();
- }
- assert_eq!(x.delay_timer.current(), 0);
-}
-
-#[test]
-fn ld_vx_dt_test() {
- let mut x = Chip8Computer::new();
- x.registers.poke(0x1, 0xf0);
- Chip8CpuInstructions::LDD(0x1).execute(&mut x);
- x.delay_timer.tick();
- x.delay_timer.tick();
- x.delay_timer.tick();
- assert_eq!(x.delay_timer.current(), 0xed);
-}
-
-#[test]
-fn subn_vx_vy_test() {
- // This instruction subtracts the value in
- // register Vx from the value in register Vy and stores the result in register Vx.
- // The subtraction is performed as follows: Vx = Vy - Vx. If Vy is less than Vx,
- // the result will wrap around (due to the 8-bit nature of the registers).
- // The carry flag (VF) is set to 1 if there is no borrow (i.e., Vy is greater
- // than or equal to Vx), and it is set to 0 if there is a borrow.
-
- let mut x = Chip8Computer::new();
- x.registers.poke(0x1, 0xa0);
- x.registers.poke(0x2, 0xab);
- Chip8CpuInstructions::SUBC(0x1, 0x2).execute(&mut x);
- // expect the result to be 0x0b
- assert_eq!(x.registers.peek(0x1), 0x0b);
- // expect the vf register to be set to 1 as there was overflow
- assert_eq!(x.registers.peek(0xf), 0x1);
-
- let mut x = Chip8Computer::new();
- x.registers.poke(0x01, 0xab);
- x.registers.poke(0x02, 0xa0);
- Chip8CpuInstructions::SUBC(0x1, 0x2).execute(&mut x);
-
- // expect the result to be 11110101, -0xB, -11, 245, 0xF5
- assert_eq!(x.registers.peek(0x1), 0xf5);
- assert_eq!(x.registers.peek(0xf), 0x0);
-
- // 8xyE - SHL Vx {, Vy}
- // Set Vx = Vx SHL 1.
- //
- // If the most-significant bit of Vx is 1, then VF is set to 1, otherwise to 0. Then Vx is multiplied by 2.
-
- let mut x = Chip8Computer::new();
- x.registers.poke(0x1, 0b00100000);
- Chip8CpuInstructions::SHL(0x1, 0x1).execute(&mut x);
- assert_eq!(x.registers.peek(0x1), 0b01000000);
- assert_eq!(x.registers.peek(0xf), 0x0);
-
- let mut x = Chip8Computer::new();
- x.registers.poke(0x1, 0b10101010);
- Chip8CpuInstructions::SHL(0x1, 0x1).execute(&mut x);
- assert_eq!(x.registers.peek(0x1), 0b01010100);
- assert_eq!(x.registers.peek(0xf), 0x1);
-
- // Fx29 - LD F, Vx
- // Set I = location of sprite for digit Vx.
- //
- // The value of I is set to the location for the hexadecimal sprite corresponding to the value of Vx. See section 2.4, Display, for more information on the Chip-8 hexadecimal font.
- let mut x = Chip8Computer::new();
- // target_sprite = 2
- // target_offset = 0x5
- x.registers.poke(0x1, 0x2);
- Chip8CpuInstructions::LDFX(0x1).execute(&mut x);
-
- assert_eq!(x.registers.peek_i(), 10);
-
- let mut x = Chip8Computer::new();
- x.registers.poke(0x01, 0x06);
- Chip8CpuInstructions::LDFX(0x1).execute(&mut x);
- assert_eq!(x.registers.peek_i(), 30);
-
- // Fx33 - LD B, Vx
- // Store BCD representation of Vx in memory locations I, I+1, and I+2.
- //
- // The interpreter takes the decimal value of Vx, and places the hundreds digit
- // in memory at location in I, the tens digit at location I+1,
- // and the ones digit at location I+2.
- let mut x = Chip8Computer::new();
-
- // load the value 123 (0x7b)
- x.registers.poke(0x1, 0x7b);
- x.registers.poke_i(0x500);
- Chip8CpuInstructions::BCD(0x1).execute(&mut x);
- assert_eq!(x.memory.peek(0x500), 0x1);
- assert_eq!(x.memory.peek(0x501), 0x2);
- assert_eq!(x.memory.peek(0x502), 0x3);
-
- // Store registers V0 through Vx in memory starting at location I.
- //
- // The interpreter copies the values of registers V0 through Vx into memory,
- // starting at the address in I.
- let mut x = Chip8Computer::new();
-
- // Load Registers.
- let to_load = [0xab, 0xba, 0xca, 0xca, 0xbe, 0xef];
- for (idx, val) in to_load.iter().enumerate() {
- x.registers.poke(idx as u8, *val);
- }
- x.registers.poke_i(0x500);
-
- Chip8CpuInstructions::LDIX(to_load.len() as u8).execute(&mut x);
-
- // Verify the values are in memory from 0x500 to 0x507
- for (idx, value) in to_load.iter().enumerate() {
- assert_eq!(x.memory.peek(0x500 + idx as u16), *value);
- }
-
- // Read registers V0 through Vx from memory starting at location I.
- //
- // The interpreter reads values from memory starting at location I into registers V0 through Vx.
-
- let mut x = Chip8Computer::new();
-
- let base_offset = 0x500;
- let to_load = [0xab, 0xba, 0xca, 0xca, 0xbe, 0xef];
-
- // start by setting values in memory
- for (idx, memory) in to_load.iter().enumerate() {
- let target_address = base_offset + idx;
- let target_value = *memory;
- x.memory.poke(target_address as u16, target_value);
- }
- // where to load from
- x.registers.poke_i(0x500);
- // how much to load
- x.registers.poke(0x6, to_load.len() as u8);
-
- // then copying them values memory to registers
- Chip8CpuInstructions::LDRI(0x6).execute(&mut x);
-
- // now check that we have the right values in our registers
- for (idx, value) in to_load.iter().enumerate() {
- assert_eq!(x.registers.peek(idx as u8), *value);
- }
-
- // ExA1 - SKNP Vx
- // Skip next instruction if key with the value of Vx is not pressed.
- //
- // Checks the keyboard,
- // and if the key corresponding to the value of Vx is currently in the up position,
- // PC is increased by 2.
- let mut x = Chip8Computer::new();
- x.keypad.push_key(0x5);
- x.registers.poke(0x1, 0x5);
- Chip8CpuInstructions::SKNP(0x1).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0x202);
- x.keypad.release_key(0x5);
- Chip8CpuInstructions::SKNP(0x1).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0x206);
-
- // Ex9E - SKP Vx
- // Skip next instruction if key with the value of Vx is pressed.
- //
- // Checks the keyboard, and if the key corresponding to the value of Vx is currently in the down position, PC is increased by 2.
- let mut x = Chip8Computer::new();
- x.keypad.push_key(0x5);
- x.registers.poke(0x1, 0x5);
- Chip8CpuInstructions::SKP(0x1).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0x204);
-
- x.keypad.release_key(0x5);
- Chip8CpuInstructions::SKP(0x1).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0x206);
-}
-
-fn draw_nibble_vx_vy_n_test_hd() {
- let mut x = Chip8Computer::new();
-
- let x_register = 0x01;
- let x_offset = 0x03;
- let y_register = 0x02;
- let y_offset = 0x04;
- let char_offset = 0x100;
- x.registers.poke(x_register, x_offset);
- x.registers.poke(y_register, y_offset);
- x.video_memory.set_highres();
- x.registers.poke_i(char_offset);
- Chip8CpuInstructions::DRW(x_register, y_register, 0).execute(&mut x);
-
- println!("[[{}]]", x.video_memory.format_as_string());
-
- assert_eq!(read_test_result(""), x.video_memory.format_as_string());
-}
-
-#[test]
-fn draw_nibble_vx_vy_n_test_sd() {
- let mut x = Chip8Computer::new();
- let x_register = 0x1;
- let y_register = 0x2;
- let x_offset = 1;
- let y_offset = 2;
- let char_offset = 0x0A;
-
- // now lets set the X and Y to 1,2
- x.registers.poke(x_register, x_offset);
- x.registers.poke(y_register, y_offset);
- x.registers.poke_i(char_offset);
- // we are using 5 rows.
- Chip8CpuInstructions::DRW(x_register, y_register, 5).execute(&mut x);
-
- // now check that video memory has the values at
- // 1,2->1,9
- // 2,2->2,9
- // 3,2->3,9
- // 4,2->4,9
- // 5,2->5,9
- // let byte_to_check = CHIP8FONT_0[0];
- for row_in_sprite in 0..5 {
- let row_data = CHIP8FONT_2[row_in_sprite];
- for bit_in_byte in 0..8 {
- let data_offset =
- (x_offset as u16 + row_in_sprite as u16) * 64 + (bit_in_byte + y_offset) as u16;
- let real_bit_in_byte = 7 - bit_in_byte;
- let shifted_one = 0x01 << real_bit_in_byte;
- let one_shift_set = (shifted_one & row_data) > 0;
- debug!("ROWDATA = \t\t[{row_data:08b}]\tBIT IN BYTE = \t[{bit_in_byte}]\tONE_SHIFT_SET = [{one_shift_set}]\tSHIFTED ONE = [{shifted_one:08b}]");
- debug!("DATA_OFFSET FOR SOURCE DATA {}x{} is {} / offset by {}x{} and should be {} working with byte {:08b}",
- bit_in_byte, row_in_sprite, data_offset, x_offset, y_offset, one_shift_set, row_data);
- }
- }
-}
-
-#[test]
-fn sub_test() {
- // 2nnn
- // Call a subroutine at 2nnn
- let mut x = Chip8Computer::new();
- Chip8CpuInstructions::CALL(0x124).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0x124);
- assert_eq!(x.stack.depth(), 1);
- Chip8CpuInstructions::CALL(0x564).execute(&mut x);
- assert_eq!(x.registers.peek_pc(), 0x564);
- assert_eq!(x.stack.depth(), 2);
-
- // SETUP
- // Return from a subroutine.
- let mut x = Chip8Computer::new();
- x.stack.push(&0x132);
- x.stack.push(&0xabc);
- // EXECUTE
- Chip8CpuInstructions::RET.execute(&mut x);
- // VERIFY
- assert_eq!(x.registers.peek_pc(), 0xabc);
- assert_eq!(x.stack.depth(), 1);
- // EXECUTE
- Chip8CpuInstructions::RET.execute(&mut x);
- // VERIFY
- assert_eq!(x.registers.peek_pc(), 0x132);
- assert_eq!(x.stack.depth(), 0);
-}
-
-#[test]
-fn ldvxk_test() {
- // SETUP
- let mut x = Chip8Computer::new();
- x.registers.poke(0x01, 0x01);
- Chip8CpuInstructions::LDRK(0x1).execute(&mut x);
- assert!(matches!(
- x.state,
- gemma::chip8::cpu_states::Chip8CpuStates::WaitingForKey
- ));
-}
-
-#[test]
-fn series8xy4_corex_tests() {
- /// 8xy4
- /// Set Vx = Vx + Vy
- /// Set VF=1 if Carry
- ///
- // 1 + 1
- let mut x = Chip8Computer::new();
- x.registers.poke(0x01, 0x01);
- x.registers.poke(0x02, 0x01);
- Chip8CpuInstructions::ADDR(0x01, 0x02).execute(&mut x);
- assert_eq!(x.registers.peek(0x01), 0x02);
- assert_eq!(x.registers.peek(0x0f), 0x00);
-
- // 255+1
- let mut x = Chip8Computer::new();
- x.registers.poke(0x01, 0xff);
- x.registers.poke(0x02, 0x01);
- Chip8CpuInstructions::ADDR(0x01, 0x02).execute(&mut x);
- assert_eq!(x.registers.peek(0x01), 0x00);
- assert_eq!(x.registers.peek(0x0f), 0x01);
-
- // 128+192
- let mut x = Chip8Computer::new();
- x.registers.poke(0x01, 128);
- x.registers.poke(0x02, 192);
- Chip8CpuInstructions::ADDR(0x01, 0x02).execute(&mut x);
- assert_eq!(x.registers.peek(0x01), 64);
- assert_eq!(x.registers.peek(0x0f), 1);
-
- // 8xy6 - SHR Vx {, Vy}
- // Set Vx = Vx SHR 1.
- //
- // If the least-significant bit of Vx is 1, then VF is set to 1,
- // otherwise 0. Then Vx is divided by 2.
- let mut x = Chip8Computer::new();
- // 0b10101010 -> 0b01010101
- x.registers.poke(0x01, 0b10101010);
- x.registers.poke(0x0f, 0x0);
-
- Chip8CpuInstructions::SHL(0x01, 0x00).execute(&mut x);
- assert_eq!(x.registers.peek(0x01), 0b01010100);
- assert_eq!(x.registers.peek(0x0f), 1);
-
- Chip8CpuInstructions::SHL(0x01, 0x00).execute(&mut x);
- assert_eq!(x.registers.peek(0x01), 0b10101000);
- assert_eq!(x.registers.peek(0x0f), 0x00);
-
- Chip8CpuInstructions::SHL(0x01, 0x00).execute(&mut x);
- assert_eq!(x.registers.peek(0x01), 0b01010000);
- assert_eq!(x.registers.peek(0x0f), 0x01);
-
- Chip8CpuInstructions::SHL(0x01, 0x00).execute(&mut x);
- assert_eq!(x.registers.peek(0x01), 0b10100000);
- assert_eq!(x.registers.peek(0x0f), 0x00);
-
- Chip8CpuInstructions::SHL(0x01, 0x00).execute(&mut x);
- assert_eq!(x.registers.peek(0x01), 0b01000000);
- assert_eq!(x.registers.peek(0x0f), 0x01);
-}
-
-#[test]
-fn random_produces_different_numbers() {
- let mut x = Chip8Computer::new();
- x.registers.poke(0x01, 0x00);
- let first_number = Chip8CpuInstructions::RND(0x01, 0xff)
- .execute(&mut x)
- .registers
- .peek(0x01);
- let second_number = Chip8CpuInstructions::RND(0x01, 0xff)
- .execute(&mut x)
- .registers
- .peek(0x01);
- assert_ne!(first_number, second_number);
-}
-
-#[test]
-fn delay_timer_ticks_reduce_time() {
- let mut st = DelayTimer::new();
- st.set_timer(100);
- st.tick();
- st.tick();
- st.tick();
- assert_eq!(st.current(), 97);
-}
-
-#[test]
-fn delay_timer_out_of_ticks_works() {
- let mut st = DelayTimer::new();
- st.set_timer(0);
- st.tick();
- st.tick();
- st.tick();
- assert_eq!(st.current(), 0);
-}
-
-#[test]
-fn keypad_keys_check() {
- let mut k = Keypad::new();
-
- for i in 0..16 {
- assert!(!k.key_state(i));
- }
-
- // press a key
- k.push_key(1);
- k.push_key(2);
- assert!(k.pressed(1));
- assert!(k.pressed(2));
- k.release_key(1);
- assert!(k.released(1));
-}
-
-#[test]
-fn keypad_string_format_test() {
- let k = Keypad::new();
-
- assert_eq!(
- k.format_as_string(),
- read_compressed_test_result("gemma_keypad_string_result")
- );
-}
-
-#[test]
-fn register_rw_test() {
- let mut x = Chip8Registers::default();
- x.poke(0x0, 0xff);
- x.poke(0x1, 0xab);
- assert_eq!(x.peek(0x0), 0xff);
- assert_eq!(x.peek(0x1), 0xab);
-}
-
-#[test]
-fn pc_test() {
- let mut x = Chip8Registers::default();
- x.set_pc(0x300);
- assert_eq!(x.peek_pc(), 0x300);
-}
-
-#[test]
-#[should_panic]
-fn invalid_register() {
- let mut x = Chip8Registers::default();
- x.poke(0x10, 0xff);
-}
-
#[test]
fn format_as_string_looks_right() {
let mut x = Chip8Registers::default();
@@ -737,38 +60,6 @@ fn format_as_string_looks_right() {
assert_eq!(result_string, String::from("Vx: 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07\n 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f\nI: 0x0cab\tPC: 0x0abc"));
}
-#[test]
-fn reset_clears_registers() {
- let mut x = Chip8Registers::default();
-
- for register in 0..0x10 {
- x.poke(register, random::());
- }
- x.reset();
- for register in 0..0x10 {
- assert_eq!(x.peek(register), 0x00);
- }
-}
-
-#[test]
-fn sound_timer_ticks_reduce_time() {
- let mut st = SoundTimer::new();
- st.set_timer(100);
- st.tick();
- st.tick();
- st.tick();
- assert_eq!(st.current(), 97);
-}
-
-#[test]
-fn sound_timer_out_of_ticks_works() {
- let mut st = SoundTimer::new();
- st.set_timer(0);
- st.tick();
- st.tick();
- st.tick();
- assert_eq!(st.current(), 0);
-}
#[test]
fn stack_push_pop_test() {
@@ -781,53 +72,6 @@ fn stack_push_pop_test() {
assert_eq!(x.depth(), 1);
}
-#[test]
-#[should_panic]
-fn stack_overflow_test() {
- let mut x = Chip8Stack::new();
- for i in 0..17 {
- x.push(&i);
- }
-}
-
-#[test]
-#[should_panic]
-fn stack_underflow_test() {
- let mut x = Chip8Stack::new();
- x.pop();
-}
-
-#[test]
-fn stack_lots_of_subs() {
- let mut x = Chip8Stack::new();
- let stack_contents = [
- 0x123, 0x321, 0xabc, 0xdef, 0xbad, 0xbef, 0xfed, 0xcab, 0xbed, 0xcad, 0xfeb, 0xcab, 0xfff,
- 0x000, 0x001,
- ];
- for i in stack_contents {
- x.push(&i);
- }
-
- assert_eq!(x.depth(), 15);
-
- // up to 50 random loops
- let num_loops: u8 = random::() % 50;
- for i in 0..num_loops {
- let start_count = x.depth();
- let num_pop = random::() % x.depth() as u8;
- for current_pop in 0..num_pop {
- x.pop();
- }
-
- let post_pop_count = x.depth();
- assert_eq!(post_pop_count as u8, start_count as u8 - num_pop);
- for current_push in 0..num_pop {
- x.push(&stack_contents[(current_push + post_pop_count as u8) as usize]);
- }
- assert_eq!(x.depth(), 15);
- }
-}
-
#[test]
fn video_split_bytes() {
// from 0xABCD we should have AB high, CD low
@@ -1120,6 +364,7 @@ fn video_write_checkboard() {
}
#[test]
+#[ignore]
fn video_zero_test() {
let mut x = Chip8Video::default();
@@ -1489,19 +734,18 @@ fn video_hires_loop_check() {
assert!(true);
}
-#[test]
-fn sound_timer_default() {
- let x = SoundTimer::default();
- assert_eq!(x.current(), 0);
-}
-
#[test]
fn system_memory_new() {
let x = Chip8SystemMemory::new();
- assert!(true);
+
+ // check its empty.
+ for i in 0..CHIP8_MEMORY_SIZE {
+ assert_eq!(x.peek(i as u16), 0x00);
+ }
}
#[test]
+#[ignore]
fn video_lowres_schip_draw_chip8_sprite() {
let mut x = Chip8Computer::new();
x.quirk_mode = QuirkMode::SChipModern;
@@ -1512,24 +756,31 @@ fn video_lowres_schip_draw_chip8_sprite() {
x.registers.poke(0x01, 0x01);
x.registers.poke(0x02, 0x02);
Chip8CpuInstructions::DRW(0x01, 0x01, 0x08).execute(&mut x);
- let expected_state = read_test_result("state/video_lowres_schip_draw_chip8_sprite_result.json");
- let actual_state = serde_json::to_string(&x).unwrap();
+ let expected_state = read_compressed_test_result("state/video_lowres_schip_draw_chip8_sprite_result");
+ let actual_state = x.dump_state_to_json();
assert_eq!(expected_state, actual_state);
}
#[test]
-fn video_lowres_schip_draw_schip_sprite() {}
+#[ignore]
+fn video_lowres_schip_draw_schip_sprite() {
+ let mut x = Chip8Computer::new();
+ x.quirk_mode = SChipModern;
+ x.video_memory.set_lowres();
+ x.registers.poke_i(0x0005);
+ x.registers.poke(0x01, 0x01);
+ x.registers.poke(0x02, 0x02);
+ Chip8CpuInstructions::DRW(0x01, 0x01, 0x08).execute(&mut x);
+ let expected_state = read_compressed_test_result("state/video_lowres_schip_draw_schip_sprite");
+ let actual_state = x.dump_state_to_json();
+ assert_eq!(expected_state, actual_state);
+}
+
#[test]
fn video_highres_schip_draw_chip8_sprite() {}
#[test]
fn video_highres_schip_draw_schip_sprite() {}
-#[test]
-fn partial_eq_chip8computer() {
- let x = Chip8Computer::new();
- let y = Chip8Computer::new();
- assert_eq!(x, y)
-}
#[test]
fn quirk_mode_labels() {
@@ -1537,67 +788,3 @@ fn quirk_mode_labels() {
assert_eq!(format!("{}", XOChip), LABEL_QUIRK_XOCHIP);
assert_eq!(format!("{}", SChipModern), LABEL_QUIRK_SCHIP);
}
-
-#[test]
-fn system_memory_load_program() {
- let mut m = Chip8SystemMemory::new();
- let mut program_to_load = vec![];
- let file_to_load = format!("{}/2-ibm-logo.ch8", TEST_ROM_ROOT);
- println!(
- "Attempt to load {} from {}",
- file_to_load,
- std::env::current_dir().unwrap().display()
- );
- let mut file_to_load_from = File::open(file_to_load).expect("Unable to load sample rom");
- file_to_load_from
- .read_to_end(&mut program_to_load)
- .expect("Unable to read sample rom");
- m.load_program(program_to_load.clone().into());
- let expected_at_200 = program_to_load[0];
- assert_eq!(m.peek(0x200), expected_at_200);
-}
-
-#[test]
-fn start_stop_computer() {
- let mut computer = Chip8ComputerManager::new();
-
- assert_eq!(computer.core_should_run, false);
- computer.start();
- assert_eq!(computer.core_should_run, true);
- computer.step();
- assert_eq!(computer.core_should_run, true);
- computer.stop();
- assert_eq!(computer.core_should_run, false);
- computer.reset(Chip8);
- assert_eq!(computer.core_should_run, false);
-}
-
-#[test]
-fn state_default_matches() {
- let computer = Chip8Computer::default();
- let mut manager = Chip8ComputerManager::default();
- assert_eq!(computer, *manager.state());
-}
-
-#[test]
-fn keys_test_manager() {
- let mut manager = Chip8ComputerManager::default();
-
- for i in 0..16 {
- assert_eq!(manager.is_key_pressed(i), false);
- }
-
- // press key 5
- manager.press_key(5);
- assert_eq!(manager.is_key_pressed(5), true);
- manager.release_key(5);
- assert_eq!(manager.is_key_pressed(5), false);
-}
-
-#[test]
-fn status_of_manager() {
- let mut manager = Chip8ComputerManager::default();
- println!("MANAGER STATUS [{}]", manager.status_as_string());
- let expected_state = load_compressed_result("test_manager_status");
- assert_eq!(expected_state, manager.status_as_string());
-}
diff --git a/gemma/tests/util_tests.rs b/gemma/tests/util.rs
similarity index 99%
rename from gemma/tests/util_tests.rs
rename to gemma/tests/util.rs
index a9eb97f..c43c9ab 100644
--- a/gemma/tests/util_tests.rs
+++ b/gemma/tests/util.rs
@@ -1,6 +1,12 @@
use std::collections::BTreeMap;
use gemma::chip8::util::InstructionUtil;
+
+#[test]
+fn smoke() {
+ assert!(true)
+}
+
#[test]
fn byte_to_bools() {
let data_set: BTreeMap = BTreeMap::from(
diff --git a/gemmatelnet/src/telnet_utils.rs b/gemmatelnet/src/telnet_utils.rs
index 89ef167..2509497 100644
--- a/gemmatelnet/src/telnet_utils.rs
+++ b/gemmatelnet/src/telnet_utils.rs
@@ -1,8 +1,7 @@
-use std::{fs, io};
+use std::fs;
use std::path::Path;
pub fn list_of_files_in_directory(root_directory: &Path) -> String {
-
let mut return_value = String::new();
if root_directory.is_dir() {
@@ -15,4 +14,4 @@ pub fn list_of_files_in_directory(root_directory: &Path) -> String {
}
}
return_value
-}
\ No newline at end of file
+}
diff --git a/gemmautil/src/bin/bin2hex.rs b/gemmautil/src/bin/bin2hex.rs
index 5ef12f0..143589e 100644
--- a/gemmautil/src/bin/bin2hex.rs
+++ b/gemmautil/src/bin/bin2hex.rs
@@ -35,6 +35,7 @@ fn main() {
print!("0x{:02x}, ", result.unwrap());
}
}
+
fn read_file_to_bools(file_path: &str) -> io::Result> {
// Open the file
let file = File::open(file_path)?;
diff --git a/gemmautil/src/bin/ch8asm.rs b/gemmautil/src/bin/ch8asm.rs
index e94e816..baf2b62 100644
--- a/gemmautil/src/bin/ch8asm.rs
+++ b/gemmautil/src/bin/ch8asm.rs
@@ -18,7 +18,7 @@ pub struct Chip8AsmParser;
fn main() {
println!("Taxation is Theft");
- let unparsed = fs::read_to_string("resources/test/gemma_disassembler_manual_document.asc")
+ let unparsed = fs::read_to_string("resources/test/asm/gemma_disassembler_manual_document.asm8")
.expect("Unable to read input");
let file = Chip8AsmParser::parse(Rule::file, &unparsed)
@@ -36,7 +36,7 @@ fn main() {
print!("record = {:?}\t", record.as_str());
let x = Chip8CpuInstructions::from_str(record.as_str());
println!("DECODED TO {:?} {:04x}", x, x.encode());
- let (high, low) = InstructionUtil::split_bytes(x.encode());
+ let (low, high) = InstructionUtil::split_bytes(x.encode());
target_file
.write_all(&[high, low])
.expect("Unable to write to the file.");
diff --git a/resources/test/asm/gemma_disassembler_manual_document.asm8 b/resources/test/asm/gemma_disassembler_manual_document.asm8
new file mode 100644
index 0000000..2f1dede
--- /dev/null
+++ b/resources/test/asm/gemma_disassembler_manual_document.asm8
@@ -0,0 +1,4 @@
+CLS
+CALL 0xf000
+EXIT
+SUBC 0x01
diff --git a/resources/test/state/smoke_001_round_trip_serialize_deserialize.deflated b/resources/test/state/smoke_001_round_trip_serialize_deserialize.deflated
new file mode 100644
index 0000000..e69de29
diff --git a/resources/test/state/smoke_001_round_trip_serialize_deserialize.json b/resources/test/state/smoke_001_round_trip_serialize_deserialize.json
deleted file mode 100644
index 8b582f5..0000000
--- a/resources/test/state/smoke_001_round_trip_serialize_deserialize.json
+++ /dev/null
@@ -1 +0,0 @@
-{"num_cycles":0,"memory":{"memory":[240,144,144,144,240,32,96,32,32,112,240,16,240,128,240,240,16,240,16,240,144,144,240,16,16,240,128,240,16,240,240,128,240,144,240,240,16,32,64,64,240,144,240,144,240,240,144,240,16,240,240,144,240,144,144,224,144,224,144,224,240,128,128,128,240,224,144,144,144,224,240,128,240,128,240,240,128,240,128,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,128,3,0,0,0,0,0,0,0,0,0,0,0,0,0,3,192,2,0,0,0,0,0,0,0,0,0,0,0,124,254,255,255,199,0,0,0,0,0,0,0,0,0,0,0,124,254,255,255,199,0,0,0,0,0,0,0,0,0,0,0,224,240,248,252,254,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,3,0,0,0,0,0,0,0,0,0,0,0,120,254,255,255,131,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,224,0,0,0,0,0,0,0,0,0,0,0,124,254,255,255,195,0,0,0,0,0,0,0,0,0,0,0,124,254,255,255,195,0,0,0,0,0,0,0,0,0,0,0,124,254,255,255,195,0,0,0,0,0,0,0,0,0,0,0,254,255,255,255,195,0,0,0,0,0,0,0,0,0,0,0,124,254,255,255,195,0,0,0,0,0,0,0,0,0,0,0,254,255,255,255,195,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,3,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},"registers":{"registers":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"i_register":0,"pc":512},"sound_timer":{"counter":0},"delay_timer":{"counter":255},"video_memory":{"memory":[false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false],"has_frame_changed":false,"current_res":"LowRes"},"state":"WaitingForInstruction","keypad":{"keys":[false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false]},"stack":{"items":[]},"quirk_mode":"Chip8"}
diff --git a/resources/test/state/smoke_002_round_trip_serialize_deserialize_compressed.tflt b/resources/test/state/smoke_002_round_trip_serialize_deserialize_compressed.tflt
deleted file mode 100644
index affadaf..0000000
--- a/resources/test/state/smoke_002_round_trip_serialize_deserialize_compressed.tflt
+++ /dev/null
@@ -1 +0,0 @@
-1f8b08000000000000ffed9bcb8adb301440f7fd162dfc0c136d0b854257dd743104636c4d2212dba924b704e37fafecb13b4e42da4099a10c87631d45575792e56897b8abdb2a2b4ec5415919884a558d39c96eaa1fa324106192fc2e433b8ec47a35d85f61188db170f55c450f63bd0c4dd562021fbac89f9a67a12979eaf66bad92e15af69de5bc4c7e159ad78eaeeb79c9b98c63a3e47cd38bbcab5d2e624309e0d509c7271dff212316e1da1fcc5be387ef331d4a3a9670bdfee7ccf98c44893f0f69348eba9139cd3597f8e6dac1f9da7178e78cc3bddcbb9ff40d3397596f3fe7bdcffdde3c0000000000000000000000000078376c7a61d4565ba78c95ddcbc7c7bf8d133a9bb365208e854cc3a817b669eb3273baf2d1aef08db1bb17a53ae4a7cbb8ff59b2173f74a99aecf20f1b4ff9c12a8131c618638c31c618638c31c618638c31c618638c31c618638c31c618e3ffd81bb1cb6df664f24a65c52eafb7aa94cfdd456b8caa5d6694955f9a9f5f95ed8575b953f25bae9daeb79f1af3b9b6ceb485d34d2df6ea74cc4bd9f9dabefa6b059bf15e8abdecb453955fcf07beb7daecb3aa2995fcb8d3c787fec32fcefd4d09ab520000
\ No newline at end of file
diff --git a/resources/test/state/smoke_002_round_trip_serialize_deserialize_compressed.tflt.uncompressed b/resources/test/state/smoke_002_round_trip_serialize_deserialize_compressed.tflt.uncompressed
deleted file mode 100644
index affadaf..0000000
--- a/resources/test/state/smoke_002_round_trip_serialize_deserialize_compressed.tflt.uncompressed
+++ /dev/null
@@ -1 +0,0 @@
-1f8b08000000000000ffed9bcb8adb301440f7fd162dfc0c136d0b854257dd743104636c4d2212dba924b704e37fafecb13b4e42da4099a10c87631d45575792e56897b8abdb2a2b4ec5415919884a558d39c96eaa1fa324106192fc2e433b8ec47a35d85f61188db170f55c450f63bd0c4dd562021fbac89f9a67a12979eaf66bad92e15af69de5bc4c7e159ad78eaeeb79c9b98c63a3e47cd38bbcab5d2e624309e0d509c7271dff212316e1da1fcc5be387ef331d4a3a9670bdfee7ccf98c44893f0f69348eba9139cd3597f8e6dac1f9da7178e78cc3bddcbb9ff40d3397596f3fe7bdcffdde3c0000000000000000000000000078376c7a61d4565ba78c95ddcbc7c7bf8d133a9bb365208e854cc3a817b669eb3273baf2d1aef08db1bb17a53ae4a7cbb8ff59b2173f74a99aecf20f1b4ff9c12a8131c618638c31c618638c31c618638c31c618638c31c618638c31c618e3ffd81bb1cb6df664f24a65c52eafb7aa94cfdd456b8caa5d6694955f9a9f5f95ed8575b953f25bae9daeb79f1af3b9b6ceb485d34d2df6ea74cc4bd9f9dabefa6b059bf15e8abdecb453955fcf07beb7daecb3aa2995fcb8d3c787fec32fcefd4d09ab520000
\ No newline at end of file
diff --git a/resources/test/state/video_lowres_schip_draw_chip8_sprite_result.deflated b/resources/test/state/video_lowres_schip_draw_chip8_sprite_result.deflated
new file mode 100644
index 0000000..e69de29
diff --git a/resources/test/state/video_lowres_schip_draw_chip8_sprite_result.json b/resources/test/state/video_lowres_schip_draw_chip8_sprite_result.json
deleted file mode 100644
index 3780284..0000000
--- a/resources/test/state/video_lowres_schip_draw_chip8_sprite_result.json
+++ /dev/null
@@ -1 +0,0 @@
-{"num_cycles":0,"memory":{"memory":[240,144,144,144,240,32,96,32,32,112,240,16,240,128,240,240,16,240,16,240,144,144,240,16,16,240,128,240,16,240,240,128,240,144,240,240,16,32,64,64,240,144,240,144,240,240,144,240,16,240,240,144,240,144,144,224,144,224,144,224,240,128,128,128,240,224,144,144,144,224,240,128,240,128,240,240,128,240,128,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,144,144,144,144,144,144,144,144,240,32,96,160,32,32,32,32,32,32,112,240,16,16,16,240,128,128,128,128,240,240,16,16,16,240,16,16,16,16,240,144,144,144,144,240,16,16,16,16,16,240,128,128,128,240,16,16,16,16,240,240,128,128,128,240,144,144,144,144,240,240,16,16,16,16,16,16,16,16,16,240,144,144,144,240,144,144,144,144,240,240,144,144,144,240,16,16,16,16,240,240,144,144,144,240,144,144,144,144,144,224,144,144,144,224,144,144,144,144,224,240,128,128,128,128,128,128,128,128,240,224,144,144,144,144,144,144,144,144,224,240,128,128,128,240,128,128,128,128,240,240,128,128,128,240,128,128,128,128,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},"registers":{"registers":[0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,1],"i_register":5,"pc":514},"sound_timer":{"counter":0},"delay_timer":{"counter":255},"video_memory":{"memory":[false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false],"has_frame_changed":true,"current_res":"LowRes"},"state":"WaitingForInstruction","keypad":{"keys":[false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false]},"stack":{"items":[]},"quirk_mode":"SChipModern"}
\ No newline at end of file