From cddbe0c46e62248fc62529219fef67449ec113f5 Mon Sep 17 00:00:00 2001 From: Trevor Merritt Date: Fri, 8 Nov 2024 09:42:28 -0500 Subject: [PATCH] fixes reset from exection completion adds 'default.oc8' adds control window size to state for load/save of settings maybe? moves TestCompressionTool code into InstructionUtil remove gemmautil and moves into gemma --- Cargo.lock | 12 +- Cargo.toml | 1 - gemma/Cargo.toml | 2 + {gemmautil => gemma}/src/bin/bin2hex.rs | 0 {gemmautil => gemma}/src/bin/ch8asm.rs | 18 + {gemmautil => gemma}/src/bin/ch8disasm.rs | 0 gemma/src/bin/stringcomp.rs | 57 --- gemma/src/bin/tct.rs | 41 +++ gemma/src/chip8/computer.rs | 24 +- gemma/src/chip8/computer_manager.rs | 2 +- gemma/src/chip8/cpu_states.rs | 3 +- gemma/src/chip8/delay_timer.rs | 2 +- gemma/src/chip8/instructions.rs | 12 +- gemma/src/chip8/keypad.rs | 2 +- gemma/src/chip8/quirk_modes.rs | 2 +- gemma/src/chip8/registers.rs | 2 +- gemma/src/chip8/sound_timer.rs | 2 +- gemma/src/chip8/stack.rs | 2 +- gemma/src/chip8/system_memory.rs | 2 +- gemma/src/chip8/util.rs | 129 ++++++- gemma/src/chip8/video.rs | 14 +- {gemmautil => gemma}/src/chip8_asm.pest | 0 {gemmautil => gemma}/tests/assmber_tests.rs | 0 gemma/tests/state_tests.rs | 38 +- gemma/tests/{ => unit_tests}/unit_tests.rs | 8 +- gemmaimgui/src/bin/gemmaimgui.rs | 1 - gemmaimgui/src/bin/support/emmagui_support.rs | 341 +++++++++--------- gemmaimgui/src/bin/support/gui_file_list.rs | 28 +- gemmaimgui/src/bin/support/mod.rs | 2 +- gemmaimgui/src/bin/support/ui_state.rs | 14 +- gemmautil/Cargo.toml | 10 - resources/custom/002-schip-scroll-tests.ch8 | Bin 26 -> 26 bytes resources/custom/sinusoid_schip.ch8 | Bin 0 -> 282 bytes resources/roms/gradsim.ch8 | Bin 0 -> 1326 bytes resources/roms/octo-default.ch8 | Bin 0 -> 56 bytes resources/roms/sinusoid_schip.ch8 | Bin 0 -> 282 bytes resources/roms/vertical_clip.ch8 | Bin 0 -> 103 bytes .../state/computer_001_system_zero_state.tct | Bin 0 -> 462 bytes ..._001_round_trip_serialize_deserialize.json | 2 +- ...trip_serialize_deserialize_compressed.tflt | 1 - ...lowres_schip_draw_chip8_sprite_result.json | 0 41 files changed, 464 insertions(+), 310 deletions(-) rename {gemmautil => gemma}/src/bin/bin2hex.rs (100%) rename {gemmautil => gemma}/src/bin/ch8asm.rs (74%) rename {gemmautil => gemma}/src/bin/ch8disasm.rs (100%) delete mode 100644 gemma/src/bin/stringcomp.rs create mode 100644 gemma/src/bin/tct.rs rename {gemmautil => gemma}/src/chip8_asm.pest (100%) rename {gemmautil => gemma}/tests/assmber_tests.rs (100%) rename gemma/tests/{ => unit_tests}/unit_tests.rs (99%) delete mode 100644 gemmautil/Cargo.toml create mode 100644 resources/custom/sinusoid_schip.ch8 create mode 100644 resources/roms/gradsim.ch8 create mode 100644 resources/roms/octo-default.ch8 create mode 100644 resources/roms/sinusoid_schip.ch8 create mode 100644 resources/roms/vertical_clip.ch8 create mode 100644 resources/test/state/computer_001_system_zero_state.tct delete mode 100644 resources/test/state/smoke_002_round_trip_serialize_deserialize_compressed.tflt delete mode 100644 resources/test/state/video_lowres_schip_draw_chip8_sprite_result.json diff --git a/Cargo.lock b/Cargo.lock index c08abba..4109af0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1789,6 +1789,8 @@ dependencies = [ "flate2", "hex", "log", + "pest", + "pest_derive", "pretty_env_logger", "rand 0.9.0-alpha.2", "serde", @@ -1845,16 +1847,6 @@ dependencies = [ "gemma", ] -[[package]] -name = "gemmautil" -version = "0.1.0" -dependencies = [ - "clap", - "gemma", - "pest", - "pest_derive", -] - [[package]] name = "generic-array" version = "0.14.7" diff --git a/Cargo.toml b/Cargo.toml index 0d87745..6e4967b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,6 @@ members = [ "gemmaimgui", "gemmatelnet", "gemmasdl2", - "gemmautil", ] resolver = "2" diff --git a/gemma/Cargo.toml b/gemma/Cargo.toml index c9ac8c0..4f1af75 100644 --- a/gemma/Cargo.toml +++ b/gemma/Cargo.toml @@ -16,3 +16,5 @@ serde_json.workspace = true flate2 = "1.0" clap = { version = "4.5.20", features = ["derive"] } hex = "0.4.3" +pest = { version = "2.7.14" } +pest_derive = { version = "2.7.14"} \ No newline at end of file diff --git a/gemmautil/src/bin/bin2hex.rs b/gemma/src/bin/bin2hex.rs similarity index 100% rename from gemmautil/src/bin/bin2hex.rs rename to gemma/src/bin/bin2hex.rs diff --git a/gemmautil/src/bin/ch8asm.rs b/gemma/src/bin/ch8asm.rs similarity index 74% rename from gemmautil/src/bin/ch8asm.rs rename to gemma/src/bin/ch8asm.rs index 914ecd4..114abab 100644 --- a/gemmautil/src/bin/ch8asm.rs +++ b/gemma/src/bin/ch8asm.rs @@ -2,6 +2,7 @@ use gemma::chip8::util::InstructionUtil; use gemma::chip8::{instructions::Chip8CpuInstructions, quirk_modes::QuirkMode}; use std::fs::{self, File}; use std::io::Write; +use clap::{Arg, Command}; // Ch8Asm // Converts well formed CH8ASM. // no variables. @@ -16,9 +17,26 @@ use pest_derive::Parser; #[grammar = "chip8_asm.pest"] pub struct Chip8AsmParser; + fn main() { println!("Taxation is Theft"); + let matches = Command::new("Chip8Assembler") + .version("0.0.1") + .author("Trevor Merritt ") + .about("Tool to assemble simple ASM into Chip8 Machine code") + .arg( + Arg::new("input-file") + .help("Name of file to assemble") + .required(true) + ) + .arg( + Arg::new("output-file") + .help("Name of file to create") + .required(false) + ) + .get_matches(); + let unparsed = fs::read_to_string("resources/test/gemma_disassembler_manual_document.asc") .expect("Unable to read input"); diff --git a/gemmautil/src/bin/ch8disasm.rs b/gemma/src/bin/ch8disasm.rs similarity index 100% rename from gemmautil/src/bin/ch8disasm.rs rename to gemma/src/bin/ch8disasm.rs diff --git a/gemma/src/bin/stringcomp.rs b/gemma/src/bin/stringcomp.rs deleted file mode 100644 index 0b235bf..0000000 --- a/gemma/src/bin/stringcomp.rs +++ /dev/null @@ -1,57 +0,0 @@ -use clap::{Parser, Subcommand}; -use flate2::{write::{GzEncoder, GzDecoder}, Compression}; -use std::io::prelude::*; -use std::io::{self, Write}; - -#[derive(Parser)] -#[command(author, version, about = "Compress or decompress a string", long_about = None)] -struct Cli { - /// Subcommand: either 'compress' or 'decompress' - #[command(subcommand)] - command: Commands, -} - -#[derive(Subcommand)] -enum Commands { - /// Compress the input string - Compress { - /// The string to compress - input: String, - }, - /// Decompress the input string (must be compressed format) - Decompress { - /// The compressed string to decompress, in hex format - input: String, - }, -} - -fn compress_string(input: &str) -> Vec { - let mut encoder = GzEncoder::new(Vec::new(), Compression::default()); - encoder.write_all(input.as_bytes()).expect("Compression failed"); - encoder.finish().expect("Failed to finish compression") -} - -fn decompress_string(input: &[u8]) -> String { - let mut decoder = GzDecoder::new(Vec::new()); - decoder.write_all(input).expect("Decompression failed"); - let decompressed_data = decoder.finish().expect("Failed to finish decompression"); - String::from_utf8(decompressed_data).expect("Invalid UTF-8") -} - -fn main() { - let cli = Cli::parse(); - - match cli.command { - Commands::Compress { input } => { - let compressed = compress_string(&input); - // Convert to hex format for easier readability in the terminal - println!("Compressed (hex): {:?} / from {}b to {}b", hex::encode(compressed.clone()), input.len(), compressed.len()); - } - Commands::Decompress { input } => { - // Decode hex string back to bytes - let compressed_bytes = hex::decode(input).expect("Invalid hex input"); - let decompressed = decompress_string(&compressed_bytes); - println!("Decompressed: {}", decompressed); - } - } -} diff --git a/gemma/src/bin/tct.rs b/gemma/src/bin/tct.rs new file mode 100644 index 0000000..2e17380 --- /dev/null +++ b/gemma/src/bin/tct.rs @@ -0,0 +1,41 @@ +use clap::{ArgGroup, Parser}; +use gemma::chip8::util::InstructionUtil; +/// TCT +/// Test Compression Tool +/// +/// A Tool to take a plaintext JSON object of the memory state +/// for the CHIP-8 emulator and compress the input into compressed +/// text. Test sizes go from ~22k to ~1k which makes a difference over +/// hundreds of tests +/// Written by Trevor Merritt and optimized by ChatGPT + +/// Simple file compression and decompression tool +#[derive(Parser, Debug)] +#[command(author, version, about)] +#[clap(group( + ArgGroup::new("mode") + .required(true) + .args(["compress", "decompress"]), +))] +struct Cli { + /// The filename to process + filename: String, + + /// Compress the file + #[arg(short = 'c', long = "compress", group = "mode")] + compress: bool, + + /// Decompress the file + #[arg(short = 'd', long = "decompress", group = "mode")] + decompress: bool, +} + +fn main() { + let cli = Cli::parse(); + + if cli.compress { + InstructionUtil::compress_file(cli.filename).expect("Derp. Can't do that."); + } else if cli.decompress { + InstructionUtil::decompress_file(cli.filename).expect("Derp. Can't do that."); + } +} diff --git a/gemma/src/chip8/computer.rs b/gemma/src/chip8/computer.rs index c34db82..cc2fd33 100644 --- a/gemma/src/chip8/computer.rs +++ b/gemma/src/chip8/computer.rs @@ -1,3 +1,8 @@ +use super::{ + cpu_states::Chip8CpuStates, instructions::Chip8CpuInstructions, + system_memory::Chip8SystemMemory, video::Chip8Video, +}; +use crate::chip8::cpu_states::Chip8CpuStates::WaitingForInstruction; use crate::chip8::delay_timer::DelayTimer; use crate::chip8::keypad::Keypad; use crate::chip8::quirk_modes::QuirkMode; @@ -7,12 +12,7 @@ use crate::chip8::stack::Chip8Stack; use log::debug; use serde::{Deserialize, Serialize}; -use super::{ - cpu_states::Chip8CpuStates, instructions::Chip8CpuInstructions, - system_memory::Chip8SystemMemory, video::Chip8Video, -}; - -#[derive(Clone, Serialize, Deserialize, Debug)] +#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Chip8Computer { pub num_cycles: i32, pub memory: Chip8SystemMemory, @@ -52,6 +52,7 @@ impl Chip8Computer { self.stack.reset(); self.memory.reset(quirk_mode); self.quirk_mode = quirk_mode; + self.state = WaitingForInstruction; } pub fn dump_keypad_to_string(&self) -> String { @@ -117,8 +118,19 @@ impl Chip8Computer { Chip8CpuStates::WaitingForKey => { debug!("waiting for a key press..."); } + Chip8CpuStates::ExecutionComplete => { + debug!("Execution has completed."); + self.num_cycles += 1; + } _ => {} } self } + + pub fn serialize(&self) -> String { + serde_json::to_string(&self).expect("Serialization failed") + } + pub fn deserialize(from: String) -> Chip8Computer { + serde_json::from_str(&from).expect("Failed to deserialize") + } } diff --git a/gemma/src/chip8/computer_manager.rs b/gemma/src/chip8/computer_manager.rs index 9cea84f..2401a1e 100644 --- a/gemma/src/chip8/computer_manager.rs +++ b/gemma/src/chip8/computer_manager.rs @@ -118,7 +118,7 @@ impl Chip8ComputerManager { self.computer.load_bytes_to_memory(0x200, &bytes_to_load); } - pub fn dump_to_string(&self, dump_type: ManagerDumpables) -> String { + pub fn dump_to_string(&self, dump_type: ManagerDumpables) -> String{ match dump_type { ManagerDumpables::Video => self.computer.video_memory.format_as_string(), ManagerDumpables::Registers => self.computer.registers.format_as_string(), diff --git a/gemma/src/chip8/cpu_states.rs b/gemma/src/chip8/cpu_states.rs index b0fa9d2..6cedeb3 100644 --- a/gemma/src/chip8/cpu_states.rs +++ b/gemma/src/chip8/cpu_states.rs @@ -1,10 +1,11 @@ use serde::{Deserialize, Serialize}; -#[derive(Clone, Copy, Default, Serialize, Deserialize, Debug)] +#[derive(Clone, Copy, Default, Serialize, Deserialize, Debug, PartialEq)] pub enum Chip8CpuStates { #[default] WaitingForInstruction, WaitingForKey, ExecutingInstruction, Error, + ExecutionComplete, } diff --git a/gemma/src/chip8/delay_timer.rs b/gemma/src/chip8/delay_timer.rs index cee823a..0b8b45f 100644 --- a/gemma/src/chip8/delay_timer.rs +++ b/gemma/src/chip8/delay_timer.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -#[derive(Clone, Copy, Serialize, Deserialize, Debug)] +#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq)] pub struct DelayTimer { counter: u8, } diff --git a/gemma/src/chip8/instructions.rs b/gemma/src/chip8/instructions.rs index 08fd579..3d2e043 100644 --- a/gemma/src/chip8/instructions.rs +++ b/gemma/src/chip8/instructions.rs @@ -11,7 +11,7 @@ use std::ascii::AsciiExt; use std::fmt::{Debug, Display, Formatter}; use std::ops::BitAnd; use std::time::Instant; - +use crate::chip8::cpu_states::Chip8CpuStates; /* nnn or addr - A 12-bit value, the lowest 12 bits of the instruction n or nibble - A 4-bit value, the lowest 4 bits of the instruction @@ -326,9 +326,9 @@ impl Chip8CpuInstructions { Chip8CpuInstructions::HIGH => INST_HIGH, Chip8CpuInstructions::ORY(_, _) => INST_ORY, JPX(_, _) => INST_JPX, + DW(_) => INST_DW, XXXXERRORINSTRUCTION => "XX ERROR XX", SCU(_) => INST_SCU, - DW(_) => INST_DW, } } @@ -681,7 +681,7 @@ impl Chip8CpuInstructions { } } pub fn execute(&self, input: &mut Chip8Computer) -> Chip8Computer { - // print!("INSTRUCTION {}", self); + println!("INSTRUCTION {}", self); let start_time = Instant::now(); let start_pc = input.registers.peek_pc(); input.registers.poke_pc(start_pc + 2); @@ -700,6 +700,12 @@ impl Chip8CpuInstructions { } // 0x1nnn Jump to Address Chip8CpuInstructions::JPA(new_address) => { + // if the jump is to the same address as we are at, we are in an infinite + // loop and the program is effectively done. stop the CPU. + if *new_address == start_pc { + input.state = Chip8CpuStates::ExecutionComplete; + println!("Execution complete."); + } input.registers.poke_pc(*new_address); } // 0x2nnn Call Subroutine diff --git a/gemma/src/chip8/keypad.rs b/gemma/src/chip8/keypad.rs index 1a032a6..4f4d0aa 100644 --- a/gemma/src/chip8/keypad.rs +++ b/gemma/src/chip8/keypad.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use crate::constants::CHIP8_KEYBOARD; -#[derive(Clone, Copy, Default, Serialize, Deserialize, Debug)] +#[derive(Clone, Copy, Default, Serialize, Deserialize, Debug, PartialEq)] pub struct Keypad { keys: [bool; 0x10], } diff --git a/gemma/src/chip8/quirk_modes.rs b/gemma/src/chip8/quirk_modes.rs index 26d3caa..0a26ab5 100644 --- a/gemma/src/chip8/quirk_modes.rs +++ b/gemma/src/chip8/quirk_modes.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use std::fmt::Display; -#[derive(Default, Clone, Serialize, Deserialize, Copy, Debug)] +#[derive(Default, Clone, Serialize, Deserialize, Copy, Debug, PartialEq)] pub enum QuirkMode { Chip8, XOChip, diff --git a/gemma/src/chip8/registers.rs b/gemma/src/chip8/registers.rs index 4fbdc3e..b19ee71 100644 --- a/gemma/src/chip8/registers.rs +++ b/gemma/src/chip8/registers.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; /// Registers. numbered 1-16 publicly. /// Privately using zero base array so -1 to shift from pub to priv. -#[derive(Clone, Copy, Serialize, Deserialize, Debug)] +#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq)] pub struct Chip8Registers { pub registers: [u8; 16], pub i_register: u16, diff --git a/gemma/src/chip8/sound_timer.rs b/gemma/src/chip8/sound_timer.rs index 8cf1f31..df2e9bc 100644 --- a/gemma/src/chip8/sound_timer.rs +++ b/gemma/src/chip8/sound_timer.rs @@ -1,7 +1,7 @@ use log::trace; use serde::{Deserialize, Serialize}; -#[derive(Clone, Copy, Serialize, Deserialize, Debug)] +#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq)] pub struct SoundTimer { counter: i32, } diff --git a/gemma/src/chip8/stack.rs b/gemma/src/chip8/stack.rs index eb58ab3..7508510 100644 --- a/gemma/src/chip8/stack.rs +++ b/gemma/src/chip8/stack.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -#[derive(Clone, Default, Serialize, Deserialize, Debug)] +#[derive(Clone, Default, Serialize, Deserialize, Debug, PartialEq)] pub struct Chip8Stack { items: Vec, } diff --git a/gemma/src/chip8/system_memory.rs b/gemma/src/chip8/system_memory.rs index 5a68a44..0d3a017 100644 --- a/gemma/src/chip8/system_memory.rs +++ b/gemma/src/chip8/system_memory.rs @@ -7,7 +7,7 @@ use serde::Serialize; use super::quirk_modes; use super::quirk_modes::QuirkMode; -#[derive(Clone, Serialize, Deserialize, Debug)] +#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Chip8SystemMemory { memory: Vec, } diff --git a/gemma/src/chip8/util.rs b/gemma/src/chip8/util.rs index c243951..0a6c600 100644 --- a/gemma/src/chip8/util.rs +++ b/gemma/src/chip8/util.rs @@ -1,3 +1,11 @@ +use flate2::read::ZlibDecoder; +use std::fs::File; +use std::io::{self, Read, Write}; +use std::path::{Path, PathBuf}; + +use flate2::write::ZlibEncoder; +use flate2::Compression; + pub struct InstructionUtil {} impl InstructionUtil { @@ -29,7 +37,6 @@ impl InstructionUtil { } pub fn join_bytes(high: u8, low: u8) -> u16 { - (high as u16) << 8 | low as u16 } @@ -40,7 +47,7 @@ impl InstructionUtil { // n or nibble - A 4-bit value, the lowest 4 bits of the instruction pub fn read_nibble_from_instruction(instruction_to_read_from: u16) -> u8 { - ( instruction_to_read_from & 0x000F )as u8 + (instruction_to_read_from & 0x000F) as u8 } // x - A 4-bit value, the lower 4 bits of the high byte of the instruction @@ -61,4 +68,122 @@ impl InstructionUtil { pub fn read_upper_byte_lower_nibble(to_read_from: u16) -> u8 { ((to_read_from & 0x0f00) >> 8) as u8 } + + pub fn compress_file>(to_compress: P) -> io::Result<()> { + let to_compress_path = to_compress.as_ref(); + let target_filename = format!("{}.tct", to_compress_path.display()); + println!( + "Compressing file: {} to {}", + to_compress_path.display(), + target_filename + ); + + // Open the source file + let mut source_file = File::open(&to_compress_path)?; + + // Read the entire file into a buffer + let mut read_buffer = Vec::new(); + source_file.read_to_end(&mut read_buffer)?; + + // Initialize the encoder and compress the read data + let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default()); + encoder.write_all(&read_buffer)?; + let encoded_data = encoder.finish()?; + + println!( + "Compressed {} bytes into {} bytes.", + read_buffer.len(), + encoded_data.len() + ); + + // Write the encoded data to the target file + let mut target_file = File::create(target_filename)?; + target_file.write_all(&encoded_data)?; + + Ok(()) + } + + pub fn decompress_file_to_string>(to_decompress: P) -> io::Result { + let to_decompress_path = to_decompress.as_ref(); + + // Ensure the file has the expected `.tct` extension + if to_decompress_path.extension() != Some("tct".as_ref()) { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "File must have a .tct extension", + )); + } + + println!( + "Decompressing file: {} to string", + to_decompress_path.display() + ); + + // Open the compressed file and set up the decoder + let compressed_file = File::open(&to_decompress_path)?; + let mut decoder = ZlibDecoder::new(compressed_file); + + // Read decompressed data + let mut decompressed_data = Vec::new(); + decoder.read_to_end(&mut decompressed_data)?; + + // Convert decompressed byte data to a UTF-8 String + match String::from_utf8(decompressed_data) { + Ok(decompressed_string) => { + // Optionally, write decompressed data to a new file + println!( + "Decompressed {} bytes into {} bytes.", + to_decompress_path.metadata()?.len(), + decompressed_string.len() + ); + + Ok(decompressed_string) + } + Err(e) => { + // Handle invalid UTF-8 data (if the decompressed data isn't valid UTF-8) + Err(io::Error::new(io::ErrorKind::InvalidData, e)) + } + } + } + pub fn decompress_file>(to_decompress: P) -> io::Result<()> { + let to_decompress_path = to_decompress.as_ref(); + + // Ensure the file has the expected `.tct` extension + if to_decompress_path.extension() != Some("tct".as_ref()) { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "File must have a .tct extension", + )); + } + + // Derive the output filename by removing the `.tct` extension + let mut output_filename = PathBuf::from(to_decompress_path); + output_filename.set_extension("untct"); // Remove .tct extension to restore original file name + + println!( + "Decompressing file: {} to {}", + to_decompress_path.display(), + output_filename.display() + ); + + // Open the compressed file and set up the decoder + let compressed_file = File::open(&to_decompress_path)?; + let mut decoder = ZlibDecoder::new(compressed_file); + + // Read decompressed data + let mut decompressed_data = Vec::new(); + decoder.read_to_end(&mut decompressed_data)?; + + // Write decompressed data to the output file + let mut output_file = File::create(&output_filename)?; + output_file.write_all(&decompressed_data)?; + + println!( + "Decompressed {} bytes into {} bytes.", + to_decompress_path.metadata()?.len(), + decompressed_data.len() + ); + + Ok(()) + } } diff --git a/gemma/src/chip8/video.rs b/gemma/src/chip8/video.rs index 146d735..f00fef9 100644 --- a/gemma/src/chip8/video.rs +++ b/gemma/src/chip8/video.rs @@ -6,13 +6,13 @@ use crate::constants::{ use log::debug; use serde::{Deserialize, Serialize}; -#[derive(Clone, Copy, Serialize, Deserialize, Debug)] +#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq)] pub enum Chip8VideoModes { LowRes, HighRes, } -#[derive(Clone, Serialize, Deserialize, Debug)] +#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Chip8Video { memory: Vec, pub has_frame_changed: bool, @@ -36,7 +36,8 @@ impl Chip8Video { } pub fn set_lowres(&mut self) { - self.current_res = LowRes + self.current_res = LowRes; + self.cls(); } pub fn get_screen_resolution(&mut self) -> Chip8VideoModes { @@ -152,7 +153,6 @@ impl Chip8Video { } pub fn scroll_right(&mut self) { - println!("SCROLLRIGHTPRE:::[{}]", self.format_as_string()); let (width, height) = self.get_resolution(); for current_row in 0..height { @@ -168,11 +168,9 @@ impl Chip8Video { // Clear the first 4 pixels in the current row self.memory[row_offset..row_offset + 4].fill(false); } - println!("SCROLLRIGHTPOST:::[{}]", self.format_as_string()); } pub fn scroll_left(&mut self) { - println!("SCROLLLEFTPRE:::[{}]", self.format_as_string()); let (width, height) = self.get_resolution(); for current_row in 0..height { @@ -181,7 +179,6 @@ impl Chip8Video { let target: usize = (row_offset + current_column) as usize; let source: usize = target + 4; self.memory[target] = self.memory[source]; - println!("Moving from {source} to {target}"); } let clear_start: usize = (row_offset + width - 4) as usize; @@ -189,7 +186,6 @@ impl Chip8Video { self.memory[clear_start..clear_end].fill(false); } - println!("SCROLLLEFTPOST:::[{}]", self.format_as_string()); } pub fn scroll_up(&mut self, how_far: &u8) { @@ -240,7 +236,7 @@ impl Default for Chip8Video { Chip8Video { memory: mem, has_frame_changed: false, - current_res: Chip8VideoModes::LowRes, + current_res: LowRes, } } } diff --git a/gemmautil/src/chip8_asm.pest b/gemma/src/chip8_asm.pest similarity index 100% rename from gemmautil/src/chip8_asm.pest rename to gemma/src/chip8_asm.pest diff --git a/gemmautil/tests/assmber_tests.rs b/gemma/tests/assmber_tests.rs similarity index 100% rename from gemmautil/tests/assmber_tests.rs rename to gemma/tests/assmber_tests.rs diff --git a/gemma/tests/state_tests.rs b/gemma/tests/state_tests.rs index e0f51bf..987df04 100644 --- a/gemma/tests/state_tests.rs +++ b/gemma/tests/state_tests.rs @@ -1,26 +1,24 @@ +use std::fs::File; use flate2::write::{GzDecoder, GzEncoder}; use flate2::Compression; use gemma::chip8::computer::Chip8Computer; +use gemma::chip8::util::InstructionUtil; +use std::io; use std::io::prelude::*; fn load_result(to_load: &str) -> String { - let full_path = format!("resources/test/state/{}", to_load); + let full_path = format!("../resources/test/state/{}", to_load); println!("Loading state => (([{}]))", full_path); std::fs::read_to_string(full_path).unwrap() } fn load_compressed_result(file_path: &str) -> io::Result { - // Load the compressed file contents - let compressed_data = fs::read(file_path)?; - - // Create a GzDecoder to uncompress the data - let mut decoder = GzDecoder::new(&compressed_data[..]); - let mut decompressed_data = String::new(); - - // Read the decompressed data directly into a String - decoder.read_to_string(&mut decompressed_data)?; - - Ok(decompressed_data) + let full_path = format!("../resources/test/state/{}", file_path); + println!( + "ATTEMPTING TO LOAD {} AS A COMPRESSED TEST RESULT.", + full_path + ); + InstructionUtil::decompress_file_to_string(full_path) } fn load_rom(to_load: &str) -> Vec { @@ -33,21 +31,21 @@ fn test_serialization_round_trip() { let expected_json = load_result("smoke_001_round_trip_serialize_deserialize.json"); // Serialize the Chip8Computer instance - let serialized = serde_json::to_string(&original_computer).expect("Serialization failed"); + let serialized = Chip8Computer::serialize(&original_computer); + let deserialized = Chip8Computer::deserialize(expected_json.clone()); // Compare the serialized output to the expected JSON println!("Serialized Output: [{}]", serialized); + assert_eq!( serialized.trim(), - expected_json.trim(), + expected_json.clone().trim(), "Serialized output does not match expected JSON" ); // Deserialize back to Chip8Computer and assert equality - let deserialized_computer: Chip8Computer = - serde_json::from_str(&serialized).expect("Deserialization failed"); assert_eq!( - deserialized_computer, original_computer, + deserialized, original_computer, "Deserialized instance does not match the original" ); } @@ -55,9 +53,9 @@ fn test_serialization_round_trip() { #[test] fn computer_001_system_zero_state() { let x = Chip8Computer::new(); - let expected_string = load_compressed_result("smoke_002_round_trip_serialize_deserialize.tflt"); - let serialized = serde_json::to_string(&x).unwrap(); + let expected_string = load_compressed_result("computer_001_system_zero_state.tct") + .expect("Unable to read result"); + let serialized = x.serialize(); assert_eq!(serialized, expected_string); } -} diff --git a/gemma/tests/unit_tests.rs b/gemma/tests/unit_tests/unit_tests.rs similarity index 99% rename from gemma/tests/unit_tests.rs rename to gemma/tests/unit_tests/unit_tests.rs index 971c64e..7095f57 100644 --- a/gemma/tests/unit_tests.rs +++ b/gemma/tests/unit_tests/unit_tests.rs @@ -35,11 +35,13 @@ fn decoder_test_invalid_instructions() { ]; for i in invalid_to_encode { - assert_eq!(Chip8CpuInstructions::decode(i, &Chip8).encode(), 0xffff); + println!("TESTING 0x{i:04x}"); + println!("DECOODED TO {:?}", Chip8CpuInstructions::decode(i, &Chip8)); assert!(matches!( Chip8CpuInstructions::decode(i, &Chip8), - Chip8CpuInstructions::XXXXERRORINSTRUCTION - )); + Chip8CpuInstructions::DW(i) + ) || + matches!(Chip8CpuInstructions::decode(i, &Chip8), Chip8CpuInstructions::XXXXERRORINSTRUCTION)); } } diff --git a/gemmaimgui/src/bin/gemmaimgui.rs b/gemmaimgui/src/bin/gemmaimgui.rs index 2440ac9..b1a31fa 100644 --- a/gemmaimgui/src/bin/gemmaimgui.rs +++ b/gemmaimgui/src/bin/gemmaimgui.rs @@ -74,7 +74,6 @@ fn main() { system.wait_for_instruction(); } else { // do we need to release it? - if system.is_key_pressed(key_reg) { system.release_key(key_reg); } diff --git a/gemmaimgui/src/bin/support/emmagui_support.rs b/gemmaimgui/src/bin/support/emmagui_support.rs index 3dad500..90902aa 100644 --- a/gemmaimgui/src/bin/support/emmagui_support.rs +++ b/gemmaimgui/src/bin/support/emmagui_support.rs @@ -12,6 +12,8 @@ use log::debug; use std::fs::File; use std::io::Read; use std::path::{Path, PathBuf}; +use imgui::sys::ImGuiIO; +use gemma::chip8::instructions::Chip8CpuInstructions; const ROM_ROOT: &str = "resources/roms"; @@ -43,70 +45,186 @@ impl GemmaImguiSupport { pub fn video_display(system_to_control: &Chip8Computer, gui_state: &ImGuiUiState, ui: &Ui) { // draw area size let (width, height) = system_to_control.video_memory.get_resolution(); - let draw_area_size = ui.io().display_size; - // println!("DRAW_AREA_SIZE = {}x{}", draw_area_size[0], draw_area_size[1]); - let cell_width = ((draw_area_size[0] as i32 / width) * 6) / 10; - let cell_height = ((draw_area_size[1] as i32 / height) * 6) / 10; + ui.window("Video") + .size([gui_state.video_window_size[0] as f32, gui_state.video_window_size[1] as f32], Condition::Once) + .build(|| { + let draw_area_size = ui.window_size(); + let draw_offset = ui.window_pos(); + // now lets move the draw_offset by 0,20 to get it off the window title bar + let draw_offset = [draw_offset[0], draw_offset[1] + 20.0]; + // and reduce the draw area size by the same values. {} + let draw_area_size = [draw_area_size[0], draw_area_size[1] - 20.0]; + // println!("DRAW_AREA_SIZE = {}x{}", draw_area_size[0], draw_area_size[1]); + let cell_width = ((draw_area_size[0] as i32 / width)); + let cell_height = ((draw_area_size[1] as i32 / height)); - let origin = ui.cursor_pos(); - let fg = ui.get_foreground_draw_list(); - if system_to_control.video_memory.is_highres() { - // ui.text("High Def Video here"); - for current_row in 0..=height { - let y_offset = origin[1] as i32 + (current_row * cell_height); - for current_column in 0..=width { - let x_offset = origin[0] as i32 + (current_column * cell_width); - let current_origin = [x_offset as f32, y_offset as f32]; - let current_limit = [ - (x_offset + cell_width) as f32, - (y_offset + cell_height) as f32, - ]; - let memory_offset = (current_row * width + current_column) as u16; - let to_render = system_to_control.video_memory.peek(memory_offset); - let color: ImColor32 = if to_render { - gui_state.on_colour - } else { - gui_state.off_colour - }; - fg.add_rect_filled_multicolor( - current_origin, - current_limit, - color, - color, - color, - color, - ); + let origin = draw_offset; + let fg = ui.get_foreground_draw_list(); + for current_row in 0..height { + let y_offset = origin[1] as i32 + (current_row * cell_height); + for current_column in 0..width { + let x_offset = origin[0] as i32 + (current_column * cell_width); + let current_origin = [x_offset as f32, y_offset as f32]; + let current_limit = [ + (x_offset + cell_width) as f32, + (y_offset + cell_height) as f32, + ]; + let memory_offset = (current_row * width + current_column) as u16; + let to_render = system_to_control.video_memory.peek(memory_offset); + let color: ImColor32 = if to_render { + gui_state.on_colour + } else { + gui_state.off_colour + }; + fg.add_rect_filled_multicolor( + current_origin, + current_limit, + color, + color, + color, + color, + ); + } + } + }).expect("cant draw the video i guess"); + } + + pub fn quirks_picker(system: &mut Chip8ComputerManager, + ui: &Ui) { + let selectors = [Chip8, SChipModern, XOChip]; + for current_selector in selectors { + let mut working_selector = + ui.selectable_config(current_selector.clone().to_string()); + match system.quirks_mode() { + Chip8 => { + working_selector = working_selector.selected(true); + } + SChipModern => { + working_selector = working_selector.selected(true); + } + XOChip => { + working_selector = working_selector.selected(true); } } - } else { - for current_row in 0..height { - let y_offset = origin[1] as i32 + (current_row * cell_height); - for current_column in 0..width { - let x_offset = origin[0] as i32 + (current_column * cell_width); - let current_origin = [x_offset as f32, y_offset as f32]; - let current_limit = [ - (x_offset + cell_width) as f32, - (y_offset + cell_height) as f32, - ]; - let memory_offset = (current_row * width + current_column) as u16; - let to_render = system_to_control.video_memory.peek(memory_offset); - let color: ImColor32 = if to_render { - gui_state.on_colour - } else { - gui_state.off_colour - }; - fg.add_rect_filled_multicolor( - current_origin, - current_limit, - color, - color, - color, - color, + if working_selector.build() { + system.reset(current_selector); + println!("CLICK ON {}", ¤t_selector); + } + } + } + + + fn control_pickers( + system: &mut Chip8ComputerManager, + gui_state: &mut ImGuiUiState, + ui: &Ui, + ) { + if CollapsingHeader::new("Controls").build(ui) { + // if the system has no program loaded hide the buttons. + let bytes: [u8; 2] = [ + system.state().memory.peek(0x200), + system.state().memory.peek(0x201), + ]; + let show_buttons = true; // bytes[0] != 0 || bytes[1] == 0xe0; + + if show_buttons { + if ui.button("Step") { + system.step(); + }; + ui.same_line(); + if ui.button("Run") { + system.start(); + } + } + ui.same_line(); + if ui.button("Stop") { + system.stop(); + } + ui.same_line(); + if ui.button("Reset") { + system.reset(system.quirks_mode()); + } + if ui.button("Dump Video Memory") { + println!("{}", system.dump_to_string(Video)); + } + ui.same_line(); + if ui.button("Dump Keypad State") { + println!("{}", system.dump_to_string(Keyboard)); + } + ui.same_line(); + if ui.button("Dump Registers") { + println!("{}", system.dump_to_string(Registers)); + } + } + } + + fn system_summary( + system: &Chip8ComputerManager, + ui: &Ui, + ) { + /* System Step Counter */ + ui.text(format!("Step {:04x}", system.num_cycles()).as_str()); + ui.text(format!("Mode {}", system.quirks_mode())); + } + + fn rom_lister( + system: &mut Chip8ComputerManager, + gui_state: &mut ImGuiUiState, + ui: &Ui, + ) { + /* ROM Lister */ + if CollapsingHeader::new("Roms").build(ui) { + let new_filename = GuiFileList::display_path( + gui_state.roms_root_path.clone(), + &gui_state.filename_to_load, + ui, + ); + if !new_filename.is_empty() { + if new_filename != gui_state.filename_to_load { + debug!("NEW FILENAME SELECTED -> {new_filename}"); + gui_state.filename_to_load = new_filename; + } + if ui.button("Load Program") { + let mut buffer: Vec = Vec::new(); + let full_name = format!( + "{}/{}", + gui_state + .roms_root_path + .clone() + .as_os_str() + .to_string_lossy(), + gui_state.filename_to_load.to_string() ); + debug!("PREPARING TO LOAD {}", full_name); + + let input_file = File::open(Path::new(&full_name)); + input_file + .unwrap() + .read_to_end(&mut buffer) + .expect("Unable to read rom."); + system.load_new_program_to_system_memory(buffer); } } } } + + fn display_options( + gui_state: &mut ImGuiUiState, + ui: &Ui, + ) { + if CollapsingHeader::new("Options").build(ui) { + ui.checkbox("Show Memory", &mut gui_state.show_memory); + ui.same_line(); + ui.checkbox("Show Video", &mut gui_state.show_video); + ui.same_line(); + ui.checkbox("Show Registers", &mut gui_state.show_registers); + ui.same_line(); + ui.checkbox("Show Keypad", &mut gui_state.show_keypad); + ui.input_int("Target IPS", &mut gui_state.target_ips) + .build(); + }; + } + pub fn system_controls( system_to_control: &mut Chip8ComputerManager, gui_state: &mut ImGuiUiState, @@ -116,114 +234,15 @@ impl GemmaImguiSupport { ui.window("!!!! CONTROLS !!!!") .position([100.0, 640.0], Condition::FirstUseEver) .build(|| { - /* System Step Counter */ - ui.text(format!("Step {:04x}", system_to_control.num_cycles()).as_str()); - ui.text(format!("Mode {}", system_to_control.quirks_mode())); - /* ROM Lister */ - if CollapsingHeader::new("Roms").build(ui) { - let new_filename = GuiFileList::display_path( - gui_state.roms_root_path.clone(), - &gui_state.filename_to_load, - ui, - ); - if !new_filename.is_empty() { - if new_filename != gui_state.filename_to_load { - debug!("NEW FILENAME SELECTED -> {new_filename}"); - gui_state.filename_to_load = new_filename; - } - if ui.button("Load Program") { - let mut buffer: Vec = Vec::new(); - let full_name = format!( - "{}/{}", - gui_state - .roms_root_path - .clone() - .as_os_str() - .to_string_lossy(), - gui_state.filename_to_load.to_string() - ); - debug!("PREPARING TO LOAD {}", full_name); + GemmaImguiSupport::system_summary(system_to_control, ui); - let input_file = File::open(Path::new(&full_name)); - input_file - .unwrap() - .read_to_end(&mut buffer) - .expect("Unable to read rom."); - system_to_control.load_new_program_to_system_memory(buffer); - } - } - } + GemmaImguiSupport::rom_lister(system_to_control, gui_state, ui); - if CollapsingHeader::new("Controls").build(ui) { - // if the system has no program loaded hide the buttons. - let bytes: [u8; 2] = [ - system_to_control.state().memory.peek(0x200), - system_to_control.state().memory.peek(0x201), - ]; - let show_buttons = bytes[0] != 0 || bytes[1] == 0xe0; + GemmaImguiSupport::control_pickers(system_to_control, gui_state, ui); - if show_buttons { - if ui.button("Step") { - system_to_control.step(); - }; - ui.same_line(); - if ui.button("Run") { - system_to_control.start(); - } - } - ui.same_line(); - if ui.button("Stop") { - system_to_control.stop(); - } - ui.same_line(); - if ui.button("Reset") { - system_to_control.reset(system_to_control.quirks_mode()); - } - if ui.button("Dump Video Memory") { - println!("{}", system_to_control.dump_to_string(Video)); - } - ui.same_line(); - if ui.button("Dump Keypad State") { - debug!("{}", system_to_control.dump_to_string(Keyboard)); - } - ui.same_line(); - if ui.button("Dump Registers") { - debug!("{}", system_to_control.dump_to_string(Registers)); - } - } + GemmaImguiSupport::display_options(gui_state, ui); - if CollapsingHeader::new("Options").build(ui) { - ui.checkbox("Show Memory", &mut gui_state.show_memory); - ui.same_line(); - ui.checkbox("Show Video", &mut gui_state.show_video); - ui.same_line(); - ui.checkbox("Show Registers", &mut gui_state.show_registers); - ui.same_line(); - ui.checkbox("Show Keypad", &mut gui_state.show_keypad); - ui.input_int("Target IPS", &mut gui_state.target_ips) - .build(); - }; - - let selectors = [Chip8, SChipModern, XOChip]; - for current_selector in selectors { - let mut working_selector = - ui.selectable_config(current_selector.clone().to_string()); - match system_to_control.quirks_mode() { - Chip8 => { - working_selector = working_selector.selected(true); - } - SChipModern => { - working_selector = working_selector.selected(true); - } - XOChip => { - working_selector = working_selector.selected(true); - } - } - if working_selector.build() { - system_to_control.reset(current_selector); - println!("CLICK ON {}", ¤t_selector); - } - } + GemmaImguiSupport::quirks_picker(system_to_control, ui); }); } @@ -232,7 +251,7 @@ impl GemmaImguiSupport { .position([100.0, 640.0], Condition::FirstUseEver) .build(|| { ui.text("Registers"); - for i in 1..0x10 { + for i in 0..0x10 { ui.text(format!("V{:X}: {}", i, system.registers.peek(i))); if i != 7 { ui.same_line(); diff --git a/gemmaimgui/src/bin/support/gui_file_list.rs b/gemmaimgui/src/bin/support/gui_file_list.rs index 666c85e..a6054d1 100644 --- a/gemmaimgui/src/bin/support/gui_file_list.rs +++ b/gemmaimgui/src/bin/support/gui_file_list.rs @@ -1,7 +1,7 @@ use std::ffi::OsString; use std::fs::read_dir; use std::path::PathBuf; -use imgui::Ui; +use imgui::{ChildWindow, Ui}; use log::debug; pub struct GuiFileList {} @@ -20,16 +20,22 @@ impl GuiFileList { known_files.sort(); - for (index, entry) in known_files.iter().enumerate() { - let mut working_select = ui.selectable_config(entry.clone().into_string().unwrap().to_string()); - if *entry.to_str().unwrap() == *selected_filename.as_str() { - working_select = working_select.selected(true); - } - if working_select.build() { - debug!("SELECTED {index} / {entry:?}"); - working_filename = entry.clone().into_string().unwrap(); - }; - } + ui.child_window("Item List") + .size([0.0, 200.0]) + .border(false) + .build(|| { + for (index, entry) in known_files.iter().enumerate() { + let mut working_select = ui.selectable_config(entry.clone().into_string().unwrap().to_string()); + if *entry.to_str().unwrap() == *selected_filename.as_str() { + working_select = working_select.selected(true); + } + if working_select.build() { + debug!("SELECTED {index} / {entry:?}"); + working_filename = entry.clone().into_string().unwrap(); + }; + } + }); + working_filename } } diff --git a/gemmaimgui/src/bin/support/mod.rs b/gemmaimgui/src/bin/support/mod.rs index d0ee045..0a39bbf 100644 --- a/gemmaimgui/src/bin/support/mod.rs +++ b/gemmaimgui/src/bin/support/mod.rs @@ -179,7 +179,7 @@ pub fn create_context() -> imgui::Context { }), }, ]); - imgui.set_ini_filename(None); +// imgui.set_ini_filename(None); imgui } diff --git a/gemmaimgui/src/bin/support/ui_state.rs b/gemmaimgui/src/bin/support/ui_state.rs index e36219d..725e391 100644 --- a/gemmaimgui/src/bin/support/ui_state.rs +++ b/gemmaimgui/src/bin/support/ui_state.rs @@ -16,7 +16,9 @@ pub struct ImGuiUiState { pub frame_time: u32, pub last_frame_instant: Instant, pub target_ips: i32, - pub roms_root_path: PathBuf + pub roms_root_path: PathBuf, + pub video_window_size: [i32; 2], + pub control_window_size: [i32; 2] } impl Clone for ImGuiUiState { @@ -33,7 +35,9 @@ impl Clone for ImGuiUiState { frame_time: self.frame_time, last_frame_instant: self.last_frame_instant, target_ips: self.target_ips, - roms_root_path: self.roms_root_path.to_owned() + roms_root_path: self.roms_root_path.to_owned(), + video_window_size: self.video_window_size, + control_window_size: self.control_window_size } } } @@ -51,8 +55,10 @@ impl Default for ImGuiUiState { is_running: false, frame_time: 16, last_frame_instant: Instant::now(), - target_ips: 200000, - roms_root_path: PathBuf::from(ROMPATH_DEFAULT) + target_ips: 20, + roms_root_path: PathBuf::from(ROMPATH_DEFAULT), + control_window_size: [200, 600], + video_window_size: [800, 600] } } } diff --git a/gemmautil/Cargo.toml b/gemmautil/Cargo.toml deleted file mode 100644 index 18d723b..0000000 --- a/gemmautil/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "gemmautil" -version = "0.1.0" -edition = "2021" - -[dependencies] -gemma = { path = "../gemma" } -clap.workspace = true -pest = "2.7.14" -pest_derive = "2.7.14" diff --git a/resources/custom/002-schip-scroll-tests.ch8 b/resources/custom/002-schip-scroll-tests.ch8 index a9f978fd17f55ffb62bb29a64de0e1ddc1547dfd..c8667491f6a681d2c83098498260893352fabe08 100644 GIT binary patch literal 26 icmZR0u%MCQeNi*7ywY?1xyCSEowAIzhMUvL1c#+jnSxahv~mwphxm3Jwbbv_5!wfukxyV zKHI;&pZBNmWj>qV=0_D(Yqi(QS-I4sJ`HJ1Q<_miR%A^!`8MBW`|OY&(^GOzF7Y+G zMfdO#6hYya%hF>WTQHY7Zw{L?o6VS2TIIAb3*%wj^_zCpF6vo1DM$Gr@1>oz6*uA< zuQ0(Gq!2?0K6v1Q12$M-f(|OkAOXe`JjNq&C=R5))RVh%M`m$VPMI{BzL)d7Q^Bd7lsJfe<#LX4Hz?Nhj&1y|kYVvSB{T$7Dh_dpXNJ3I~7ABSX(%UL&Hyz~% zu@WMLQhR|yf11QB{ zWDP1Qx=U+F#FNJ}->_Sr#`LPi#%vrjjM?D7TPT=q@$RKUo*coCmLrV?47u3ZCFIyv zyJHNzAOsSPCya+{5MI>08u&p@-e-^lzZBb5YfC88-)#YZM7yvSVIKOUQ{YeHI8TvU zqHpjw%GwVX9&#o-jW2m8e~B&`O66g*#cS0!RkW}z#JW@AVqI*T#!6d47SX!XmEO*8 z*YDJ}(=J*(=QMTL>SwL=n%p$08g$-FeL-V^voZfVf1SU{U*j9|F*kDhRPS1-hI{J; z$_8aHm>gJD!{&*#RGw&qEbG#E@WaAUhYNPRG~&Dy#u8Ek=sXdoUSSzfgIenWEl#P+ z0A5Lp89>VbFrrVAJ~qb=M4QWpeI|*?4U9`C$F@vp%+nsnte4r+`&Be2WZ0R?2HWl#Btz|85!n3r10(5wje?QTqrIU z-}hZSUw#C6+33#BP87DS2>iI++WJ%zz94@hn8i^nZlvv0lguAgoVoyOC?({xU=oe~5pP!9|UW8VRfq78dNi*7ywY?1xyCSEowAIzhMUvL1c#+jnSxahv~mwphxm3Jwbbv_5!wfukxyV zKHI;&pZBNmWj>qV=0_D(Yqi(QS-I4sJ`HJ1Q<_miR%A^!`8MBW`|OY&(^GOzF7Y+G zMfdO#6hYya%hF>WTQHY7Zw{L?o6VS2TIIAb3*%wj^_zCpF6vo1DM$Gr@1>oz6*uA< zuQ0(Gq!2?0K6v1Q12$M-f(|OkAOXe`JjNq&C=R5))RVh%M`m$VPMI{BzL)d7Q^Bd7lsJfe<#LX4Hz?Nhj&1y|kYVvSB{T$7DhnRUA8z7ESjn)5wuxBn$ik>xL=3*Y8@eo-#o z<}RcDd!L2%oJsG0Z@zCjXAjG^*E)3>^GbLR9^Nol+xzar{<%l?sLPkiKKDEJ{PC3I zoBrocnisc4+nsF z1GNcO6aL-mTDNTHrdQpD3#;eGBC3co^#c93VhrK(_R~9icAcF^LpQn3d z>5Gdr}{ts7I!pTI>Yzzk!Npi?OR#2ILmyK@X}nlrZ*9)*N>VR zO!HY@_Qf-F(^=;AQ*1X1f=*`w? zy(hQ+cK7BC=Bwp&OnUaw9&buO0f1f#UZCC&Q u6A5(@!8?nBwUo2Xm%pxgGd1pMY4pyk|Nid`nZ1A8I_Zy}xF%=j@Bski{p#re literal 0 HcmV?d00001 diff --git a/resources/test/state/smoke_001_round_trip_serialize_deserialize.json b/resources/test/state/smoke_001_round_trip_serialize_deserialize.json index 8b582f5..406a858 100644 --- a/resources/test/state/smoke_001_round_trip_serialize_deserialize.json +++ b/resources/test/state/smoke_001_round_trip_serialize_deserialize.json @@ -1 +1 @@ -{"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"} +{"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,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":"SChipModern"} \ No newline at end of file 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/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 e69de29..0000000