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 @@ - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - { - "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" + - - - - - - - - - - - - - - - - + + + - - @@ -428,93 +242,16 @@ - - 1730734609486 + + 1748624969802 - - - - - - - - - - - - - - - \ 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