671 lines
739 KiB
HTML
671 lines
739 KiB
HTML
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<style>html, body {
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
.app {
|
|
margin: 10px;
|
|
padding: 0;
|
|
}
|
|
|
|
.files-list {
|
|
margin: 10px 0 0;
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
}
|
|
.files-list__head {
|
|
border: 1px solid #999;
|
|
}
|
|
.files-list__head > tr > th {
|
|
padding: 10px;
|
|
border: 1px solid #999;
|
|
text-align: left;
|
|
font-weight: normal;
|
|
background: #ddd;
|
|
}
|
|
.files-list__body {
|
|
}
|
|
.files-list__file {
|
|
cursor: pointer;
|
|
}
|
|
.files-list__file:hover {
|
|
background: #ccf;
|
|
}
|
|
.files-list__file > td {
|
|
padding: 10px;
|
|
border: 1px solid #999;
|
|
}
|
|
.files-list__file > td:first-child::before {
|
|
content: '\01F4C4';
|
|
margin-right: 1em;
|
|
}
|
|
.files-list__file_low {
|
|
background: #fcc;
|
|
}
|
|
.files-list__file_medium {
|
|
background: #ffc;
|
|
}
|
|
.files-list__file_high {
|
|
background: #cfc;
|
|
}
|
|
.files-list__file_folder > td:first-child::before {
|
|
content: '\01F4C1';
|
|
margin-right: 1em;
|
|
}
|
|
|
|
.file-header {
|
|
border: 1px solid #999;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
position: sticky;
|
|
top: 0;
|
|
background: white;
|
|
}
|
|
|
|
.file-header__back {
|
|
margin: 10px;
|
|
cursor: pointer;
|
|
flex-shrink: 0;
|
|
flex-grow: 0;
|
|
text-decoration: underline;
|
|
color: #338;
|
|
}
|
|
|
|
.file-header__name {
|
|
margin: 10px;
|
|
flex-shrink: 2;
|
|
flex-grow: 2;
|
|
}
|
|
|
|
.file-header__stat {
|
|
margin: 10px;
|
|
flex-shrink: 0;
|
|
flex-grow: 0;
|
|
}
|
|
|
|
.file-content {
|
|
margin: 10px 0 0;
|
|
border: 1px solid #999;
|
|
padding: 10px;
|
|
counter-reset: line;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.code-line::before {
|
|
content: counter(line);
|
|
margin-right: 10px;
|
|
}
|
|
.code-line {
|
|
margin: 0;
|
|
padding: 0.3em;
|
|
height: 1em;
|
|
counter-increment: line;
|
|
}
|
|
.code-line_covered {
|
|
background: #cfc;
|
|
}
|
|
.code-line_uncovered {
|
|
background: #fcc;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="root"></div>
|
|
<script>
|
|
var data = {"files":[{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","computer.rs"],"content":"use log::{debug};\nuse crate::chip8::delay_timer::DelayTimer;\nuse crate::chip8::keypad::Keypad;\nuse crate::chip8::quirk_modes::QuirkMode;\nuse crate::chip8::quirk_modes::QuirkMode::Chip8;\nuse crate::chip8::registers::Chip8Registers;\nuse crate::chip8::sound_timer::SoundTimer;\nuse crate::chip8::stack::Chip8Stack;\n\nuse super::{\n cpu_states::Chip8CpuStates, instructions::Chip8CpuInstructions, system_memory::Chip8SystemMemory, video::Chip8Video,\n};\n\n#[derive(Clone)]\npub struct Chip8Computer {\n pub num_cycles: i32,\n pub memory: Chip8SystemMemory,\n pub registers: Chip8Registers,\n pub sound_timer: SoundTimer,\n pub delay_timer: DelayTimer,\n pub video_memory: Chip8Video,\n pub state: Chip8CpuStates,\n pub keypad: Keypad,\n pub stack: Chip8Stack,\n pub quirk_mode: QuirkMode\n}\nimpl Default for Chip8Computer {\n fn default() -\u003e Self {\n Self {\n num_cycles: 0,\n memory: Chip8SystemMemory::default(),\n video_memory: Chip8Video::default(),\n registers: Chip8Registers::default(),\n sound_timer: SoundTimer::new(),\n delay_timer: DelayTimer::new(),\n state: Chip8CpuStates::default(),\n keypad: Keypad::default(),\n stack: Chip8Stack::default(),\n quirk_mode: QuirkMode::default()\n }\n }\n}\n\nimpl Chip8Computer {\n pub fn reset(\u0026mut self) {\n self.video_memory.reset();\n self.num_cycles = 0;\n self.registers.reset();\n self.delay_timer.reset();\n self.sound_timer.reset();\n self.stack.reset();\n self.memory.reset();\n self.quirk_mode = QuirkMode::Chip8;\n }\n\n pub fn dump_keypad_to_string(\u0026self) -\u003e String {\n self.keypad.format_as_string()\n }\n\n pub fn dump_registers_to_string(\u0026self) -\u003e String {\n self.registers.format_as_string()\n }\n\n pub fn dump_video_to_string(\u0026self) -\u003e String {\n self.clone().video_memory.format_as_string()\n }\n\n pub fn new_with_program(new_program: Vec\u003cu16\u003e) -\u003e Self {\n let mut working = Chip8Computer::new();\n\n for (i, \u0026word) in new_program.iter().enumerate() {\n let high = (word \u003e\u003e 8) as u8;\n let low = (word \u0026 0xff) as u8;\n let base_offset = (i * 2) as u16;\n working.memory.poke(base_offset, high);\n working.memory.poke(base_offset + 1, low);\n }\n working\n }\n pub fn new() -\u003e Self {\n Chip8Computer::default()\n }\n\n pub fn load_bytes_to_memory(\u0026mut self, offset: u16, to_load: \u0026Vec\u003cu8\u003e) {\n let total_len = to_load.len() as u16;\n for current_index in 0..total_len {\n let new_value = to_load[current_index as usize];\n let new_location = current_index + offset;\n self.memory.poke(new_location, new_value);\n }\n self.registers.set_pc(offset);\n }\n\n pub fn step_system(\u0026mut self) -\u003e \u0026mut Chip8Computer {\n debug!(\"Stepping System 1 Step\");\n // read the next instruction\n let local_memory = \u0026self.memory;\n\n // let mut working_instruction: u16 = 0b0000000000000000;\n let start_pc = self.registers.peek_pc();\n let high_byte = (local_memory.peek(start_pc) as u16).rotate_left(8);\n let low_byte = local_memory.peek(start_pc + 1) as u16;\n let result = high_byte | low_byte;\n let decoded_instruction =\n Chip8CpuInstructions::decode(result, \u0026self.quirk_mode);\n // todo: THIS IS BAD AND IS A SIDE EFFECT\n decoded_instruction.execute(self);\n\n match self.state {\n Chip8CpuStates::WaitingForInstruction =\u003e {\n self.sound_timer.tick();\n self.delay_timer.tick();\n self.video_memory.tick();\n self.num_cycles += 1;\n }\n Chip8CpuStates::WaitingForKey =\u003e {\n debug!(\"waiting for a key press...\");\n }\n _ =\u003e {}\n }\n self\n }\n}\n","traces":[{"line":28,"address":[1160032,1160542],"length":1,"stats":{"Line":3}},{"line":31,"address":[602624],"length":1,"stats":{"Line":7}},{"line":32,"address":[377074],"length":1,"stats":{"Line":7}},{"line":33,"address":[754655],"length":1,"stats":{"Line":8}},{"line":34,"address":[842350],"length":1,"stats":{"Line":7}},{"line":35,"address":[602733],"length":1,"stats":{"Line":4}},{"line":36,"address":[842380],"length":1,"stats":{"Line":7}},{"line":37,"address":[685351],"length":1,"stats":{"Line":7}},{"line":38,"address":[685370],"length":1,"stats":{"Line":8}},{"line":39,"address":[42137293],"length":1,"stats":{"Line":3}},{"line":45,"address":[3564352],"length":1,"stats":{"Line":1}},{"line":46,"address":[603149],"length":1,"stats":{"Line":1}},{"line":47,"address":[603159],"length":1,"stats":{"Line":1}},{"line":48,"address":[685761],"length":1,"stats":{"Line":1}},{"line":49,"address":[42137682],"length":1,"stats":{"Line":1}},{"line":50,"address":[1160643],"length":1,"stats":{"Line":1}},{"line":51,"address":[755220],"length":1,"stats":{"Line":1}},{"line":52,"address":[42137730],"length":1,"stats":{"Line":1}},{"line":53,"address":[685840],"length":1,"stats":{"Line":1}},{"line":56,"address":[1160720],"length":1,"stats":{"Line":1}},{"line":57,"address":[755297],"length":1,"stats":{"Line":1}},{"line":60,"address":[685920],"length":1,"stats":{"Line":1}},{"line":61,"address":[1160785],"length":1,"stats":{"Line":1}},{"line":64,"address":[603376,603512],"length":1,"stats":{"Line":2}},{"line":65,"address":[843057],"length":1,"stats":{"Line":2}},{"line":68,"address":[604222,603536],"length":1,"stats":{"Line":0}},{"line":69,"address":[377946],"length":1,"stats":{"Line":0}},{"line":71,"address":[603635,603704,603957],"length":1,"stats":{"Line":0}},{"line":72,"address":[756012],"length":1,"stats":{"Line":0}},{"line":73,"address":[378369],"length":1,"stats":{"Line":0}},{"line":74,"address":[686638,686705],"length":1,"stats":{"Line":0}},{"line":75,"address":[604089],"length":1,"stats":{"Line":0}},{"line":76,"address":[378473],"length":1,"stats":{"Line":0}},{"line":78,"address":[755918],"length":1,"stats":{"Line":0}},{"line":80,"address":[686848],"length":1,"stats":{"Line":5}},{"line":81,"address":[1161704],"length":1,"stats":{"Line":9}},{"line":84,"address":[604288],"length":1,"stats":{"Line":1}},{"line":85,"address":[378653],"length":1,"stats":{"Line":4}},{"line":86,"address":[1161784,1161873],"length":1,"stats":{"Line":5}},{"line":87,"address":[3565664],"length":1,"stats":{"Line":1}},{"line":88,"address":[3565760,3565705],"length":1,"stats":{"Line":4}},{"line":89,"address":[756523],"length":1,"stats":{"Line":1}},{"line":91,"address":[844039],"length":1,"stats":{"Line":4}},{"line":94,"address":[1162000],"length":1,"stats":{"Line":1}},{"line":95,"address":[687187,687402],"length":1,"stats":{"Line":5}},{"line":97,"address":[844267],"length":1,"stats":{"Line":4}},{"line":100,"address":[1162095],"length":1,"stats":{"Line":1}},{"line":101,"address":[3565965,3565902],"length":1,"stats":{"Line":8}},{"line":102,"address":[844389,844770,844595],"length":1,"stats":{"Line":5}},{"line":103,"address":[3566215],"length":1,"stats":{"Line":1}},{"line":104,"address":[379328],"length":1,"stats":{"Line":4}},{"line":107,"address":[844689],"length":1,"stats":{"Line":1}},{"line":109,"address":[605106],"length":1,"stats":{"Line":1}},{"line":110,"address":[1162732],"length":1,"stats":{"Line":1}},{"line":111,"address":[379473],"length":1,"stats":{"Line":4}},{"line":112,"address":[757190],"length":1,"stats":{"Line":1}},{"line":113,"address":[844840],"length":1,"stats":{"Line":4}},{"line":114,"address":[379584,379595,379517],"length":1,"stats":{"Line":5}},{"line":117,"address":[844870,844973],"length":1,"stats":{"Line":2}}],"covered":50,"coverable":59},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","computer_manager.rs"],"content":"use std::sync::mpsc::{channel, Sender};\nuse std::thread;\nuse std::thread::{sleep, JoinHandle, Thread};\nuse std::time::{Duration, Instant};\nuse crate::chip8::computer::Chip8Computer;\nuse crate::chip8::cpu_states::Chip8CpuStates;\nuse crate::chip8::cpu_states::Chip8CpuStates::WaitingForInstruction;\npub enum ManagerDumpables {\n Video,\n Registers,\n Keyboard\n}\n\npub struct Chip8ComputerManager {\n core_should_run: bool,\n one_step: bool,\n core_cycle_timer: bool,\n core_last_cycle_start: Instant,\n computer: Chip8Computer\n}\n\nimpl Default for Chip8ComputerManager {\n fn default() -\u003e Self {\n Chip8ComputerManager {\n core_should_run: false,\n one_step: false,\n core_cycle_timer: false,\n core_last_cycle_start: Instant::now() ,\n computer: Chip8Computer::new()\n }\n }\n}\n\nimpl Chip8ComputerManager {\n pub fn reset(\u0026mut self) {\n self.one_step = false;\n self.core_should_run = false;\n self.computer.reset();\n }\n pub fn new() -\u003e Chip8ComputerManager {\n let core_handle = thread::spawn(move || {\n loop {\n let start_time = Instant::now();\n let sleep_time = Instant::now().duration_since(start_time).as_millis();\n sleep(Duration::from_millis((16 - sleep_time) as u64));\n }\n });\n\n Chip8ComputerManager::default()\n }\n\n pub fn start(\u0026mut self) {\n self.core_should_run = true;\n }\n\n pub fn stop(\u0026mut self) {\n self.core_should_run = false\n }\n\n pub fn step(\u0026mut self) {\n self.one_step = true;\n }\n\n pub fn state(\u0026mut self) -\u003e \u0026Chip8Computer {\n \u0026self.computer\n }\n\n pub fn tick( \u0026mut self) -\u003e bool {\n // println!(\"STARTING TICK\");\n let mut did_tick: bool = false;\n if self.one_step | self.core_should_run {\n match self.computer.state {\n WaitingForInstruction =\u003e {\n self.core_last_cycle_start = Instant::now();\n self.computer.step_system();\n did_tick = true\n // println!(\"SYSTEM STEP\");\n }\n _ =\u003e {}\n }\n };\n if self.one_step {\n println!(\"SYSTEM HALTED AFTER 1 STEP\");\n // stop the CPU for the next cycle, we are only\n // wanting one step.\n self.one_step = false;\n did_tick = true;\n }\n did_tick\n }\n\n pub fn press_key(\u0026mut self, key_index: u8) {\n self.computer.keypad.push_key(key_index);\n if matches!(self.computer.state, Chip8CpuStates::WaitingForKey) {\n self.computer.state = WaitingForInstruction\n }\n }\n pub fn release_key(\u0026mut self, key_index: u8) {\n self.computer.keypad.release_key(key_index);\n }\n\n pub fn sound(managed: \u0026Chip8ComputerManager) -\u003e bool {\n managed.computer.sound_timer.current() \u003e 0\n }\n\n pub fn wait_for_instruction(\u0026mut self) {\n self.computer.state = WaitingForInstruction;\n }\n\n pub fn is_key_pressed(\u0026self, key_index: u8) -\u003e bool {\n self.computer.keypad.pressed(key_index)\n }\n\n pub fn num_cycles(\u0026self) -\u003e i32 {\n self.computer.num_cycles\n }\n\n pub fn load_bytes_to_system_memory(\u0026mut self, bytes_to_load: Vec\u003cu8\u003e) {\n self.computer.load_bytes_to_memory(0x200, \u0026bytes_to_load);\n }\n\n pub fn dump_to_string(\u0026self, dump_type: ManagerDumpables) -\u003e String {\n match dump_type {\n ManagerDumpables::Video =\u003e {\n self.computer.video_memory.format_as_string()\n }\n ManagerDumpables::Registers =\u003e {\n self.computer.registers.format_as_string()\n }\n ManagerDumpables::Keyboard =\u003e {\n self.computer.keypad.format_as_string()\n }\n }\n }\n}","traces":[{"line":23,"address":[42109728],"length":1,"stats":{"Line":0}},{"line":28,"address":[3535296],"length":1,"stats":{"Line":0}},{"line":29,"address":[3535310],"length":1,"stats":{"Line":0}},{"line":35,"address":[3535408],"length":1,"stats":{"Line":0}},{"line":36,"address":[42109877],"length":1,"stats":{"Line":0}},{"line":37,"address":[314908],"length":1,"stats":{"Line":0}},{"line":38,"address":[314915],"length":1,"stats":{"Line":0}},{"line":40,"address":[3535440,3535535],"length":1,"stats":{"Line":0}},{"line":41,"address":[3556336],"length":1,"stats":{"Line":0}},{"line":43,"address":[672692],"length":1,"stats":{"Line":0}},{"line":44,"address":[42132428],"length":1,"stats":{"Line":0}},{"line":45,"address":[42132506],"length":1,"stats":{"Line":0}},{"line":49,"address":[42109936],"length":1,"stats":{"Line":0}},{"line":52,"address":[315040],"length":1,"stats":{"Line":0}},{"line":53,"address":[315045],"length":1,"stats":{"Line":0}},{"line":56,"address":[3535584],"length":1,"stats":{"Line":0}},{"line":57,"address":[315061],"length":1,"stats":{"Line":0}},{"line":60,"address":[42110064],"length":1,"stats":{"Line":0}},{"line":61,"address":[42110069],"length":1,"stats":{"Line":0}},{"line":64,"address":[315088],"length":1,"stats":{"Line":0}},{"line":68,"address":[42110096],"length":1,"stats":{"Line":0}},{"line":70,"address":[3535645],"length":1,"stats":{"Line":0}},{"line":71,"address":[3535650],"length":1,"stats":{"Line":0}},{"line":72,"address":[42110151],"length":1,"stats":{"Line":0}},{"line":74,"address":[42110164],"length":1,"stats":{"Line":0}},{"line":75,"address":[315195],"length":1,"stats":{"Line":0}},{"line":76,"address":[315200],"length":1,"stats":{"Line":0}},{"line":82,"address":[42110136,42110256],"length":1,"stats":{"Line":0}},{"line":83,"address":[315218],"length":1,"stats":{"Line":0}},{"line":86,"address":[315251],"length":1,"stats":{"Line":0}},{"line":87,"address":[42110251],"length":1,"stats":{"Line":0}},{"line":89,"address":[3535736],"length":1,"stats":{"Line":0}},{"line":92,"address":[42110272],"length":1,"stats":{"Line":0}},{"line":93,"address":[3535829],"length":1,"stats":{"Line":0}},{"line":94,"address":[3535847],"length":1,"stats":{"Line":0}},{"line":95,"address":[315336],"length":1,"stats":{"Line":0}},{"line":98,"address":[42110352],"length":1,"stats":{"Line":0}},{"line":99,"address":[3535904],"length":1,"stats":{"Line":0}},{"line":102,"address":[315408],"length":1,"stats":{"Line":0}},{"line":103,"address":[42110405],"length":1,"stats":{"Line":0}},{"line":106,"address":[3535968],"length":1,"stats":{"Line":0}},{"line":107,"address":[3535973],"length":1,"stats":{"Line":0}},{"line":110,"address":[3536000],"length":1,"stats":{"Line":0}},{"line":111,"address":[3536016],"length":1,"stats":{"Line":0}},{"line":114,"address":[3536048],"length":1,"stats":{"Line":0}},{"line":115,"address":[315525],"length":1,"stats":{"Line":0}},{"line":118,"address":[3536145,3536064],"length":1,"stats":{"Line":0}},{"line":119,"address":[3536081],"length":1,"stats":{"Line":0}},{"line":122,"address":[3536176],"length":1,"stats":{"Line":0}},{"line":123,"address":[315662],"length":1,"stats":{"Line":0}},{"line":125,"address":[315706],"length":1,"stats":{"Line":0}},{"line":128,"address":[315723],"length":1,"stats":{"Line":0}},{"line":131,"address":[315747],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":53},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","cpu_states.rs"],"content":"#[derive(Clone, Copy, Default)]\npub enum Chip8CpuStates {\n #[default]\n WaitingForInstruction,\n WaitingForKey,\n ExecutingInstruction,\n Error,\n}\n\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","delay_timer.rs"],"content":"#[derive(Clone, Copy)]\npub struct DelayTimer {\n counter: u8\n}\n\nimpl DelayTimer {\n pub fn current(\u0026self) -\u003e u8 {\n self.counter\n }\n\n pub fn new() -\u003e Self {\n DelayTimer {\n counter: 0xff\n }\n }\n\n pub fn reset(\u0026mut self) {\n self.counter = 0xff;\n }\n\n pub fn set_timer(\u0026mut self, new_value: u8) {\n self.counter = new_value as u8\n }\n\n pub fn tick(\u0026mut self) {\n if self.counter \u003e 0 {\n self.counter -= 1;\n }\n }\n}\n","traces":[{"line":7,"address":[42094400],"length":1,"stats":{"Line":1}},{"line":8,"address":[701285],"length":1,"stats":{"Line":1}},{"line":17,"address":[636432],"length":1,"stats":{"Line":1}},{"line":18,"address":[3571029],"length":1,"stats":{"Line":1}},{"line":21,"address":[674368],"length":1,"stats":{"Line":2}},{"line":22,"address":[1185564],"length":1,"stats":{"Line":2}},{"line":25,"address":[1185568],"length":1,"stats":{"Line":6}},{"line":26,"address":[290302,290343],"length":1,"stats":{"Line":5}},{"line":27,"address":[832733,832761],"length":1,"stats":{"Line":5}}],"covered":9,"coverable":9},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","instructions.rs"],"content":"use std::arch::x86_64::_mm_xor_pd;\nuse std::fmt::{Debug, Display, Formatter};\nuse std::ops::{BitAnd, Deref, Shr};\nuse std::time::Instant;\nuse chrono::ParseMonthError;\nuse log::debug;\nuse rand::{random, Rng};\nuse crate::chip8::computer::{Chip8Computer};\nuse crate::chip8::cpu_states::Chip8CpuStates::WaitingForKey;\nuse crate::chip8::instructions::Chip8CpuInstructions::*;\nuse crate::chip8::quirk_modes::QuirkMode;\nuse crate::chip8::util::InstructionUtil;\nuse crate::constants::{*};\n\n/*\nnnn or addr - A 12-bit value, the lowest 12 bits of the instruction\nn or nibble - A 4-bit value, the lowest 4 bits of the instruction\nx - A 4-bit value, the lower 4 bits of the high byte of the instruction\ny - A 4-bit value, the upper 4 bits of the low byte of the instruction\nkk or byte - An 8-bit value, the lowest 8 bits of the instruction\n */\n\n#[derive(Debug)]\npub enum Chip8CpuInstructions {\n /// 0nnn\n /// Exit to System Call at nnn\n SYS(u16),\n /// 00E0\n /// Clear the display.\n CLS,\n /// 00EE\n /// Return from a subroutine.\n ///\n /// The interpreter sets the program counter to the address at the top of the stack,\n /// then subtracts 1 from the stack pointer.\n RET,\n /// 1nnn\n /// Jump to location nnn.\n ///\n /// The interpreter sets the program counter to nnn.\n JPA(u16),\n /// 2nnn\n /// Call subroutine at nnn.\n ///\n /// The interpreter increments the stack pointer, then puts the current PC on the top\n /// of the stack. The PC is then set to nnn.\n CALL(u16),\n /// 0x3xkk\n /// Skip next instruction if Vx = kk.\n ///\n /// The interpreter compares register Vx to kk, and if they are equal, increments the\n /// program counter by 2.\n SEX(u8, u8),\n /// 4xkk\n /// Skip next instruction if Vx != kk.\n ///\n /// The interpreter compares register Vx to kk, and if they are not equal, increments\n /// the program counter by 2.\n SNEB(u8, u8),\n /// 5xy0\n /// Skip next instruction if Vx = Vy.\n ///\n /// The interpreter compares register Vx to register Vy, and if they are equal, increments\n /// the program counter by 2.\n SEY(u8, u8),\n /// 6xkk\n /// Set Vx = kk\n LDR(u8, u8),\n /// 7xkk\n /// The interpreter puts the value kk into register Vx.\n ADD(u8, u8),\n /// 8xy0\n /// Adds the value kk to the value of register Vx, then stores the result in Vx.\n LDR_Y(u8, u8),\n /// 8xy1\n /// Stores the value of register Vy in register Vx.\n OR(u8, u8),\n /// 8xy2\n /// Set Vx = Vx OR Vy.\n ///\n /// Performs a bitwise OR on the values of Vx and Vy, then stores the result in Vx.\n /// A bitwise OR compares the corrseponding bits from two values, and if either\n /// bit is 1, then the same bit in the result is also 1. Otherwise, it is 0.\n AND(u8, u8),\n /// 8xy3\n /// Set Vx = Vx AND Vy.\n ///\n /// Performs a bitwise AND on the values of Vx and Vy, then stores the result in Vx.\n /// A bitwise AND compares the corrseponding bits from two values, and if both bits\n /// are 1, then the same bit in the result is also 1. Otherwise, it is 0.\n ORY(u8, u8),\n /// 8xy4\n /// Set Vx = Vx XOR Vy.\n ///\n /// Performs a bitwise exclusive OR on the values of Vx and Vy, then stores the\n /// result in Vx. An exclusive OR compares the corrseponding bits from two values,\n /// and if the bits are not both the same, then the corresponding bit in the result\n /// is set to 1. Otherwise, it is 0.\n ADDR(u8, u8),\n /// 8xy5\n /// Set Vx = Vx + Vy, set VF = carry.\n ///\n /// The values of Vx and Vy are added together. If the result is greater than 8 bits\n /// (i.e., \u003e 255,) VF is set to 1, otherwise 0. Only the lowest 8 bits of the result\n /// are kept, and stored in Vx.\n SUB(u8, u8),\n /// 8xy6\n /// Set Vx = Vx - Vy, set VF = NOT borrow.\n ///\n /// If Vx \u003e Vy, then VF is set to 1, otherwise 0. Then Vy is subtracted from Vx, and the\n /// results stored in Vx.\n SHR(u8, u8),\n /// 8xy7\n /// If the least-significant bit of Vx is 1, then VF is set to 1, otherwise 0. Then Vx\n /// is divided by 2.\n SUBC(u8, u8),\n /// 8xye\n /// Set Vx = Vy - Vx, set VF = NOT borrow.\n //\n /// If Vy \u003e Vx, then VF is set to 1, otherwise 0. Then Vx is subtracted from Vy, and the\n /// results stored in Vx.\n SHL(u8, u8),\n /// 9xy0\n /// Skip next instruction if Vx != Vy.\n ///\n /// The values of Vx and Vy are compared, and if they are not equal, the program\n /// counter is increased by 2.\n SNEY(u8, u8),\n /// Annn\n /// Set I = nnn.\n ///\n /// The value of register I is set to nnn\n LDIA(u16),\n /// Bnnn\n /// Jump to location nnn + V0.\n ///\n /// The program counter is set to nnn plus the value of V0.\n JPI(u16),\n /// Cxkk\n /// Set Vx = random byte AND kk.\n ///\n /// The interpreter generates a random number from 0 to 255, which is then\n /// ANDed with the value kk. The results are stored in Vx. See instruction\n /// 8xy2 for more information on AND.\n RND(u8, u8),\n /// Dxyn\n /// Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision.\n ///\n /// In Chip-8,\n ///\n /// The interpreter reads n bytes from memory, starting at the address stored in I.\n /// These bytes are then displayed as sprites on screen at coordinates (Vx, Vy).\n /// Sprites are XORed onto the existing screen. If this causes any pixels to be erased,\n /// VF is set to 1, otherwise it is set to 0. If the sprite is positioned so part of\n /// it is outside the coordinates of the display, it wraps around to the opposite side\n /// of the screen. See instruction 8xy3 for more information on XOR, and section 2.4,\n /// Display, for more information on the Chip-8 screen and sprites.\n ///\n /// In SCHIP\n ///\n /// Show N-byte sprite from M(I) at Coords (VX,VY) VF = Collision.\n /// If N=0 AND ExtendedMode, 16x16 sprite\n DRW(u8, u8, u8),\n /// Ex9E\n /// Skip next instruction if key with the value of Vx is pressed.\n ///\n /// Checks the keyboard, and if the key corresponding to the value of Vx is currently\n /// in the down position, PC is increased by 2.\n SKP(u8),\n /// ExA1\n /// Skip next instruction if key with the value of Vx is not pressed.\n ///\n /// Checks the keyboard, and if the key corresponding to the value of Vx is currently in\n /// the up position, PC is increased by 2.\n SKNP(u8),\n /// Fx07\n /// The value of DT is placed into Vx.\n LDRD(u8),\n /// Fx0A\n /// Wait for a key press, store the value of the key in Vx.\n ///\n /// All execution stops until a key is pressed, then the value of that key is stored in Vx.\n LDRK(u8),\n /// Fx15\n /// Set delay timer = Vx.\n ///\n /// DT is set equal to the value of Vx.\n LDD(u8), // 0xFx15 Set Delay Timer\n /// Fx18\n /// Set sound timer = Vx.\n ///\n /// ST is set equal to the value of Vx.\n LDIS(u8),\n /// Fx1E - ADD I, Vx\n /// Set I = I + Vx.\n ///\n /// The values of I and Vx are added, and the results are stored in I.\n ADDI(u8),\n /// Fx29 - LD F, Vx\n /// Set I = location of sprite for digit Vx.\n ///\n /// The value of I is set to the location for the hexadecimal sprite\n /// corresponding to the value of Vx. See section 2.4, Display, for\n /// more information on the Chip-8 hexadecimal font.\n LDFX(u8),\n /// Fx33 - LD B, Vx\n /// Store BCD representation of Vx in memory locations I, I+1, and I+2.\n ///\n /// The interpreter takes the decimal value of Vx, and places the hundreds\n /// digit in memory at location in I, the tens digit at location I+1, and the\n /// ones digit at location I+2.\n BCD(u8),\n /// Fx55 - LD [I], Vx\n /// Store registers V0 through Vx in memory starting at location I.\n ///\n /// The interpreter copies the values of registers V0 through Vx into memory,\n /// starting at the address in I.\n LDIX(u8),\n /// Fx65 - LD Vx, [I]\n /// Read registers V0 through Vx from memory starting at location I.\n ///\n /// The interpreter reads values from memory starting at location I into registers\n /// V0 through Vx.\n LDRI(u8),\n XXXXERRORINSTRUCTION,\n /* START OF SCHIP-8 */\n /// 00CN\n ///\n /// Scrolll Display N Lines Down\n SDN(u8),\n /// 00FB\n ///\n /// Scroll 4 lines Right\n SRT,\n /// 00FC\n ///\n /// Scroll 4 lines Left\n SLF,\n /// 00FE\n ///\n /// Disable Extended Mode\n DIS,\n /// 00FF\n ///\n /// Enable Extended Mode\n ENA,\n /// 00FD\n ///\n /// Exit App\n EXIT,\n /// FX30\n ///\n /// Point I to 10 yte font sprite for digit VX (0..9)\n LDF2(u8),\n /// FX75\n ///\n /// Store V0..VX in RPL user flags (X \u003c= 7\n STR(u8),\n /// FX85\n ///\n /// Load V0..VX from RPL user flags (X \u003c= 7)\n LIDR(u8),\n}\n\nimpl Chip8CpuInstructions {\n pub fn name(\u0026self) -\u003e \u0026str {\n match self {\n Chip8CpuInstructions::ADDI(_) =\u003e INST_ADDI,\n Chip8CpuInstructions::ADD(_, _) =\u003e INST_ADD,\n Chip8CpuInstructions::ADDR(_, _) =\u003e INST_ADDR,\n Chip8CpuInstructions::AND(_, _) =\u003e INST_AND,\n Chip8CpuInstructions::CLS =\u003e INST_CLS,\n Chip8CpuInstructions::CALL(_) =\u003e INST_CALL,\n Chip8CpuInstructions::DRW(_, _, _) =\u003e INST_DRW,\n Chip8CpuInstructions::EXIT =\u003e INST_EXIT,\n Chip8CpuInstructions::JPA(_) =\u003e INST_JPA,\n Chip8CpuInstructions::JPI(_) =\u003e INST_JPI,\n Chip8CpuInstructions::BCD(_) =\u003e INST_BCD,\n Chip8CpuInstructions::LDD(_) =\u003e INST_LDD,\n Chip8CpuInstructions::LDFX(_) =\u003e INST_LDF,\n Chip8CpuInstructions::LDF2(_) =\u003e INST_LDF2,\n Chip8CpuInstructions::LDIA(_) =\u003e INST_LDIA,\n Chip8CpuInstructions::LDIX(_) =\u003e INST_LDIX,\n Chip8CpuInstructions::LIDR(_) =\u003e INST_LIDR,\n Chip8CpuInstructions::LDIS(_) =\u003e INST_LDIS,\n Chip8CpuInstructions::LDR(_, _) =\u003e INST_LDR,\n Chip8CpuInstructions::LDRD(_) =\u003e INST_LDRD,\n Chip8CpuInstructions::LDRI(_) =\u003e INST_LDRI,\n Chip8CpuInstructions::LDRK(_) =\u003e INST_LDRK,\n Chip8CpuInstructions::LDR_Y(_, _) =\u003e INST_LDRY,\n Chip8CpuInstructions::OR(_, _) =\u003e INST_OR,\n Chip8CpuInstructions::RET =\u003e INST_RET,\n Chip8CpuInstructions::RND(_, _) =\u003e INST_RND,\n Chip8CpuInstructions::SDN(_) =\u003e INST_SDN,\n Chip8CpuInstructions::SLF =\u003e INST_SLF,\n Chip8CpuInstructions::SRT =\u003e INST_SRT,\n Chip8CpuInstructions::SEX(_, _) =\u003e INST_SEX,\n Chip8CpuInstructions::SEY(_, _) =\u003e INST_SEY,\n Chip8CpuInstructions::SHL(_, _) =\u003e INST_SHL,\n Chip8CpuInstructions::SHR(_, _) =\u003e INST_SHR,\n Chip8CpuInstructions::SKP(_) =\u003e INST_SKP,\n Chip8CpuInstructions::SNEB(_, _) =\u003e INST_SNEB,\n Chip8CpuInstructions::SNEY(_, _) =\u003e INST_SNEY,\n Chip8CpuInstructions::SKNP(_) =\u003e INST_SKNP,\n Chip8CpuInstructions::STR(_) =\u003e INST_STR,\n Chip8CpuInstructions::SUB(_, _) =\u003e INST_SUB,\n Chip8CpuInstructions::SUBC(_, _) =\u003e INST_SUBC,\n Chip8CpuInstructions::SYS(_) =\u003e INST_SYS,\n Chip8CpuInstructions::DIS =\u003e INST_DIS,\n Chip8CpuInstructions::ENA =\u003e INST_ENA,\n Chip8CpuInstructions::ORY(_, _) =\u003e INST_ORY,\n XXXXERRORINSTRUCTION =\u003e \"XX ERROR XX\",\n }\n }\n\n pub fn operands(\u0026self) -\u003e String {\n match self {\n Chip8CpuInstructions::SYS(addr) |\n Chip8CpuInstructions::JPI(addr) |\n Chip8CpuInstructions::JPA(addr) |\n Chip8CpuInstructions::LDIA(addr) |\n Chip8CpuInstructions::CALL(addr) =\u003e {\n format!(\"0x{addr:04x}\")\n }\n Chip8CpuInstructions::SEX(x, byte) |\n Chip8CpuInstructions::SNEB(x, byte) |\n Chip8CpuInstructions::LDR(x, byte) |\n Chip8CpuInstructions::RND(x, byte) |\n Chip8CpuInstructions::ADD(x, byte) =\u003e {\n format!(\"0x{x:02x}, 0x{byte:02x}\")\n }\n // Reg, Reg\n SEY(x, y) |\n LDR_Y(x, y) |\n Chip8CpuInstructions::OR(x, y) |\n Chip8CpuInstructions::AND(x, y) |\n Chip8CpuInstructions::ORY(x, y) |\n Chip8CpuInstructions::ADDR(x, y) |\n Chip8CpuInstructions::SUB(x, y) |\n Chip8CpuInstructions::SHR(x, y) |\n Chip8CpuInstructions::SUBC(x, y) |\n Chip8CpuInstructions::SHL(x, y) |\n Chip8CpuInstructions::SNEY(x, y) =\u003e {\n format!(\"0x{x:01x}, 0x{y:01x}\")\n }\n // Reg, Reg, Nibble\n Chip8CpuInstructions::DRW(x, y, nibble) =\u003e {\n format!(\"0x{x:02x}, 0x{y:02x}, 0x{nibble:02x}\")\n }\n // Registers. 0-F\n Chip8CpuInstructions::LDD(x) |\n Chip8CpuInstructions::LDIS(x) |\n Chip8CpuInstructions::ADDI(x) |\n Chip8CpuInstructions::LDFX(x) |\n Chip8CpuInstructions::BCD(x) |\n Chip8CpuInstructions::LDIX(x) |\n Chip8CpuInstructions::LDRD(x) |\n Chip8CpuInstructions::LDRK(x) |\n Chip8CpuInstructions::LDRI(x) |\n Chip8CpuInstructions::LDF2(x) |\n Chip8CpuInstructions::STR(x) |\n Chip8CpuInstructions::LIDR(x) |\n Chip8CpuInstructions::SDN(x) |\n Chip8CpuInstructions::SKNP(x) |\n Chip8CpuInstructions::SKP(x) =\u003e {\n format!(\"0x{x:02x}\")\n }\n Chip8CpuInstructions::EXIT |\n Chip8CpuInstructions::ENA |\n Chip8CpuInstructions::DIS |\n Chip8CpuInstructions::SLF |\n Chip8CpuInstructions::XXXXERRORINSTRUCTION |\n Chip8CpuInstructions::SRT |\n Chip8CpuInstructions::CLS |\n Chip8CpuInstructions::RET =\u003e {\n String::new()\n }\n }\n }\n}\n\nimpl Display for Chip8CpuInstructions {\n fn fmt(\u0026self, f: \u0026mut Formatter\u003c'_\u003e) -\u003e std::fmt::Result {\n let ops = self.operands();\n let space = if ops.is_empty() { \"\" } else { \" \" };\n write!(f, \"{}{}{}\", self.name(), space, ops)\n }\n}\n\nimpl Chip8CpuInstructions {\n pub fn from_str(input: \u0026str) -\u003e Chip8CpuInstructions {\n let mut parts = input.split(\" \");\n // print!(\"THERE ARE {} PARTS\", parts.clone().count());\n let first_part = parts.next().unwrap_or(\"\");\n // take the next value...\n // ...strip off the extra...\n // ...convert it to an integer from base 16\n let param1 = u16::from_str_radix(parts.next().unwrap_or(\"0\").trim_start_matches(\"0x\").trim_end_matches(\",\"), 16).unwrap_or(0);\n let param2 = u16::from_str_radix(parts.next().unwrap_or(\"0\").trim_start_matches(\"0x\").trim_end_matches(\",\"), 16).unwrap_or(0);\n let param3 = u16::from_str_radix(parts.next().unwrap_or(\"0\").trim_start_matches(\"0x\").trim_end_matches(\",\"), 16).unwrap_or(0);\n // println!(\"\\tFirst part is {:?} / {:?} / {:?} / {:?}\", first_part, param1 ,param2 ,param3);\n match first_part {\n INST_CLS =\u003e {\n CLS\n }\n INST_DRW =\u003e {\n DRW(param1 as u8, param2 as u8, param3 as u8)\n }\n INST_ADD =\u003e {\n ADD(param1 as u8, param2 as u8)\n }\n INST_CALL =\u003e {\n CALL(param1)\n }\n INST_SYS =\u003e {\n SYS(param1)\n }\n INST_RET =\u003e {\n RET\n }\n INST_JPA =\u003e {\n JPA(param1)\n }\n INST_JPI =\u003e {\n JPI(param1)\n }\n INST_SEX =\u003e {\n SEX(param1 as u8, param2 as u8)\n }\n INST_SNEB =\u003e {\n SNEB(param1 as u8, param2 as u8)\n }\n INST_SDN =\u003e {\n SDN(param1 as u8)\n }\n INST_SRT =\u003e {\n SRT\n }\n INST_SLF =\u003e {\n SLF\n }\n INST_EXIT =\u003e {\n EXIT\n }\n INST_DIS =\u003e {\n DIS\n }\n INST_ENA =\u003e {\n ENA\n }\n INST_SEY =\u003e {\n SEY(param1 as u8, param2 as u8)\n }\n INST_LDRY =\u003e {\n LDR_Y(param1 as u8, param2 as u8)\n }\n INST_LDR =\u003e {\n LDR(param1 as u8, param2 as u8)\n }\n INST_OR =\u003e {\n OR(param1 as u8, param2 as u8)\n }\n INST_AND =\u003e {\n AND(param1 as u8, param2 as u8)\n }\n INST_ORY =\u003e {\n ORY(param1 as u8, param2 as u8)\n }\n INST_ADDR =\u003e {\n ADDR(param1 as u8, param2 as u8)\n }\n INST_SUB =\u003e {\n SUB(param1 as u8, param2 as u8)\n }\n INST_SHR =\u003e {\n SHR(param1 as u8, param2 as u8)\n }\n INST_SHL =\u003e {\n SHL(param1 as u8, param2 as u8)\n }\n INST_SUBC =\u003e {\n SUBC(param1 as u8, param2 as u8)\n }\n INST_SNEY =\u003e {\n SNEY(param1 as u8, param2 as u8)\n }\n INST_LDIA =\u003e {\n LDIA(param1)\n }\n INST_RND =\u003e {\n RND(param1 as u8, param2 as u8)\n }\n INST_SKP =\u003e {\n SKP(param1 as u8)\n }\n INST_SKNP =\u003e {\n SKNP(param1 as u8)\n }\n INST_LDRD =\u003e {\n LDRD(param1 as u8)\n }\n INST_LDRK =\u003e {\n LDRK(param1 as u8)\n }\n INST_LDRI =\u003e {\n LDRI(param1 as u8)\n }\n INST_BCD =\u003e {\n BCD(param1 as u8)\n }\n INST_LDF =\u003e {\n LDFX(param1 as u8)\n }\n INST_LDF2 =\u003e {\n LDF2(param1 as u8)\n }\n INST_LDIX =\u003e {\n LDIX(param1 as u8)\n }\n INST_LIDR =\u003e {\n LIDR(param1 as u8)\n }\n INST_LDIS =\u003e {\n LDIS(param1 as u8)\n }\n INST_STR =\u003e {\n STR(param1 as u8)\n }\n INST_LDD =\u003e {\n LDD(param1 as u8)\n }\n _ =\u003e {\n XXXXERRORINSTRUCTION\n }\n }\n }\n\n pub fn encode(\u0026self) -\u003e u16 {\n match self {\n Chip8CpuInstructions::SYS(target) =\u003e 0x0000 | (target \u0026 0x0FFF) as u16,\n Chip8CpuInstructions::CLS =\u003e 0x00E0,\n Chip8CpuInstructions::RET =\u003e 0x00EE,\n Chip8CpuInstructions::JPA(new_addr) =\u003e 0x1000 | (new_addr \u0026 0x0FFF) as u16,\n Chip8CpuInstructions::CALL(address) =\u003e 0x2000 | (address \u0026 0x0FFF) as u16,\n Chip8CpuInstructions::SEX(vx_register, byte) =\u003e 0x3000 | ((*vx_register as u16) \u003c\u003c 8) | (*byte as u16),\n Chip8CpuInstructions::SNEB(vx_register, byte) =\u003e 0x4000 | ((*vx_register as u16) \u003c\u003c 8) | (*byte as u16),\n Chip8CpuInstructions::SEY(x_register, y_register) =\u003e 0x5000 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::LDR(x_register, byte) =\u003e 0x6000 | ((*x_register as u16) \u003c\u003c 8) | (*byte as u16),\n Chip8CpuInstructions::ADD(x_register, byte) =\u003e 0x7000 | ((*x_register as u16) \u003c\u003c 8) | (*byte as u16),\n Chip8CpuInstructions::LDR_Y(x_register, y_register) =\u003e 0x8000 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::OR(x_register, y_register) =\u003e 0x8001 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::AND(x_register, y_register) =\u003e 0x8002 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::ORY(x_register, y_register) =\u003e 0x8003 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::ADDR(x_register, y_register) =\u003e 0x8004 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::SUB(x_register, y_register) =\u003e 0x8005 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::SHR(x_register, y_register) =\u003e 0x8006 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::SUBC(x_register, y_register) =\u003e 0x8007 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::SHL(x_register, y_register) =\u003e 0x800E | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::SNEY(x_register, y_register) =\u003e 0x9000 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::LDIA(addr) =\u003e 0xA000 | addr,\n Chip8CpuInstructions::JPI(addr) =\u003e 0xB000 | addr,\n Chip8CpuInstructions::RND(x_register, byte) =\u003e 0xC000 | ((*x_register as u16) \u003c\u003c 8) | (*byte as u16),\n Chip8CpuInstructions::DRW(x_register, y_register, height) =\u003e {\n 0xD000 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4) | (*height as u16)\n }\n Chip8CpuInstructions::SKP(x_register) =\u003e 0xE09E | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::SKNP(x_register) =\u003e 0xE0A1 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::LDRD(x_register) =\u003e 0xF007 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::LDRK(x_register) =\u003e 0xF00A | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::LDD(x_register) =\u003e 0xF015 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::LDIS(x_register) =\u003e 0xF018 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::ADDI(x_register) =\u003e 0xF01E | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::LDFX(x_register) =\u003e 0xF029 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::BCD(x_register) =\u003e 0xF033 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::LDIX(x_register) =\u003e 0xF055 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::LDRI(x_register) =\u003e 0xF065 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::SDN(x_register) =\u003e 0x00C0 | (*x_register as u16),\n Chip8CpuInstructions::SRT =\u003e 0x00FB,\n Chip8CpuInstructions::SLF =\u003e 0x00FC,\n Chip8CpuInstructions::DIS =\u003e 0x00FE,\n Chip8CpuInstructions::ENA =\u003e 0x00FF,\n Chip8CpuInstructions::EXIT =\u003e 0x00FD,\n Chip8CpuInstructions::LDF2(x_register) =\u003e 0xF030 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::STR(x_register) =\u003e 0xF075 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::LIDR(x_register) =\u003e 0xF085 | ((*x_register as u16) \u003c\u003c 8),\n XXXXERRORINSTRUCTION =\u003e 0xFFFF\n }\n }\n pub fn decode(input: u16, quirk_mode: \u0026QuirkMode) -\u003e Chip8CpuInstructions {\n let x_param = InstructionUtil::read_x_from_instruction(input);\n let y_param = InstructionUtil::read_y_from_instruction(input);\n let addr_param = InstructionUtil::read_addr_from_instruction(input);\n let byte_param = InstructionUtil::read_byte_from_instruction(input);\n let nibble_param = InstructionUtil::read_nibble_from_instruction(input);\n let ubln = InstructionUtil::read_upper_byte_lower_nibble(input);\n let last_byte = (input \u0026 0xFF) as u8;\n let last_nibble = (input \u0026 0xF) as u8;\n\n match input {\n 0x00C0..=0x00CF =\u003e {\n match quirk_mode {\n QuirkMode::Chip8 =\u003e {\n XXXXERRORINSTRUCTION\n }\n QuirkMode::XOChip =\u003e {\n SDN(last_nibble)\n }\n QuirkMode::SChipModern =\u003e {\n SDN(last_nibble)\n }\n }\n },\n 0x00E0 =\u003e Chip8CpuInstructions::CLS,\n 0x00EE =\u003e Chip8CpuInstructions::RET,\n 0x00FB =\u003e {\n match quirk_mode {\n QuirkMode::Chip8 =\u003e {\n // does not exist on Chip8\n XXXXERRORINSTRUCTION\n }\n QuirkMode::XOChip =\u003e {\n Chip8CpuInstructions::SRT\n }\n QuirkMode::SChipModern =\u003e {\n Chip8CpuInstructions::SRT\n }\n }\n },\n 0x00FC =\u003e Chip8CpuInstructions::SLF,\n 0x00FD =\u003e Chip8CpuInstructions::EXIT,\n 0x00FE =\u003e Chip8CpuInstructions::DIS,\n 0x00FF =\u003e Chip8CpuInstructions::ENA,\n 0x0000..=0x0FFF =\u003e Chip8CpuInstructions::SYS(addr_param),\n 0x1000..=0x1FFF =\u003e Chip8CpuInstructions::JPA(addr_param),\n 0x2000..=0x2FFF =\u003e Chip8CpuInstructions::CALL(addr_param),\n 0x3000..=0x3FFF =\u003e Chip8CpuInstructions::SEX(x_param, byte_param),\n 0x4000..=0x4FFF =\u003e Chip8CpuInstructions::SNEB(x_param, byte_param),\n 0x5000..=0x5FF0 if input \u0026 0x01 == 0 =\u003e Chip8CpuInstructions::SEY(x_param, y_param),\n 0x6000..=0x6FFF =\u003e Chip8CpuInstructions::LDR(x_param, byte_param),\n 0x7000..=0x7FFF =\u003e Chip8CpuInstructions::ADD(x_param, byte_param),\n 0x8000..=0x8FFE =\u003e match last_nibble {\n 0x0 =\u003e Chip8CpuInstructions::LDR_Y(x_param, y_param),\n 0x1 =\u003e Chip8CpuInstructions::OR(x_param, y_param),\n 0x2 =\u003e Chip8CpuInstructions::AND(x_param, y_param),\n 0x3 =\u003e Chip8CpuInstructions::ORY(x_param, y_param),\n 0x4 =\u003e Chip8CpuInstructions::ADDR(x_param, y_param),\n 0x5 =\u003e Chip8CpuInstructions::SUB(x_param, y_param),\n 0x6 =\u003e Chip8CpuInstructions::SHR(x_param, y_param),\n 0x7 =\u003e Chip8CpuInstructions::SUBC(x_param, y_param),\n 0xE =\u003e Chip8CpuInstructions::SHL(x_param, y_param),\n _ =\u003e XXXXERRORINSTRUCTION\n }\n 0x9000..=0x9FF0 if input \u0026 0x01 == 0 =\u003e Chip8CpuInstructions::SNEY(x_param, y_param),\n 0xA000..=0xAFFF =\u003e Chip8CpuInstructions::LDIA(addr_param),\n 0xB000..=0xBFFF =\u003e Chip8CpuInstructions::JPI(addr_param),\n 0xC000..=0xCFFF =\u003e Chip8CpuInstructions::RND(x_param, byte_param),\n 0xD000..=0xDFFF =\u003e Chip8CpuInstructions::DRW(x_param, y_param, nibble_param),\n 0xE09E..=0xEFA1 =\u003e match last_byte {\n 0x9E =\u003e Chip8CpuInstructions::SKP(ubln),\n 0xA1 =\u003e Chip8CpuInstructions::SKNP(ubln),\n _ =\u003e XXXXERRORINSTRUCTION\n }\n 0xF007..=0xFF65 =\u003e match last_byte {\n 0x07 =\u003e Chip8CpuInstructions::LDRD(ubln),\n 0x0A =\u003e Chip8CpuInstructions::LDRK(ubln),\n 0x15 =\u003e Chip8CpuInstructions::LDD(ubln),\n 0x18 =\u003e Chip8CpuInstructions::LDIS(ubln),\n 0x1E =\u003e Chip8CpuInstructions::ADDI(ubln),\n 0x29 =\u003e Chip8CpuInstructions::LDFX(ubln),\n 0x30 =\u003e Chip8CpuInstructions::LDF2(ubln),\n 0x33 =\u003e Chip8CpuInstructions::BCD(ubln),\n 0x55 =\u003e Chip8CpuInstructions::LDIX(ubln),\n 0x65 =\u003e Chip8CpuInstructions::LDRI(ubln),\n 0x75 =\u003e Chip8CpuInstructions::STR(ubln),\n 0x85 =\u003e Chip8CpuInstructions::LIDR(ubln),\n _ =\u003e XXXXERRORINSTRUCTION\n }\n _ =\u003e XXXXERRORINSTRUCTION\n }\n }\n pub fn execute(\u0026self, input: \u0026mut Chip8Computer) -\u003e Chip8Computer {\n // print!(\"INSTRUCTION {}\", self);\n let start_time = Instant::now();\n let start_pc = input.registers.peek_pc();\n input.registers.poke_pc(start_pc + 2);\n let _ = match self {\n // 0x0nnn Exit to System Call\n Chip8CpuInstructions::SYS(new_address) =\u003e {\n input.registers.poke_pc(*new_address as u16);\n }\n // * 0x00E0 Clear Screen\n Chip8CpuInstructions::CLS =\u003e {\n input.video_memory.cls();\n }\n // 0x00EE Return from Subroutine\n Chip8CpuInstructions::RET =\u003e {\n input.registers.poke_pc(input.stack.pop());\n }\n // 0x1nnn Jump to Address\n Chip8CpuInstructions::JPA(new_address) =\u003e {\n input.registers.poke_pc(*new_address as u16);\n }\n // 0x2nnn Call Subroutine\n Chip8CpuInstructions::CALL(new_address) =\u003e {\n let return_address = input.registers.peek_pc();\n input.registers.poke_pc(*new_address as u16);\n input.stack.push(\u0026return_address);\n }\n // 0x3xkk Skip next instruction if Vx = kk.\n Chip8CpuInstructions::SEX(vx_register, byte) =\u003e {\n if input.registers.peek(*vx_register as u8) == *byte as u8 {\n input.registers.advance_pc();\n }\n }\n // 0x4xkk Skip next instruction if Vx != kk\n Chip8CpuInstructions::SNEB(x, byte) =\u003e {\n // 4xkk - SNE Vx, byte\n // Skip next instruction if Vx != kk.\n //\n // The interpreter compares register Vx to kk, and if they are not equal,\n // increments the program counter by 2.\n if input.registers.peek(*x) != *byte {\n input.registers.advance_pc();\n }\n }\n // 0x5xy0 Skip next instruction if Vx == Vy\n Chip8CpuInstructions::SEY(x, y) =\u003e {\n if input.registers.peek(*x as u8) == input.registers.peek(*y as u8) {\n input.registers.advance_pc();\n }\n }\n // 0x6xkk Set Vx = kk\n Chip8CpuInstructions::LDR(register, byte) =\u003e {\n input.registers.poke(*register, *byte);\n }\n // 0x7xkk Set Vx = Vx + kk\n Chip8CpuInstructions::ADD(vx_register, byte) =\u003e {\n input.registers.poke(*vx_register, (input.registers.peek(*vx_register) as u16 + *byte as u16) as u8);\n }\n // 0x8xy0 Set value of Vy in Vx\n Chip8CpuInstructions::LDR_Y(x, y) =\u003e {\n input.registers.poke(*x as u8, input.registers.peek(*y as u8));\n }\n // 0x8xy1 Set Vx = Vx OR Vy\n Chip8CpuInstructions::OR(x, y) =\u003e {\n // shift them to 16 bit\n let working_16_x = input.registers.peek(*x as u8) as u16;\n let working_16_y = input.registers.peek(*y as u8) as u16;\n // OR them\n let working_16_or = working_16_x | working_16_y;\n // shift them back to 8 bit.\n input.registers.poke(*x as u8, working_16_or as u8);\n debug!(\"OrVxVy [0x{x:1x}] [0x{y:1x}]\")\n }\n // 0x8xy2 Set Vx = Vx AND Vy\n Chip8CpuInstructions::AND(x, y) =\u003e {\n let lhs_16 = input.registers.peek(*x as u8) as u16;\n let rhs_16 = input.registers.peek(*y as u8) as u16;\n input.registers.poke(*x as u8, (lhs_16 \u0026 rhs_16) as u8);\n }\n // 0x8xy3 Set Vx = Vx XOR Vy\n Chip8CpuInstructions::ORY(x, y) =\u003e {\n let lhs_16 = input.registers.peek(*x as u8) as u16;\n let rhs_16 = input.registers.peek(*y as u8) as u16;\n input.registers.poke(*x as u8, (lhs_16 ^ rhs_16) as u8);\n }\n // 0x8xy4 Set Vx = Vx + Vy (SET VF on Carry)\n Chip8CpuInstructions::ADDR(x, y) =\u003e {\n let lhs = input.registers.peek(*x as u8) as i16;\n let rhs = input.registers.peek(*y as u8) as i16;\n let working = lhs + rhs;\n input.registers.poke(*x as u8, working as u8);\n\n if working \u003e= 0x100 {\n input.registers.poke(0xf, 0x01);\n } else {\n input.registers.poke(0x0f, 0x00);\n }\n }\n Chip8CpuInstructions::SUB(x, y) =\u003e {\n // 8xy5 - SUB Vx, Vy\n // Set Vx = Vx - Vy, set VF = NOT borrow.\n //\n // If Vx \u003e Vy, then VF is set to 1, otherwise 0. Then Vy is subtracted from Vx, and the results stored in Vx.\n\n let lhs = input.registers.peek(*x);\n let rhs = input.registers.peek(*y);\n\n let mut result = 0;\n\n let borrow_flag: u8 = if rhs \u003e lhs {\n result = (lhs as u16 + 0x100) - rhs as u16;\n 0\n } else {\n result = lhs as u16 - rhs as u16;\n 1\n };\n\n input.registers.poke(*x as u8, result as u8);\n input.registers.poke(0x0f, borrow_flag);\n }\n Chip8CpuInstructions::SHR(x, _) =\u003e {\n // 8xy6 - SHR Vx {, Vy}\n // Set Vx = Vx SHR 1.\n // SHIFT 1 Bit ----\u003e\n // If the least-significant bit of Vx is 1, then VF is set to 1, otherwise 0. Then Vx is divided by 2.\n let initial_value = input.registers.peek(*x);\n\n // overflow check\n let rotated = initial_value \u003e\u003e 1;\n input.registers.poke(*x as u8, rotated);\n if initial_value.bitand(0b1) == 1 {\n input.registers.poke(0x0f, 0x01);\n } else {\n input.registers.poke(0x0f, 0x00);\n }\n }\n Chip8CpuInstructions::SUBC(x, y) =\u003e {\n // 8xy7 - SUBN Vx, Vy\n // Set Vx = Vy - Vx, set VF = NOT borrow.\n //\n // If Vy \u003e Vx, then VF is set to 1, otherwise 0. Then Vx is subtracted from Vy, and the results stored in Vx.\n let y_register = input.registers.peek(*y as u8);\n let x_register = input.registers.peek(*x as u8);\n let mut value_to_poke = 0;\n\n let new_value = if y_register \u003c x_register {\n value_to_poke = (y_register as u16 + 256) - x_register as u16;\n 0\n } else {\n value_to_poke = (y_register - x_register) as u16;\n 1\n };\n\n debug!(\"SUB CARRY -\u003e REGISTER 1 = [0x{x:02x}] / [{x_register}] REGISTER 2 = [0x{y:02x}] / [{y_register}] SUB = {value_to_poke} CARRY = {new_value}\");\n\n input.registers.poke(*x, value_to_poke as u8);\n input.registers.poke(0xf, new_value);\n }\n\n Chip8CpuInstructions::SHL(x, _) =\u003e {\n // 8xyE - SHL Vx {, Vy}\n // Set Vx = Vx SHL 1.\n //\n // If the most-significant bit of Vx is 1, then VF is set to 1, otherwise to 0. Then Vx is multiplied by 2.\n let initial_value = input.registers.peek(*x);\n\n // overflow check\n let rotated = initial_value \u003c\u003c 1;\n input.registers.poke(*x as u8, rotated);\n if initial_value.bitand(0b10000000) == 0b10000000 {\n input.registers.poke(0x0f, 0x01);\n } else {\n input.registers.poke(0x0f, 0x00);\n }\n }\n Chip8CpuInstructions::SNEY(vx_register, vy_register) =\u003e {\n // 9xy0 - SNE Vx, Vy\n // Skip next instruction if Vx != Vy.\n //\n // The values of Vx and Vy are compared, and if they are not equal, the program counter is increased by 2.\n\n let x_reg_value = input.registers.peek(*vx_register as u8);\n let y_reg_value = input.registers.peek(*vy_register as u8);\n if x_reg_value != y_reg_value {\n input.registers.advance_pc();\n }\n }\n Chip8CpuInstructions::LDIA(new_index) =\u003e {\n // Annn - LD I, addr\n // Set I = nnn.\n //\n // The value of register I is set to nnn.\n // debug!(\"LdiAddr [0x{new_index:3x}]\");\n input.registers.poke_i(*new_index);\n }\n // 0xBnnn Jump to nnn+V0\n Chip8CpuInstructions::JPI(addr) =\u003e {\n // Bnnn - JP V0, addr\n // Jump to location nnn + V0.\n //\n // The program counter is set to nnn plus the value of V0.\n input.registers.poke_pc(input.registers.peek(0) as u16 + addr);\n }\n Chip8CpuInstructions::RND(x, byte) =\u003e {\n // Cxkk - RND Vx, byte\n // Set Vx = random byte AND kk.\n //\n // The interpreter generates a random number from 0 to 255,\n // which is then ANDed with the value kk.\n // The results are stored in Vx.\n let mut rng = rand::thread_rng();\n let new_value: u8 = rng.random();\n let and_value: u8 = *byte;\n let result = new_value \u0026 and_value;\n debug!(\"RANDOM: [{new_value:02x}] AND: [{and_value:02x} Result: [{result:02x}]\");\n input.registers.poke(*x as u8, new_value \u0026 *byte as u8)\n }\n Chip8CpuInstructions::DRW(y, x, n) =\u003e {\n // Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision.\n\n // The interpreter reads n bytes from memory, starting at the address stored in I.\n\n // These bytes are then displayed as sprites on screen at coordinates (Vx, Vy).\n // Sprites are XORed onto the existing screen.\n // If this causes any pixels to be erased, VF is set to 1,\n // otherwise it is set to 0.\n // If the sprite is positioned so part of it is outside the coordinates of the display,\n // it wraps around to the opposite side of the screen.\n\n let source_memory_offset = input.registers.peek_i();\n let x_offset = input.registers.peek(*x) as u16;\n let y_offset = input.registers.peek(*y) as u16;\n if input.video_memory.is_highres() {\n // if n == 0 we have a 16 row sprite (font maybe)\n let actual_num_loops = if *n == 0u8 {\n 16\n } else {\n *n\n };\n for byte_index in 0..actual_num_loops {\n let current_byte = input.memory.peek(byte_index as u16 + source_memory_offset);\n let next_byte = input.memory.peek(byte_index as u16 + 1u16 + source_memory_offset);\n let x_offset = (x_offset + byte_index as u16) * 64;\n for bit_index in 0..8 {\n input.video_memory.poke(x_offset + (y_offset + bit_index as u16), (current_byte \u0026 (0x80 \u003e\u003e bit_index)) != 0);\n input.video_memory.poke(x_offset + (y_offset + bit_index as u16) + 8, (current_byte \u0026 (0x80 \u003e\u003e bit_index)) != 0);\n }\n }\n } else {\n for byte_index in 0..*n {\n let current_byte = input.memory.peek(byte_index as u16 + source_memory_offset);\n let x_offset: u16 = (x_offset + byte_index as u16) * 64;\n for bit_index in 0..8 {\n input.video_memory.poke(x_offset + (y_offset + bit_index as u16), (current_byte \u0026 (0x80 \u003e\u003e bit_index)) != 0);\n }\n }\n }\n\n let target = if input.video_memory.has_frame_changed {\n 1u8\n } else {\n 0u8\n };\n\n input.registers.poke(0xf, target);\n }\n Chip8CpuInstructions::SKP(x) =\u003e {\n // Ex9E - SKP Vx\n // Skip next instruction if key with the value of Vx is pressed.\n //\n // Checks the keyboard, and if the key corresponding to the value of Vx is currently in the down position, PC is increased by 2.\n let key_to_check = input.registers.peek(*x as u8);\n let is_pressed = input.keypad.pressed(key_to_check);\n if is_pressed {\n input.registers.advance_pc();\n }\n }\n Chip8CpuInstructions::SKNP(x) =\u003e {\n // ExA1 - SKNP Vx\n // Skip next instruction if key with the value of Vx is not pressed.\n //\n\n // Checks the keyboard,\n // and if the key corresponding to the value of Vx is currently in the up position,\n // PC is increased by 2.\n let target_key = input.registers.peek(*x as u8);\n let is_pressed = input.keypad.pressed(target_key);\n debug!(\"SnKpVx [{x:1x}]\");\n if !is_pressed {\n input.registers.advance_pc();\n }\n }\n Chip8CpuInstructions::LDRD(x) =\u003e {\n // Fx07 - LD Vx, DT\n // Set Vx = delay timer value.\n //\n // The value of DT is placed into Vx.\n let value_to_set = input.delay_timer.current();\n input.registers.poke(*x as u8, value_to_set as u8);\n }\n Chip8CpuInstructions::LDRK(x) =\u003e {\n // Fx0A - LD Vx, K\n // Wait for a key press, store the value of the key in Vx.\n //\n // All execution stops until a key is pressed, then the value of that key is stored in Vx.\n input.state = WaitingForKey;\n }\n Chip8CpuInstructions::LDD(source_register) =\u003e {\n // Fx15 - LD DT, Vx\n // Set delay timer = Vx.\n //\n // DT is set equal to the value of Vx.\n let new_time = input.registers.peek(*source_register as u8);\n input.delay_timer.set_timer(new_time);\n }\n Chip8CpuInstructions::LDIS(new_time) =\u003e {\n let new_value = input.registers.peek(*new_time as u8);\n input.sound_timer.set_timer(new_value as i32);\n }\n Chip8CpuInstructions::ADDI(x) =\u003e {\n // Fx1E - ADD I, Vx\n // Set I = I + Vx.\n //\n // The values of I and Vx are added, and the results are stored in I.\n let base = input.registers.peek_i();\n let x_value = input.registers.peek(*x as u8);\n input.registers.poke_i(base + x_value as u16);\n }\n Chip8CpuInstructions::LDFX(x) =\u003e {\n // Fx29 - LD F, Vx\n // Set I = location of sprite for digit Vx.\n //\n // The value of I is set to the location for the hexadecimal sprite corresponding\n // to the value of Vx. See section 2.4, Display, for more information on\n // the Chip-8 hexadecimal font.\n\n let x_value: u8 = input.registers.peek(*x);\n\n let real_offset = x_value as u16 * 5;\n input.registers.poke_i(real_offset as u16);\n }\n Chip8CpuInstructions::BCD(x) =\u003e {\n // Fx33 - LD B, Vx\n // Store BCD representation of Vx in memory locations I, I+1, and I+2.\n //\n // The interpreter takes the decimal value of Vx, and places the hundreds\n // digit in memory at location in I, the tens digit at location I+1,\n // and the ones digit at location I+2.\n\n let to_convert = input.registers.peek(*x as u8);\n\n // how many hundreds\n let hundreds = to_convert / 100;\n // how many tens, minus the hundreds\n let tens = (to_convert / 10) - (hundreds * 10);\n // whats the leftover when dividing by 10\n let units = to_convert % 10;\n\n // Convert to BCD\n let result = ((hundreds as u16) \u003c\u003c 8) | units as u16 | ((tens as u16) \u003c\u003c 4) | units as u16;\n // write them to the memory pointed to by I, I+1, and I+2\n let target_start_offset = input.registers.peek_i();\n input.memory.poke(target_start_offset, hundreds);\n input.memory.poke(target_start_offset + 1, tens);\n input.memory.poke(target_start_offset + 2, units);\n }\n Chip8CpuInstructions::LDIX(x) =\u003e {\n // Store registers V0 through Vx in memory starting at location I.\n //\n // The interpreter copies the values of registers V0 through Vx into memory,\n // starting at the address in I.\n let offset = input.registers.peek_i();\n for i in 0..=*x {\n input.memory.poke(offset + i as u16, input.registers.peek(i as u8));\n }\n input.registers.poke_i(offset + 1);\n }\n Chip8CpuInstructions::LDRI(x) =\u003e {\n // Read registers V0 through Vx from memory starting at location I.\n //\n // The interpreter reads values from memory starting at location I into registers V0 through Vx.\n let offset = input.registers.peek_i();\n debug!(\"STARTING TO READ AT {offset:03x}\");\n let num_loops = x + 1;\n debug!(\"WILL READ {num_loops:x} BYTES\");\n for index in 0..num_loops {\n let src_value = input.memory.peek(index as u16 + offset);\n input.registers.poke(index as u8, src_value);\n debug!(\"POKING Register 0x{index:02x} with 0x{src_value:04x} using offset 0x{offset:04x}\");\n }\n input.registers.poke_i(offset + 1);\n }\n Chip8CpuInstructions::XXXXERRORINSTRUCTION =\u003e {}\n Chip8CpuInstructions::SDN(x) =\u003e {\n input.video_memory.scroll_down(*x as i32);\n }\n Chip8CpuInstructions::SRT =\u003e {\n input.video_memory.scroll_right();\n }\n Chip8CpuInstructions::SLF =\u003e {\n input.video_memory.scroll_left();\n }\n Chip8CpuInstructions::DIS =\u003e {\n input.video_memory.set_lowres();\n }\n Chip8CpuInstructions::ENA =\u003e {\n input.video_memory.set_highres();\n }\n Chip8CpuInstructions::EXIT =\u003e {\n println!(\"EXIT INTERPRETER\");\n }\n Chip8CpuInstructions::LDF2(x) =\u003e {\n println!(\"POINTING TO FONT AT {x:02x}\");\n // base = 0x100 + 0x0A*X\n input.registers.poke_i(0x100 + (0xA * x) as u16);\n }\n Chip8CpuInstructions::STR(x) =\u003e {\n println!(\"STORING FROM RPL FOR {x}\");\n }\n Chip8CpuInstructions::LIDR(x) =\u003e {\n println!(\"LOADING FROM RPL FOR {x}\");\n }\n };\n let cycle_time = Instant::now().duration_since(start_time).as_nanos();\n // println!(\"\\t\\tTook {cycle_time}ms\");\n input.to_owned()\n }\n\n pub fn from_string(input: \u0026str) -\u003e Chip8CpuInstructions {\n let parts = input.split(\" \");\n println!(\"Parts -\u003e {:?}\", parts);\n\n Chip8CpuInstructions::XXXXERRORINSTRUCTION\n }\n}\n","traces":[{"line":266,"address":[330080],"length":1,"stats":{"Line":1}},{"line":267,"address":[330085],"length":1,"stats":{"Line":1}},{"line":268,"address":[755584],"length":1,"stats":{"Line":0}},{"line":269,"address":[42143294],"length":1,"stats":{"Line":0}},{"line":270,"address":[42143424],"length":1,"stats":{"Line":0}},{"line":271,"address":[596796],"length":1,"stats":{"Line":0}},{"line":272,"address":[330142],"length":1,"stats":{"Line":1}},{"line":273,"address":[3571292],"length":1,"stats":{"Line":0}},{"line":274,"address":[755402],"length":1,"stats":{"Line":0}},{"line":275,"address":[331176],"length":1,"stats":{"Line":0}},{"line":276,"address":[754882],"length":1,"stats":{"Line":1}},{"line":277,"address":[755350],"length":1,"stats":{"Line":0}},{"line":278,"address":[1189876],"length":1,"stats":{"Line":0}},{"line":279,"address":[1189772],"length":1,"stats":{"Line":0}},{"line":280,"address":[1189850],"length":1,"stats":{"Line":0}},{"line":281,"address":[710623],"length":1,"stats":{"Line":0}},{"line":282,"address":[645372],"length":1,"stats":{"Line":0}},{"line":283,"address":[597342],"length":1,"stats":{"Line":0}},{"line":284,"address":[645981],"length":1,"stats":{"Line":0}},{"line":285,"address":[710294],"length":1,"stats":{"Line":0}},{"line":286,"address":[709748],"length":1,"stats":{"Line":0}},{"line":287,"address":[710216],"length":1,"stats":{"Line":0}},{"line":288,"address":[42143944],"length":1,"stats":{"Line":0}},{"line":289,"address":[330818],"length":1,"stats":{"Line":0}},{"line":290,"address":[709800],"length":1,"stats":{"Line":0}},{"line":291,"address":[1189330],"length":1,"stats":{"Line":0}},{"line":292,"address":[596536],"length":1,"stats":{"Line":1}},{"line":293,"address":[597056],"length":1,"stats":{"Line":0}},{"line":294,"address":[645788],"length":1,"stats":{"Line":0}},{"line":295,"address":[710528],"length":1,"stats":{"Line":0}},{"line":296,"address":[3572150],"length":1,"stats":{"Line":0}},{"line":297,"address":[709670],"length":1,"stats":{"Line":0}},{"line":298,"address":[3571370],"length":1,"stats":{"Line":0}},{"line":299,"address":[645320],"length":1,"stats":{"Line":0}},{"line":300,"address":[755220],"length":1,"stats":{"Line":0}},{"line":301,"address":[597108],"length":1,"stats":{"Line":0}},{"line":302,"address":[330272],"length":1,"stats":{"Line":0}},{"line":303,"address":[42143554],"length":1,"stats":{"Line":0}},{"line":304,"address":[645502],"length":1,"stats":{"Line":0}},{"line":305,"address":[597590],"length":1,"stats":{"Line":0}},{"line":306,"address":[645242],"length":1,"stats":{"Line":0}},{"line":307,"address":[755246],"length":1,"stats":{"Line":0}},{"line":308,"address":[42143060],"length":1,"stats":{"Line":1}},{"line":309,"address":[597498],"length":1,"stats":{"Line":0}},{"line":310,"address":[710577],"length":1,"stats":{"Line":0}},{"line":311,"address":[3571526],"length":1,"stats":{"Line":0}},{"line":312,"address":[331026],"length":1,"stats":{"Line":0}},{"line":316,"address":[1190208],"length":1,"stats":{"Line":2}},{"line":317,"address":[758386,758320,756096,758276,758210,756614,756318,756670,758342,756170,756429,758144,758254,756133,756577,755998,756651,756244,756355,756392,756689,758298,756281,756466,758188,758232,758364,758408,758122,756207,758430,756043,756540,756726,758166,756077,756503],"length":1,"stats":{"Line":9}},{"line":318,"address":[1190274],"length":1,"stats":{"Line":2}},{"line":323,"address":[42147053,42147172,42146792],"length":1,"stats":{"Line":6}},{"line":325,"address":[1190939],"length":1,"stats":{"Line":0}},{"line":330,"address":[3575821,3576053,3575525,3576223],"length":1,"stats":{"Line":0}},{"line":333,"address":[711138],"length":1,"stats":{"Line":0}},{"line":344,"address":[3576744,3576448,3576976],"length":1,"stats":{"Line":0}},{"line":347,"address":[332048],"length":1,"stats":{"Line":0}},{"line":348,"address":[3574052,3574284,3574484,3573492,3573820],"length":1,"stats":{"Line":0}},{"line":351,"address":[42146454],"length":1,"stats":{"Line":0}},{"line":366,"address":[760885,761149,761289],"length":1,"stats":{"Line":0}},{"line":376,"address":[756053],"length":1,"stats":{"Line":1}},{"line":383,"address":[761296,761952],"length":1,"stats":{"Line":1}},{"line":384,"address":[603015],"length":1,"stats":{"Line":1}},{"line":385,"address":[3577743,3577799],"length":1,"stats":{"Line":2}},{"line":386,"address":[716204,716563],"length":1,"stats":{"Line":2}},{"line":391,"address":[716720],"length":1,"stats":{"Line":1}},{"line":392,"address":[1196253],"length":1,"stats":{"Line":1}},{"line":394,"address":[42150293],"length":1,"stats":{"Line":1}},{"line":398,"address":[652143],"length":1,"stats":{"Line":1}},{"line":399,"address":[42150514],"length":1,"stats":{"Line":1}},{"line":400,"address":[762421],"length":1,"stats":{"Line":1}},{"line":403,"address":[762594],"length":1,"stats":{"Line":1}},{"line":404,"address":[604328],"length":1,"stats":{"Line":1}},{"line":406,"address":[762625],"length":1,"stats":{"Line":1}},{"line":407,"address":[762706],"length":1,"stats":{"Line":0}},{"line":409,"address":[604348],"length":1,"stats":{"Line":1}},{"line":410,"address":[717507],"length":1,"stats":{"Line":0}},{"line":412,"address":[42150994],"length":1,"stats":{"Line":1}},{"line":413,"address":[3579211],"length":1,"stats":{"Line":0}},{"line":415,"address":[604479],"length":1,"stats":{"Line":1}},{"line":416,"address":[652928],"length":1,"stats":{"Line":1}},{"line":418,"address":[762852],"length":1,"stats":{"Line":1}},{"line":419,"address":[762928],"length":1,"stats":{"Line":1}},{"line":421,"address":[604585],"length":1,"stats":{"Line":1}},{"line":422,"address":[653024],"length":1,"stats":{"Line":1}},{"line":424,"address":[1197188],"length":1,"stats":{"Line":0}},{"line":425,"address":[338307],"length":1,"stats":{"Line":0}},{"line":427,"address":[1197241],"length":1,"stats":{"Line":0}},{"line":428,"address":[338365],"length":1,"stats":{"Line":0}},{"line":430,"address":[1197294],"length":1,"stats":{"Line":0}},{"line":431,"address":[338426],"length":1,"stats":{"Line":0}},{"line":433,"address":[3579499],"length":1,"stats":{"Line":0}},{"line":434,"address":[1197444],"length":1,"stats":{"Line":0}},{"line":436,"address":[338454],"length":1,"stats":{"Line":0}},{"line":437,"address":[3579635],"length":1,"stats":{"Line":0}},{"line":439,"address":[717964],"length":1,"stats":{"Line":0}},{"line":440,"address":[718030],"length":1,"stats":{"Line":0}},{"line":442,"address":[1197511],"length":1,"stats":{"Line":0}},{"line":443,"address":[653385],"length":1,"stats":{"Line":0}},{"line":445,"address":[718050],"length":1,"stats":{"Line":0}},{"line":446,"address":[1197620],"length":1,"stats":{"Line":0}},{"line":448,"address":[763357],"length":1,"stats":{"Line":0}},{"line":449,"address":[718159],"length":1,"stats":{"Line":0}},{"line":451,"address":[3579784],"length":1,"stats":{"Line":0}},{"line":452,"address":[763476],"length":1,"stats":{"Line":0}},{"line":454,"address":[763443],"length":1,"stats":{"Line":0}},{"line":455,"address":[605217],"length":1,"stats":{"Line":0}},{"line":457,"address":[763504],"length":1,"stats":{"Line":0}},{"line":458,"address":[42151854],"length":1,"stats":{"Line":0}},{"line":460,"address":[718301],"length":1,"stats":{"Line":0}},{"line":461,"address":[3580043],"length":1,"stats":{"Line":0}},{"line":463,"address":[763626],"length":1,"stats":{"Line":0}},{"line":464,"address":[338998],"length":1,"stats":{"Line":0}},{"line":466,"address":[763687],"length":1,"stats":{"Line":0}},{"line":467,"address":[718517],"length":1,"stats":{"Line":0}},{"line":469,"address":[339026],"length":1,"stats":{"Line":0}},{"line":470,"address":[605522],"length":1,"stats":{"Line":0}},{"line":472,"address":[3580193],"length":1,"stats":{"Line":0}},{"line":473,"address":[1198143],"length":1,"stats":{"Line":0}},{"line":475,"address":[763870],"length":1,"stats":{"Line":0}},{"line":476,"address":[1198204],"length":1,"stats":{"Line":0}},{"line":478,"address":[605611],"length":1,"stats":{"Line":0}},{"line":479,"address":[654073],"length":1,"stats":{"Line":0}},{"line":481,"address":[605672],"length":1,"stats":{"Line":0}},{"line":482,"address":[339364],"length":1,"stats":{"Line":0}},{"line":484,"address":[339331],"length":1,"stats":{"Line":0}},{"line":485,"address":[1198387],"length":1,"stats":{"Line":0}},{"line":487,"address":[605794],"length":1,"stats":{"Line":0}},{"line":488,"address":[339481],"length":1,"stats":{"Line":0}},{"line":490,"address":[605855],"length":1,"stats":{"Line":0}},{"line":491,"address":[654309],"length":1,"stats":{"Line":0}},{"line":493,"address":[1198468],"length":1,"stats":{"Line":0}},{"line":494,"address":[3580701],"length":1,"stats":{"Line":0}},{"line":496,"address":[605969],"length":1,"stats":{"Line":0}},{"line":497,"address":[42152625],"length":1,"stats":{"Line":0}},{"line":499,"address":[339619],"length":1,"stats":{"Line":0}},{"line":500,"address":[3580805],"length":1,"stats":{"Line":0}},{"line":502,"address":[3580777],"length":1,"stats":{"Line":0}},{"line":503,"address":[3580857],"length":1,"stats":{"Line":0}},{"line":505,"address":[3580829],"length":1,"stats":{"Line":0}},{"line":506,"address":[719261],"length":1,"stats":{"Line":0}},{"line":508,"address":[1198737],"length":1,"stats":{"Line":0}},{"line":509,"address":[339855],"length":1,"stats":{"Line":0}},{"line":511,"address":[1198789],"length":1,"stats":{"Line":0}},{"line":512,"address":[606309],"length":1,"stats":{"Line":0}},{"line":514,"address":[1198841],"length":1,"stats":{"Line":0}},{"line":515,"address":[654729],"length":1,"stats":{"Line":0}},{"line":517,"address":[606333],"length":1,"stats":{"Line":0}},{"line":518,"address":[340011],"length":1,"stats":{"Line":0}},{"line":520,"address":[1198945],"length":1,"stats":{"Line":0}},{"line":521,"address":[764785],"length":1,"stats":{"Line":0}},{"line":523,"address":[1198997],"length":1,"stats":{"Line":0}},{"line":524,"address":[606514],"length":1,"stats":{"Line":0}},{"line":526,"address":[654854],"length":1,"stats":{"Line":0}},{"line":527,"address":[764883],"length":1,"stats":{"Line":0}},{"line":529,"address":[764855],"length":1,"stats":{"Line":0}},{"line":530,"address":[654954],"length":1,"stats":{"Line":0}},{"line":533,"address":[764894],"length":1,"stats":{"Line":0}},{"line":538,"address":[654976],"length":1,"stats":{"Line":1}},{"line":539,"address":[3581328],"length":1,"stats":{"Line":2}},{"line":540,"address":[340259],"length":1,"stats":{"Line":1}},{"line":541,"address":[765019],"length":1,"stats":{"Line":1}},{"line":542,"address":[3581415],"length":1,"stats":{"Line":1}},{"line":543,"address":[340327],"length":1,"stats":{"Line":1}},{"line":544,"address":[606771],"length":1,"stats":{"Line":1}},{"line":545,"address":[42153391],"length":1,"stats":{"Line":1}},{"line":546,"address":[606872],"length":1,"stats":{"Line":1}},{"line":547,"address":[655297],"length":1,"stats":{"Line":1}},{"line":548,"address":[720046],"length":1,"stats":{"Line":1}},{"line":549,"address":[42153623],"length":1,"stats":{"Line":1}},{"line":550,"address":[340707],"length":1,"stats":{"Line":1}},{"line":551,"address":[42153750],"length":1,"stats":{"Line":1}},{"line":552,"address":[765561],"length":1,"stats":{"Line":1}},{"line":553,"address":[42153884],"length":1,"stats":{"Line":1}},{"line":554,"address":[765695],"length":1,"stats":{"Line":1}},{"line":555,"address":[607442],"length":1,"stats":{"Line":1}},{"line":556,"address":[607509],"length":1,"stats":{"Line":1}},{"line":557,"address":[765896],"length":1,"stats":{"Line":1}},{"line":558,"address":[720699],"length":1,"stats":{"Line":1}},{"line":559,"address":[1200270],"length":1,"stats":{"Line":1}},{"line":560,"address":[607777],"length":1,"stats":{"Line":1}},{"line":561,"address":[656188],"length":1,"stats":{"Line":1}},{"line":562,"address":[42154439],"length":1,"stats":{"Line":1}},{"line":563,"address":[656294],"length":1,"stats":{"Line":1}},{"line":564,"address":[42154547],"length":1,"stats":{"Line":1}},{"line":566,"address":[766335],"length":1,"stats":{"Line":1}},{"line":567,"address":[766376],"length":1,"stats":{"Line":1}},{"line":568,"address":[656465],"length":1,"stats":{"Line":1}},{"line":569,"address":[721194],"length":1,"stats":{"Line":1}},{"line":570,"address":[608179],"length":1,"stats":{"Line":1}},{"line":571,"address":[1200780],"length":1,"stats":{"Line":1}},{"line":572,"address":[1200821],"length":1,"stats":{"Line":1}},{"line":573,"address":[341902],"length":1,"stats":{"Line":1}},{"line":574,"address":[608343],"length":1,"stats":{"Line":1}},{"line":575,"address":[608384],"length":1,"stats":{"Line":1}},{"line":576,"address":[3583129],"length":1,"stats":{"Line":1}},{"line":577,"address":[608478],"length":1,"stats":{"Line":1}},{"line":578,"address":[42155087],"length":1,"stats":{"Line":1}},{"line":579,"address":[3583227],"length":1,"stats":{"Line":1}},{"line":580,"address":[342135],"length":1,"stats":{"Line":1}},{"line":581,"address":[3583251],"length":1,"stats":{"Line":1}},{"line":582,"address":[608556],"length":1,"stats":{"Line":1}},{"line":583,"address":[721625],"length":1,"stats":{"Line":1}},{"line":584,"address":[42155183],"length":1,"stats":{"Line":1}},{"line":585,"address":[1201205],"length":1,"stats":{"Line":1}},{"line":586,"address":[3583166],"length":1,"stats":{"Line":1}},{"line":589,"address":[721760],"length":1,"stats":{"Line":3}},{"line":590,"address":[608731],"length":1,"stats":{"Line":6}},{"line":591,"address":[608755],"length":1,"stats":{"Line":3}},{"line":592,"address":[657147],"length":1,"stats":{"Line":6}},{"line":593,"address":[1201366],"length":1,"stats":{"Line":3}},{"line":594,"address":[721886],"length":1,"stats":{"Line":6}},{"line":595,"address":[3583558],"length":1,"stats":{"Line":3}},{"line":596,"address":[342470],"length":1,"stats":{"Line":6}},{"line":597,"address":[721947],"length":1,"stats":{"Line":3}},{"line":599,"address":[3583624],"length":1,"stats":{"Line":6}},{"line":600,"address":[42155482,42155544],"length":1,"stats":{"Line":9}},{"line":601,"address":[1201539],"length":1,"stats":{"Line":0}},{"line":603,"address":[344273],"length":1,"stats":{"Line":0}},{"line":606,"address":[769013],"length":1,"stats":{"Line":0}},{"line":609,"address":[42157287],"length":1,"stats":{"Line":0}},{"line":613,"address":[722090],"length":1,"stats":{"Line":2}},{"line":614,"address":[342635],"length":1,"stats":{"Line":2}},{"line":616,"address":[3583757],"length":1,"stats":{"Line":0}},{"line":619,"address":[3583824],"length":1,"stats":{"Line":0}},{"line":622,"address":[609127],"length":1,"stats":{"Line":0}},{"line":625,"address":[722190],"length":1,"stats":{"Line":0}},{"line":629,"address":[609083],"length":1,"stats":{"Line":0}},{"line":630,"address":[767410],"length":1,"stats":{"Line":0}},{"line":631,"address":[3583801],"length":1,"stats":{"Line":0}},{"line":632,"address":[657472],"length":1,"stats":{"Line":0}},{"line":633,"address":[3583729,3583866],"length":1,"stats":{"Line":10}},{"line":634,"address":[342740,342800],"length":1,"stats":{"Line":10}},{"line":635,"address":[657618,657558],"length":1,"stats":{"Line":9}},{"line":636,"address":[3583938,3584001],"length":1,"stats":{"Line":9}},{"line":637,"address":[657718,657649],"length":1,"stats":{"Line":9}},{"line":638,"address":[610661,609334,609403],"length":1,"stats":{"Line":10}},{"line":639,"address":[343048,342981],"length":1,"stats":{"Line":9}},{"line":640,"address":[1201998,1202067],"length":1,"stats":{"Line":8}},{"line":641,"address":[1202051,1202120],"length":1,"stats":{"Line":10}},{"line":642,"address":[658795],"length":1,"stats":{"Line":1}},{"line":643,"address":[42157029],"length":1,"stats":{"Line":1}},{"line":644,"address":[723535],"length":1,"stats":{"Line":1}},{"line":645,"address":[42157081],"length":1,"stats":{"Line":1}},{"line":646,"address":[723587],"length":1,"stats":{"Line":2}},{"line":647,"address":[610557],"length":1,"stats":{"Line":2}},{"line":648,"address":[344177],"length":1,"stats":{"Line":1}},{"line":649,"address":[344203],"length":1,"stats":{"Line":1}},{"line":650,"address":[610635],"length":1,"stats":{"Line":1}},{"line":651,"address":[768729],"length":1,"stats":{"Line":1}},{"line":653,"address":[343985,343138,343220],"length":1,"stats":{"Line":10}},{"line":654,"address":[3584381,3584314],"length":1,"stats":{"Line":9}},{"line":655,"address":[343255,343318],"length":1,"stats":{"Line":6}},{"line":656,"address":[343365,343302],"length":1,"stats":{"Line":7}},{"line":657,"address":[42156331,42156400],"length":1,"stats":{"Line":6}},{"line":658,"address":[42156384,42156461],"length":1,"stats":{"Line":6}},{"line":659,"address":[3585055],"length":1,"stats":{"Line":0}},{"line":660,"address":[1202929],"length":1,"stats":{"Line":0}},{"line":661,"address":[343931],"length":1,"stats":{"Line":1}},{"line":663,"address":[42156513,42156445],"length":1,"stats":{"Line":6}},{"line":664,"address":[723181],"length":1,"stats":{"Line":0}},{"line":665,"address":[768463],"length":1,"stats":{"Line":1}},{"line":666,"address":[768481],"length":1,"stats":{"Line":0}},{"line":667,"address":[723235],"length":1,"stats":{"Line":0}},{"line":668,"address":[343791],"length":1,"stats":{"Line":1}},{"line":669,"address":[343809],"length":1,"stats":{"Line":0}},{"line":670,"address":[42156809],"length":1,"stats":{"Line":0}},{"line":671,"address":[3584955],"length":1,"stats":{"Line":1}},{"line":672,"address":[3584973],"length":1,"stats":{"Line":2}},{"line":673,"address":[610287],"length":1,"stats":{"Line":1}},{"line":674,"address":[723361],"length":1,"stats":{"Line":0}},{"line":675,"address":[658691],"length":1,"stats":{"Line":0}},{"line":676,"address":[768431],"length":1,"stats":{"Line":1}},{"line":678,"address":[3584626],"length":1,"stats":{"Line":1}},{"line":681,"address":[736082,723792],"length":1,"stats":{"Line":2}},{"line":683,"address":[610806],"length":1,"stats":{"Line":2}},{"line":684,"address":[344434],"length":1,"stats":{"Line":4}},{"line":685,"address":[723935,724040],"length":1,"stats":{"Line":4}},{"line":686,"address":[3585653],"length":1,"stats":{"Line":4}},{"line":688,"address":[659386],"length":1,"stats":{"Line":1}},{"line":689,"address":[611033],"length":1,"stats":{"Line":1}},{"line":693,"address":[42157639],"length":1,"stats":{"Line":2}},{"line":697,"address":[42157658],"length":1,"stats":{"Line":2}},{"line":700,"address":[344722],"length":1,"stats":{"Line":4}},{"line":701,"address":[611162],"length":1,"stats":{"Line":4}},{"line":704,"address":[724256],"length":1,"stats":{"Line":3}},{"line":705,"address":[724268],"length":1,"stats":{"Line":3}},{"line":706,"address":[769572],"length":1,"stats":{"Line":3}},{"line":707,"address":[611277],"length":1,"stats":{"Line":3}},{"line":710,"address":[769636],"length":1,"stats":{"Line":2}},{"line":711,"address":[659714],"length":1,"stats":{"Line":2}},{"line":712,"address":[664936],"length":1,"stats":{"Line":2}},{"line":716,"address":[769721],"length":1,"stats":{"Line":2}},{"line":722,"address":[345001],"length":1,"stats":{"Line":2}},{"line":723,"address":[42163170],"length":1,"stats":{"Line":3}},{"line":727,"address":[769806],"length":1,"stats":{"Line":2}},{"line":728,"address":[345085],"length":1,"stats":{"Line":2}},{"line":729,"address":[774940],"length":1,"stats":{"Line":1}},{"line":733,"address":[659981],"length":1,"stats":{"Line":3}},{"line":734,"address":[345210],"length":1,"stats":{"Line":2}},{"line":737,"address":[770007],"length":1,"stats":{"Line":2}},{"line":738,"address":[665029,660085],"length":1,"stats":{"Line":4}},{"line":741,"address":[724876],"length":1,"stats":{"Line":2}},{"line":742,"address":[345415],"length":1,"stats":{"Line":2}},{"line":745,"address":[1204503],"length":1,"stats":{"Line":2}},{"line":747,"address":[611970],"length":1,"stats":{"Line":2}},{"line":748,"address":[660389],"length":1,"stats":{"Line":2}},{"line":750,"address":[1204634],"length":1,"stats":{"Line":2}},{"line":752,"address":[1204645],"length":1,"stats":{"Line":2}},{"line":753,"address":[730037,730565,725170,730333,729778],"length":1,"stats":{"Line":4}},{"line":756,"address":[770496],"length":1,"stats":{"Line":2}},{"line":757,"address":[42158782],"length":1,"stats":{"Line":2}},{"line":758,"address":[1204820],"length":1,"stats":{"Line":2}},{"line":759,"address":[612314],"length":1,"stats":{"Line":2}},{"line":762,"address":[770680],"length":1,"stats":{"Line":2}},{"line":763,"address":[612390],"length":1,"stats":{"Line":2}},{"line":764,"address":[42159020],"length":1,"stats":{"Line":3}},{"line":765,"address":[725554],"length":1,"stats":{"Line":3}},{"line":768,"address":[612544],"length":1,"stats":{"Line":3}},{"line":769,"address":[42159158],"length":1,"stats":{"Line":3}},{"line":770,"address":[42159212],"length":1,"stats":{"Line":3}},{"line":771,"address":[42164330,42159250,42164375],"length":1,"stats":{"Line":6}},{"line":772,"address":[1210322],"length":1,"stats":{"Line":3}},{"line":774,"address":[1210351],"length":1,"stats":{"Line":3}},{"line":775,"address":[42164432],"length":1,"stats":{"Line":2}},{"line":777,"address":[730879],"length":1,"stats":{"Line":2}},{"line":780,"address":[612717],"length":1,"stats":{"Line":3}},{"line":786,"address":[42159331],"length":1,"stats":{"Line":3}},{"line":787,"address":[771124],"length":1,"stats":{"Line":3}},{"line":789,"address":[612842],"length":1,"stats":{"Line":3}},{"line":791,"address":[1210725,1205412,1210544],"length":1,"stats":{"Line":6}},{"line":792,"address":[42164677,42164508,42164746],"length":1,"stats":{"Line":2}},{"line":793,"address":[618157],"length":1,"stats":{"Line":1}},{"line":795,"address":[731024,731042,730954],"length":1,"stats":{"Line":4}},{"line":796,"address":[3592680],"length":1,"stats":{"Line":2}},{"line":799,"address":[351508],"length":1,"stats":{"Line":3}},{"line":800,"address":[618055],"length":1,"stats":{"Line":3}},{"line":802,"address":[3587585],"length":1,"stats":{"Line":2}},{"line":807,"address":[771216],"length":1,"stats":{"Line":2}},{"line":810,"address":[661311],"length":1,"stats":{"Line":2}},{"line":811,"address":[771272],"length":1,"stats":{"Line":3}},{"line":812,"address":[661347],"length":1,"stats":{"Line":3}},{"line":813,"address":[666562],"length":1,"stats":{"Line":2}},{"line":815,"address":[731286],"length":1,"stats":{"Line":2}},{"line":818,"address":[1205581],"length":1,"stats":{"Line":2}},{"line":823,"address":[726104],"length":1,"stats":{"Line":2}},{"line":824,"address":[1205647],"length":1,"stats":{"Line":2}},{"line":825,"address":[661486],"length":1,"stats":{"Line":2}},{"line":827,"address":[3593183,3593045,3587832],"length":1,"stats":{"Line":6}},{"line":828,"address":[731466,731537,731342],"length":1,"stats":{"Line":4}},{"line":829,"address":[731527],"length":1,"stats":{"Line":2}},{"line":831,"address":[666711,666623,666690],"length":1,"stats":{"Line":4}},{"line":832,"address":[351819],"length":1,"stats":{"Line":2}},{"line":835,"address":[669212,668100,668320,668552,666727,668772,667676,666977,668992],"length":1,"stats":{"Line":4}},{"line":837,"address":[1211065],"length":1,"stats":{"Line":2}},{"line":838,"address":[776870],"length":1,"stats":{"Line":2}},{"line":841,"address":[3587873],"length":1,"stats":{"Line":2}},{"line":846,"address":[1205744],"length":1,"stats":{"Line":2}},{"line":849,"address":[346776],"length":1,"stats":{"Line":2}},{"line":850,"address":[613240],"length":1,"stats":{"Line":2}},{"line":851,"address":[42159843],"length":1,"stats":{"Line":2}},{"line":852,"address":[42167776],"length":1,"stats":{"Line":3}},{"line":854,"address":[734292],"length":1,"stats":{"Line":2}},{"line":857,"address":[346853],"length":1,"stats":{"Line":2}},{"line":863,"address":[661707],"length":1,"stats":{"Line":2}},{"line":864,"address":[771708],"length":1,"stats":{"Line":2}},{"line":865,"address":[346963],"length":1,"stats":{"Line":2}},{"line":866,"address":[621269],"length":1,"stats":{"Line":1}},{"line":869,"address":[3588154],"length":1,"stats":{"Line":2}},{"line":875,"address":[3588169],"length":1,"stats":{"Line":4}},{"line":878,"address":[3588207],"length":1,"stats":{"Line":1}},{"line":883,"address":[3588227],"length":1,"stats":{"Line":1}},{"line":885,"address":[347150],"length":1,"stats":{"Line":3}},{"line":892,"address":[662021],"length":1,"stats":{"Line":3}},{"line":893,"address":[621346,613670],"length":1,"stats":{"Line":5}},{"line":894,"address":[3596057],"length":1,"stats":{"Line":3}},{"line":895,"address":[669730],"length":1,"stats":{"Line":2}},{"line":896,"address":[42168517,42168845,42168129,42169309,42167961,42169077],"length":1,"stats":{"Line":6}},{"line":897,"address":[1214027],"length":1,"stats":{"Line":3}},{"line":899,"address":[613715],"length":1,"stats":{"Line":2}},{"line":911,"address":[347300],"length":1,"stats":{"Line":4}},{"line":912,"address":[3588517],"length":1,"stats":{"Line":2}},{"line":913,"address":[42160443],"length":1,"stats":{"Line":4}},{"line":914,"address":[726967],"length":1,"stats":{"Line":2}},{"line":916,"address":[736147,736771],"length":1,"stats":{"Line":0}},{"line":917,"address":[1216267],"length":1,"stats":{"Line":0}},{"line":919,"address":[672093],"length":1,"stats":{"Line":0}},{"line":921,"address":[736790],"length":1,"stats":{"Line":0}},{"line":922,"address":[672409,672333,672221],"length":1,"stats":{"Line":0}},{"line":923,"address":[672549,672441,672373],"length":1,"stats":{"Line":0}},{"line":924,"address":[624205,624158,624290],"length":1,"stats":{"Line":0}},{"line":925,"address":[737362,737317],"length":1,"stats":{"Line":0}},{"line":926,"address":[624377,624550],"length":1,"stats":{"Line":0}},{"line":927,"address":[358031,357985],"length":1,"stats":{"Line":0}},{"line":931,"address":[623056,623105,623192],"length":1,"stats":{"Line":10}},{"line":932,"address":[3597917,3598029],"length":1,"stats":{"Line":2}},{"line":933,"address":[736490,736358,736405],"length":1,"stats":{"Line":6}},{"line":934,"address":[781725,781770],"length":1,"stats":{"Line":6}},{"line":935,"address":[356991],"length":1,"stats":{"Line":4}},{"line":940,"address":[781481,782220],"length":1,"stats":{"Line":2}},{"line":941,"address":[1216462],"length":1,"stats":{"Line":4}},{"line":943,"address":[672260],"length":1,"stats":{"Line":0}},{"line":946,"address":[42170494],"length":1,"stats":{"Line":2}},{"line":948,"address":[3588650],"length":1,"stats":{"Line":1}},{"line":953,"address":[662329],"length":1,"stats":{"Line":1}},{"line":954,"address":[42160569],"length":1,"stats":{"Line":1}},{"line":955,"address":[347547],"length":1,"stats":{"Line":1}},{"line":956,"address":[624763],"length":1,"stats":{"Line":1}},{"line":959,"address":[1206607],"length":1,"stats":{"Line":1}},{"line":967,"address":[3588763],"length":1,"stats":{"Line":1}},{"line":968,"address":[42160674],"length":1,"stats":{"Line":1}},{"line":969,"address":[358422,347654,358276,358686],"length":1,"stats":{"Line":2}},{"line":970,"address":[673156],"length":1,"stats":{"Line":1}},{"line":971,"address":[42172014],"length":1,"stats":{"Line":1}},{"line":974,"address":[662557],"length":1,"stats":{"Line":0}},{"line":979,"address":[347728],"length":1,"stats":{"Line":0}},{"line":980,"address":[42160813],"length":1,"stats":{"Line":0}},{"line":982,"address":[662646],"length":1,"stats":{"Line":2}},{"line":987,"address":[1206850],"length":1,"stats":{"Line":2}},{"line":989,"address":[772652],"length":1,"stats":{"Line":1}},{"line":994,"address":[727403],"length":1,"stats":{"Line":2}},{"line":995,"address":[614379],"length":1,"stats":{"Line":2}},{"line":997,"address":[3589120],"length":1,"stats":{"Line":1}},{"line":998,"address":[3589135],"length":1,"stats":{"Line":1}},{"line":999,"address":[614463],"length":1,"stats":{"Line":1}},{"line":1001,"address":[3589204],"length":1,"stats":{"Line":2}},{"line":1006,"address":[42161088],"length":1,"stats":{"Line":2}},{"line":1007,"address":[348080],"length":1,"stats":{"Line":2}},{"line":1008,"address":[662970,673840],"length":1,"stats":{"Line":4}},{"line":1010,"address":[614663],"length":1,"stats":{"Line":1}},{"line":1018,"address":[3589382],"length":1,"stats":{"Line":1}},{"line":1020,"address":[614702,625518,625547],"length":1,"stats":{"Line":2}},{"line":1021,"address":[1218086],"length":1,"stats":{"Line":1}},{"line":1023,"address":[614752],"length":1,"stats":{"Line":2}},{"line":1031,"address":[727823],"length":1,"stats":{"Line":2}},{"line":1034,"address":[773118],"length":1,"stats":{"Line":2}},{"line":1036,"address":[3600511,3589533,3600281],"length":1,"stats":{"Line":4}},{"line":1038,"address":[738693],"length":1,"stats":{"Line":2}},{"line":1041,"address":[783990],"length":1,"stats":{"Line":2}},{"line":1043,"address":[738763],"length":1,"stats":{"Line":2}},{"line":1044,"address":[42172327],"length":1,"stats":{"Line":2}},{"line":1045,"address":[738893,738945,738836],"length":1,"stats":{"Line":4}},{"line":1046,"address":[784239,784182],"length":1,"stats":{"Line":4}},{"line":1048,"address":[727952],"length":1,"stats":{"Line":3}},{"line":1053,"address":[663275],"length":1,"stats":{"Line":3}},{"line":1054,"address":[614953,625952,626062],"length":1,"stats":{"Line":9}},{"line":1055,"address":[784400,784481],"length":1,"stats":{"Line":6}},{"line":1057,"address":[674487,674384],"length":1,"stats":{"Line":6}},{"line":1059,"address":[615181],"length":1,"stats":{"Line":2}},{"line":1063,"address":[1207761],"length":1,"stats":{"Line":2}},{"line":1064,"address":[626739,615222,626475,626326],"length":1,"stats":{"Line":4}},{"line":1065,"address":[359663],"length":1,"stats":{"Line":2}},{"line":1066,"address":[784572,785311,785457],"length":1,"stats":{"Line":4}},{"line":1067,"address":[3602012,3601632,3602113],"length":1,"stats":{"Line":6}},{"line":1068,"address":[740479,740669,740572],"length":1,"stats":{"Line":4}},{"line":1069,"address":[740596],"length":1,"stats":{"Line":2}},{"line":1070,"address":[786906,785977,786674,785891,786346,787138],"length":1,"stats":{"Line":4}},{"line":1072,"address":[1219924,1220036],"length":1,"stats":{"Line":4}},{"line":1075,"address":[728483],"length":1,"stats":{"Line":1}},{"line":1076,"address":[663810],"length":1,"stats":{"Line":1}},{"line":1079,"address":[42162041],"length":1,"stats":{"Line":1}},{"line":1082,"address":[773804],"length":1,"stats":{"Line":1}},{"line":1085,"address":[615503],"length":1,"stats":{"Line":1}},{"line":1088,"address":[349021],"length":1,"stats":{"Line":1}},{"line":1091,"address":[42162109],"length":1,"stats":{"Line":0}},{"line":1093,"address":[663949],"length":1,"stats":{"Line":0}},{"line":1094,"address":[1208263,1208527],"length":1,"stats":{"Line":0}},{"line":1096,"address":[664438,677451],"length":1,"stats":{"Line":0}},{"line":1098,"address":[664516],"length":1,"stats":{"Line":0}},{"line":1099,"address":[729326],"length":1,"stats":{"Line":0}},{"line":1101,"address":[729414],"length":1,"stats":{"Line":0}},{"line":1102,"address":[774800],"length":1,"stats":{"Line":0}},{"line":1105,"address":[773588],"length":1,"stats":{"Line":2}},{"line":1107,"address":[728445],"length":1,"stats":{"Line":2}},{"line":1110,"address":[362544],"length":1,"stats":{"Line":0}},{"line":1111,"address":[742205],"length":1,"stats":{"Line":0}},{"line":1112,"address":[677642],"length":1,"stats":{"Line":0}},{"line":1114,"address":[787669],"length":1,"stats":{"Line":0}}],"covered":305,"coverable":477},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","keypad.rs"],"content":"use crate::constants::CHIP8_KEYBOARD;\n\n#[derive(Clone, Copy)]\npub struct Keypad {\n keys: [bool; 0x10],\n}\n\nimpl Keypad {\n pub fn format_as_string(\u0026self) -\u003e String {\n let mut return_value = String::new();\n // draw a 4x4 grid showing the keys with * filling the cells that are depressed\n for row in CHIP8_KEYBOARD.iter() {\n for (index, key) in row.iter().enumerate() {\n let is_lit = if self.keys[*key as usize] {\n \"*\".to_string()\n } else {\n char::from_digit(*key as u32, 16).unwrap_or(' ').to_string()\n };\n\n if index == 3 {\n return_value += format!(\"|{}|\\n\", is_lit).as_str();\n\n } else {\n return_value += format!(\"|{}\", is_lit).as_str();\n }\n }\n }\n\n return_value\n }\n}\n\nimpl Default for Keypad {\n fn default() -\u003e Self {\n Keypad {\n keys: [ false; 16]\n }\n }\n}\n\nimpl Keypad {\n pub fn push_key(\u0026mut self, key_index: u8) {\n self.keys[key_index as usize] = true;\n }\n\n pub fn release_key(\u0026mut self, key_index: u8) {\n self.keys[key_index as usize] = false;\n }\n\n pub fn key_state(\u0026self, key_index: u8) -\u003e bool {\n self.keys[key_index as usize]\n }\n\n pub fn new() -\u003e Keypad {\n Keypad::default()\n }\n\n pub fn pressed(\u0026self, key: u8) -\u003e bool {\n self.key_state(key)\n }\n pub fn released(\u0026self, key: u8) -\u003e bool {\n !self.key_state(key)\n }\n}\n","traces":[{"line":9,"address":[42103032,42103278,42101712],"length":1,"stats":{"Line":1}},{"line":10,"address":[594783],"length":1,"stats":{"Line":1}},{"line":12,"address":[632743,632915,632644],"length":1,"stats":{"Line":3}},{"line":13,"address":[632931],"length":1,"stats":{"Line":1}},{"line":14,"address":[42102311],"length":1,"stats":{"Line":1}},{"line":15,"address":[595524,595424],"length":1,"stats":{"Line":2}},{"line":17,"address":[791631,791581],"length":1,"stats":{"Line":2}},{"line":20,"address":[746620],"length":1,"stats":{"Line":1}},{"line":21,"address":[791976,792105],"length":1,"stats":{"Line":2}},{"line":24,"address":[3562705,3562834],"length":1,"stats":{"Line":2}},{"line":29,"address":[595016],"length":1,"stats":{"Line":1}},{"line":34,"address":[792496],"length":1,"stats":{"Line":4}},{"line":36,"address":[1226942],"length":1,"stats":{"Line":7}},{"line":42,"address":[3563024],"length":1,"stats":{"Line":2}},{"line":43,"address":[1227051,1227013],"length":1,"stats":{"Line":2}},{"line":46,"address":[792640],"length":1,"stats":{"Line":1}},{"line":47,"address":[792661,792699],"length":1,"stats":{"Line":1}},{"line":50,"address":[42103520],"length":1,"stats":{"Line":1}},{"line":51,"address":[1227173,1227212],"length":1,"stats":{"Line":1}},{"line":54,"address":[42103616],"length":1,"stats":{"Line":2}},{"line":55,"address":[3563288],"length":1,"stats":{"Line":2}},{"line":58,"address":[792848],"length":1,"stats":{"Line":1}},{"line":59,"address":[596688],"length":1,"stats":{"Line":1}},{"line":61,"address":[747808],"length":1,"stats":{"Line":1}},{"line":62,"address":[792896],"length":1,"stats":{"Line":1}}],"covered":25,"coverable":25},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","quirk_modes.rs"],"content":"#[derive(Default, Clone)]\npub enum QuirkMode {\n #[default]\n Chip8,\n XOChip,\n SChipModern\n}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","registers.rs"],"content":"/// Registers. numbered 1-16 publicly.\n/// Privately using zero base array so -1 to shift from pub to priv.\n#[derive(Clone, Copy)]\npub struct Chip8Registers {\n pub registers: [u8; 16],\n pub i_register: u16,\n pub pc: u16,\n}\n\nimpl Chip8Registers {\n pub fn advance_pc(\u0026mut self) {\n self.pc += 2;\n }\n}\n\nimpl Default for Chip8Registers {\n fn default() -\u003e Self {\n Chip8Registers {\n registers: [0x00; 16],\n i_register: 0x00,\n pc: 0x200,\n }\n }\n}\n\nimpl Chip8Registers {\n pub fn reset(\u0026mut self) {\n self.registers = [0x00; 16];\n self.i_register = 0x00;\n self.pc = 0x200;\n }\n\n pub fn poke_pc(\u0026mut self, new_pc: u16) {\n self.pc = new_pc\n }\n pub fn peek_i(\u0026self) -\u003e u16 {\n self.i_register\n }\n\n pub fn poke_i(\u0026mut self, new_value: u16) {\n self.i_register = new_value;\n }\n pub fn peek(\u0026self, register_number: u8) -\u003e u8 {\n self.registers[register_number as usize]\n }\n\n pub fn poke(\u0026mut self, register_number: u8, value: u8) {\n if register_number \u003e 0xf {\n panic!(\"INVALID REGISTER\");\n }\n self.registers[register_number as usize] = value;\n }\n\n pub fn peek_pc(\u0026self) -\u003e u16 {\n self.pc\n }\n\n pub fn set_pc(\u0026mut self, new_pc: u16) {\n self.pc = new_pc\n }\n\n pub fn format_as_string(\u0026self) -\u003e String {\n format!(\"Vx: 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x}\\n 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x}\\nI: 0x{:04x}\\tPC: 0x{:04x}\",\n self.registers[0x0],\n self.registers[0x1],\n self.registers[0x2],\n self.registers[0x3],\n self.registers[0x4],\n self.registers[0x5],\n self.registers[0x6],\n self.registers[0x7],\n self.registers[0x8],\n self.registers[0x9],\n self.registers[0xa],\n self.registers[0xb],\n self.registers[0xc],\n self.registers[0xd],\n self.registers[0xe],\n self.registers[0xf],\n self.i_register,\n self.pc\n )\n }\n}\n","traces":[{"line":11,"address":[822928],"length":1,"stats":{"Line":2}},{"line":12,"address":[626963,626925],"length":1,"stats":{"Line":2}},{"line":17,"address":[3514992],"length":1,"stats":{"Line":3}},{"line":19,"address":[627006],"length":1,"stats":{"Line":7}},{"line":27,"address":[292896],"length":1,"stats":{"Line":2}},{"line":28,"address":[292910],"length":1,"stats":{"Line":2}},{"line":29,"address":[42086639],"length":1,"stats":{"Line":2}},{"line":30,"address":[42086645],"length":1,"stats":{"Line":2}},{"line":33,"address":[823136],"length":1,"stats":{"Line":4}},{"line":34,"address":[627133],"length":1,"stats":{"Line":4}},{"line":36,"address":[823168],"length":1,"stats":{"Line":2}},{"line":37,"address":[3515157],"length":1,"stats":{"Line":4}},{"line":40,"address":[664864],"length":1,"stats":{"Line":2}},{"line":41,"address":[293005],"length":1,"stats":{"Line":4}},{"line":43,"address":[693584],"length":1,"stats":{"Line":4}},{"line":44,"address":[293045,293082],"length":1,"stats":{"Line":2}},{"line":47,"address":[1139744],"length":1,"stats":{"Line":3}},{"line":48,"address":[1139779],"length":1,"stats":{"Line":2}},{"line":49,"address":[42086875],"length":1,"stats":{"Line":1}},{"line":51,"address":[823416,823339,823429],"length":1,"stats":{"Line":5}},{"line":54,"address":[42086976],"length":1,"stats":{"Line":7}},{"line":55,"address":[665141],"length":1,"stats":{"Line":4}},{"line":58,"address":[627456],"length":1,"stats":{"Line":2}},{"line":59,"address":[693853],"length":1,"stats":{"Line":5}},{"line":62,"address":[1139952],"length":1,"stats":{"Line":1}},{"line":63,"address":[824374,829252,827396,828788,826932,829716,823630,824281,827860,828092,828556,827628,824467,823909,828324,824746,826468,823723,829020,826004,823816,824188,825208,829484,824653,824095,825118,826700,829948,825025,826236,824932,824839,824002,827164,824560],"length":1,"stats":{"Line":36}}],"covered":26,"coverable":26},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","sound_timer.rs"],"content":"use log::trace;\n\n#[derive(Clone, Copy)]\npub struct SoundTimer {\n counter: i32\n}\n\nimpl SoundTimer {\n pub fn current(\u0026self) -\u003e i32 {\n self.counter\n }\n pub fn new() -\u003e Self {\n SoundTimer {\n counter: 0\n }\n }\n pub fn set_timer(\u0026mut self, new_value: i32) {\n trace!(\"SETTING SOUND TIMER TO {new_value}\");\n self.counter = new_value\n }\n\n pub fn tick(\u0026mut self) {\n trace!(\"TICKING SOUND FROM {} to {}\", self.counter, self.counter - 1);\n if self.counter \u003e 0 {\n self.counter -= 1;\n /*\n todo: this breaks tests. maybe its wrong?\n if let good_thread = thread::spawn(|| {\n beep(440).expect(\"Unable to beep\");\n thread::sleep(time::Duration::from_millis(500));\n }).join().unwrap().\n */\n }\n }\n\n pub fn reset(\u0026mut self) {\n self.counter = 0x00;\n }\n}\n","traces":[{"line":9,"address":[3554960],"length":1,"stats":{"Line":1}},{"line":10,"address":[386085],"length":1,"stats":{"Line":1}},{"line":17,"address":[42131040],"length":1,"stats":{"Line":1}},{"line":18,"address":[42131064,42131142,42131264],"length":1,"stats":{"Line":2}},{"line":19,"address":[663660],"length":1,"stats":{"Line":1}},{"line":22,"address":[42131408],"length":1,"stats":{"Line":2}},{"line":23,"address":[781698,781620,781813,781951],"length":1,"stats":{"Line":7}},{"line":24,"address":[626852,626328],"length":1,"stats":{"Line":6}},{"line":25,"address":[626854,626828],"length":1,"stats":{"Line":1}},{"line":36,"address":[387088],"length":1,"stats":{"Line":1}},{"line":37,"address":[822901],"length":1,"stats":{"Line":1}}],"covered":11,"coverable":11},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","stack.rs"],"content":"#[derive(Clone)]\npub struct Chip8Stack {\n items: Vec\u003cu16\u003e\n}\n\nimpl Default for Chip8Stack {\n fn default() -\u003e Self {\n Chip8Stack {\n items: vec![],\n }\n }\n}\n\nimpl Chip8Stack {\n pub fn push(\u0026mut self, new_value: \u0026u16) {\n if self.depth() == 16 {\n // println!(\"Deep deep stack?\");\n panic!(\"Stack Overflow\");\n }\n self.items.push(*new_value );\n }\n pub fn pop(\u0026mut self) -\u003e u16 {\n if self.items.is_empty() {\n panic!(\"Stack Underflow\");\n }\n self.items.pop().unwrap()\n }\n pub fn depth(\u0026self) -\u003e u16 {\n self.items.len() as u16\n }\n\n pub fn new() -\u003e Self {\n Chip8Stack {\n items: vec![]\n }\n }\n\n pub fn reset(\u0026mut self) {\n self.items = vec![]\n }\n}\n","traces":[{"line":7,"address":[651936],"length":1,"stats":{"Line":3}},{"line":9,"address":[42122045],"length":1,"stats":{"Line":8}},{"line":15,"address":[1173984],"length":1,"stats":{"Line":5}},{"line":16,"address":[617512],"length":1,"stats":{"Line":5}},{"line":18,"address":[769556],"length":1,"stats":{"Line":1}},{"line":20,"address":[652091],"length":1,"stats":{"Line":3}},{"line":22,"address":[307440],"length":1,"stats":{"Line":2}},{"line":23,"address":[1174110],"length":1,"stats":{"Line":2}},{"line":24,"address":[3569303],"length":1,"stats":{"Line":1}},{"line":26,"address":[652141],"length":1,"stats":{"Line":3}},{"line":28,"address":[617744],"length":1,"stats":{"Line":6}},{"line":29,"address":[42122357],"length":1,"stats":{"Line":6}},{"line":32,"address":[1174256],"length":1,"stats":{"Line":4}},{"line":34,"address":[617773],"length":1,"stats":{"Line":4}},{"line":38,"address":[810656,810719],"length":1,"stats":{"Line":1}},{"line":39,"address":[810749,810669],"length":1,"stats":{"Line":2}}],"covered":16,"coverable":16},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","system_memory.rs"],"content":"use log::{trace};\n\nuse crate::constants::*;\n\n#[derive(Clone, Copy)]\npub struct Chip8SystemMemory {\n memory: [u8; CHIP8_MEMORY_SIZE as usize],\n}\n\nimpl Default for Chip8SystemMemory {\n fn default() -\u003e Self {\n\n let mut x = Chip8SystemMemory {\n memory: [0x00; CHIP8_MEMORY_SIZE as usize],\n };\n\n x.load_fonts_to_memory();\n x.load_schip_fonts_to_memory();\n x\n }\n}\nimpl Chip8SystemMemory {\n\n pub fn reset(\u0026mut self){\n self.memory = [0x00; CHIP8_MEMORY_SIZE as usize];\n self.load_fonts_to_memory();\n self.load_schip_fonts_to_memory();\n }\n \n pub fn new() -\u003e Self {\n Chip8SystemMemory {\n memory: [0x00; CHIP8_MEMORY_SIZE as usize],\n }\n }\n\n pub fn peek(\u0026self, address: u16) -\u003e u8 {\n trace!(\"PEEK: {} / {}\", address, self.memory[address as usize].clone());\n self.memory[address as usize]\n }\n\n pub fn poke(\u0026mut self, address: u16, value: u8) {\n trace!(\"POKE: {} / {} to {}\", address, self.memory[address as usize], value);\n self.memory[address as usize] = value;\n }\n\n pub fn load_program(\u0026mut self, program_to_load: Box\u003cVec\u003cu8\u003e\u003e) {\n for load_index in 0..program_to_load.len() {\n self.poke((load_index + 0x200) as u16, program_to_load[load_index]);\n }\n }\n\n pub fn load_fonts_to_memory(\u0026mut self) {\n let all_font_characters = [\n CHIP8FONT_0,\n CHIP8FONT_1,\n CHIP8FONT_2,\n CHIP8FONT_3,\n CHIP8FONT_4,\n CHIP8FONT_5,\n CHIP8FONT_6,\n CHIP8FONT_7,\n CHIP8FONT_8,\n CHIP8FONT_9,\n CHIP8FONT_A,\n CHIP8FONT_B,\n CHIP8FONT_C,\n CHIP8FONT_D,\n CHIP8FONT_E,\n CHIP8FONT_F,\n ];\n\n for (font_index, current_font) in all_font_characters.iter().enumerate() {\n for font_mem_offset in 0..=4 {\n let real_offset = font_index * 5 + font_mem_offset;\n self.poke(real_offset as u16, current_font[font_mem_offset]);\n }\n }\n }\n\n pub fn load_schip_fonts_to_memory(\u0026mut self) {\n let all_font_characters = [\n SCHIPFONT_0, SCHIPFONT_1, SCHIPFONT_2, SCHIPFONT_3,\n SCHIPFONT_4, SCHIPFONT_5, SCHIPFONT_6, SCHIPFONT_7,\n SCHIPFONT_8, SCHIPFONT_9, SCHIPFONT_A, SCHIPFONT_B,\n SCHIPFONT_C, SCHIPFONT_D, SCHIPFONT_E, SCHIPFONT_F\n ];\n for (font_index, current_font) in all_font_characters.iter().enumerate() {\n let base_offset = 0x100;\n for font_mem_offset in 0..=4 {\n let real_offset = base_offset + font_index * 0x10 + font_mem_offset;\n self.poke(real_offset as u16, current_font[font_mem_offset]);\n }\n }\n }\n}","traces":[{"line":11,"address":[42097104],"length":1,"stats":{"Line":3}},{"line":14,"address":[3524732],"length":1,"stats":{"Line":5}},{"line":17,"address":[640151],"length":1,"stats":{"Line":6}},{"line":18,"address":[836786],"length":1,"stats":{"Line":3}},{"line":19,"address":[3524802],"length":1,"stats":{"Line":7}},{"line":24,"address":[322704],"length":1,"stats":{"Line":1}},{"line":25,"address":[1149614],"length":1,"stats":{"Line":1}},{"line":26,"address":[322735],"length":1,"stats":{"Line":1}},{"line":27,"address":[640250],"length":1,"stats":{"Line":1}},{"line":30,"address":[679856],"length":1,"stats":{"Line":0}},{"line":32,"address":[679885],"length":1,"stats":{"Line":0}},{"line":36,"address":[322848],"length":1,"stats":{"Line":2}},{"line":37,"address":[3525004,3525218,3525090,3525370],"length":1,"stats":{"Line":7}},{"line":38,"address":[322907,323459,323475],"length":1,"stats":{"Line":7}},{"line":41,"address":[323504],"length":1,"stats":{"Line":7}},{"line":42,"address":[837752,837666,837880,838102],"length":1,"stats":{"Line":10}},{"line":43,"address":[1150465,1151140,1151120],"length":1,"stats":{"Line":13}},{"line":46,"address":[1151168,1151509],"length":1,"stats":{"Line":0}},{"line":47,"address":[324357,324294,324462],"length":1,"stats":{"Line":0}},{"line":48,"address":[706833],"length":1,"stats":{"Line":0}},{"line":52,"address":[324624],"length":1,"stats":{"Line":5}},{"line":53,"address":[838788],"length":1,"stats":{"Line":2}},{"line":72,"address":[682089,682259],"length":1,"stats":{"Line":13}},{"line":73,"address":[1152109],"length":1,"stats":{"Line":3}},{"line":74,"address":[682555,682465],"length":1,"stats":{"Line":6}},{"line":75,"address":[682591,682547],"length":1,"stats":{"Line":9}},{"line":80,"address":[1152448],"length":1,"stats":{"Line":8}},{"line":81,"address":[643085],"length":1,"stats":{"Line":3}},{"line":87,"address":[42101067,42101237],"length":1,"stats":{"Line":14}},{"line":88,"address":[839692],"length":1,"stats":{"Line":6}},{"line":89,"address":[1153631],"length":1,"stats":{"Line":3}},{"line":90,"address":[644403,644532],"length":1,"stats":{"Line":7}},{"line":91,"address":[841192,841148],"length":1,"stats":{"Line":10}}],"covered":28,"coverable":33},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","util.rs"],"content":"pub struct InstructionUtil {}\n\nimpl InstructionUtil {\n pub fn byte_to_bools(to_convert: u8) -\u003e [bool; 8] {\n let mut return_values = [false; 8];\n for i in 0..8 {\n let new_value = to_convert \u003e\u003e i \u0026 0x1 == 1;\n return_values[i as usize] = new_value;\n }\n return_values\n }\n\n pub fn bools_to_byte(to_convert: [bool; 8]) -\u003e u8 {\n let mut return_value = 0u8;\n for i in 0..to_convert.len() {\n let new_bit = 0x1 \u003c\u003c i;\n if to_convert[i] {\n return_value = return_value | new_bit\n }\n }\n return_value\n }\n\n pub fn split_bytes(to_split: u16) -\u003e (u8, u8) {\n let high = to_split.rotate_left(8) as u8;\n let low = (to_split \u0026 0xff) as u8;\n\n (high, low)\n }\n\n pub fn join_bytes(high: u8, low: u8) -\u003e u16 {\n let result = (high as u16) \u003c\u003c 8 | low as u16;\n result\n }\n\n // nnn or addr - A 12-bit value, the lowest 12 bits of the instruction\n pub fn read_addr_from_instruction(instruction_to_read_from: u16) -\u003e u16 {\n instruction_to_read_from \u0026 0x0FFF\n }\n\n // n or nibble - A 4-bit value, the lowest 4 bits of the instruction\n pub fn read_nibble_from_instruction(instruction_to_read_from: u16) -\u003e u8 {\n ( instruction_to_read_from \u0026 0x000F )as u8\n }\n\n // x - A 4-bit value, the lower 4 bits of the high byte of the instruction\n pub fn read_x_from_instruction(instruction_to_read_from: u16) -\u003e u8 {\n (instruction_to_read_from \u0026 0x0F00).rotate_right(8) as u8\n }\n\n // y - A 4-bit value, the upper 4 bits of the low byte of the instruction\n pub fn read_y_from_instruction(instruction_to_read_from: u16) -\u003e u8 {\n (instruction_to_read_from \u0026 0x00F0).rotate_right(4) as u8\n }\n\n // kk or byte - An 8-bit value, the lowest 8 bits of the instruction\n pub fn read_byte_from_instruction(instruction_to_read_from: u16) -\u003e u8 {\n (instruction_to_read_from \u0026 0x00FF) as u8\n }\n\n pub fn read_upper_byte_lower_nibble(to_read_from: u16) -\u003e u8 {\n ((to_read_from \u0026 0x0f00) \u003e\u003e 8) as u8\n }\n}\n","traces":[{"line":4,"address":[634800],"length":1,"stats":{"Line":1}},{"line":5,"address":[793135],"length":1,"stats":{"Line":1}},{"line":6,"address":[1227675,1227574,1227504],"length":1,"stats":{"Line":3}},{"line":7,"address":[3607467,3607410],"length":1,"stats":{"Line":1}},{"line":8,"address":[1227628,1227668,1227685],"length":1,"stats":{"Line":2}},{"line":10,"address":[634882],"length":1,"stats":{"Line":1}},{"line":13,"address":[793360],"length":1,"stats":{"Line":1}},{"line":14,"address":[793379],"length":1,"stats":{"Line":1}},{"line":15,"address":[3607623,3607560],"length":1,"stats":{"Line":2}},{"line":16,"address":[3607678,3607638],"length":1,"stats":{"Line":1}},{"line":17,"address":[1227922,1227846,1227875],"length":1,"stats":{"Line":3}},{"line":18,"address":[3607738],"length":1,"stats":{"Line":1}},{"line":21,"address":[3607614],"length":1,"stats":{"Line":1}},{"line":24,"address":[748512],"length":1,"stats":{"Line":1}},{"line":25,"address":[748549],"length":1,"stats":{"Line":1}},{"line":26,"address":[748553],"length":1,"stats":{"Line":1}},{"line":31,"address":[373680],"length":1,"stats":{"Line":1}},{"line":32,"address":[3607822],"length":1,"stats":{"Line":1}},{"line":37,"address":[1228032],"length":1,"stats":{"Line":3}},{"line":38,"address":[635368],"length":1,"stats":{"Line":6}},{"line":42,"address":[793696],"length":1,"stats":{"Line":3}},{"line":43,"address":[748632],"length":1,"stats":{"Line":6}},{"line":47,"address":[748640],"length":1,"stats":{"Line":3}},{"line":48,"address":[373768],"length":1,"stats":{"Line":6}},{"line":52,"address":[748688],"length":1,"stats":{"Line":6}},{"line":53,"address":[793768],"length":1,"stats":{"Line":3}},{"line":57,"address":[793808],"length":1,"stats":{"Line":6}},{"line":58,"address":[748744],"length":1,"stats":{"Line":3}},{"line":61,"address":[1228176],"length":1,"stats":{"Line":6}},{"line":62,"address":[793832],"length":1,"stats":{"Line":3}}],"covered":30,"coverable":30},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","video.rs"],"content":"use log::{debug};\nuse crate::chip8::util::InstructionUtil;\nuse crate::chip8::video::Chip8VideoModes::{HighRes, LowRes};\nuse crate::constants::{CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_MEMORY, CHIP8_VIDEO_WIDTH, SCHIP_VIDE_MEMORY, SCHIP_VIDEO_HEIGHT, SCHIP_VIDEO_WIDTH};\n\n#[derive(Clone, Copy)]\nenum Chip8VideoModes {\n LowRes,\n HighRes,\n}\n\n#[derive(Clone)]\npub struct Chip8Video {\n memory: Vec\u003cbool\u003e,\n pub has_frame_changed: bool,\n current_res: Chip8VideoModes,\n}\n\nimpl Chip8Video {\n pub fn reset(\u0026mut self) {\n self.cls();\n self.start_frame();\n }\n\n pub fn is_highres(\u0026self) -\u003e bool {\n matches!(self.current_res, HighRes)\n }\n\n pub fn set_highres(\u0026mut self) {\n self.current_res = HighRes;\n self.cls();\n }\n\n pub fn set_lowres(\u0026mut self) {\n self.current_res = LowRes\n }\n\n pub fn get_screen_resolution(\u0026mut self) -\u003e Chip8VideoModes {\n self.current_res\n }\n\n pub fn cls(\u0026mut self) {\n self.memory.clear();\n let num_loops = match self.current_res {\n LowRes =\u003e {\n CHIP8_VIDEO_MEMORY\n }\n HighRes =\u003e {\n SCHIP_VIDE_MEMORY\n }\n };\n for i in 0..num_loops {\n self.memory.push(false);\n }\n }\n\n pub fn start_frame(\u0026mut self) {\n self.has_frame_changed = false;\n }\n\n pub fn new(initial_configuration: Box\u003cVec\u003cbool\u003e\u003e) -\u003e Self {\n Self {\n memory: *initial_configuration,\n has_frame_changed: false,\n current_res: Chip8VideoModes::LowRes,\n }\n }\n\n pub fn peek(\u0026self, address: u16) -\u003e bool {\n let loop_value: u16 = if self.is_highres() {\n SCHIP_VIDE_MEMORY as u16\n } else {\n CHIP8_VIDEO_MEMORY as u16\n };\n let effective_address = if address \u003e= loop_value {\n address % loop_value\n } else { address };\n self.memory[effective_address as usize]\n }\n\n pub fn poke(\u0026mut self, address: u16, new_value: bool) {\n let loop_value: u16 = self.get_memory_size() as u16;\n // Loop the address\n let effective_address = address % loop_value;\n\n let old_value = self.memory[effective_address as usize];\n let xored_value = new_value ^ old_value; // XOR of the video\n // if the frame has already changed we dont care if it changed again.\n if !self.has_frame_changed {\n if old_value != xored_value {\n self.has_frame_changed = true\n };\n }\n\n // println!(\"VIDEO POKE COMPLETE WITH {effective_address} SET TO {xored_value}\");\n self.memory[effective_address as usize] = xored_value;\n }\n\n pub fn poke_byte(\u0026mut self, first_address: u16, to_write: u8) {\n for i in (0..8).rev() {\n self.poke(first_address + (7 - i), (to_write \u0026 (1 \u003c\u003c i)) != 0);\n }\n }\n\n pub fn poke_2byte(\u0026mut self, first_address: u16, to_write: [u8; 2]) {\n for (idx, _) in to_write.iter().enumerate() {\n for i in (0..8).rev() {\n self.poke(first_address + (idx * 8) as u16 + (7 - i), (to_write[idx] \u0026 (1 \u003c\u003c i)) != 0);\n }\n }\n }\n\n pub fn format_as_string(\u0026self) -\u003e String {\n let (width, height) = self.get_resolution();\n println!(\"FORMATTING {width}x{height}\");\n let mut output = String::new();\n for row in 0..height {\n for column in 0..width {\n let data_offset = row * width + column;\n debug!(\"Rendering {data_offset} with value {}\", self.memory[data_offset as usize]);\n if self.memory[data_offset as usize] {\n output += \"*\"\n } else {\n output += \" \"\n }\n }\n output += \"\\n\";\n }\n output\n }\n\n pub fn get_resolution(\u0026self) -\u003e (i32, i32) {\n if self.is_highres() {\n (SCHIP_VIDEO_WIDTH, SCHIP_VIDEO_HEIGHT)\n } else {\n (CHIP8_VIDEO_WIDTH, CHIP8_VIDEO_HEIGHT)\n }\n }\n fn get_memory_size(\u0026self) -\u003e i32 {\n let (width, height) = self.get_resolution();\n width * height\n }\n\n pub fn tick(\u0026mut self) {\n self.has_frame_changed = false;\n }\n\n pub fn scroll_right(\u0026mut self) {\n let (width, height) = self.get_resolution();\n\n for current_row in 0..height {\n let row_offset: usize = (current_row * width) as usize;\n for current_column in (0..(width - 4)).rev() {\n let source_address = row_offset + current_column as usize;\n let target_address = source_address + 4;\n self.memory[target_address] = self.memory[source_address];\n }\n self.memory[row_offset..row_offset + 4].fill(false);\n }\n }\n\n pub fn scroll_left(\u0026mut self) {\n let (width, height) = self.get_resolution();\n\n for current_row in 0..height {\n let row_offset = current_row * width;\n for current_column in (0..width - 4) {\n let source: usize = (row_offset + current_column) as usize;\n let target: usize = source + 4;\n self.memory[target] = self.memory[source];\n }\n\n let clear_start: usize = (row_offset + width - 4) as usize;\n let clear_end: usize = clear_start + 4;\n\n self.memory[clear_start..clear_end].fill(false);\n }\n }\n\n pub fn scroll_down(\u0026mut self, how_far: i32) {\n let (width, height) = self.get_resolution();\n let row_shift = how_far * width;\n\n let max_source_row = height - how_far;\n for current_source_row in (0..max_source_row).rev() {\n let current_source_offset = current_source_row * width;\n for current_source_column in (0..width) {\n let base_offset: usize = (current_source_offset + current_source_column) as usize;\n let extended_offset: usize = base_offset + row_shift as usize;\n self.memory[extended_offset] = self.memory[base_offset];\n };\n }\n\n // Clear the new top rows after shifting\n let clear_end = (how_far * width) as usize;\n self.memory[0..clear_end].fill(false);\n }\n}\n\nimpl Default for Chip8Video {\n fn default() -\u003e Self {\n let mut mem = vec![];\n for _ in 0..CHIP8_VIDEO_MEMORY { mem.push(false); }\n Chip8Video { memory: mem, has_frame_changed: false, current_res: Chip8VideoModes::LowRes }\n }\n}\n","traces":[{"line":20,"address":[596784],"length":1,"stats":{"Line":2}},{"line":21,"address":[748798],"length":1,"stats":{"Line":2}},{"line":22,"address":[3529481],"length":1,"stats":{"Line":2}},{"line":25,"address":[301648],"length":1,"stats":{"Line":2}},{"line":26,"address":[301653],"length":1,"stats":{"Line":2}},{"line":29,"address":[748880],"length":1,"stats":{"Line":1}},{"line":30,"address":[793961],"length":1,"stats":{"Line":1}},{"line":31,"address":[1154343],"length":1,"stats":{"Line":1}},{"line":34,"address":[596928],"length":1,"stats":{"Line":1}},{"line":35,"address":[1154373],"length":1,"stats":{"Line":1}},{"line":38,"address":[596960],"length":1,"stats":{"Line":0}},{"line":39,"address":[1154405],"length":1,"stats":{"Line":0}},{"line":42,"address":[301792],"length":1,"stats":{"Line":2}},{"line":43,"address":[596990],"length":1,"stats":{"Line":2}},{"line":44,"address":[749001],"length":1,"stats":{"Line":2}},{"line":46,"address":[635767],"length":1,"stats":{"Line":2}},{"line":49,"address":[3529698],"length":1,"stats":{"Line":1}},{"line":52,"address":[749035,749099],"length":1,"stats":{"Line":4}},{"line":53,"address":[749109],"length":1,"stats":{"Line":2}},{"line":57,"address":[3529792],"length":1,"stats":{"Line":2}},{"line":58,"address":[635877],"length":1,"stats":{"Line":2}},{"line":61,"address":[597136],"length":1,"stats":{"Line":1}},{"line":63,"address":[636034,635907],"length":1,"stats":{"Line":1}},{"line":69,"address":[3529984],"length":1,"stats":{"Line":2}},{"line":70,"address":[794428,794411],"length":1,"stats":{"Line":4}},{"line":71,"address":[42104494],"length":1,"stats":{"Line":0}},{"line":73,"address":[1154789],"length":1,"stats":{"Line":2}},{"line":75,"address":[42104506,42104597,42104523],"length":1,"stats":{"Line":5}},{"line":76,"address":[302204,302265,302277],"length":1,"stats":{"Line":2}},{"line":77,"address":[1154822],"length":1,"stats":{"Line":2}},{"line":78,"address":[749412],"length":1,"stats":{"Line":2}},{"line":81,"address":[302304],"length":1,"stats":{"Line":2}},{"line":82,"address":[42104663],"length":1,"stats":{"Line":2}},{"line":84,"address":[1155087,1154982],"length":1,"stats":{"Line":2}},{"line":86,"address":[302394],"length":1,"stats":{"Line":2}},{"line":87,"address":[794698],"length":1,"stats":{"Line":2}},{"line":89,"address":[794711],"length":1,"stats":{"Line":3}},{"line":90,"address":[749671,749733],"length":1,"stats":{"Line":5}},{"line":91,"address":[42104865],"length":1,"stats":{"Line":3}},{"line":96,"address":[42104828],"length":1,"stats":{"Line":2}},{"line":99,"address":[636496],"length":1,"stats":{"Line":3}},{"line":100,"address":[597853,597781],"length":1,"stats":{"Line":4}},{"line":101,"address":[302681],"length":1,"stats":{"Line":1}},{"line":105,"address":[636800],"length":1,"stats":{"Line":1}},{"line":106,"address":[750242,750102],"length":1,"stats":{"Line":2}},{"line":107,"address":[795335],"length":1,"stats":{"Line":1}},{"line":108,"address":[3531050],"length":1,"stats":{"Line":1}},{"line":113,"address":[304920,303472],"length":1,"stats":{"Line":2}},{"line":114,"address":[3531398],"length":1,"stats":{"Line":2}},{"line":115,"address":[795956],"length":1,"stats":{"Line":2}},{"line":116,"address":[3531647],"length":1,"stats":{"Line":2}},{"line":117,"address":[598980,599072,599201],"length":1,"stats":{"Line":6}},{"line":118,"address":[3532034,3531891],"length":1,"stats":{"Line":4}},{"line":119,"address":[638164,638250,638132],"length":1,"stats":{"Line":4}},{"line":120,"address":[796679,796592,796528,796890,796984],"length":1,"stats":{"Line":6}},{"line":121,"address":[304291,304851],"length":1,"stats":{"Line":4}},{"line":122,"address":[638922,638890],"length":1,"stats":{"Line":4}},{"line":124,"address":[3532837,3532783],"length":1,"stats":{"Line":5}},{"line":127,"address":[599331,599399],"length":1,"stats":{"Line":5}},{"line":129,"address":[796230],"length":1,"stats":{"Line":2}},{"line":132,"address":[752208],"length":1,"stats":{"Line":2}},{"line":133,"address":[752217,752243],"length":1,"stats":{"Line":4}},{"line":134,"address":[3532917],"length":1,"stats":{"Line":1}},{"line":136,"address":[42107363],"length":1,"stats":{"Line":2}},{"line":139,"address":[639040],"length":1,"stats":{"Line":2}},{"line":140,"address":[797369],"length":1,"stats":{"Line":2}},{"line":141,"address":[305046,305067],"length":1,"stats":{"Line":2}},{"line":144,"address":[305088],"length":1,"stats":{"Line":3}},{"line":145,"address":[600357],"length":1,"stats":{"Line":6}},{"line":148,"address":[3533040],"length":1,"stats":{"Line":1}},{"line":149,"address":[752385],"length":1,"stats":{"Line":1}},{"line":151,"address":[600405,600462],"length":1,"stats":{"Line":2}},{"line":152,"address":[752517,752470],"length":1,"stats":{"Line":1}},{"line":153,"address":[42107639,42107673,42107772,42107983],"length":1,"stats":{"Line":4}},{"line":154,"address":[600733,600757,600647],"length":1,"stats":{"Line":2}},{"line":155,"address":[1158181,1158228,1158292],"length":1,"stats":{"Line":2}},{"line":156,"address":[639548],"length":1,"stats":{"Line":1}},{"line":158,"address":[1158055,1158120],"length":1,"stats":{"Line":2}},{"line":162,"address":[639632],"length":1,"stats":{"Line":1}},{"line":163,"address":[305617],"length":1,"stats":{"Line":1}},{"line":165,"address":[639675,639732],"length":1,"stats":{"Line":2}},{"line":166,"address":[3533704,3533663],"length":1,"stats":{"Line":1}},{"line":167,"address":[305855,306163,305769,305735],"length":1,"stats":{"Line":4}},{"line":168,"address":[798403,798223,798434],"length":1,"stats":{"Line":2}},{"line":169,"address":[601393,601457,601346],"length":1,"stats":{"Line":2}},{"line":170,"address":[42108537],"length":1,"stats":{"Line":1}},{"line":173,"address":[753123,753240,753175],"length":1,"stats":{"Line":2}},{"line":174,"address":[3533896,3533943,3533983],"length":1,"stats":{"Line":2}},{"line":176,"address":[305994],"length":1,"stats":{"Line":1}},{"line":180,"address":[1158928],"length":1,"stats":{"Line":1}},{"line":181,"address":[798585],"length":1,"stats":{"Line":1}},{"line":182,"address":[306283,306242],"length":1,"stats":{"Line":1}},{"line":184,"address":[306270,306333,306303],"length":1,"stats":{"Line":2}},{"line":185,"address":[306349,306403,306307],"length":1,"stats":{"Line":3}},{"line":186,"address":[3534386,3534483,3534508],"length":1,"stats":{"Line":2}},{"line":187,"address":[640794,640570,640604],"length":1,"stats":{"Line":3}},{"line":188,"address":[753900,753952],"length":1,"stats":{"Line":1}},{"line":189,"address":[601934,601983,602047],"length":1,"stats":{"Line":2}},{"line":190,"address":[3534663],"length":1,"stats":{"Line":1}},{"line":195,"address":[640539,640489,640437],"length":1,"stats":{"Line":2}},{"line":196,"address":[640500],"length":1,"stats":{"Line":1}},{"line":201,"address":[602360,602064],"length":1,"stats":{"Line":3}},{"line":202,"address":[1159521],"length":1,"stats":{"Line":8}},{"line":203,"address":[799167,799248,799409],"length":1,"stats":{"Line":17}}],"covered":101,"coverable":104},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","constants.rs"],"content":"pub const CHIP8_REGISTER_COUNT: i32 = 16;\npub const CHIP8_MEMORY_SIZE: i32 = 4096i32;\npub const CHIP8_VIDEO_WIDTH: i32 = 64i32;\npub const CHIP8_VIDEO_HEIGHT: i32 = 32i32;\npub const CHIP8_VIDEO_MEMORY: usize = (CHIP8_VIDEO_HEIGHT * CHIP8_VIDEO_WIDTH) as usize;\npub const CHIP8_ROM_SIZE: usize = 512;\n\npub const RESOURCES_ROOT: \u0026str = \"../resources\";\npub const TESTS_ROOT: \u0026str = \"../resources/tests/\";\n\npub const CHIP8_KEYBOARD: [[u8; 4]; 4] = [\n [0x01, 0x02, 0x03, 0x0C],\n [0x04, 0x05, 0x06, 0x0D],\n [0x07, 0x08, 0x09, 0x0E],\n [0x0A, 0x00, 0x0B, 0x0F]\n];\n\npub const SCHIP_VIDEO_HEIGHT: i32 = 64;\npub const SCHIP_VIDEO_WIDTH: i32 = 128;\npub const SCHIP_VIDE_MEMORY: usize = (SCHIP_VIDEO_HEIGHT * SCHIP_VIDEO_WIDTH) as usize;\n\npub const INST_ADDI: \u0026str = \"ADDI\";\npub const INST_ADD: \u0026str = \"ADD\";\npub const INST_ADDR: \u0026str = \"ADDR\";\npub const INST_AND: \u0026str = \"AND\";\npub const INST_CLS: \u0026str = \"CLS\";\npub const INST_CALL: \u0026str = \"CALL\";\npub const INST_DRW: \u0026str = \"DRW\";\npub const INST_EXIT: \u0026str = \"EXIT\";\npub const INST_JPA: \u0026str = \"JPA\";\npub const INST_JPI: \u0026str = \"JPI\";\npub const INST_BCD: \u0026str = \"BCD\";\npub const INST_LDD: \u0026str = \"LDD\";\npub const INST_LDF: \u0026str = \"LDF\";\npub const INST_LDF2: \u0026str = \"LDF2\";\npub const INST_LDIA: \u0026str = \"LDIA\";\npub const INST_LDIX: \u0026str = \"LDIX\";\npub const INST_LIDR: \u0026str = \"LIDR\";\npub const INST_LDIS: \u0026str = \"LDIS\";\npub const INST_LDR: \u0026str = \"LDR\";\npub const INST_LDRD: \u0026str = \"LDRD\";\npub const INST_LDRI: \u0026str = \"LDRI\";\npub const INST_LDRK: \u0026str = \"LDRK\";\npub const INST_LDRY: \u0026str = \"LDRY\";\npub const INST_OR: \u0026str = \"OR\";\npub const INST_RET: \u0026str = \"RET\";\npub const INST_RND: \u0026str = \"RND\";\npub const INST_SDN: \u0026str = \"SDN\";\npub const INST_SRT: \u0026str = \"SRT\";\npub const INST_SLF: \u0026str = \"SLF\";\npub const INST_SEX: \u0026str = \"SEX\";\npub const INST_SEY: \u0026str = \"SEY\";\npub const INST_SHL: \u0026str = \"SHL\";\npub const INST_SHR: \u0026str = \"SHR\";\npub const INST_SKP: \u0026str = \"SKP\";\npub const INST_SKNP: \u0026str = \"SKNP\";\npub const INST_SNEB: \u0026str = \"SNEB\";\npub const INST_SNEY: \u0026str = \"SNEY\";\npub const INST_STR: \u0026str = \"STR\";\npub const INST_SUB: \u0026str = \"SUB\";\npub const INST_SUBC: \u0026str = \"SUBC\";\npub const INST_SYS: \u0026str = \"SYS\";\npub const INST_DIS: \u0026str = \"DIS\";\npub const INST_ENA: \u0026str = \"ENA\";\npub const INST_ORY: \u0026str = \"ORY\";\n\npub const CHIP8_PROGRAM_LOAD_OFFSET: i32 = 0x200;\npub const CHIP8FONT_0: [u8; 5] = [0xF0, 0x90, 0x90, 0x90, 0xF0];\npub const CHIP8FONT_1: [u8; 5] = [0x20, 0x60, 0x20, 0x20, 0x70];\npub const CHIP8FONT_2: [u8; 5] = [0xF0, 0x10, 0xF0, 0x80, 0xF0];\npub const CHIP8FONT_3: [u8; 5] = [0xF0, 0x10, 0xF0, 0x10, 0xF0];\npub const CHIP8FONT_4: [u8; 5] = [0x90, 0x90, 0xF0, 0x10, 0x10];\npub const CHIP8FONT_5: [u8; 5] = [0xF0, 0x80, 0xF0, 0x10, 0xF0];\npub const CHIP8FONT_6: [u8; 5] = [0xF0, 0x80, 0xF0, 0x90, 0xF0];\npub const CHIP8FONT_7: [u8; 5] = [0xF0, 0x10, 0x20, 0x40, 0x40];\npub const CHIP8FONT_8: [u8; 5] = [0xF0, 0x90, 0xF0, 0x90, 0xF0];\npub const CHIP8FONT_9: [u8; 5] = [0xF0, 0x90, 0xF0, 0x10, 0xF0];\npub const CHIP8FONT_A: [u8; 5] = [0xF0, 0x90, 0xF0, 0x90, 0x90];\npub const CHIP8FONT_B: [u8; 5] = [0xE0, 0x90, 0xE0, 0x90, 0xE0];\npub const CHIP8FONT_C: [u8; 5] = [0xF0, 0x80, 0x80, 0x80, 0xF0];\npub const CHIP8FONT_D: [u8; 5] = [0xE0, 0x90, 0x90, 0x90, 0xE0];\npub const CHIP8FONT_E: [u8; 5] = [0xF0, 0x80, 0xF0, 0x80, 0xF0];\npub const CHIP8FONT_F: [u8; 5] = [0xF0, 0x80, 0xF0, 0x80, 0x80];\n\npub const SCHIPFONT_0: [u8; 0x20] = [\n 0x00, 0x00,\n 0x01, 0x80,\n 0x03, 0xc0,\n 0x06, 0x60,\n 0x0c, 0x30,\n 0x0c, 0x30,\n 0x18, 0x18,\n 0x18, 0x18,\n 0x18, 0x18,\n 0x18, 0x18,\n 0x0c, 0x30,\n 0x0c, 0x30,\n 0x06, 0x60,\n 0x03, 0xc0, // 0b0000001111000000\n 0x01, 0x80, // 0b0000000110000000\n 0x00, 0x00 // 0b0000000000000000\n];\npub const SCHIPFONT_1: [u8; 0x20] = [\n 0x00, 0x00,\n 0x03, 0xc0,\n 0x02, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x03, 0xf0,\n 0x00, 0x00\n];\npub const SCHIPFONT_2: [u8; 0x20] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC7, 0xC3, 0xC0, 0xE0,\n 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0xFF, 0xFF,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78];\npub const SCHIPFONT_3: [u8; 0x20] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC7, 0xC3, 0xC0, 0xE0,\n 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0xFF, 0xFF,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78];\npub const SCHIPFONT_4: [u8; 0x20] = [0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xF7, 0xF3, 0xF1,\n 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78];\npub const SCHIPFONT_5: [u8; 0x20] = [0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x3F, 0x7F, 0x7F,\n 0x01, 0x01, 0xC1, 0xE3, 0xFF, 0xFE, 0xFC, 0x78,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78];\npub const SCHIPFONT_6: [u8; 0x20] = [0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78\n];\npub const SCHIPFONT_7: [u8; 0x20] = [0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0x78, 0x3C,\n 0x1E, 0x0F, 0x07, 0x03, 0x01, 0x01, 0x01, 0x01,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78\n];\npub const SCHIPFONT_8: [u8; 0x20] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF,\n 0x7E, 0xFE, 0xC3, 0xC3, 0xFF, 0xFF, 0xFE, 0x7C,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78\n];\npub const SCHIPFONT_9: [u8; 0x20] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF,\n 0xFF, 0x7F, 0x03, 0x03, 0xC7, 0xFF, 0xFE, 0x7C,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78\n];\npub const SCHIPFONT_A: [u8; 0x20] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78\n];\npub const SCHIPFONT_B: [u8; 0x20] = [0xFE, 0xFF, 0xFF, 0xFF, 0xC3, 0xC3, 0xFE, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xFE,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78\n];\npub const SCHIPFONT_C: [u8; 0x20] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0x01, 0x01,\n 0x01, 0x01, 0xC3, 0xC3, 0xFF, 0xFE, 0xFC, 0x78,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78\n];\npub const SCHIPFONT_D: [u8; 0x20] = [0xFE, 0xFF, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3,\n 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xFE, 0x7C, 0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78\n];\npub const SCHIPFONT_E: [u8; 0x20] = [0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x03, 0xFF,\n 0xFF, 0xFF, 0x03, 0x03, 0xFF, 0xFF, 0xFF, 0xFF,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78\n];\npub const SCHIPFONT_F: [u8; 0x20] = [0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x03, 0xFF,\n 0xFF, 0xFF, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78];\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","lib.rs"],"content":"pub mod chip8 {\n pub mod video;\n pub mod sound_timer;\n pub mod delay_timer;\n pub mod keypad;\n pub mod computer;\n pub mod system_memory;\n pub mod instructions;\n pub mod cpu_states;\n pub mod util;\n pub mod registers;\n\n pub mod stack;\n pub mod computer_manager;\n pub mod quirk_modes;\n}\n\npub mod constants;","traces":[],"covered":0,"coverable":0},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","tests","computer_tests.rs"],"content":"use gemma::chip8::computer::Chip8Computer;\nuse gemma::constants::CHIP8_VIDEO_MEMORY;\n\n#[test]\nfn smoke() { assert!(true) }\n\nfn load_result(to_load: \u0026str) -\u003e String {\n std::fs::read_to_string(format!(\"../resources/test/{}\", to_load)).unwrap()\n}\n\nfn load_rom(to_load: \u0026str) -\u003e Vec\u003cu8\u003e {\n std::fs::read(format!(\"../resources/roms/{}\", to_load)).unwrap()\n}\n\n#[test]\nfn reset_clears_video() {\n let mut x = Chip8Computer::new();\n\n for i in 0..CHIP8_VIDEO_MEMORY {\n x.video_memory.poke(i as u16, i % 2 == 0);\n }\n\n x.reset();\n x.video_memory.reset();\n\n assert_eq!(x.dump_video_to_string(), x.video_memory.format_as_string());\n\n for i in 0..CHIP8_VIDEO_MEMORY {\n assert!(!x.video_memory.peek(i as u16));\n }\n}\n\n#[test]\nfn level1_test() {\n let mut x = Chip8Computer::new();\n let level_1_rom = load_rom(\"1-chip8-logo.ch8\");\n x.load_bytes_to_memory(0x200, (\u0026level_1_rom).into());\n\n // run for 0x40 cycles\n while x.num_cycles \u003c 0x40 {\n x.step_system();\n }\n assert_eq!(x.dump_video_to_string(), load_result(\"gemma_integration_level_1_test.asc\"));\n}\n\n#[test]\nfn level2_test() {\n let mut x = Chip8Computer::new();\n // Load the IBM rom and run it.\n // it takes 39 cycles to get to the end so lets run it 40.\n let test_rom_to_run = load_rom(\"2-ibm-logo.ch8\");\n x.load_bytes_to_memory(0x200, (\u0026test_rom_to_run).into());\n for _ in 0..40 {\n x.step_system();\n }\n // ...then verify that the current video memory of the chip-8\n // simulator matches what we expect it to be\n\n assert_eq!(x.dump_video_to_string(), load_result(\"gemma_integration_ibm_rom_output.asc\"));\n}\n\n#[test]\nfn level3_test() {\n let mut x = Chip8Computer::new();\n\n x.load_bytes_to_memory(\n 0x200, (\u0026load_rom(\"3-corax+.ch8\")).into()\n );\n for i in 0..0x180 {\n x.step_system();\n }\n\n assert_eq!(x.dump_video_to_string(), load_result(\"gemma_integration_corax_plus.asc\"));\n}\n\n#[test]\nfn rps_test() {\n let mut x = Chip8Computer::new();\n x.load_bytes_to_memory(0x200, \u0026load_rom(\"RPS.ch8\").into());\n for _ in 0..0xF0 {\n x.step_system();\n }\n assert_eq!(x.dump_video_to_string(), load_result(\"gemma_integration_rps_stage1.asc\"));\n x.keypad.push_key(0x01);\n for _ in 0..0x200 {\n x.step_system();\n }\n assert_eq!(x.dump_video_to_string(), load_result(\"gemma_integration_rps_stage2.asc\"));\n}\n\n#[test]\nfn level4_test() {\n // flags\n let mut x = Chip8Computer::new();\n x.load_bytes_to_memory(0x200, \u0026load_rom(\"4-flags.ch8\").into());\n for _ in 0..0x400 {\n x.step_system();\n }\n\n assert_eq!(x.dump_video_to_string(), load_result(\"gemma_integration_flags.asc\"));\n}\n","traces":[{"line":7,"address":[299120],"length":1,"stats":{"Line":1}},{"line":8,"address":[299247,299350],"length":1,"stats":{"Line":2}},{"line":11,"address":[299568],"length":1,"stats":{"Line":4}},{"line":12,"address":[299798,299695],"length":1,"stats":{"Line":5}}],"covered":4,"coverable":4},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","tests","unit_tests.rs"],"content":"use std::collections::{BTreeMap, BTreeSet};\nuse log::debug;\nuse rand::random;\nuse gemma::chip8::computer::Chip8Computer;\nuse gemma::chip8::delay_timer::DelayTimer;\nuse gemma::chip8::instructions::Chip8CpuInstructions;\nuse gemma::chip8::instructions::Chip8CpuInstructions::JPA;\nuse gemma::chip8::keypad::Keypad;\nuse gemma::chip8::quirk_modes::QuirkMode::{Chip8, SChipModern, XOChip};\nuse gemma::chip8::registers::Chip8Registers;\nuse gemma::chip8::sound_timer::SoundTimer;\nuse gemma::chip8::stack::Chip8Stack;\nuse gemma::chip8::util::InstructionUtil;\nuse gemma::chip8::video::Chip8Video;\nuse gemma::constants::*;\n\nconst TEST_OUTPUT_SAMPLE_DIR: \u0026str = \"../resources/test/\";\n\nfn read_test_result(suffix: \u0026str) -\u003e String {\n std::fs::read_to_string(TEST_OUTPUT_SAMPLE_DIR.to_owned() + suffix)\n .unwrap()\n}\n\n#[test]\nfn smoke() {\n assert!(true)\n}\n\n#[test]\nfn encode_decode_test() {\n assert_eq!(Chip8CpuInstructions::CLS.encode(), 0x00E0);\n assert_eq!(Chip8CpuInstructions::RET.encode(), 0x00EE);\n assert_eq!(Chip8CpuInstructions::SYS(0x123).encode(), 0x0123);\n assert_eq!(Chip8CpuInstructions::JPA(0x234).encode(), 0x1234);\n assert_eq!(Chip8CpuInstructions::CALL(0x345).encode(), 0x2345);\n assert_eq!(Chip8CpuInstructions::SEX(0x4, 0x56).encode(), 0x3456);\n assert_eq!(Chip8CpuInstructions::SNEB(0xa, 0xbc).encode(), 0x4abc);\n assert_eq!(Chip8CpuInstructions::SEY(0xa, 0xb).encode(), 0x5ab0);\n assert_eq!(Chip8CpuInstructions::LDR(0xa, 0xff).encode(), 0x6aff);\n assert_eq!(Chip8CpuInstructions::ADD(0xa, 0xbc).encode(), 0x7abc);\n assert_eq!(Chip8CpuInstructions::LDR_Y(0xa, 0xb).encode(), 0x8ab0);\n assert_eq!(Chip8CpuInstructions::OR(0xb, 0xa).encode(), 0x8ba1);\n assert_eq!(Chip8CpuInstructions::AND(0xc, 0xd).encode(), 0x8cd2);\n assert_eq!(Chip8CpuInstructions::ORY(0xd, 0xe).encode(), 0x8de3);\n assert_eq!(Chip8CpuInstructions::ADDR(0xe, 0xf).encode(), 0x8ef4);\n assert_eq!(Chip8CpuInstructions::SUB(0xf, 0x0).encode(), 0x8f05);\n assert_eq!(Chip8CpuInstructions::SHR(0x0, 0x1).encode(), 0x8016);\n assert_eq!(Chip8CpuInstructions::SUBC(0x1, 0x2).encode(), 0x8127);\n assert_eq!(Chip8CpuInstructions::SHL(0x3, 0x4).encode(), 0x834e);\n assert_eq!(Chip8CpuInstructions::SNEY(0xa, 0xb).encode(), 0x9ab0);\n assert_eq!(Chip8CpuInstructions::LDIA(0x123).encode(), 0xa123);\n assert_eq!(Chip8CpuInstructions::JPI(0x234).encode(), 0xb234);\n assert_eq!(Chip8CpuInstructions::RND(0xa, 0xca).encode(), 0xcaca);\n assert_eq!(Chip8CpuInstructions::DRW(0xa, 0xb, 0x4).encode(), 0xdab4);\n assert_eq!(Chip8CpuInstructions::SKP(0x1).encode(), 0xe19e);\n assert_eq!(Chip8CpuInstructions::SKNP(0x2).encode(), 0xe2a1);\n assert_eq!(Chip8CpuInstructions::LDRD(0x1).encode(), 0xf107);\n assert_eq!(Chip8CpuInstructions::LDRK(0x4).encode(), 0xf40a);\n assert_eq!(Chip8CpuInstructions::LDD(0x6).encode(), 0xf615);\n assert_eq!(Chip8CpuInstructions::LDIS(0xb).encode(), 0xfb18);\n assert_eq!(Chip8CpuInstructions::ADDI(0xd).encode(), 0xfd1e);\n assert_eq!(Chip8CpuInstructions::LDFX(0xc).encode(), 0xfc29);\n assert_eq!(Chip8CpuInstructions::BCD(0xd).encode(), 0xfd33);\n assert_eq!(Chip8CpuInstructions::LDIX(0xe).encode(), 0xfe55);\n assert_eq!(Chip8CpuInstructions::LDRI(0x3).encode(), 0xf365);\n assert_eq!(Chip8CpuInstructions::SDN(0x1).encode(), 0x00C1);\n assert_eq!(Chip8CpuInstructions::SLF.encode(), 0x00FC);\n assert_eq!(Chip8CpuInstructions::SRT.encode(), 0x00FB);\n assert_eq!(Chip8CpuInstructions::EXIT.encode(), 0x00FD);\n assert_eq!(Chip8CpuInstructions::ENA.encode(), 0x00FF);\n assert_eq!(Chip8CpuInstructions::DIS.encode(), 0x00FE);\n assert_eq!(Chip8CpuInstructions::LDF2(0).encode(), 0xF030);\n assert_eq!(Chip8CpuInstructions::STR(1).encode(), 0xF175);\n assert_eq!(Chip8CpuInstructions::LIDR(1).encode(), 0xF185);\n\n\n/*\n assert!(matches!(Chip8CpuInstructions::decode(0xF175), Chip8CpuInstructions::STR(1)));\n assert!(matches!(Chip8CpuInstructions::decode(0xF185), Chip8CpuInstructions::LIDR(1)));\n assert!(matches!(Chip8CpuInstructions::decode(0x00C1u16), Chip8CpuInstructions::SDN(0x01)));\n assert!(matches!(Chip8CpuInstructions::decode(0x00FCu16), Chip8CpuInstructions::SLF));\n assert!(matches!(Chip8CpuInstructions::decode(0x00FBu16), Chip8CpuInstructions::SRT));\n assert!(matches!(Chip8CpuInstructions::decode(0x00FDu16), Chip8CpuInstructions::EXIT));\n assert!(matches!(Chip8CpuInstructions::decode(0x00FEu16), Chip8CpuInstructions::DIS));\n assert!(matches!(Chip8CpuInstructions::decode(0x00FFu16), Chip8CpuInstructions::ENA));\n assert!(matches!(Chip8CpuInstructions::decode(0xF030u16), Chip8CpuInstructions::LDF2(0)));\n assert!(matches!(Chip8CpuInstructions::decode(0x00E0u16), Chip8CpuInstructions::CLS));\n assert!(matches!(Chip8CpuInstructions::decode(0x00EEu16), Chip8CpuInstructions::RET));\n assert!(matches!(Chip8CpuInstructions::decode(0x0123), Chip8CpuInstructions::SYS(0x123)));\n assert!(matches!(Chip8CpuInstructions::decode(0x0FFF), Chip8CpuInstructions::SYS(0xfff)));\n assert!(matches!(Chip8CpuInstructions::decode(0x1002), Chip8CpuInstructions::JPA(0x2)));\n assert!(matches!(Chip8CpuInstructions::decode(0x1FF0), Chip8CpuInstructions::JPA(0xFF0)));\n assert!(matches!(Chip8CpuInstructions::decode(0x2002), Chip8CpuInstructions::CALL(0x2)));\n assert!(matches!(Chip8CpuInstructions::decode(0x3123), Chip8CpuInstructions::SEX(0x1, 0x23)));\n assert!(matches!(Chip8CpuInstructions::decode(0x4abc), Chip8CpuInstructions::SNEB(0xa, 0xbc)));\n assert!(matches!(Chip8CpuInstructions::decode(0x5ab0), Chip8CpuInstructions::SEY(0xa, 0xb)));\n assert!(matches!(Chip8CpuInstructions::decode(0x6aff), Chip8CpuInstructions::LDR(0xa, 0xff)));\n assert!(matches!(Chip8CpuInstructions::decode(0x7abc), Chip8CpuInstructions::ADD(0xa, 0xbc)));\n assert!(matches!(Chip8CpuInstructions::decode(0x8ab0), Chip8CpuInstructions::LDR_Y(0xa, 0xb)));\n assert!(matches!(Chip8CpuInstructions::decode(0x8ba1), Chip8CpuInstructions::OR(0xb, 0xa)));\n assert!(matches!(Chip8CpuInstructions::decode(0x8cd2), Chip8CpuInstructions::AND(0xc, 0xd)));\n assert!(matches!(Chip8CpuInstructions::decode(0x8de3), Chip8CpuInstructions::ORY(0xd, 0xe)));\n assert!(matches!(Chip8CpuInstructions::decode(0x8ef4), Chip8CpuInstructions::ADDR(0xe, 0xf)));\n assert!(matches!(Chip8CpuInstructions::decode(0x8f05), Chip8CpuInstructions::SUB(0xf, 0x0)));\n assert!(matches!(Chip8CpuInstructions::decode(0x8016), Chip8CpuInstructions::SHR(0x0, 0x1)));\n assert!(matches!(Chip8CpuInstructions::decode(0x8127), Chip8CpuInstructions::SUBC(0x1, 0x2)));\n assert!(matches!(Chip8CpuInstructions::decode(0x834e), Chip8CpuInstructions::SHL(0x3, 0x4)));\n assert!(matches!(Chip8CpuInstructions::decode(0x9ab0), Chip8CpuInstructions::SNEY(0xa, 0xb)));\n assert!(matches!(Chip8CpuInstructions::decode(0xa123), Chip8CpuInstructions::LDIA(0x123)));\n assert!(matches!(Chip8CpuInstructions::decode(0xb234), Chip8CpuInstructions::JPI(0x234)));\n assert!(matches!(Chip8CpuInstructions::decode(0xcaca), Chip8CpuInstructions::RND(0xa, 0xca)));\n assert!(matches!(Chip8CpuInstructions::decode(0xdab4), Chip8CpuInstructions::DRW(0xa, 0xb, 0x4)));\n assert!(matches!(Chip8CpuInstructions::decode(0xe19e), Chip8CpuInstructions::SKP(0x1)));\n assert!(matches!(Chip8CpuInstructions::decode(0xe2a1), Chip8CpuInstructions::SKNP(0x2)));\n assert!(matches!(Chip8CpuInstructions::decode(0xf107), Chip8CpuInstructions::LDRD(0x1)));\n assert!(matches!(Chip8CpuInstructions::decode(0xf40a), Chip8CpuInstructions::LDRK(0x4)));\n assert!(matches!(Chip8CpuInstructions::decode(0xf615), Chip8CpuInstructions::LDD(0x6)));\n assert!(matches!(Chip8CpuInstructions::decode(0xfb18), Chip8CpuInstructions::LDIS(0xb)));\n assert!(matches!(Chip8CpuInstructions::decode(0xfd1e), Chip8CpuInstructions::ADDI(0xd)));\n assert!(matches!(Chip8CpuInstructions::decode(0xfc29), Chip8CpuInstructions::LDFX(0xc)));\n assert!(matches!(Chip8CpuInstructions::decode(0xfd33), Chip8CpuInstructions::BCD(0xd)));\n assert!(matches!(Chip8CpuInstructions::decode(0xfe55), Chip8CpuInstructions::LDIX(0xe)));\n assert!(matches!(Chip8CpuInstructions::decode(0xf365), Chip8CpuInstructions::LDRI(0x3)));\n*/\n}\n\n#[test]\nfn decoder_test_invalid_instructions() {\n let invalid_to_encode = [\n 0x5ab1, 0x5abf, 0x8ab8, 0x8abd, 0x8abf,\n 0x9ab1, 0x9abf, 0xea9d, 0xea9f, 0xeaa0,\n 0xeaa2, 0xf006, 0xf008\n ];\n\n for i in invalid_to_encode {\n assert_eq!(Chip8CpuInstructions::decode(i, \u0026Chip8).encode(), 0xffff);\n assert!(matches!(Chip8CpuInstructions::decode(i, \u0026Chip8), Chip8CpuInstructions::XXXXERRORINSTRUCTION));\n }\n}\n\n/// START OF THE EXECUTION TESTS\n#[test]\nfn instruction_tests() {\n // 0x0nnn Exit to System Call\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::SYS(0).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0);\n\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::SYS(0xFA0).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0xFA0);\n\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::SYS(0x0AF).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x0AF);\n\n // 0x1nnn Jump to Address\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::JPA(0).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0);\n\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::JPA(0xABC).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0xABC);\n\n // 0x6xkk Set Vx = kk\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::LDR(1, 0x12).execute(\u0026mut x);\n assert_eq!(x.registers.peek(1), 0x12);\n\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::LDR(2, 0x21).execute(\u0026mut x);\n assert_eq!(x.registers.peek(2), 0x21);\n\n // 0x3xkk Skip next instruction if Vx = kk.\n // The interpreter compares register Vx to kk,\n // and if they are equal, increments the program counter by 2.\n\n // test setup: Load value 0x84 into V1\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0x84);\n Chip8CpuInstructions::SEX(1, 0x48).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x202);\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0x84);\n Chip8CpuInstructions::SEX(1, 0x84).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x204);\n\n // 0x4xkk Skip next instruction if Vx != kk\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0x84);\n x.registers.poke(0x2, 0x84);\n // skip, compare 0x84 to 0x84\n Chip8CpuInstructions::SEY(0x1, 0x2).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x204);\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0x84);\n x.registers.poke(0x2, 0x48);\n Chip8CpuInstructions::SEY(0x01, 0x02).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x202);\n\n // 0x8xy0 Set value of Vy in Vx\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0x01);\n x.registers.poke(0x02, 0x02);\n Chip8CpuInstructions::LDR_Y(0x01, 0x02).execute(\u0026mut x);\n assert_eq!(x.registers.peek(1), 0x02);\n\n // 0x8xy1 Set Vx = Vx OR Vy\n // 0b0101 0000 (0x50)\n // | 0b0000 1010 (0x0A)\n // 0b0101 1010 (0x5A)\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0b01010000);\n x.registers.poke(0x02, 0b00001010);\n Chip8CpuInstructions::OR(1, 2).execute(\u0026mut x);\n assert_eq!(x.registers.peek(1), 0b01011010);\n\n // 0x8xy2 Set Vx = Vx AND Vy\n // 0b1111 1100 (0xFC)\n // \u0026 0b1100 1010 (0xCA)\n // 0b1100 1000 (0xC8)\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0xFC);\n x.registers.poke(0x02, 0xCA);\n Chip8CpuInstructions::AND(1, 2).execute(\u0026mut x);\n assert_eq!(x.registers.peek(1), 0xC8);\n\n // 0x8xy3 Set Vx = Vx XOR Vy\n // 0b1111 1100 (0xFC)\n // ^ 0b1100 1010 (0xCA)\n // 0b0011 0110 (0x36)\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0b11111100);\n x.registers.poke(0x02, 0b11001010);\n Chip8CpuInstructions::ORY(1, 2).execute(\u0026mut x);\n assert_eq!(x.registers.peek(1), 0b00110110);\n\n // 0x8xy4 Set Vx = Vx + Vy (SET VF on Carry)\n // T1 T2: Judgement Test\n // 0x01 0xFF\n // + 0x01 0x01\n // 0x02 F0 0x00 F1\n let mut x = Chip8Computer::new();\n x.registers.poke(0x0f, 00);\n x.registers.poke(0x01, 0x01);\n x.registers.poke(0x02, 0x01);\n Chip8CpuInstructions::ADDR(0x01, 0x02).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0xf), 0x00);\n assert_eq!(x.registers.peek(0x01), 0x02);\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x0f, 0x00);\n x.registers.poke(0x01, 0xff);\n x.registers.poke(0x02, 0x01);\n Chip8CpuInstructions::ADDR(1, 2).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0xf), 1);\n assert_eq!(x.registers.peek(1), 0);\n\n /*\n Set Vx = Vx SHR 1.\n\n If the least-significant bit of Vx is 1, then VF is set to 1, otherwise 0. Then Vx is divided by 2.\n */\n let mut x = Chip8Computer::new();\n x.registers.poke(0x0f, 0x00);\n x.registers.poke(0x01, 0b00001000);\n x.registers.poke(0x02, 0b00000000);\n Chip8CpuInstructions::SHR(0x1, 0x2).execute(\u0026mut x); // 0b0000 0010 (0x02) (Not Set)\n assert_eq!(x.registers.peek(1), 0b00000100);\n assert_eq!(x.registers.peek(0xf), 0);\n\n x = Chip8Computer::new();\n x.registers.poke(0x0f, 0x00);\n x.registers.poke(0x01, 0b00001001);\n Chip8CpuInstructions::SHR(0x1, 0x2).execute(\u0026mut x);\n assert_eq!(x.registers.peek(1), 0b00000100);\n assert_eq!(x.registers.peek(0xf), 1);\n\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::LDIA(0x123).execute(\u0026mut x);\n assert_eq!(x.registers.peek_i(), 0x123);\n assert_eq!(x.registers.peek_pc(), 0x202);\n}\n\n#[test]\nfn jp_v0addr_test() {\n let mut x = Chip8Computer::new();\n /// jump to I + nnn\n x.registers.poke(0x0, 0xff);\n Chip8CpuInstructions::JPI(0x100).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x1FF);\n}\n\n#[test]\nfn cls_test() {\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::CLS.execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x202);\n for i in 0..CHIP8_VIDEO_MEMORY {\n assert_eq!(x.video_memory.peek(i as u16), false);\n }\n // draw some thing to the video memory\n x.video_memory.poke(0x01, true);\n x.video_memory.poke(0x03, true);\n x.video_memory.poke(0x05, true);\n\n Chip8CpuInstructions::CLS.execute(\u0026mut x);\n\n for i in 0..CHIP8_VIDEO_MEMORY {\n assert_eq!(x.video_memory.peek(i as u16), false);\n }\n}\n\n#[test]\nfn skip_next_instruction_ne_text() {\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0xf0);\n Chip8CpuInstructions::SNEB(0x1, 0x0f).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x204);\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0xf0);\n Chip8CpuInstructions::SNEB(0x1, 0xf0).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x202);\n}\n\n#[test]\nfn addivx_test() {\n let mut x = Chip8Computer::new();\n x.registers.poke_i(0xabc);\n x.registers.poke(0x0, 0x10);\n Chip8CpuInstructions::ADDI(0x0).execute(\u0026mut x);\n assert_eq!(x.registers.peek_i(), 0xacc);\n}\n\n#[test]\nfn ldstvt_test() {\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0xf0);\n Chip8CpuInstructions::LDIS(0x01).execute(\u0026mut x);\n assert_eq!(x.sound_timer.current(), 0xf0);\n x.sound_timer.tick();\n x.sound_timer.tick();\n x.sound_timer.tick();\n assert_eq!(x.sound_timer.current(), 0xed);\n}\n\n#[test]\nfn rnd_vx_byte_text() {\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::RND(0x1, 0x0f).execute(\u0026mut x);\n let new_value = x.registers.peek(0x1);\n assert!(new_value \u003c 0x10);\n}\n\n#[test]\nfn add_vx_byte_test() {\n let mut x = Chip8Computer::new();\n // set a value in the register\n x.registers.poke(0x01, 0xab);\n // add 0x10 to register\n Chip8CpuInstructions::ADD(0x1, 0x10).execute(\u0026mut x);\n assert_eq!(x.registers.peek(1), 0xbb);\n}\n\n#[test]\nfn sub_vx_vy_test() {\n let mut x = Chip8Computer::new();\n // load values in 2 registers\n x.registers.poke(0x1, 0x10);\n x.registers.poke(0x2, 0x08);\n Chip8CpuInstructions::SUB(0x1, 0x02).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0xf), 1);\n assert_eq!(x.registers.peek(0x1), 0x8);\n assert_eq!(x.registers.peek_pc(), 0x202);\n}\n\n#[test]\nfn sne_vx_vy_test() {\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0x10);\n x.registers.poke(0x2, 0x10);\n Chip8CpuInstructions::SNEY(0x1, 0x2).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x202);\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0x10);\n x.registers.poke(0x2, 0x00);\n Chip8CpuInstructions::SNEY(0x01, 0x02).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x204)\n}\n\n#[test]\nfn ld_dt_vx_test() {\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0x10);\n Chip8CpuInstructions::LDD(0x1).execute(\u0026mut x);\n assert_eq!(x.delay_timer.current(), 0x10);\n for i in 0..0x20 {\n x.delay_timer.tick();\n }\n assert_eq!(x.delay_timer.current(), 0);\n}\n\n#[test]\nfn ld_vx_dt_test() {\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0xf0);\n Chip8CpuInstructions::LDD(0x1).execute(\u0026mut x);\n x.delay_timer.tick();\n x.delay_timer.tick();\n x.delay_timer.tick();\n assert_eq!(x.delay_timer.current(), 0xed);\n}\n\n#[test]\nfn subn_vx_vy_test() {\n // This instruction subtracts the value in\n // register Vx from the value in register Vy and stores the result in register Vx.\n // The subtraction is performed as follows: Vx = Vy - Vx. If Vy is less than Vx,\n // the result will wrap around (due to the 8-bit nature of the registers).\n // The carry flag (VF) is set to 1 if there is no borrow (i.e., Vy is greater\n // than or equal to Vx), and it is set to 0 if there is a borrow.\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0xa0);\n x.registers.poke(0x2, 0xab);\n Chip8CpuInstructions::SUBC(0x1, 0x2).execute(\u0026mut x);\n // expect the result to be 0x0b\n assert_eq!(x.registers.peek(0x1), 0x0b);\n // expect the vf register to be set to 1 as there was overflow\n assert_eq!(x.registers.peek(0xf), 0x1);\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0xab);\n x.registers.poke(0x02, 0xa0);\n Chip8CpuInstructions::SUBC(0x1, 0x2).execute(\u0026mut x);\n\n // expect the result to be 11110101, -0xB, -11, 245, 0xF5\n assert_eq!(x.registers.peek(0x1), 0xf5);\n assert_eq!(x.registers.peek(0xf), 0x0);\n\n // 8xyE - SHL Vx {, Vy}\n // Set Vx = Vx SHL 1.\n //\n // If the most-significant bit of Vx is 1, then VF is set to 1, otherwise to 0. Then Vx is multiplied by 2.\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0b00100000);\n Chip8CpuInstructions::SHL(0x1, 0x1).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x1), 0b01000000);\n assert_eq!(x.registers.peek(0xf), 0x0);\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0b10101010);\n Chip8CpuInstructions::SHL(0x1, 0x1).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x1), 0b01010100);\n assert_eq!(x.registers.peek(0xf), 0x1);\n\n // Fx29 - LD F, Vx\n // Set I = location of sprite for digit Vx.\n //\n // 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.\n let mut x = Chip8Computer::new();\n // target_sprite = 2\n // target_offset = 0x5\n x.registers.poke(0x1, 0x2);\n Chip8CpuInstructions::LDFX(0x1).execute(\u0026mut x);\n\n assert_eq!(x.registers.peek_i(), 10);\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0x06);\n Chip8CpuInstructions::LDFX(0x1).execute(\u0026mut x);\n assert_eq!(x.registers.peek_i(), 30);\n\n // Fx33 - LD B, Vx\n // Store BCD representation of Vx in memory locations I, I+1, and I+2.\n //\n // The interpreter takes the decimal value of Vx, and places the hundreds digit\n // in memory at location in I, the tens digit at location I+1,\n // and the ones digit at location I+2.\n let mut x = Chip8Computer::new();\n\n // load the value 123 (0x7b)\n x.registers.poke(0x1, 0x7b);\n x.registers.poke_i(0x500);\n Chip8CpuInstructions::BCD(0x1).execute(\u0026mut x);\n assert_eq!(x.memory.peek(0x500), 0x1);\n assert_eq!(x.memory.peek(0x501), 0x2);\n assert_eq!(x.memory.peek(0x502), 0x3);\n\n // Store registers V0 through Vx in memory starting at location I.\n //\n // The interpreter copies the values of registers V0 through Vx into memory,\n // starting at the address in I.\n let mut x = Chip8Computer::new();\n\n // Load Registers.\n let to_load = [0xab, 0xba, 0xca, 0xca, 0xbe, 0xef];\n for (idx, val) in to_load.iter().enumerate() {\n x.registers.poke(idx as u8, *val);\n }\n x.registers.poke_i(0x500);\n\n Chip8CpuInstructions::LDIX(to_load.len() as u8).execute(\u0026mut x);\n\n // Verify the values are in memory from 0x500 to 0x507\n for (idx, value) in to_load.iter().enumerate() {\n assert_eq!(x.memory.peek(0x500 + idx as u16), *value);\n }\n\n // Read registers V0 through Vx from memory starting at location I.\n //\n // The interpreter reads values from memory starting at location I into registers V0 through Vx.\n\n let mut x = Chip8Computer::new();\n\n let base_offset = 0x500;\n let to_load = [0xab, 0xba, 0xca, 0xca, 0xbe, 0xef];\n\n // start by setting values in memory\n for (idx, memory) in to_load.iter().enumerate() {\n let target_address = base_offset + idx;\n let target_value = *memory;\n x.memory.poke(target_address as u16, target_value);\n }\n // where to load from\n x.registers.poke_i(0x500);\n // how much to load\n x.registers.poke(0x6, to_load.len() as u8);\n\n // then copying them values memory to registers\n Chip8CpuInstructions::LDRI(0x6).execute(\u0026mut x);\n\n // now check that we have the right values in our registers\n for (idx, value) in to_load.iter().enumerate() {\n assert_eq!(x.registers.peek(idx as u8), *value);\n }\n\n // ExA1 - SKNP Vx\n // Skip next instruction if key with the value of Vx is not pressed.\n //\n // Checks the keyboard,\n // and if the key corresponding to the value of Vx is currently in the up position,\n // PC is increased by 2.\n let mut x = Chip8Computer::new();\n x.keypad.push_key(0x5);\n x.registers.poke(0x1, 0x5);\n Chip8CpuInstructions::SKNP(0x1).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x202);\n x.keypad.release_key(0x5);\n Chip8CpuInstructions::SKNP(0x1).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x206);\n\n // Ex9E - SKP Vx\n // Skip next instruction if key with the value of Vx is pressed.\n //\n // Checks the keyboard, and if the key corresponding to the value of Vx is currently in the down position, PC is increased by 2.\n let mut x = Chip8Computer::new();\n x.keypad.push_key(0x5);\n x.registers.poke(0x1, 0x5);\n Chip8CpuInstructions::SKP(0x1).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x204);\n\n x.keypad.release_key(0x5);\n Chip8CpuInstructions::SKP(0x1).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x206);\n}\n\nfn draw_nibble_vx_vy_n_test_hd() {\n let mut x = Chip8Computer::new();\n\n let x_register = 0x01;\n let x_offset = 0x03;\n let y_register = 0x02;\n let y_offset = 0x04;\n let char_offset = 0x100;\n x.registers.poke(x_register, x_offset);\n x.registers.poke(y_register, y_offset);\n x.video_memory.set_highres();\n x.registers.poke_i(char_offset);\n Chip8CpuInstructions::DRW(x_register, y_register, 0).execute(\u0026mut x);\n\n println!(\"[[{}]]\", x.video_memory.format_as_string());\n\n assert_eq!(read_test_result(\"\"), x.video_memory.format_as_string());\n}\n\n#[test]\nfn draw_nibble_vx_vy_n_test_sd() {\n let mut x = Chip8Computer::new();\n let x_register = 0x1;\n let y_register = 0x2;\n let x_offset = 1;\n let y_offset = 2;\n let char_offset = 0x0A;\n\n // now lets set the X and Y to 1,2\n x.registers.poke(x_register, x_offset);\n x.registers.poke(y_register, y_offset);\n x.registers.poke_i(char_offset);\n // we are using 5 rows.\n Chip8CpuInstructions::DRW(x_register, y_register, 5).execute(\u0026mut x);\n\n // now check that video memory has the values at\n // 1,2-\u003e1,9\n // 2,2-\u003e2,9\n // 3,2-\u003e3,9\n // 4,2-\u003e4,9\n // 5,2-\u003e5,9\n // let byte_to_check = CHIP8FONT_0[0];\n for row_in_sprite in 0..5 {\n let row_data = CHIP8FONT_2[row_in_sprite];\n for bit_in_byte in 0..8 {\n let data_offset = (x_offset\n as u16 + row_in_sprite as u16) * 64 + (bit_in_byte + y_offset) as u16;\n let real_bit_in_byte = 7 - bit_in_byte;\n let shifted_one = 0x01 \u003c\u003c real_bit_in_byte;\n let one_shift_set = (shifted_one \u0026 row_data) \u003e 0;\n 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}]\");\n debug!(\"DATA_OFFSET FOR SOURCE DATA {}x{} is {} / offset by {}x{} and should be {} working with byte {:08b}\",\n bit_in_byte, row_in_sprite, data_offset, x_offset, y_offset, one_shift_set, row_data);\n }\n }\n}\n\n#[test]\nfn sub_test() {\n // 2nnn\n // Call a subroutine at 2nnn\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::CALL(0x124).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x124);\n assert_eq!(x.stack.depth(), 1);\n Chip8CpuInstructions::CALL(0x564).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x564);\n assert_eq!(x.stack.depth(), 2);\n\n // SETUP\n // Return from a subroutine.\n let mut x = Chip8Computer::new();\n x.stack.push(\u00260x132);\n x.stack.push(\u00260xabc);\n // EXECUTE\n Chip8CpuInstructions::RET.execute(\u0026mut x);\n // VERIFY\n assert_eq!(x.registers.peek_pc(), 0xabc);\n assert_eq!(x.stack.depth(), 1);\n // EXECUTE\n Chip8CpuInstructions::RET.execute(\u0026mut x);\n // VERIFY\n assert_eq!(x.registers.peek_pc(), 0x132);\n assert_eq!(x.stack.depth(), 0);\n}\n\n\n#[test]\nfn ldvxk_test() {\n // SETUP\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0x01);\n Chip8CpuInstructions::LDRK(0x1).execute(\u0026mut x);\n assert!(matches!(x.state, gemma::chip8::cpu_states::Chip8CpuStates::WaitingForKey));\n}\n\n#[test]\nfn series8xy4_corex_tests() {\n /// 8xy4\n /// Set Vx = Vx + Vy\n /// Set VF=1 if Carry\n ///\n\n // 1 + 1\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0x01);\n x.registers.poke(0x02, 0x01);\n Chip8CpuInstructions::ADDR(0x01, 0x02).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x01), 0x02);\n assert_eq!(x.registers.peek(0x0f), 0x00);\n\n // 255+1\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0xff);\n x.registers.poke(0x02, 0x01);\n Chip8CpuInstructions::ADDR(0x01, 0x02).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x01), 0x00);\n assert_eq!(x.registers.peek(0x0f), 0x01);\n\n // 128+192\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 128);\n x.registers.poke(0x02, 192);\n Chip8CpuInstructions::ADDR(0x01, 0x02).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x01), 64);\n assert_eq!(x.registers.peek(0x0f), 1);\n\n // 8xy6 - SHR Vx {, Vy}\n // Set Vx = Vx SHR 1.\n //\n // If the least-significant bit of Vx is 1, then VF is set to 1,\n // otherwise 0. Then Vx is divided by 2.\n let mut x = Chip8Computer::new();\n // 0b10101010 -\u003e 0b01010101\n x.registers.poke(0x01, 0b10101010);\n x.registers.poke(0x0f, 0x0);\n\n Chip8CpuInstructions::SHL(0x01, 0x00).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x01), 0b01010100);\n assert_eq!(x.registers.peek(0x0f), 1);\n\n Chip8CpuInstructions::SHL(0x01, 0x00).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x01), 0b10101000);\n assert_eq!(x.registers.peek(0x0f), 0x00);\n\n Chip8CpuInstructions::SHL(0x01, 0x00).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x01), 0b01010000);\n assert_eq!(x.registers.peek(0x0f), 0x01);\n\n Chip8CpuInstructions::SHL(0x01, 0x00).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x01), 0b10100000);\n assert_eq!(x.registers.peek(0x0f), 0x00);\n\n Chip8CpuInstructions::SHL(0x01, 0x00).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x01), 0b01000000);\n assert_eq!(x.registers.peek(0x0f), 0x01);\n}\n\n#[test]\nfn random_produces_different_numbers() {\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0x00);\n let first_number = Chip8CpuInstructions::RND(0x01, 0xff).execute(\u0026mut x).registers.peek(0x01);\n let second_number = Chip8CpuInstructions::RND(0x01, 0xff).execute(\u0026mut x).registers.peek(0x01);\n assert_ne!(first_number, second_number);\n}\n\n#[test]\nfn delay_timer_ticks_reduce_time() {\n let mut st = DelayTimer::new();\n st.set_timer(100);\n st.tick();\n st.tick();\n st.tick();\n assert_eq!(st.current(), 97);\n}\n\n#[test]\nfn delay_timer_out_of_ticks_works() {\n let mut st = DelayTimer::new();\n st.set_timer(0);\n st.tick();\n st.tick();\n st.tick();\n assert_eq!(st.current(), 0);\n}\n\n#[test]\nfn keypad_keys_check() {\n let mut k = Keypad::new();\n\n for i in 0..16 {\n assert!(!k.key_state(i));\n }\n\n // press a key\n k.push_key(1);\n k.push_key(2);\n assert!(k.pressed(1));\n assert!(k.pressed(2));\n k.release_key(1);\n assert!(k.released(1));\n}\n\n\n#[test]\nfn keypad_string_format_test() {\n let mut k = Keypad::new();\n\n\n assert_eq!(k.format_as_string(), read_test_result(\"gemma_keypad_string_result.asc\"));\n}\n\n#[test]\nfn register_rw_test() {\n let mut x = Chip8Registers::default();\n x.poke(0x0, 0xff);\n x.poke(0x1, 0xab);\n assert_eq!(x.peek(0x0), 0xff);\n assert_eq!(x.peek(0x1), 0xab);\n}\n\n#[test]\nfn pc_test() {\n let mut x = Chip8Registers::default();\n x.set_pc(0x300);\n assert_eq!(x.peek_pc(), 0x300);\n}\n\n#[test]\n#[should_panic]\nfn invalid_register() {\n let mut x = Chip8Registers::default();\n x.poke(0x10, 0xff);\n}\n\n#[test]\nfn format_as_string_looks_right() {\n let mut x = Chip8Registers::default();\n for i in 0..0x10 {\n x.registers[i] = i as u8;\n }\n x.pc = 0xabc;\n x.i_register = 0xcab;\n let result_string = x.format_as_string();\n 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\"));\n}\n\n#[test]\nfn reset_clears_registers() {\n let mut x = Chip8Registers::default();\n\n for register in 0..0x10 {\n x.poke(register, random::\u003cu8\u003e());\n }\n x.reset();\n for register in 0..0x10 {\n assert_eq!(x.peek(register), 0x00);\n }\n}\n\n#[test]\nfn sound_timer_ticks_reduce_time() {\n let mut st = SoundTimer::new();\n st.set_timer(100);\n st.tick();\n st.tick();\n st.tick();\n assert_eq!(st.current(), 97);\n}\n\n#[test]\nfn sound_timer_out_of_ticks_works() {\n let mut st = SoundTimer::new();\n st.set_timer(0);\n st.tick();\n st.tick();\n st.tick();\n assert_eq!(st.current(), 0);\n}\n\n#[test]\nfn stack_push_pop_test() {\n let mut x = Chip8Stack::new();\n\n // lets see if we can push and pop a bunch\n x.push(\u00260xabcu16);\n x.push(\u00260xcdeu16);\n x.pop();\n assert_eq!(x.depth(), 1);\n}\n\n#[test]\n#[should_panic]\nfn stack_overflow_test() {\n let mut x = Chip8Stack::new();\n for i in 0..17 {\n x.push(\u0026i);\n }\n}\n\n#[test]\n#[should_panic]\nfn stack_underflow_test() {\n let mut x = Chip8Stack::new();\n x.pop();\n}\n\n#[test]\nfn stack_lots_of_subs() {\n let mut x = Chip8Stack::new();\n let stack_contents = [0x123, 0x321, 0xabc, 0xdef,\n 0xbad, 0xbef, 0xfed, 0xcab,\n 0xbed, 0xcad, 0xfeb, 0xcab,\n 0xfff, 0x000, 0x001];\n for i in stack_contents {\n x.push(\u0026i);\n }\n\n assert_eq!(x.depth(), 15);\n\n // up to 50 random loops\n let num_loops: u8 = random::\u003cu8\u003e() % 50;\n for i in 0..num_loops {\n let start_count = x.depth();\n let num_pop = random::\u003cu8\u003e() % x.depth() as u8;\n for current_pop in 0..num_pop {\n x.pop();\n }\n\n let post_pop_count = x.depth();\n assert_eq!(post_pop_count as u8, start_count as u8 - num_pop);\n for current_push in 0..num_pop {\n x.push(\u0026stack_contents[(current_push + post_pop_count as u8) as usize]);\n }\n assert_eq!(x.depth(), 15);\n }\n}\n\n\n#[test]\nfn video_split_bytes() {\n // from 0xABCD we should have AB high, CD low\n let (low, high) = InstructionUtil::split_bytes(0xabcd);\n assert_eq!(low, 0xAB);\n assert_eq!(high, 0xCD);\n}\n\n#[test]\nfn video_join_bytes() {\n // from 0xAB low and 0xCD high we get 0xABCD\n let merged = InstructionUtil::join_bytes(0xcd, 0xab);\n assert_eq!(merged, 0xcdab);\n}\n\n#[test]\nfn instruction_read_from_instruction() {\n // from 0xABCD\n let source = 0xABCD;\n assert_eq!(InstructionUtil::read_addr_from_instruction(source), 0xBCD);\n assert_eq!(InstructionUtil::read_nibble_from_instruction(source), 0xD);\n assert_eq!(InstructionUtil::read_x_from_instruction(source), 0xB);\n assert_eq!(InstructionUtil::read_y_from_instruction(source), 0xC);\n assert_eq!(InstructionUtil::read_byte_from_instruction(source), 0xCD);\n}\n\n#[test]\nfn instruction_ubln() {\n // from 0xABCD we should see B\n assert_eq!(InstructionUtil::read_upper_byte_lower_nibble(0xABCD), 0xB);\n assert_eq!(InstructionUtil::read_upper_byte_lower_nibble(0x0123), 0x1);\n assert_eq!(InstructionUtil::read_upper_byte_lower_nibble(0x0000), 0x0);\n}\n\n#[test]\nfn instruction_byte_to_bool_changes() {\n assert_eq!(InstructionUtil::byte_to_bools(0b00000000), [false, false, false, false, false, false, false, false]);\n assert_eq!(InstructionUtil::byte_to_bools(0b11111111), [true, true, true, true, true, true, true, true]);\n assert_eq!(InstructionUtil::byte_to_bools(0b11001100), [false, false, true, true, false, false, true, true]);\n assert_eq!(InstructionUtil::byte_to_bools(0b11110000), [false, false, false, false, true, true, true, true]);\n assert_eq!(InstructionUtil::bools_to_byte([false, false, false, false, false, false, false, false]), 0b00000000);\n assert_eq!(InstructionUtil::bools_to_byte([true, true, true, true, true, true, true, true]), 0b11111111);\n assert_eq!(InstructionUtil::bools_to_byte([false, false, true, true, false, false, true, true]), 0b11001100);\n assert_eq!(InstructionUtil::bools_to_byte([false, false, false, false, true, true, true, true]), 0b11110000);\n}\n\n\nfn real_build_checkboard(in_hd: bool) -\u003e Chip8Video {\n let mut r = Chip8Video::default();\n let (width, height) = if in_hd {\n r.set_highres();\n (SCHIP_VIDEO_WIDTH, SCHIP_VIDEO_HEIGHT)\n } else {\n (CHIP8_VIDEO_WIDTH, CHIP8_VIDEO_HEIGHT)\n };\n\n println!(\"BUILDING BOARD WITH SIZE OF {width}x{height}\");\n\n for row in 0..height {\n let data_offset = row * width;\n\n for col in 0..width {\n // XOR row and column indices to alternate in a checkerboard pattern\n let to_poke = (row % 2) ^ (col % 2) == 1;\n let local_offset: u16 = (data_offset + col) as u16;\n\n r.poke(local_offset, to_poke);\n }\n }\n r\n}\n\nfn build_checkboard_hd() -\u003e Chip8Video {\n real_build_checkboard(true)\n}\n\nfn build_checkerboard() -\u003e Chip8Video {\n real_build_checkboard(false)\n}\n\n#[test]\nfn video_default_test() {\n let mut x = Chip8Video::default();\n\n for i in 0..CHIP8_VIDEO_MEMORY {\n assert!(!x.clone().peek(i as u16));\n // then flip the value and test again.\n \u0026x.poke(i as u16, true);\n assert!(x.clone().peek(i as u16));\n }\n}\n\n#[test]\nfn video_set_initial_memory_sd() {\n let mut x = Chip8Video::default();\n // let mut initial_memory = [false; CHIP8_VIDEO_MEMORY];\n let mut ws = String::new();\n // set our checkerboard\n for cbr in 0..32 {\n for cbc in 0..64 {\n let dof = cbr * 64 + cbc;\n if (dof as i32 % 2) == 0 {\n x.poke(dof, true);\n ws += \"*\";\n } else {\n ws += \" \";\n }\n }\n ws += \"\\n\";\n }\n assert_eq!(x.format_as_string(), ws);\n}\n\n#[test]\nfn video_poke_byte_test() {\n let to_poke = 0b11001111;\n let mut x = Chip8Video::default();\n x.poke_byte(0x05, to_poke);\n let mut expected = String::new();\n expected = \" ** **** \\n\".to_string();\n for i in 0..31 {\n expected += \u0026*(\" \".repeat(64) + \"\\n\");\n }\n assert_eq!(x.format_as_string(), expected);\n}\n\n#[test]\nfn video_poke_2byte_test() {\n let to_poke: [u8; 2] = [\n 0b11001111,\n 0b00111100\n ];\n\n let mut x = Chip8Video::default();\n x.poke_2byte(0x00, to_poke);\n\n let mut expected = String::new();\n expected = \"** **** **** \".to_string() + \u0026*\" \".repeat(64 - 16).to_string() + \"\\n\";\n for i in 0..31 {\n expected += \u0026*((\u0026*\" \".repeat(64)).to_string() + \"\\n\");\n }\n\n assert_eq!(expected, x.format_as_string());\n}\n\n#[test]\nfn video_poke_multirow_2_byte_sprite() {\n // take 2 rows of 16bits and write them to memory\n}\n\n#[test]\nfn video_cls_stddef() {\n let width = 64;\n let height = 32;\n let mut initial_memory = vec![];\n let mut ws = String::new();\n let mut set_x = Chip8Video::new(initial_memory.into());\n for cbr in 0..32 {\n ws += \u0026*\" \".repeat(width);\n ws += \"\\n\";\n }\n set_x.cls();\n\n assert_eq!(set_x.format_as_string(), ws);\n}\n\n#[test]\nfn video_poke_byte_test_2() {\n let to_poke = 0b10101010;\n let mut v = Chip8Video::default();\n v.poke_byte(0x00, to_poke);\n assert!(v.clone().peek(0x00));\n assert!(!v.clone().peek(0x01));\n assert!(v.clone().peek(0x02));\n assert!(!v.clone().peek(0x03));\n assert!(v.clone().peek(0x04));\n assert!(!v.clone().peek(0x05));\n assert!(v.clone().peek(0x06));\n assert!(!v.clone().peek(0x07));\n for i in 0x8..CHIP8_VIDEO_MEMORY {\n assert!(!v.clone().peek(i as u16));\n }\n}\n\n#[test]\nfn video_poke_multi_line_test() {\n let mut v = Chip8Video::default();\n let to_poke = [\n 0b00000000,\n 0b11111111,\n 0b10101010,\n 0b01010101\n ];\n\n for (byte_in_set, byte_to_poke) in to_poke.iter().enumerate() {\n let base_offset = byte_in_set * 64;\n v.poke_byte(base_offset as u16, *byte_to_poke);\n }\n\n // row 2 column 1\n {\n assert!(v.clone().peek(0x40));\n assert!(v.clone().peek(0x41));\n assert!(v.clone().peek(0x42));\n assert!(v.clone().peek(0x43));\n assert!(v.clone().peek(0x44));\n assert!(v.clone().peek(0x45));\n assert!(v.clone().peek(0x46));\n assert!(v.clone().peek(0x47));\n\n // row 3 column 1\n assert!(!v.clone().peek(0xC0));\n assert!(v.clone().peek(0xC1));\n assert!(!v.clone().peek(0xC2));\n assert!(v.clone().peek(0xC3));\n assert!(!v.clone().peek(0xC4));\n assert!(v.clone().peek(0xC5));\n assert!(!v.clone().peek(0xC6));\n assert!(v.clone().peek(0xC7));\n }\n}\n\n#[test]\nfn video_moved_poke_test() {\n let mut v = Chip8Video::default();\n let to_poke = [\n 0b00000000,\n 0b11111111,\n 0b10101010,\n 0b01010101\n ];\n\n let x_offset = 20;\n let y_offset = 5;\n\n\n for (byte_in_set, byte_to_poke) in to_poke.iter().enumerate() {\n let base_offset = (x_offset + byte_in_set) * 64 + y_offset;\n v.poke_byte(base_offset as u16, *byte_to_poke);\n }\n\n let test_offset = (x_offset * 64 + y_offset) as u16;\n assert!(!v.clone().peek(test_offset));\n assert!(!v.clone().peek(test_offset + 1));\n assert!(!v.clone().peek(test_offset + 2));\n assert!(!v.clone().peek(test_offset + 3));\n assert!(!v.clone().peek(test_offset + 4));\n assert!(!v.clone().peek(test_offset + 5));\n assert!(!v.clone().peek(test_offset + 6));\n assert!(!v.clone().peek(test_offset + 7));\n\n let test_offset = test_offset + 0x40;\n assert!(v.clone().peek(test_offset));\n assert!(v.clone().peek(test_offset + 1));\n assert!(v.clone().peek(test_offset + 2));\n assert!(v.clone().peek(test_offset + 3));\n assert!(v.clone().peek(test_offset + 4));\n assert!(v.clone().peek(test_offset + 5));\n assert!(v.clone().peek(test_offset + 6));\n assert!(v.clone().peek(test_offset + 7));\n}\n\n#[test]\nfn video_verify_change_registered() {\n let mut v = Chip8Video::default();\n v.poke(0x01, true);\n v.poke(0x01, true);\n assert!(v.has_frame_changed);\n\n v.start_frame();\n assert!(!v.has_frame_changed);\n}\n\n#[test]\nfn video_write_checkboard() {\n let mut v = build_checkerboard();\n assert_eq!(v.clone().format_as_string(), read_test_result(\"test_video_write_checkerboard.asc\"));\n}\n\n#[test]\nfn video_zero_test() {\n let mut x = Chip8Video::default();\n\n for (byte_index, data_offset) in (0..=0x100).step_by(0x40).enumerate() {\n x.poke_byte(data_offset as u16, CHIP8FONT_0[byte_index]);\n }\n\n assert_eq!(read_test_result(\"test_video_zero.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_multi_sprite_test() {\n let mut x = Chip8Video::default();\n // draw a row of digits 01234567\n let to_draw = [CHIP8FONT_0, CHIP8FONT_1, CHIP8FONT_2, CHIP8FONT_3, CHIP8FONT_4, CHIP8FONT_5, CHIP8FONT_6, CHIP8FONT_7];\n for (index, sprite) in to_draw.iter().enumerate() {\n let data_base_offset = index * 0x8;\n for (index, offset) in (0..=0x100).step_by(0x40).enumerate() {\n x.poke_byte((data_base_offset + offset) as u16, sprite[index]);\n }\n }\n\n assert_eq!(read_test_result(\"test_multi_sprite.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_reset_test() {\n let mut x = build_checkerboard();\n x.reset();\n assert_eq!(x.format_as_string(), read_test_result(\"test_reset_clears_video.asc\"));\n}\n\n#[test]\nfn video_collision_test() {\n // Setup: Set 0xFF to 0x00 with a new frame ready\n // Action: Run Poke to the same area\n // Test: Verify the 'changed' flag is tripped\n let mut x = Chip8Video::default();\n x.poke_byte(0x00, 0xff);\n x.tick();\n // set the cell thats already set...\n x.poke(0x00, true);\n // it becomes unset and theres a frame changed\n assert_eq!(false, x.peek(0x00));\n\n assert_eq!(true, x.clone().has_frame_changed);\n}\n\n#[test]\nfn video_collision_test2() {\n let mut x = Chip8Video::default();\n x.poke_byte(0x00, 0b11110000);\n assert_eq!(true, x.has_frame_changed);\n x.tick();\n assert_eq!(false, x.has_frame_changed);\n // clear the 'has changed' flag\n\n // now set a no-collision value\n x.poke_byte(0x00, 0b00001111);\n assert_eq!(true, x.has_frame_changed);\n}\n\n#[test]\nfn video_peek_out_of_bounds_doesnt_panic() {\n let x = Chip8Video::default();\n\n let y = x.clone().peek(2049);\n let y = x.clone().peek(0);\n\n // if we got here we didn't panic\n assert!(true);\n}\n\n#[test]\nfn video_scroll_down_1_row_test() {\n let mut x = build_checkerboard();\n x.scroll_down(1);\n assert_eq!(read_test_result(\"test_video_scroll_down_1.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_scroll_down_10_row_test() {\n let mut x = build_checkerboard();\n x.scroll_down(10);\n assert_eq!(read_test_result(\"test_video_scroll_down_10.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_high_res_has_right_resolution() {\n let mut x = build_checkboard_hd();\n println!(\"[{}]\", x.format_as_string());\n assert_eq!(read_test_result(\"test_video_highdef.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_scroll_down_1_row_test_schip() {\n let mut x = build_checkboard_hd();\n x.scroll_down(1);\n\n println!(\"[{}]\", x.format_as_string());\n println!(\"[{}]\", read_test_result(\"test_scroll_down_1_hd.asc\"));\n\n assert_eq!(read_test_result(\"test_scroll_down_1_hd.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_scroll_down_10_row_test_schip() {\n let mut x = build_checkboard_hd();\n x.scroll_down(10);\n assert_eq!(read_test_result(\"test_scroll_down_10_hd.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_scroll_left_4_row_test_std_def() {\n let mut x = build_checkerboard();\n x.scroll_left();\n assert_eq!(read_test_result(\"test_scroll_left_4.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_scroll_left_4_row_test_high_def() {\n let mut x = build_checkboard_hd();\n x.scroll_left();\n assert_eq!(read_test_result(\"test_scroll_left_4_hd.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_scroll_right_4_row_test_std_def() {\n let mut x = build_checkerboard();\n x.scroll_right();\n assert_eq!(read_test_result(\"test_scroll_right_4.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_scroll_right_4_row_test_high_def() {\n let mut x = build_checkboard_hd();\n x.scroll_right();\n assert_eq!(read_test_result(\"test_scroll_right_4_hd.asc\"), x.format_as_string());\n}\n\n\n#[test]\nfn instructions_operands_tests() {\n assert_eq!(Chip8CpuInstructions::SYS(0x000).operands(), \"0x0000\");\n assert_eq!(Chip8CpuInstructions::JPI(0x123).operands(), \"0x0123\");\n assert_eq!(Chip8CpuInstructions::JPA(0x234).operands(), \"0x0234\");\n assert_eq!(Chip8CpuInstructions::LDIA(0x345).operands(), \"0x0345\");\n assert_eq!(Chip8CpuInstructions::CALL(0x456).operands(), \"0x0456\");\n}\n\n#[test]\nfn instruction_ena_dis_tests() {\n let mut x = Chip8Computer::new();\n assert!(!x.video_memory.is_highres());\n Chip8CpuInstructions::ENA.execute(\u0026mut x);\n assert!(x.video_memory.is_highres());\n Chip8CpuInstructions::ENA.execute(\u0026mut x);\n assert!(x.video_memory.is_highres());\n Chip8CpuInstructions::DIS.execute(\u0026mut x);\n assert!(!x.video_memory.is_highres());\n}\n\n#[test]\nfn instruction_test_scrolling_lowres() {\n let mut x = Chip8Computer::new();\n x.video_memory = build_checkerboard();\n Chip8CpuInstructions::SRT.execute(\u0026mut x);\n\n assert_eq!(read_test_result(\"test_scroll_right_4.asc\"), x.dump_video_to_string());\n\n x = Chip8Computer::new();\n x.video_memory = build_checkerboard();\n Chip8CpuInstructions::SLF.execute(\u0026mut x);\n\n assert_eq!(read_test_result(\"test_scroll_left_4.asc\"), x.dump_video_to_string());\n\n x = Chip8Computer::new();\n x.video_memory = build_checkerboard();\n Chip8CpuInstructions::SDN(0x01).execute(\u0026mut x);\n assert_eq!(read_test_result(\"test_video_scroll_down_1.asc\"), x.dump_video_to_string());\n\n x = Chip8Computer::new();\n x.video_memory = build_checkerboard();\n Chip8CpuInstructions::SDN(0xA).execute(\u0026mut x);\n assert_eq!(read_test_result(\"test_video_scroll_down_10.asc\"), x.dump_video_to_string());\n}\n\n#[test]\nfn computer_dump_keypad_to_string() {\n let mut x = Chip8Computer::new();\n x.keypad.push_key(0x1);\n x.keypad.push_key(0x2);\n assert_eq!(read_test_result(\"test_keypad_to_string.asc\"), x.dump_keypad_to_string());\n}\n\n#[test]\nfn computer_dump_registers_to_string() {\n let mut x = Chip8Computer::new();\n let values_to_set = [0x0b, 0xad, 0xbe, 0xef,\n 0xca, 0xb0,\n 0x7a, 0xc0, 0xca, 0x70,\n 0xba, 0xdb, 0xed, 0x00,\n 0x00, 0x00\n ];\n let expected_value = \"Vx: 0x0b 0xad 0xbe 0xef 0xca 0xb0 0x7a 0xc0\\n 0xca 0x70 0xba 0xdb 0xed 0x00 0x00 0x00\\nI: 0x0000\\tPC: 0x0200\";\n\n for i in 0..16 {\n x.registers.poke(i, values_to_set[i as usize]);\n }\n\n // now verify.\n assert_eq!(expected_value, x.dump_registers_to_string());\n}\n","traces":[{"line":19,"address":[315984],"length":1,"stats":{"Line":1}},{"line":20,"address":[316021],"length":1,"stats":{"Line":1}},{"line":574,"address":[316288,317173],"length":1,"stats":{"Line":0}},{"line":575,"address":[316342],"length":1,"stats":{"Line":0}},{"line":577,"address":[316356],"length":1,"stats":{"Line":0}},{"line":578,"address":[316325],"length":1,"stats":{"Line":0}},{"line":579,"address":[316364],"length":1,"stats":{"Line":0}},{"line":580,"address":[316330],"length":1,"stats":{"Line":0}},{"line":581,"address":[316335],"length":1,"stats":{"Line":0}},{"line":582,"address":[316372],"length":1,"stats":{"Line":0}},{"line":583,"address":[316442],"length":1,"stats":{"Line":0}},{"line":584,"address":[316471],"length":1,"stats":{"Line":0}},{"line":585,"address":[316487],"length":1,"stats":{"Line":0}},{"line":586,"address":[316511],"length":1,"stats":{"Line":0}},{"line":588,"address":[316594,316730],"length":1,"stats":{"Line":0}},{"line":590,"address":[316879],"length":1,"stats":{"Line":0}},{"line":961,"address":[318234,317200],"length":1,"stats":{"Line":1}},{"line":962,"address":[317233],"length":1,"stats":{"Line":1}},{"line":963,"address":[317289,317268,317248,317465],"length":1,"stats":{"Line":4}},{"line":964,"address":[317270],"length":1,"stats":{"Line":1}},{"line":965,"address":[317449],"length":1,"stats":{"Line":1}},{"line":967,"address":[317252],"length":1,"stats":{"Line":1}},{"line":970,"address":[317571],"length":1,"stats":{"Line":1}},{"line":972,"address":[317818,317656],"length":1,"stats":{"Line":2}},{"line":973,"address":[317886,317836],"length":1,"stats":{"Line":1}},{"line":975,"address":[317861,317914],"length":1,"stats":{"Line":2}},{"line":977,"address":[318146,318016],"length":1,"stats":{"Line":1}},{"line":978,"address":[318133,318175,318208],"length":1,"stats":{"Line":2}},{"line":980,"address":[318186,318229],"length":1,"stats":{"Line":2}},{"line":983,"address":[317775],"length":1,"stats":{"Line":1}},{"line":986,"address":[318256],"length":1,"stats":{"Line":1}},{"line":987,"address":[318264],"length":1,"stats":{"Line":1}},{"line":990,"address":[318288],"length":1,"stats":{"Line":1}},{"line":991,"address":[318296],"length":1,"stats":{"Line":1}}],"covered":20,"coverable":34},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","tests","unit_tests_instructions.rs"],"content":"use gemma::chip8::instructions::Chip8CpuInstructions;\nuse gemma::chip8::instructions::Chip8CpuInstructions::*;\nuse gemma::chip8::quirk_modes::QuirkMode::{Chip8, SChipModern, XOChip};\nuse gemma::constants::*;\n\nstruct InstructionTestQuirks {\n chip8: Chip8CpuInstructions,\n schip: Chip8CpuInstructions,\n xochip: Chip8CpuInstructions\n}\n\nstruct InstructionTest {\n name: String,\n instruction: Chip8CpuInstructions,\n operands: String,\n asm: String,\n encoded: u16,\n quirks: InstructionTestQuirks\n}\n\n#[test]\nfn instructions_encode_decode_tests_with_quirks() {\n let it = vec![\n InstructionTest {\n name: INST_SYS.to_string(),\n instruction: Chip8CpuInstructions::SYS(0x123),\n operands: \"0x0123\".to_string(),\n asm: \"SYS 0x0123\".to_string(),\n encoded: 0x0123,\n quirks: InstructionTestQuirks {\n chip8: SYS(0x123),\n schip: XXXXERRORINSTRUCTION,\n xochip: XXXXERRORINSTRUCTION,\n }\n },\n InstructionTest {\n name: INST_CLS.to_string(),\n instruction: Chip8CpuInstructions::CLS,\n asm: \"CLS\".to_string(),\n operands: \"\".to_string(),\n encoded: 0x00E0,\n quirks: InstructionTestQuirks {\n chip8: CLS,\n schip: CLS,\n xochip: CLS\n }\n },\n InstructionTest {\n name: INST_RET.to_string(),\n instruction: Chip8CpuInstructions::RET,\n asm: \"RET\".to_string(),\n operands: \"\".to_string(),\n encoded: 0x00ee,\n quirks: InstructionTestQuirks {\n chip8: RET,\n schip: RET,\n xochip: RET\n }\n },\n InstructionTest {\n name: INST_JPA.to_string(),\n instruction: JPA(0x234),\n asm: \"JPA 0x0234\".to_string(),\n encoded: 0xb234,\n operands: \"0x0234\".to_string(),\n quirks: InstructionTestQuirks {\n chip8: JPA(0x0234),\n schip: JPA(0x0234),\n xochip: JPA(0x0234)\n }\n } /*\n\n\n ,\n InstructionTest {\n name: INST_CALL.to_string(),\n instruction: Chip8CpuInstructions::CALL(0x123),\n asm: \"CALL 0x0123\".to_string(),\n encoded: 0x2123,\n operands: \"0x0123\".to_string()\n },\n InstructionTest {\n name: INST_DRW.to_string(),\n instruction: Chip8CpuInstructions::DRW(0x01, 0x02, 0x03),\n operands: \"0x01, 0x02, 0x03\".to_string(),\n asm: \"DRW 0x01, 0x02, 0x03\".to_string(),\n encoded: 0xd123\n },\n InstructionTest {\n name: INST_JPI.to_string(),\n instruction: Chip8CpuInstructions::JPI(0x321),\n operands: \"0x0321\".to_string(),\n asm: \"JPI 0x0321\".to_string(),\n encoded: 0xb321\n },\n InstructionTest {\n name: INST_SDN.to_string(),\n instruction: Chip8CpuInstructions::SDN(0x01),\n operands: \"0x01\".to_string(),\n asm: \"SDN 0x01\".to_string(),\n encoded: 0x00c1\n },\n InstructionTest {\n name: INST_SRT.to_string(),\n instruction: Chip8CpuInstructions::SRT,\n operands: \"\".to_string(),\n asm: \"SRT\".to_string(),\n encoded: 0x00FB\n },\n InstructionTest {\n name: INST_SLF.to_string(),\n instruction: Chip8CpuInstructions::SLF,\n operands: \"\".to_string(),\n asm: \"SLF\".to_string(),\n encoded: 0x00FC,\n },\n InstructionTest {\n name: INST_EXIT.to_string(),\n instruction: Chip8CpuInstructions::EXIT,\n operands: \"\".to_string(),\n asm: \"EXIT\".to_string(),\n encoded: 0x00FD,\n },\n InstructionTest {\n name: INST_DIS.to_string(),\n instruction: Chip8CpuInstructions::DIS,\n operands: \"\".to_string(),\n asm: \"DIS\".to_string(),\n encoded: 0x00FE,\n },\n InstructionTest {\n name: INST_ENA.to_string(),\n instruction: Chip8CpuInstructions::ENA,\n operands: \"\".to_string(),\n asm: \"ENA\".to_string(),\n encoded: 0x00FF,\n },\n InstructionTest {\n name: INST_SEX.to_string(),\n instruction: Chip8CpuInstructions::SEX(0x01, 0xfa),\n operands: \"0x01, 0xfa\".to_string(),\n asm: \"SEX 0x01, 0xfa\".to_string(),\n encoded: 0x32fa,\n },\n InstructionTest {\n name: INST_SNEB.to_string(),\n instruction: Chip8CpuInstructions::SNEB(0x01, 0xab),\n operands: \"0x01, 0xab\".to_string(),\n asm: \"SNEB 0x01, 0xab\".to_string(),\n encoded: 0x41ab,\n },\n InstructionTest {\n name: INST_SEY.to_string(),\n instruction: Chip8CpuInstructions::SEY(0x1, 0x2),\n operands: \"0x1, 0x2\".to_string(),\n asm: \"SEY 0x1, 0x2\".to_string(),\n encoded: 0x5120\n },\n InstructionTest {\n name: INST_LDR.to_string(),\n instruction: Chip8CpuInstructions::LDR(0xa, 0xbe),\n operands: \"0x0a, 0xbe\".to_string(),\n asm: \"LDR 0x0a, 0xbe\".to_string(),\n encoded: 0x6abe,\n },\n InstructionTest {\n name: INST_ADD.to_string(),\n instruction: Chip8CpuInstructions::ADD(0x01, 0xab),\n operands: \"0x01, 0xab\".to_string(),\n asm: \"ADD 0x01, 0xab\".to_string(),\n encoded: 0x71ab\n },\n InstructionTest {\n name: INST_LDRY.to_string(),\n instruction: Chip8CpuInstructions::LDR_Y(0x1, 0x2),\n operands: \"0x1, 0x2\".to_string(),\n asm: \"LDRY 0x1, 0x2\".to_string(),\n encoded: 0x8120,\n },\n InstructionTest {\n name: INST_OR.to_string(),\n instruction: Chip8CpuInstructions::OR(0x1, 0x2),\n operands: \"0x1, 0x2\".to_string(),\n asm: \"OR 0x1, 0x2\".to_string(),\n encoded: 0x8121\n },\n InstructionTest {\n name: INST_AND.to_string(),\n instruction: Chip8CpuInstructions::AND(0xb, 0xc),\n operands: \"0xb, 0xc\".to_string(),\n asm: \"AND 0xb, 0xc\".to_string(),\n encoded: 0x8bc2,\n },\n InstructionTest {\n name: INST_ORY.to_string(),\n instruction: Chip8CpuInstructions::ORY(0xa, 0x3),\n operands: \"0xa, 0x3\".to_string(),\n asm: \"ORY 0xa, 0x3\".to_string(),\n encoded: 0x8a33\n },\n InstructionTest {\n name: INST_ADDR.to_string(),\n instruction: Chip8CpuInstructions::ADDR(0x1, 0x2),\n operands: \"0x1, 0x2\".to_string(),\n asm: \"ADDR 0x1, 0x2\".to_string(),\n encoded: 0x8124\n },\n InstructionTest {\n name: INST_SUB.to_string(),\n instruction: Chip8CpuInstructions::SUB(0x4, 0x5),\n operands: \"0x4, 0x5\".to_string(),\n asm: \"SUB 0x4, 0x5\".to_string(),\n encoded: 0x8455\n },\n InstructionTest {\n name: INST_SHR.to_string(),\n instruction: Chip8CpuInstructions::SHR(0x01, 0x1),\n operands: \"0x1, 0x1\".to_string(),\n asm: \"SHR 0x1, 0x1\".to_string(),\n encoded: 0x8116,\n },\n InstructionTest {\n name: INST_SUBC.to_string(),\n instruction: Chip8CpuInstructions::SUBC(0xf, 0xa),\n operands: \"0xf, 0xa\".to_string(),\n asm: \"SUBC 0xf, 0xa\".to_string(),\n encoded: 0x8fa7,\n },\n InstructionTest {\n name: INST_SHL.to_string(),\n instruction: Chip8CpuInstructions::SHL(0x1, 0x4),\n operands: \"0x1, 0x4\".to_string(),\n asm: \"SHL 0x1, 0x4\".to_string(),\n encoded: 0x814e,\n },\n InstructionTest {\n name: INST_SNEY.to_string(),\n instruction: Chip8CpuInstructions::SNEY(0x4, 0x5),\n operands: \"0x4, 0x5\".to_string(),\n asm: \"SNEY 0x4, 0x5\".to_string(),\n encoded: 0x9450,\n },\n InstructionTest {\n name: INST_LDIA.to_string(),\n instruction: Chip8CpuInstructions::LDIA(0xbee),\n operands: \"0x0bee\".to_string(),\n asm: \"LDIA 0x0bee\".to_string(),\n encoded: 0x9bee\n },\n InstructionTest {\n name: INST_JPI.to_string(),\n instruction: Chip8CpuInstructions::JPI(0xfee),\n operands: \"0x0fee\".to_string(),\n asm: \"JPI 0x0fee\".to_string(),\n encoded: 0xbfee\n },\n InstructionTest {\n name: INST_RND.to_string(),\n instruction: Chip8CpuInstructions::RND(0x1, 0xae),\n operands: \"0x01, 0xae\".to_string(),\n asm: \"RND 0x01, 0xae\".to_string(),\n encoded: 0xc1ae,\n },\n InstructionTest {\n name: INST_DRW.to_string(),\n instruction: Chip8CpuInstructions::DRW(0x1, 0x2, 0xf),\n operands: \"0x01, 0x02, 0x0f\".to_string(),\n asm: \"DRW 0x01, 0x02, 0x0f\".to_string(),\n encoded: 0xd12f\n },\n InstructionTest {\n name: INST_SKP.to_string(),\n instruction: Chip8CpuInstructions::SKP(0x4),\n operands: \"0x04\".to_string(),\n asm: \"SKP 0x04\".to_string(),\n encoded: 0xe49e,\n },\n InstructionTest {\n name: INST_SKNP.to_string(),\n instruction: Chip8CpuInstructions::SKNP(0x3),\n operands: \"0x03\".to_string(),\n asm: \"SKNP 0x03\".to_string(),\n encoded: 0x83a1\n },\n InstructionTest {\n name: INST_LDRD.to_string(),\n instruction: Chip8CpuInstructions::LDRD(0x4),\n operands: \"0x04\".to_string(),\n asm: \"LDRD 0x04\".to_string(),\n encoded: 0xF407\n },\n InstructionTest {\n name: INST_LDRK.to_string(),\n instruction: Chip8CpuInstructions::LDRK(0x6),\n operands: \"0x06\".to_string(),\n asm: \"LDRK 0x06\".to_string(),\n encoded: 0xF60A\n },\n InstructionTest {\n name: INST_LDD.to_string(),\n instruction: Chip8CpuInstructions::LDD(0x02),\n operands: \"0x02\".to_string(),\n asm: \"LDD 0x02\".to_string(),\n encoded: 0xF215,\n },\n InstructionTest {\n name: INST_LDRI.to_string(),\n instruction: Chip8CpuInstructions::LDRI(0x01),\n operands: \"0x01\".to_string(),\n asm: \"LDRI 0x01\".to_string(),\n encoded: 0xF118,\n },\n InstructionTest {\n name: INST_BCD.to_string(),\n instruction: Chip8CpuInstructions::BCD(0x4),\n operands: \"0x04\".to_string(),\n asm: \"BCD 0x04\".to_string(),\n encoded: 0xF433,\n },\n InstructionTest {\n name: INST_LDF.to_string(),\n instruction: Chip8CpuInstructions::LDFX(0x5),\n operands: \"0x05\".to_string(),\n asm: \"LDF 0x05\".to_string(),\n encoded: 0xF529\n },\n InstructionTest {\n name: INST_LDF2.to_string(),\n instruction: Chip8CpuInstructions::LDF2(0x6),\n operands: \"0x06\".to_string(),\n asm: \"LDF2 0x06\".to_string(),\n encoded: 0xF630\n },\n InstructionTest {\n name: INST_LDIX.to_string(),\n instruction: Chip8CpuInstructions::LDIX(0x5),\n operands: \"0x05\".to_string(),\n asm: \"LDIX 0x05\".to_string(),\n encoded: 0xF555\n },\n InstructionTest {\n name: INST_LDIS.to_string(),\n instruction: Chip8CpuInstructions::LDIS(0xf),\n operands: \"0x0f\".to_string(),\n asm: \"LDIS 0x0f\".to_string(),\n encoded: 0xFF18\n },\n InstructionTest {\n name: INST_LIDR.to_string(),\n instruction: Chip8CpuInstructions::LIDR(0x4),\n operands: \"0x04\".to_string(),\n asm: \"LIDR 0x04\".to_string(),\n encoded: 0xF485,\n },\n InstructionTest {\n name: INST_STR.to_string(),\n instruction: Chip8CpuInstructions::STR(0xa),\n operands: \"0x0a\".to_string(),\n asm: \"STR 0x0a\".to_string(),\n encoded: 0xF000\n }\n */\n ];\n\n for current in it {\n assert_eq!(current.instruction.name(), current.name);\n let i = current.instruction;\n assert!(matches!(Chip8CpuInstructions::decode(current.encoded, \u0026Chip8), i));\n assert_eq!(i.to_string(), current.asm);\n let asm = Chip8CpuInstructions::from_str(\u0026current.asm);\n assert_eq!(i.to_string(), asm.to_string());\n assert_eq!(i.operands(), current.operands);\n // test quirks\n let as_chip8 = Chip8CpuInstructions::decode(current.encoded, \u0026Chip8);\n let quirks_chip8 = current.quirks.chip8;\n let as_schip = Chip8CpuInstructions::decode(current.encoded, \u0026SChipModern);\n let quirks_schip = current.quirks.schip;\n let as_xochip = Chip8CpuInstructions::decode(current.encoded, \u0026XOChip);\n let quirks_xochip = current.quirks.xochip;\n\n assert!(matches!(as_chip8, quirks_chip8));\n assert!(matches!(as_schip, quirks_schip));\n assert!(matches!(as_xochip, quirks_xochip));\n\n }\n}","traces":[],"covered":0,"coverable":0},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmaegui","src","bin","gemmaegui.rs"],"content":"use std::path::PathBuf;\nuse std::time::Instant;\nuse crate::support::gemma_egui_support::{EGuiFileList, GemmaEguiSupport};\nuse crate::support::gemma_egui_state::GemmaEGuiState;\nuse eframe::egui;\nuse egui::{Key, Ui};\nuse gemma::chip8::computer::Chip8Computer;\nuse gemma::chip8::computer_manager::Chip8ComputerManager;\n\nmod support;\n\nconst LIN_KEYS: [[(Key, u8); 4]; 4] = [\n [(Key::Num1, 0x01), (Key::Num2, 0x02), (Key::Num3, 0x03), (Key::Num4, 0x0c)],\n [(Key::Q, 0x04), (Key::W, 0x05), (Key::E, 0x06), (Key::R, 0x0d)],\n [(Key::A, 0x07), (Key::S, 0x08), (Key::D, 0x09), (Key::F, 0x0e)],\n [(Key::Z, 0x0a), (Key::X, 0x00), (Key::C, 0x0b), (Key::V, 0x0F)]\n];\n\n#[derive(Default)]\nstruct DisplayOptions {\n pub video: bool,\n pub registers: bool,\n pub memory: bool,\n}\npub struct GemmaViewerState {\n pub selected_file_index: i32,\n pub selected_filename: String,\n pub display_options: DisplayOptions,\n}\n\nimpl Default for GemmaViewerState {\n fn default() -\u003e Self {\n GemmaViewerState {\n selected_file_index: -1,\n selected_filename: String::new(),\n display_options: Default::default(),\n }\n }\n}\n\nimpl GemmaViewerState {\n pub fn new() -\u003e GemmaViewerState {\n GemmaViewerState {\n ..Default::default()\n }\n }\n}\n\nfn main() -\u003e eframe::Result {\n println!(\"Taxation is Theft\");\n\n let mut computer = Chip8ComputerManager::new();\n let mut state = GemmaViewerState::new();\n\n let options = eframe::NativeOptions {\n viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]),\n ..Default::default()\n };\n\n eframe::run_simple_native(\"EGUI Gemma\", options, move |ctx, _frame| {\n catppuccin_egui::set_theme(\u0026ctx, catppuccin_egui::MOCHA);\n egui::CentralPanel::default().show(ctx, |ui| {\n let frame_start_time = Instant::now();\n\n let local_computer = computer.state();\n //if state.display_video {\n GemmaEguiSupport::video_view(local_computer, ui);\n // }\n\n ui.heading(\"EGUI Gemma\");\n\n // if state.display_memory {\n GemmaEguiSupport::memory_view(\u0026local_computer, ui);\n // }\n\n // if state.display_registers {\n GemmaEguiSupport::registers_view(\u0026local_computer, ui);\n // }\n ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {\n if ui.button(\"Start\").clicked() {\n computer.start();\n }\n if ui.button(\"Step\").clicked() {\n computer.step();\n }\n\n if ui.button(\"Stop\").clicked() {\n computer.stop();\n // state.is_running = false;\n }\n if ui.button(\"Reset\").clicked() {\n computer.reset();\n // state.is_running = false;\n }\n });\n\n if ui.button(format!(\"Load {}\", state.selected_filename)).clicked() {\n // println!(\"Should load the bin now\");\n let read_bin = std::fs::read(PathBuf::from(format!(\"resources/roms/{}\", state.selected_filename))).unwrap();\n computer.load_bytes_to_system_memory(read_bin);\n };\n EGuiFileList::display_path(PathBuf::from(\"resources/roms\"), \u0026mut state.selected_filename, ui);\n let input = ctx.input(|input| {\n // loop through the keys we are checking...\n for row in LIN_KEYS {\n for (keyboard_key, keypad_key) in row {\n if input.key_pressed(keyboard_key) {\n computer.press_key(keypad_key);\n // println!(\"KEY {keypad_key:02x} DOWN\");\n } else {\n // release it if the user just did\n if computer.is_key_pressed(keypad_key) {\n computer.release_key(keypad_key);\n // println!(\"KEY {keypad_key:02x} up\");\n }\n }\n }\n }\n });\n\n // run our target number of ticks in the amount of available time.\n let time_consumed = Instant::now().duration_since(frame_start_time).as_millis();\n let mut num_ticks = 0;\n while num_ticks \u003c 1000 {\n computer.tick();\n num_ticks += 1;\n }\n ctx.request_repaint();\n });\n })\n}\n","traces":[{"line":32,"address":[3199832,3199664],"length":1,"stats":{"Line":0}},{"line":35,"address":[3199683],"length":1,"stats":{"Line":0}},{"line":36,"address":[3199688,3199745],"length":1,"stats":{"Line":0}},{"line":42,"address":[3199856],"length":1,"stats":{"Line":0}},{"line":49,"address":[3201026,3199952,3200995],"length":1,"stats":{"Line":0}},{"line":50,"address":[3199999],"length":1,"stats":{"Line":0}},{"line":52,"address":[3200063],"length":1,"stats":{"Line":0}},{"line":53,"address":[3200093],"length":1,"stats":{"Line":0}},{"line":56,"address":[3200157,3200202],"length":1,"stats":{"Line":0}},{"line":60,"address":[3157424],"length":1,"stats":{"Line":0}},{"line":61,"address":[3157457],"length":1,"stats":{"Line":0}},{"line":62,"address":[3159257,3157616,3157509],"length":1,"stats":{"Line":0}},{"line":63,"address":[3157641],"length":1,"stats":{"Line":0}},{"line":65,"address":[3157684],"length":1,"stats":{"Line":0}},{"line":67,"address":[3157706],"length":1,"stats":{"Line":0}},{"line":70,"address":[3157721],"length":1,"stats":{"Line":0}},{"line":73,"address":[3157767],"length":1,"stats":{"Line":0}},{"line":77,"address":[3157782],"length":1,"stats":{"Line":0}},{"line":79,"address":[3160195,3157901,3159296],"length":1,"stats":{"Line":0}},{"line":80,"address":[3159435,3159321],"length":1,"stats":{"Line":0}},{"line":81,"address":[3159510],"length":1,"stats":{"Line":0}},{"line":83,"address":[3159526,3159649],"length":1,"stats":{"Line":0}},{"line":84,"address":[3159733],"length":1,"stats":{"Line":0}},{"line":87,"address":[3159749,3159872],"length":1,"stats":{"Line":0}},{"line":88,"address":[3159956],"length":1,"stats":{"Line":0}},{"line":91,"address":[3159972,3160095],"length":1,"stats":{"Line":0}},{"line":92,"address":[3160176],"length":1,"stats":{"Line":0}},{"line":97,"address":[3158376,3158122,3158257,3158032],"length":1,"stats":{"Line":0}},{"line":99,"address":[3158688,3158468,3158558],"length":1,"stats":{"Line":0}},{"line":100,"address":[3158951],"length":1,"stats":{"Line":0}},{"line":102,"address":[3158968],"length":1,"stats":{"Line":0}},{"line":103,"address":[3160224,3159031,3157633,3160882],"length":1,"stats":{"Line":0}},{"line":105,"address":[3160406,3160473,3160249],"length":1,"stats":{"Line":0}},{"line":106,"address":[3160733,3160489,3160663],"length":1,"stats":{"Line":0}},{"line":107,"address":[3160761,3160725],"length":1,"stats":{"Line":0}},{"line":108,"address":[3160877,3160817],"length":1,"stats":{"Line":0}},{"line":112,"address":[3160840,3160790],"length":1,"stats":{"Line":0}},{"line":113,"address":[3160853],"length":1,"stats":{"Line":0}},{"line":122,"address":[3159043],"length":1,"stats":{"Line":0}},{"line":123,"address":[3159142],"length":1,"stats":{"Line":0}},{"line":124,"address":[3159153,3159239],"length":1,"stats":{"Line":0}},{"line":125,"address":[3159201],"length":1,"stats":{"Line":0}},{"line":126,"address":[3159210,3159241],"length":1,"stats":{"Line":0}},{"line":128,"address":[3159171],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":44},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmaegui","src","bin","support","gemma_egui_state.rs"],"content":"use std::ops::Range;\nuse gemma::chip8::computer_manager::Chip8ComputerManager;\n\npub struct GemmaEGuiState {\n pub display_video: bool,\n pub display_memory: bool,\n pub display_registers: bool,\n pub memory_view: Range\u003ci32\u003e,\n pub computer: Chip8ComputerManager,\n pub selected_rom_filename: String\n}\n\nimpl Default for GemmaEGuiState {\n fn default() -\u003e Self {\n Self {\n display_video: true,\n display_memory: true,\n display_registers: true,\n memory_view: 0x00..0x200,\n computer: Chip8ComputerManager::new(),\n selected_rom_filename: String::new()\n }\n }\n}\n","traces":[{"line":14,"address":[3182160,3182383],"length":1,"stats":{"Line":0}},{"line":20,"address":[3182191],"length":1,"stats":{"Line":0}},{"line":21,"address":[3182213],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":3},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmaegui","src","bin","support","gemma_egui_support.rs"],"content":"use std::fs::read_dir;\nuse std::ops::Index;\nuse std::path::{Display, PathBuf};\nuse std::thread;\nuse std::time::Duration;\nuse egui::{Align, Color32, ComboBox, Direction, Pos2, Response, TextBuffer};\nuse egui::Rect;\nuse egui::Vec2;\nuse egui::Ui;\nuse egui::WidgetType::SelectableLabel;\nuse crate::Chip8Computer;\n\nconst CELL_WIDTH: f32 = 5.0;\nconst CELL_HEIGHT: f32 = 5.0;\n\npub struct EGuiFileList {}\nimpl EGuiFileList {\n pub fn display_path(root: PathBuf, selected_filename: \u0026mut String, ui: \u0026mut Ui) {\n let mut working_filename = selected_filename.clone();\n ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {\n // ui.label(format!(\"Displaying {}\", root.to_str().unwrap_or(\"Unable to Load Path\")));\n ComboBox::from_label(\"Select ROM\")\n .selected_text(selected_filename.clone())\n .show_ui(ui, |ui| {\n\n let mut sorted_options = vec![];\n for option in read_dir(root.as_path()).unwrap() {\n let to_push = option.unwrap().file_name().into_string().unwrap_or( String::new());\n sorted_options.push(to_push);\n }\n\n sorted_options.sort();\n for item in sorted_options {\n // Add each option to the ComboBox\n if ui.selectable_label(selected_filename.eq(\u0026item.as_str()), item.clone()).clicked()\n {\n *selected_filename = item;\n }\n }\n });\n // Display the selected option\n });\n }\n}\n\npub struct GemmaEguiSupport {}\n\nimpl GemmaEguiSupport {\n pub fn controls_view(system: \u0026mut Chip8Computer, ui: \u0026mut Ui) {\n\n ui.with_layout(egui::Layout::left_to_right(Align::TOP), |ui| {\n // ui.checkbox(\u0026mut state.display_memory, \"Display Memory\");\n // ui.checkbox(\u0026mut state.display_video, \"Display Video\");\n // ui.checkbox(\u0026mut state.display_registers, \"Display Registers\");\n });\n }\n\n pub fn registers_view(system: \u0026Chip8Computer, ui: \u0026mut Ui) {\n ui.label(format!(\"V0-7: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} \",\n system.registers.peek(0x00),\n system.registers.peek(0x01),\n system.registers.peek(0x02),\n system.registers.peek(0x03),\n system.registers.peek(0x04),\n system.registers.peek(0x05),\n system.registers.peek(0x06),\n system.registers.peek(0x07)\n ));\n ui.label(format!(\"V8-F: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} \",\n system.registers.peek(0x08),\n system.registers.peek(0x09),\n system.registers.peek(0x0A),\n system.registers.peek(0x0B),\n system.registers.peek(0x0C),\n system.registers.peek(0x0D),\n system.registers.peek(0x0E),\n system.registers.peek(0x0F)\n ));\n ui.label(format!(\"PC: {:04x}\\tI: {:04x}\", system.registers.peek_pc(), system.registers.peek_i()));\n }\n\n pub fn video_view(system: \u0026Chip8Computer, ui: \u0026mut Ui) {\n let (_resp, painter) = ui.allocate_painter(Vec2::new(350.0, 165.0), egui::Sense::hover());\n for current_row in 0..32 {\n for current_col in 0..64 {\n let data_offset = current_row * 64 + current_col;\n let x_offset = current_col as f32 * CELL_WIDTH;\n let y_offset = current_row as f32 * CELL_HEIGHT;\n let origin = Pos2::new(x_offset, y_offset);\n let colour = if system.video_memory.peek(data_offset) {\n Color32::RED\n } else {\n Color32::WHITE\n };\n let rect = Rect::from_min_size(origin, Vec2::new(CELL_WIDTH, CELL_HEIGHT));\n painter.rect_filled(rect, 0.0, colour);\n // println!(\"Cell {current_col}x{current_row} at {}x{} -\u003e {}\",\n // origin.x, origin.y,\n // system.video_memory.peek(data_offset));\n }\n }\n // thread::sleep(Duration::from_secs(1));\n }\n\n pub fn memory_view(system: \u0026Chip8Computer, ui: \u0026mut Ui) {\n ui.label(\"Memory View\");\n\n for i in (0..=0x200).step_by(16) {\n ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {\n for y in 0..16 {\n ui.label(format!(\"{:02x}\", system.memory.peek((i + y) as u16)).as_str());\n }\n });\n }\n ui.label(\"Should have **something** to adjust the 'memory window'\");\n }\n}\n","traces":[{"line":18,"address":[3164097,3163664],"length":1,"stats":{"Line":0}},{"line":19,"address":[3163694],"length":1,"stats":{"Line":0}},{"line":20,"address":[3163925],"length":1,"stats":{"Line":0}},{"line":22,"address":[3186670,3186780,3186846],"length":1,"stats":{"Line":0}},{"line":23,"address":[3186896,3186828,3186715],"length":1,"stats":{"Line":0}},{"line":24,"address":[3186836,3186928,3188719,3189140],"length":1,"stats":{"Line":0}},{"line":26,"address":[3186964],"length":1,"stats":{"Line":0}},{"line":27,"address":[3187490,3189091,3187021,3187523,3187351,3187125],"length":1,"stats":{"Line":0}},{"line":28,"address":[3189118,3188750],"length":1,"stats":{"Line":0}},{"line":29,"address":[3189016],"length":1,"stats":{"Line":0}},{"line":32,"address":[3187765],"length":1,"stats":{"Line":0}},{"line":33,"address":[3187989,3187799,3188695,3188039],"length":1,"stats":{"Line":0}},{"line":35,"address":[3188189,3188682,3188390,3188079],"length":1,"stats":{"Line":0}},{"line":37,"address":[3188501],"length":1,"stats":{"Line":0}},{"line":49,"address":[3164128],"length":1,"stats":{"Line":0}},{"line":51,"address":[3164247],"length":1,"stats":{"Line":0}},{"line":58,"address":[3164368],"length":1,"stats":{"Line":0}},{"line":59,"address":[3167176,3166944,3168020,3166480,3167640,3165528,3166712,3166016,3167408,3166248],"length":1,"stats":{"Line":0}},{"line":60,"address":[3164416],"length":1,"stats":{"Line":0}},{"line":61,"address":[3164553],"length":1,"stats":{"Line":0}},{"line":62,"address":[3164693],"length":1,"stats":{"Line":0}},{"line":63,"address":[3164833],"length":1,"stats":{"Line":0}},{"line":64,"address":[3164973],"length":1,"stats":{"Line":0}},{"line":65,"address":[3165113],"length":1,"stats":{"Line":0}},{"line":66,"address":[3165253],"length":1,"stats":{"Line":0}},{"line":67,"address":[3165393],"length":1,"stats":{"Line":0}},{"line":69,"address":[3169890,3169658,3169170,3170354,3170122,3171662,3170586,3171282,3171050,3170818],"length":1,"stats":{"Line":0}},{"line":70,"address":[3168055],"length":1,"stats":{"Line":0}},{"line":71,"address":[3168195],"length":1,"stats":{"Line":0}},{"line":72,"address":[3168335],"length":1,"stats":{"Line":0}},{"line":73,"address":[3168475],"length":1,"stats":{"Line":0}},{"line":74,"address":[3168615],"length":1,"stats":{"Line":0}},{"line":75,"address":[3168755],"length":1,"stats":{"Line":0}},{"line":76,"address":[3168895],"length":1,"stats":{"Line":0}},{"line":77,"address":[3169035],"length":1,"stats":{"Line":0}},{"line":79,"address":[3171839,3172681,3172266,3171970,3172498,3171703],"length":1,"stats":{"Line":0}},{"line":82,"address":[3174124,3172736],"length":1,"stats":{"Line":0}},{"line":83,"address":[3172791],"length":1,"stats":{"Line":0}},{"line":84,"address":[3173103,3173185,3173289],"length":1,"stats":{"Line":0}},{"line":85,"address":[3173408,3173310],"length":1,"stats":{"Line":0}},{"line":86,"address":[3173523,3173692],"length":1,"stats":{"Line":0}},{"line":87,"address":[3173612],"length":1,"stats":{"Line":0}},{"line":88,"address":[3173646],"length":1,"stats":{"Line":0}},{"line":89,"address":[3173732],"length":1,"stats":{"Line":0}},{"line":90,"address":[3173809,3173768],"length":1,"stats":{"Line":0}},{"line":91,"address":[3173811],"length":1,"stats":{"Line":0}},{"line":93,"address":[3173796],"length":1,"stats":{"Line":0}},{"line":96,"address":[3174038],"length":1,"stats":{"Line":0}},{"line":105,"address":[3174160],"length":1,"stats":{"Line":0}},{"line":106,"address":[3174192],"length":1,"stats":{"Line":0}},{"line":108,"address":[3174438,3174226],"length":1,"stats":{"Line":0}},{"line":109,"address":[3174551],"length":1,"stats":{"Line":0}},{"line":110,"address":[3189230,3189288],"length":1,"stats":{"Line":0}},{"line":111,"address":[3189677,3189299,3189429,3189859],"length":1,"stats":{"Line":0}},{"line":115,"address":[3174381],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":55},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmaegui","src","bin","support","mod.rs"],"content":"pub mod gemma_egui_state;\npub mod gemma_egui_support;\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmaimgui","src","bin","gemmaimgui.rs"],"content":"use std::default::Default;\nuse std::fs::DirEntry;\nuse std::time::Instant;\nuse gemma::{\n chip8::computer::Chip8Computer,\n constants::{CHIP8_MEMORY_SIZE, CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH},\n};\nuse imgui::*;\nuse sys::{ImColor, ImVec2, ImVector_ImU32};\nuse rand::random;\nuse gemma::chip8::computer_manager::Chip8ComputerManager;\nuse gemma::chip8::cpu_states::Chip8CpuStates::WaitingForInstruction;\nuse gemma::chip8::system_memory::Chip8SystemMemory;\nuse support::{emmagui_support::GemmaImguiSupport, ui_state::ImGuiUiState};\nuse clap::{Parser, Subcommand};\nuse gemma::chip8::quirk_modes::QuirkMode;\nuse gemma::chip8::quirk_modes::QuirkMode::Chip8;\n\n\nmod support;\n\n/// Keypad Mappings for my Linux box\n/// 1 2 3 C\n/// 4 5 6 D\n/// 7 8 9 E\n/// A 0 B F\n\nconst LIN_KEYS: [(u16, u8); 0x10] = [(537, 0x01),(538, 0x02),(539, 0x03),(540, 0x0c),\n (562, 0x04),(568, 0x05),(550, 0x06),(563, 0x0d),\n (546, 7),(564, 8),(549, 9),(551, 0xe),\n (571, 0xa),(569, 0),(548, 0xb),(567, 0xf)];\n\nfn main() {\n pretty_env_logger::init();\n\n let mut system = Chip8ComputerManager::default();\n let mut ui_state = ImGuiUiState::default();\n let target_ips = ui_state.target_ips;\n\n support::simple_init(file!(), move |_, ui| {\n let current_time = Instant::now();\n let mut num_cycles = 0;\n\n // Key Checks\n let down_keys = ui.io().keys_down;\n\n // START DEBUG CODE TO DISPLAY WHAT KEYS WE TRAPPED\n for (idx, val) in down_keys.iter().enumerate() {\n if *val {\n println!(\"{idx} = {val}\");\n }\n }\n // END DEBUG CODE\n\n for (key_code, key_reg) in LIN_KEYS {\n if down_keys[key_code as usize] {\n system.press_key(key_reg);\n system.wait_for_instruction();\n } else {\n // do we need to release it?\n\n if system.is_key_pressed(key_reg) {\n system.release_key(key_reg);\n }\n }\n }\n\n let target_ms = ui_state.frame_time;\n let loop_start_time = Instant::now();\n while Instant::now().duration_since(current_time).as_millis() \u003c target_ms as u128 \u0026\u0026 num_cycles \u003c target_ips {\n if system.tick() {\n num_cycles += 1;\n }\n }\n let cycles_time = Instant::now().duration_since(loop_start_time);\n if num_cycles \u003e 0 {\n println!(\"Ran for {}ms and executed {}/{} cycles.\", cycles_time.as_millis(), num_cycles, target_ips);\n }\n // GUI Parts\n if ui_state.show_video {\n GemmaImguiSupport::video_display(\u0026system.state(), \u0026ui_state, ui);\n }\n\n GemmaImguiSupport::system_controls(\u0026mut system, \u0026mut ui_state, ui);\n\n if ui_state.show_registers {\n GemmaImguiSupport::registers_view(\u0026system.state(), ui);\n }\n\n if ui_state.show_memory {\n let active_instruction = system.state().registers.peek_pc();\n GemmaImguiSupport::hex_memory_display(system.state().memory.clone(), (0x100, 0x10), active_instruction as i16, ui);\n }\n\n if ui_state.show_keypad {\n GemmaImguiSupport::keypad_display(\u0026system.state(), ui);\n }\n });\n}\n","traces":[{"line":33,"address":[4072608,4072911,4072940],"length":1,"stats":{"Line":0}},{"line":34,"address":[4072645],"length":1,"stats":{"Line":0}},{"line":36,"address":[4072662],"length":1,"stats":{"Line":0}},{"line":37,"address":[4072692],"length":1,"stats":{"Line":0}},{"line":38,"address":[4072740],"length":1,"stats":{"Line":0}},{"line":40,"address":[4072758],"length":1,"stats":{"Line":0}},{"line":41,"address":[4175144],"length":1,"stats":{"Line":0}},{"line":42,"address":[4175179],"length":1,"stats":{"Line":0}},{"line":45,"address":[4175187],"length":1,"stats":{"Line":0}},{"line":48,"address":[4175218,4175453],"length":1,"stats":{"Line":0}},{"line":49,"address":[4175485],"length":1,"stats":{"Line":0}},{"line":50,"address":[4177245],"length":1,"stats":{"Line":0}},{"line":55,"address":[4175515,4175379,4175572,4175704],"length":1,"stats":{"Line":0}},{"line":56,"address":[4176852,4175738],"length":1,"stats":{"Line":0}},{"line":57,"address":[4176927],"length":1,"stats":{"Line":0}},{"line":58,"address":[4176987],"length":1,"stats":{"Line":0}},{"line":62,"address":[4176945,4176900],"length":1,"stats":{"Line":0}},{"line":63,"address":[4176963],"length":1,"stats":{"Line":0}},{"line":68,"address":[4175655],"length":1,"stats":{"Line":0}},{"line":69,"address":[4175672],"length":1,"stats":{"Line":0}},{"line":70,"address":[4175941,4175763],"length":1,"stats":{"Line":0}},{"line":71,"address":[4175958,4176826],"length":1,"stats":{"Line":0}},{"line":72,"address":[4176803,4176831],"length":1,"stats":{"Line":0}},{"line":75,"address":[4175863],"length":1,"stats":{"Line":0}},{"line":76,"address":[4175927],"length":1,"stats":{"Line":0}},{"line":77,"address":[4176248,4176340,4176008],"length":1,"stats":{"Line":0}},{"line":80,"address":[4175982],"length":1,"stats":{"Line":0}},{"line":81,"address":[4176530],"length":1,"stats":{"Line":0}},{"line":84,"address":[4176494],"length":1,"stats":{"Line":0}},{"line":86,"address":[4176514],"length":1,"stats":{"Line":0}},{"line":87,"address":[4176597],"length":1,"stats":{"Line":0}},{"line":90,"address":[4176581],"length":1,"stats":{"Line":0}},{"line":91,"address":[4176652],"length":1,"stats":{"Line":0}},{"line":92,"address":[4176692],"length":1,"stats":{"Line":0}},{"line":95,"address":[4176636],"length":1,"stats":{"Line":0}},{"line":96,"address":[4176769],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":36},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmaimgui","src","bin","support","emmagui_support.rs"],"content":"use std::ffi::OsString;\nuse gemma::constants::CHIP8_KEYBOARD;\nuse std::fs::{File, read_dir};\nuse std::io::Read;\nuse std::path::{Path, PathBuf};\nuse std::time::Duration;\nuse imgui::{Condition, ImColor32, Ui};\nuse log::debug;\nuse gemma::chip8::computer::Chip8Computer;\nuse gemma::chip8::computer_manager::Chip8ComputerManager;\nuse gemma::chip8::computer_manager::ManagerDumpables::{Keyboard, Registers, Video};\nuse gemma::chip8::keypad::Keypad;\nuse gemma::chip8::system_memory::Chip8SystemMemory;\nuse gemma::constants::{CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH};\nuse crate::ImGuiUiState;\nuse crate::support::gui_file_list::GuiFileList;\nuse super::ui_state;\n\nconst ROM_ROOT: \u0026str = \"/home/tmerritt/Projects/chip8_toy/resources/roms\";\n\npub struct GemmaImguiSupport {}\n\nconst CELL_WIDTH: i32 = 5i32;\nconst CELL_HEIGHT: i32 = 5i32;\n\nimpl GemmaImguiSupport {\n pub fn keypad_display(system_to_display: \u0026Chip8Computer, ui: \u0026Ui) {\n ui.window(format!(\"Keypad\"))\n .size([100.0, 100.0], Condition::FirstUseEver)\n .build(|| {\n for row in CHIP8_KEYBOARD {\n for key in row {\n let label = if system_to_display.keypad.pressed(key) {\n format!(\"*{:1x}*\", key)\n } else {\n format!(\"{:1x}\", key)\n };\n ui.text(format!(\"{}\", label));\n ui.same_line();\n }\n ui.text(\"\");\n }\n });\n }\n\n pub fn video_display(system_to_control: \u0026Chip8Computer, gui_state: \u0026ImGuiUiState, ui: \u0026Ui) {\n // draw area size\n let (width, height) = system_to_control.video_memory.get_resolution();\n let draw_area_size = ui.io().display_size;\n // println!(\"DRAW_AREA_SIZE = {}x{}\", draw_area_size[0], draw_area_size[1]);\n let cell_width = ((draw_area_size[0] as i32 / width) * 6) / 10;\n let cell_height = ((draw_area_size[1] as i32 / height) * 6) / 10;\n\n ui.window(format!(\"Display {cell_width}x{cell_height}\"))\n .size([300.0, 300.0], Condition::Once)\n .build(|| {\n let origin = ui.cursor_pos();\n let fg = ui.get_window_draw_list();\n if system_to_control.video_memory.is_highres() {\n // ui.text(\"High Def Video here\");\n for current_row in 0..=height {\n let y_offset = origin[1] as i32 + (current_row * cell_height);\n for current_column in 0..=width {\n let x_offset = origin[0] as i32 + (current_column * cell_width);\n let current_origin = [x_offset as f32, y_offset as f32];\n let current_limit = [(x_offset + cell_width) as f32, (y_offset + cell_height) as f32];\n let memory_offset = (current_row * width + current_column) as u16;\n let to_render = system_to_control.video_memory.peek(memory_offset);\n let color: ImColor32 = if to_render {\n gui_state.on_colour\n } else {\n gui_state.off_colour\n };\n fg.add_rect_filled_multicolor(current_origin, current_limit, color, color, color, color);\n }\n }\n } else {\n for current_row in 0..height {\n let y_offset = origin[1] as i32 + (current_row * cell_height);\n for current_column in 0..width {\n let x_offset = origin[0] as i32 + (current_column * cell_width);\n let current_origin = [x_offset as f32, y_offset as f32];\n let current_limit = [(x_offset + cell_width) as f32, (y_offset + cell_height) as f32];\n let memory_offset = (current_row * width + current_column) as u16;\n let to_render = system_to_control.video_memory.peek(memory_offset);\n let color: ImColor32 = if to_render {\n gui_state.on_colour\n } else {\n gui_state.off_colour\n };\n fg.add_rect_filled_multicolor(current_origin, current_limit, color, color, color, color);\n }\n }\n }\n });\n }\n pub fn system_controls(system_to_control: \u0026mut Chip8ComputerManager, gui_state: \u0026mut ImGuiUiState, ui: \u0026Ui) {\n // let mut state: Chip8Computer = system_to_control;\n ui.window(\"!!!! CONTROLS !!!!\")\n .size([345.0, 200.0], Condition::FirstUseEver)\n .build(|| {\n /* System Step Counter */\n ui.text(format!(\"Step {:04x}\", system_to_control.num_cycles()).as_str());\n\n /* ROM Lister */\n let new_filename = GuiFileList::display_path(PathBuf::from(ROM_ROOT), \u0026gui_state.filename_to_load, ui);\n if !new_filename.is_empty() {\n if new_filename != gui_state.filename_to_load {\n debug!(\"NEW FILENAME SELECTED -\u003e {new_filename}\");\n gui_state.filename_to_load = new_filename;\n }\n if ui.button(\"Load Program\") {\n let mut buffer = Vec::new();\n debug!(\"PREPARING TO LOAD {}\", gui_state.filename_to_load);\n // let mut input_file = File::open(Path::new(\"./1-chip8-logo.ch8\")).expect(\"put 1-chip8-logo.ch8 in this directory\");\n let mut input_file = File::open(Path::new(\u0026(ROM_ROOT.to_string() + \"/\" + \u0026gui_state.filename_to_load))).expect(\"put 1-chip8-logo.ch8 in this directory\");\n input_file.read_to_end(\u0026mut buffer).expect(\"unable to read file\");\n system_to_control.load_bytes_to_system_memory((\u0026*buffer).into());\n }\n }\n ui.separator();\n // if the system has no program loaded hide the buttons.\n if system_to_control.state().memory.peek(0x200) != 0x00 {\n if ui.button(\"Step\") {\n system_to_control.step();\n };\n ui.same_line();\n if ui.button(\"Run\") {\n system_to_control.start();\n }\n }\n ui.same_line();\n if ui.button(\"Stop\") {\n system_to_control.stop();\n }\n ui.same_line();\n if ui.button(\"Reset\") {\n system_to_control.reset();\n }\n if ui.button(\"Dump Video Memory\") {\n println!(\"{}\", system_to_control.dump_to_string(Video));\n }\n ui.same_line();\n if ui.button(\"Dump Keypad State\") {\n debug!(\"{}\", system_to_control.dump_to_string(Keyboard));\n }\n ui.same_line();\n if ui.button(\"Dump Registers\") {\n debug!(\"{}\", system_to_control.dump_to_string(Registers));\n }\n ui.separator();\n\n ui.checkbox(\"Show Memory\", \u0026mut gui_state.show_memory);\n ui.same_line();\n ui.checkbox(\"Show Video\", \u0026mut gui_state.show_video);\n ui.same_line();\n ui.checkbox(\"Show Registers\", \u0026mut gui_state.show_registers);\n });\n }\n\n pub fn registers_view(system: \u0026Chip8Computer, ui: \u0026Ui) {\n ui.window(\"Registers\")\n .size([400.0, 500.0], Condition::FirstUseEver)\n .build(|| {\n ui.text(\"Registers\");\n for i in 1..0x10 {\n ui.text(format!(\"V{:X}: {}\", i, system.registers.peek(i)));\n if i != 7 {\n ui.same_line();\n }\n }\n ui.text(\"\");\n ui.text(format!(\"I: {:03X}\", system.registers.peek_i()));\n ui.same_line();\n ui.text(format!(\"ST: {:02X}\", system.sound_timer.current()));\n ui.same_line();\n ui.text(format!(\"DT: {:02X}\", system.delay_timer.current()));\n ui.text(format!(\"PC: {:02X}\", system.registers.peek_pc()));\n ui.text(format!(\"SP: {:02X}\", system.stack.depth()));\n });\n }\n\n pub fn hex_memory_display(bytes: Chip8SystemMemory, position: (i32, i32), active: i16, ui: \u0026Ui) {\n let rows = position.0;\n let cols = position.1;\n ui.window(\"System Memory\")\n .size([400.0, 300.0], Condition::FirstUseEver)\n .build(|| {\n let mut current_x_hover: i32 = 0;\n let mut current_y_hover: i32 = 0;\n // display a block of data\n for current_row in 0..rows {\n ui.text(format!(\"{:02x}\", current_row * cols));\n ui.same_line();\n for current_column in 0..cols {\n let data_offset = current_row * cols + current_column;\n let formatted_text = format!(\"{:02x}\", bytes.peek(data_offset as u16));\n let text_location = ui.cursor_screen_pos();\n let text_size = ui.calc_text_size(formatted_text.clone());\n let bounding_box = imgui::sys::ImVec2 {\n x: text_location[0] + text_size[0],\n y: text_location[1] + text_size[1],\n };\n\n let hovering = ui.is_mouse_hovering_rect(text_location, [bounding_box.x, bounding_box.y]);\n let is_active = data_offset == active as i32;\n\n ui.text_colored(if hovering {\n [0., 1., 1., 1.]\n } else if is_active {\n [1., 0., 1., 1.]\n } else {\n [1., 1., 0., 1.]\n }, formatted_text.clone());\n\n // if we are hovering show that at the bottom...\n if hovering {\n // Optionally change the text color to indicate it's interactable\n current_x_hover = current_column;\n current_y_hover = current_row;\n\n // Check if the left mouse button is clicked while hovering over the text\n if ui.is_mouse_clicked(imgui::MouseButton::Left) {\n debug!(\"Offset: [{}] [0x{:02x}] Value: [{}]\", data_offset, data_offset, formatted_text.clone());\n // Perform any action here, e.g., call a function, trigger an event, etc.\n }\n }\n\n // are we on the same line?\n if current_column != (cols - 1) {\n ui.same_line();\n }\n }\n }\n ui.text(format!(\"Offset 0x{:03x}\", current_x_hover * cols + current_y_hover));\n });\n }\n}","traces":[{"line":27,"address":[4022816],"length":1,"stats":{"Line":0}},{"line":28,"address":[4022848,4022943,4023006],"length":1,"stats":{"Line":0}},{"line":29,"address":[4022964],"length":1,"stats":{"Line":0}},{"line":30,"address":[4194493,4192528],"length":1,"stats":{"Line":0}},{"line":31,"address":[4192692,4192767,4192545],"length":1,"stats":{"Line":0}},{"line":32,"address":[4192941,4192991,4192775],"length":1,"stats":{"Line":0}},{"line":33,"address":[4193005,4193067],"length":1,"stats":{"Line":0}},{"line":34,"address":[4194109,4194265,4193845],"length":1,"stats":{"Line":0}},{"line":36,"address":[4193718,4193564,4193300],"length":1,"stats":{"Line":0}},{"line":38,"address":[4193720,4194448,4194314],"length":1,"stats":{"Line":0}},{"line":39,"address":[4194455],"length":1,"stats":{"Line":0}},{"line":41,"address":[4193037],"length":1,"stats":{"Line":0}},{"line":46,"address":[4023088],"length":1,"stats":{"Line":0}},{"line":48,"address":[4023134],"length":1,"stats":{"Line":0}},{"line":49,"address":[4023153],"length":1,"stats":{"Line":0}},{"line":51,"address":[4023168,4023407],"length":1,"stats":{"Line":0}},{"line":52,"address":[4024167,4023427,4023357],"length":1,"stats":{"Line":0}},{"line":54,"address":[4024141,4023937,4024000,4023770],"length":1,"stats":{"Line":0}},{"line":55,"address":[4023958],"length":1,"stats":{"Line":0}},{"line":56,"address":[4024065],"length":1,"stats":{"Line":0}},{"line":57,"address":[4194543],"length":1,"stats":{"Line":0}},{"line":58,"address":[4194587],"length":1,"stats":{"Line":0}},{"line":59,"address":[4194622,4194691],"length":1,"stats":{"Line":0}},{"line":61,"address":[4194746,4195896],"length":1,"stats":{"Line":0}},{"line":62,"address":[4196025,4196169],"length":1,"stats":{"Line":0}},{"line":63,"address":[4196206,4196146],"length":1,"stats":{"Line":0}},{"line":64,"address":[4196335,4196503],"length":1,"stats":{"Line":0}},{"line":65,"address":[4196460],"length":1,"stats":{"Line":0}},{"line":66,"address":[4196486,4196540,4196650],"length":1,"stats":{"Line":0}},{"line":67,"address":[4196755,4196679,4196632],"length":1,"stats":{"Line":0}},{"line":68,"address":[4196780,4196736],"length":1,"stats":{"Line":0}},{"line":69,"address":[4196792,4196818],"length":1,"stats":{"Line":0}},{"line":70,"address":[4196828],"length":1,"stats":{"Line":0}},{"line":72,"address":[4196804],"length":1,"stats":{"Line":0}},{"line":74,"address":[4196842],"length":1,"stats":{"Line":0}},{"line":78,"address":[4194705,4194786,4194895],"length":1,"stats":{"Line":0}},{"line":79,"address":[4194931,4195102],"length":1,"stats":{"Line":0}},{"line":80,"address":[4195069,4195134],"length":1,"stats":{"Line":0}},{"line":81,"address":[4195244,4195415],"length":1,"stats":{"Line":0}},{"line":82,"address":[4195372],"length":1,"stats":{"Line":0}},{"line":83,"address":[4195455,4195568,4195398],"length":1,"stats":{"Line":0}},{"line":84,"address":[4195550,4195597,4195673],"length":1,"stats":{"Line":0}},{"line":85,"address":[4195654,4195698],"length":1,"stats":{"Line":0}},{"line":86,"address":[4195736,4195710],"length":1,"stats":{"Line":0}},{"line":87,"address":[4195746],"length":1,"stats":{"Line":0}},{"line":89,"address":[4195722],"length":1,"stats":{"Line":0}},{"line":91,"address":[4195760],"length":1,"stats":{"Line":0}},{"line":97,"address":[4024192],"length":1,"stats":{"Line":0}},{"line":99,"address":[4024251,4024318,4024452],"length":1,"stats":{"Line":0}},{"line":100,"address":[4024276],"length":1,"stats":{"Line":0}},{"line":101,"address":[4024383],"length":1,"stats":{"Line":0}},{"line":103,"address":[4197007,4197373,4197561,4197125],"length":1,"stats":{"Line":0}},{"line":106,"address":[4197676],"length":1,"stats":{"Line":0}},{"line":107,"address":[4197773,4197835],"length":1,"stats":{"Line":0}},{"line":108,"address":[4197849,4198597,4197911],"length":1,"stats":{"Line":0}},{"line":109,"address":[4197957,4198129,4198297],"length":1,"stats":{"Line":0}},{"line":110,"address":[4198484,4198023],"length":1,"stats":{"Line":0}},{"line":112,"address":[4197925,4198609],"length":1,"stats":{"Line":0}},{"line":113,"address":[4198618],"length":1,"stats":{"Line":0}},{"line":114,"address":[4198817,4198637,4198733,4198973],"length":1,"stats":{"Line":0}},{"line":116,"address":[4199781,4198739,4199152],"length":1,"stats":{"Line":0}},{"line":117,"address":[4199552],"length":1,"stats":{"Line":0}},{"line":118,"address":[4199633],"length":1,"stats":{"Line":0}},{"line":121,"address":[4197887],"length":1,"stats":{"Line":0}},{"line":123,"address":[4199811],"length":1,"stats":{"Line":0}},{"line":124,"address":[4199901],"length":1,"stats":{"Line":0}},{"line":125,"address":[4199967],"length":1,"stats":{"Line":0}},{"line":127,"address":[4199945],"length":1,"stats":{"Line":0}},{"line":128,"address":[4199992],"length":1,"stats":{"Line":0}},{"line":129,"address":[4200039],"length":1,"stats":{"Line":0}},{"line":132,"address":[4199876],"length":1,"stats":{"Line":0}},{"line":133,"address":[4200067],"length":1,"stats":{"Line":0}},{"line":134,"address":[4200133],"length":1,"stats":{"Line":0}},{"line":136,"address":[4200111],"length":1,"stats":{"Line":0}},{"line":137,"address":[4200158],"length":1,"stats":{"Line":0}},{"line":138,"address":[4200236],"length":1,"stats":{"Line":0}},{"line":140,"address":[4200257,4200202],"length":1,"stats":{"Line":0}},{"line":141,"address":[4200447,4200296],"length":1,"stats":{"Line":0}},{"line":143,"address":[4200271],"length":1,"stats":{"Line":0}},{"line":144,"address":[4200590],"length":1,"stats":{"Line":0}},{"line":145,"address":[4200651,4200745,4200956],"length":1,"stats":{"Line":0}},{"line":147,"address":[4200634],"length":1,"stats":{"Line":0}},{"line":148,"address":[4201198],"length":1,"stats":{"Line":0}},{"line":149,"address":[4201564,4201259,4201353],"length":1,"stats":{"Line":0}},{"line":151,"address":[4201242],"length":1,"stats":{"Line":0}},{"line":153,"address":[4201806],"length":1,"stats":{"Line":0}},{"line":154,"address":[4201840],"length":1,"stats":{"Line":0}},{"line":155,"address":[4201862],"length":1,"stats":{"Line":0}},{"line":156,"address":[4201896],"length":1,"stats":{"Line":0}},{"line":157,"address":[4201918],"length":1,"stats":{"Line":0}},{"line":161,"address":[4024480],"length":1,"stats":{"Line":0}},{"line":162,"address":[4024576,4024512],"length":1,"stats":{"Line":0}},{"line":163,"address":[4024534],"length":1,"stats":{"Line":0}},{"line":164,"address":[4202032],"length":1,"stats":{"Line":0}},{"line":165,"address":[4202049],"length":1,"stats":{"Line":0}},{"line":166,"address":[4205059,4202071],"length":1,"stats":{"Line":0}},{"line":167,"address":[4205067,4205178,4205318,4205464],"length":1,"stats":{"Line":0}},{"line":168,"address":[4205474],"length":1,"stats":{"Line":0}},{"line":169,"address":[4205485],"length":1,"stats":{"Line":0}},{"line":172,"address":[4202135],"length":1,"stats":{"Line":0}},{"line":173,"address":[4202154,4202300,4202564,4202717],"length":1,"stats":{"Line":0}},{"line":174,"address":[4202730],"length":1,"stats":{"Line":0}},{"line":175,"address":[4202886,4203150,4203303,4202741],"length":1,"stats":{"Line":0}},{"line":176,"address":[4203316],"length":1,"stats":{"Line":0}},{"line":177,"address":[4203327,4203889,4203472,4203736],"length":1,"stats":{"Line":0}},{"line":178,"address":[4204048,4204465,4203902,4204312],"length":1,"stats":{"Line":0}},{"line":179,"address":[4205038,4204621,4204478,4204885],"length":1,"stats":{"Line":0}},{"line":183,"address":[4024656],"length":1,"stats":{"Line":0}},{"line":184,"address":[4024707],"length":1,"stats":{"Line":0}},{"line":185,"address":[4024711],"length":1,"stats":{"Line":0}},{"line":186,"address":[4024897,4024715,4024782],"length":1,"stats":{"Line":0}},{"line":187,"address":[4024740],"length":1,"stats":{"Line":0}},{"line":188,"address":[4024842],"length":1,"stats":{"Line":0}},{"line":189,"address":[4205519],"length":1,"stats":{"Line":0}},{"line":190,"address":[4205530],"length":1,"stats":{"Line":0}},{"line":192,"address":[4205541,4205665],"length":1,"stats":{"Line":0}},{"line":193,"address":[4205686,4206968,4206479,4206743,4206362,4206899],"length":1,"stats":{"Line":0}},{"line":194,"address":[4206920],"length":1,"stats":{"Line":0}},{"line":195,"address":[4206938,4206984],"length":1,"stats":{"Line":0}},{"line":196,"address":[4207686,4207062],"length":1,"stats":{"Line":0}},{"line":197,"address":[4207484,4207138,4207236],"length":1,"stats":{"Line":0}},{"line":198,"address":[4207666,4207759],"length":1,"stats":{"Line":0}},{"line":199,"address":[4207783],"length":1,"stats":{"Line":0}},{"line":200,"address":[4207957],"length":1,"stats":{"Line":0}},{"line":201,"address":[4207873],"length":1,"stats":{"Line":0}},{"line":202,"address":[4207909],"length":1,"stats":{"Line":0}},{"line":205,"address":[4207975],"length":1,"stats":{"Line":0}},{"line":206,"address":[4208096],"length":1,"stats":{"Line":0}},{"line":208,"address":[4208398,4208127,4208217],"length":1,"stats":{"Line":0}},{"line":209,"address":[4208154],"length":1,"stats":{"Line":0}},{"line":210,"address":[4208144,4208285],"length":1,"stats":{"Line":0}},{"line":211,"address":[4208287],"length":1,"stats":{"Line":0}},{"line":213,"address":[4208222],"length":1,"stats":{"Line":0}},{"line":214,"address":[4208350],"length":1,"stats":{"Line":0}},{"line":217,"address":[4208409],"length":1,"stats":{"Line":0}},{"line":219,"address":[4208468],"length":1,"stats":{"Line":0}},{"line":220,"address":[4208475],"length":1,"stats":{"Line":0}},{"line":223,"address":[4208482],"length":1,"stats":{"Line":0}},{"line":224,"address":[4209847,4208527,4208624,4208896,4209035,4209395,4209627],"length":1,"stats":{"Line":0}},{"line":230,"address":[4208423,4210140],"length":1,"stats":{"Line":0}},{"line":231,"address":[4210193],"length":1,"stats":{"Line":0}},{"line":235,"address":[4205617,4206318,4205733,4206339,4206162,4205898],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":142},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmaimgui","src","bin","support","gui_file_list.rs"],"content":"use std::ffi::OsString;\nuse std::fs::read_dir;\nuse std::path::PathBuf;\nuse imgui::Ui;\nuse log::debug;\n\npub struct GuiFileList {}\n\nimpl GuiFileList {\n pub fn display_path(root: PathBuf, selected_filename: \u0026String, ui: \u0026Ui) -\u003e String {\n let mut working_filename = selected_filename.clone();\n ui.text(format!(\"Displaying {}\", root.to_str().unwrap_or(\"Unable to parse path\")));\n\n let mut known_files: Vec\u003cOsString\u003e = vec![];\n\n for entry in read_dir(root.as_path()).unwrap() {\n known_files.push(entry.unwrap().file_name());\n }\n\n known_files.sort();\n\n for (index, entry) in known_files.iter().enumerate() {\n let mut working_select = ui.selectable_config(format!(\"{}\", entry.clone().into_string().unwrap()));\n if entry.to_str().unwrap().to_string() == selected_filename.as_str().to_string() {\n working_select = working_select.selected(true);\n }\n if working_select.build() {\n debug!(\"SELECTED {index} / {entry:?}\");\n working_filename = entry.clone().into_string().unwrap();\n };\n }\n working_filename\n }\n}\n","traces":[{"line":10,"address":[3557597,3557436,3553120],"length":1,"stats":{"Line":0}},{"line":11,"address":[3553194,3553281],"length":1,"stats":{"Line":0}},{"line":12,"address":[3553366,3553586,3553289,3553723],"length":1,"stats":{"Line":0}},{"line":14,"address":[3553730],"length":1,"stats":{"Line":0}},{"line":16,"address":[3554315,3554344,3553912,3553757,3554156],"length":1,"stats":{"Line":0}},{"line":17,"address":[3557463],"length":1,"stats":{"Line":0}},{"line":20,"address":[3554592],"length":1,"stats":{"Line":0}},{"line":22,"address":[3554638,3556448,3554966],"length":1,"stats":{"Line":0}},{"line":23,"address":[3555075,3554998,3555719,3555419],"length":1,"stats":{"Line":0}},{"line":24,"address":[3556288,3556425,3555734,3555974,3555830],"length":1,"stats":{"Line":0}},{"line":25,"address":[3556307],"length":1,"stats":{"Line":0}},{"line":27,"address":[3556210,3556434,3557431],"length":1,"stats":{"Line":0}},{"line":28,"address":[3556453,3556573,3556842],"length":1,"stats":{"Line":0}},{"line":29,"address":[3557047,3556505,3557273],"length":1,"stats":{"Line":0}},{"line":32,"address":[3554916],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":15},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmaimgui","src","bin","support","mod.rs"],"content":"use glium::glutin::surface::WindowSurface;\nuse glium::{Display, Surface};\nuse imgui::{Context, FontConfig, FontGlyphRanges, FontSource, Ui};\nuse imgui_glium_renderer::Renderer;\nuse imgui_winit_support::winit::event::{Event, WindowEvent};\nuse imgui_winit_support::winit::event_loop::EventLoop;\nuse imgui_winit_support::winit::window::WindowBuilder;\nuse imgui_winit_support::{HiDpiMode, WinitPlatform};\nuse std::path::Path;\nuse std::time::Instant;\n\npub mod ui_state;\npub mod emmagui_support;\nmod gui_file_list;\n\nuse copypasta::{ClipboardContext, ClipboardProvider};\nuse imgui::ClipboardBackend;\n\npub struct ClipboardSupport(pub ClipboardContext);\n\npub fn clipboard_init() -\u003e Option\u003cClipboardSupport\u003e {\n ClipboardContext::new().ok().map(ClipboardSupport)\n}\n\nimpl ClipboardBackend for ClipboardSupport {\n fn get(\u0026mut self) -\u003e Option\u003cString\u003e {\n self.0.get_contents().ok()\n }\n fn set(\u0026mut self, text: \u0026str) {\n // ignore errors?\n let _ = self.0.set_contents(text.to_owned());\n }\n}\n\npub const FONT_SIZE: f32 = 13.0;\n\n#[allow(dead_code)] // annoyingly, RA yells that this is unusued\npub fn simple_init\u003cF: FnMut(\u0026mut bool, \u0026mut Ui) + 'static\u003e(title: \u0026str, run_ui: F) {\n init_with_startup(title, |_, _, _| {}, run_ui);\n}\n\npub fn init_with_startup\u003cFInit, FUi\u003e(title: \u0026str, mut startup: FInit, mut run_ui: FUi)\nwhere\n FInit: FnMut(\u0026mut Context, \u0026mut Renderer, \u0026Display\u003cWindowSurface\u003e) + 'static,\n FUi: FnMut(\u0026mut bool, \u0026mut Ui) + 'static,\n{\n let mut imgui = create_context();\n\n let title = match Path::new(\u0026title).file_name() {\n Some(file_name) =\u003e file_name.to_str().unwrap(),\n None =\u003e title,\n };\n let event_loop = EventLoop::new().expect(\"Failed to create EventLoop\");\n\n let builder = WindowBuilder::new()\n .with_maximized(true)\n .with_title(title);\n // .with_inner_size(LogicalSize::new(1024, 768));\n let (window, display) = glium::backend::glutin::SimpleWindowBuilder::new()\n .set_window_builder(builder)\n .build(\u0026event_loop);\n let mut renderer = Renderer::init(\u0026mut imgui, \u0026display).expect(\"Failed to initialize renderer\");\n\n if let Some(backend) = clipboard_init() {\n imgui.set_clipboard_backend(backend);\n } else {\n eprintln!(\"Failed to initialize clipboard\");\n }\n\n let mut platform = WinitPlatform::init(\u0026mut imgui);\n {\n let dpi_mode = if let Ok(factor) = std::env::var(\"IMGUI_EXAMPLE_FORCE_DPI_FACTOR\") {\n // Allow forcing of HiDPI factor for debugging purposes\n match factor.parse::\u003cf64\u003e() {\n Ok(f) =\u003e HiDpiMode::Locked(f),\n Err(e) =\u003e panic!(\"Invalid scaling factor: {}\", e),\n }\n } else {\n HiDpiMode::Default\n };\n\n platform.attach_window(imgui.io_mut(), \u0026window, dpi_mode);\n }\n\n let mut last_frame = Instant::now();\n\n startup(\u0026mut imgui, \u0026mut renderer, \u0026display);\n\n event_loop\n .run(move |event, window_target| match event {\n Event::NewEvents(_) =\u003e {\n let now = Instant::now();\n imgui.io_mut().update_delta_time(now - last_frame);\n last_frame = now;\n }\n Event::AboutToWait =\u003e {\n platform\n .prepare_frame(imgui.io_mut(), \u0026window)\n .expect(\"Failed to prepare frame\");\n window.request_redraw();\n }\n Event::WindowEvent {\n event: WindowEvent::RedrawRequested,\n ..\n } =\u003e {\n let ui = imgui.frame();\n\n let mut run = true;\n run_ui(\u0026mut run, ui);\n if !run {\n window_target.exit();\n }\n\n let mut target = display.draw();\n target.clear_color_srgb(1.0, 1.0, 1.0, 1.0);\n platform.prepare_render(ui, \u0026window);\n let draw_data = imgui.render();\n renderer\n .render(\u0026mut target, draw_data)\n .expect(\"Rendering failed\");\n target.finish().expect(\"Failed to swap buffers\");\n }\n Event::WindowEvent {\n event: WindowEvent::Resized(new_size),\n ..\n } =\u003e {\n if new_size.width \u003e 0 \u0026\u0026 new_size.height \u003e 0 {\n display.resize((new_size.width, new_size.height));\n }\n platform.handle_event(imgui.io_mut(), \u0026window, \u0026event);\n }\n Event::WindowEvent {\n event: WindowEvent::CloseRequested,\n ..\n } =\u003e window_target.exit(),\n event =\u003e {\n platform.handle_event(imgui.io_mut(), \u0026window, \u0026event);\n }\n })\n .expect(\"EventLoop error\");\n}\n\n/// Creates the imgui context\npub fn create_context() -\u003e imgui::Context {\n let mut imgui = Context::create();\n // Fixed font size. Note imgui_winit_support uses \"logical\n // pixels\", which are physical pixels scaled by the devices\n // scaling factor. Meaning, 13.0 pixels should look the same size\n // on two different screens, and thus we do not need to scale this\n // value (as the scaling is handled by winit)\n imgui.fonts().add_font(\u0026[\n FontSource::TtfData {\n data: include_bytes!(\"../../../../resources/Roboto-Regular.ttf\"),\n size_pixels: FONT_SIZE,\n config: Some(FontConfig {\n // As imgui-glium-renderer isn't gamma-correct with\n // it's font rendering, we apply an arbitrary\n // multiplier to make the font a bit \"heavier\". With\n // default imgui-glow-renderer this is unnecessary.\n rasterizer_multiply: 1.5,\n // Oversampling font helps improve text rendering at\n // expense of larger font atlas texture.\n oversample_h: 4,\n oversample_v: 4,\n ..FontConfig::default()\n }),\n },\n FontSource::TtfData {\n data: include_bytes!(\"../../../../resources/mplus-1p-regular.ttf\"),\n size_pixels: FONT_SIZE,\n config: Some(FontConfig {\n // Oversampling font helps improve text rendering at\n // expense of larger font atlas texture.\n oversample_h: 4,\n oversample_v: 4,\n // Range of glyphs to rasterize\n glyph_ranges: FontGlyphRanges::japanese(),\n ..FontConfig::default()\n }),\n },\n ]);\n imgui.set_ini_filename(None);\n\n imgui\n}\n","traces":[{"line":21,"address":[3981264],"length":1,"stats":{"Line":0}},{"line":22,"address":[3981281],"length":1,"stats":{"Line":0}},{"line":26,"address":[3981344],"length":1,"stats":{"Line":0}},{"line":27,"address":[3981363],"length":1,"stats":{"Line":0}},{"line":29,"address":[3981408],"length":1,"stats":{"Line":0}},{"line":31,"address":[3981431],"length":1,"stats":{"Line":0}},{"line":38,"address":[],"length":0,"stats":{"Line":0}},{"line":39,"address":[],"length":0,"stats":{"Line":0}},{"line":42,"address":[3445718,3446701,3443632],"length":1,"stats":{"Line":0}},{"line":47,"address":[],"length":0,"stats":{"Line":0}},{"line":49,"address":[3443952,3443859],"length":1,"stats":{"Line":0}},{"line":50,"address":[3444260,3444074],"length":1,"stats":{"Line":0}},{"line":51,"address":[],"length":0,"stats":{"Line":0}},{"line":53,"address":[],"length":0,"stats":{"Line":0}},{"line":55,"address":[],"length":0,"stats":{"Line":0}},{"line":57,"address":[3444415,3444458],"length":1,"stats":{"Line":0}},{"line":59,"address":[],"length":0,"stats":{"Line":0}},{"line":60,"address":[],"length":0,"stats":{"Line":0}},{"line":61,"address":[],"length":0,"stats":{"Line":0}},{"line":62,"address":[3444782,3444734],"length":1,"stats":{"Line":0}},{"line":64,"address":[],"length":0,"stats":{"Line":0}},{"line":65,"address":[],"length":0,"stats":{"Line":0}},{"line":67,"address":[],"length":0,"stats":{"Line":0}},{"line":70,"address":[],"length":0,"stats":{"Line":0}},{"line":72,"address":[],"length":0,"stats":{"Line":0}},{"line":74,"address":[],"length":0,"stats":{"Line":0}},{"line":75,"address":[],"length":0,"stats":{"Line":0}},{"line":76,"address":[3445460,3445640],"length":1,"stats":{"Line":0}},{"line":79,"address":[],"length":0,"stats":{"Line":0}},{"line":82,"address":[],"length":0,"stats":{"Line":0}},{"line":85,"address":[],"length":0,"stats":{"Line":0}},{"line":87,"address":[],"length":0,"stats":{"Line":0}},{"line":89,"address":[],"length":0,"stats":{"Line":0}},{"line":90,"address":[],"length":0,"stats":{"Line":0}},{"line":91,"address":[],"length":0,"stats":{"Line":0}},{"line":92,"address":[],"length":0,"stats":{"Line":0}},{"line":93,"address":[3447228],"length":1,"stats":{"Line":0}},{"line":94,"address":[3447343],"length":1,"stats":{"Line":0}},{"line":96,"address":[],"length":0,"stats":{"Line":0}},{"line":97,"address":[],"length":0,"stats":{"Line":0}},{"line":98,"address":[],"length":0,"stats":{"Line":0}},{"line":99,"address":[],"length":0,"stats":{"Line":0}},{"line":100,"address":[],"length":0,"stats":{"Line":0}},{"line":102,"address":[],"length":0,"stats":{"Line":0}},{"line":103,"address":[],"length":0,"stats":{"Line":0}},{"line":104,"address":[],"length":0,"stats":{"Line":0}},{"line":105,"address":[],"length":0,"stats":{"Line":0}},{"line":106,"address":[],"length":0,"stats":{"Line":0}},{"line":108,"address":[],"length":0,"stats":{"Line":0}},{"line":109,"address":[],"length":0,"stats":{"Line":0}},{"line":110,"address":[],"length":0,"stats":{"Line":0}},{"line":111,"address":[],"length":0,"stats":{"Line":0}},{"line":114,"address":[],"length":0,"stats":{"Line":0}},{"line":115,"address":[3447715],"length":1,"stats":{"Line":0}},{"line":116,"address":[],"length":0,"stats":{"Line":0}},{"line":117,"address":[],"length":0,"stats":{"Line":0}},{"line":118,"address":[3447885],"length":1,"stats":{"Line":0}},{"line":119,"address":[],"length":0,"stats":{"Line":0}},{"line":120,"address":[],"length":0,"stats":{"Line":0}},{"line":121,"address":[3447949],"length":1,"stats":{"Line":0}},{"line":123,"address":[],"length":0,"stats":{"Line":0}},{"line":124,"address":[],"length":0,"stats":{"Line":0}},{"line":125,"address":[],"length":0,"stats":{"Line":0}},{"line":126,"address":[],"length":0,"stats":{"Line":0}},{"line":127,"address":[],"length":0,"stats":{"Line":0}},{"line":128,"address":[],"length":0,"stats":{"Line":0}},{"line":130,"address":[3447478,3447582],"length":1,"stats":{"Line":0}},{"line":132,"address":[],"length":0,"stats":{"Line":0}},{"line":133,"address":[],"length":0,"stats":{"Line":0}},{"line":134,"address":[],"length":0,"stats":{"Line":0}},{"line":135,"address":[],"length":0,"stats":{"Line":0}},{"line":136,"address":[],"length":0,"stats":{"Line":0}},{"line":137,"address":[],"length":0,"stats":{"Line":0}},{"line":144,"address":[3981488,3983036],"length":1,"stats":{"Line":0}},{"line":145,"address":[3981505],"length":1,"stats":{"Line":0}},{"line":151,"address":[3981529,3982630],"length":1,"stats":{"Line":0}},{"line":152,"address":[3981928],"length":1,"stats":{"Line":0}},{"line":155,"address":[3981605],"length":1,"stats":{"Line":0}},{"line":165,"address":[3981586],"length":1,"stats":{"Line":0}},{"line":168,"address":[3982496],"length":1,"stats":{"Line":0}},{"line":171,"address":[3982181],"length":1,"stats":{"Line":0}},{"line":177,"address":[3982062],"length":1,"stats":{"Line":0}},{"line":178,"address":[3982147],"length":1,"stats":{"Line":0}},{"line":182,"address":[3982975],"length":1,"stats":{"Line":0}},{"line":184,"address":[3983008],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":85},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmaimgui","src","bin","support","ui_state.rs"],"content":"use std::time::Instant;\nuse imgui::ImColor32;\n\npub struct ImGuiUiState {\n pub show_registers: bool,\n pub show_memory: bool,\n pub show_video: bool,\n pub show_keypad: bool,\n pub filename_to_load: String,\n pub on_colour: ImColor32,\n pub off_colour: ImColor32,\n pub is_running: bool,\n pub frame_time: u32,\n pub last_frame_instant: Instant,\n pub target_ips: i32\n}\n\nimpl Clone for ImGuiUiState {\n fn clone(\u0026self) -\u003e Self {\n ImGuiUiState {\n show_registers: self.show_registers,\n show_memory: self.show_memory,\n show_video: self.show_video,\n show_keypad: self.show_keypad,\n filename_to_load: self.filename_to_load.to_string(),\n on_colour: self.on_colour,\n off_colour: self.off_colour,\n is_running: self.is_running,\n frame_time: self.frame_time,\n last_frame_instant: self.last_frame_instant,\n target_ips: self.target_ips\n }\n }\n}\n\nimpl Default for ImGuiUiState {\n fn default() -\u003e Self {\n ImGuiUiState {\n show_registers: false,\n show_memory: false,\n show_video: true,\n show_keypad: true,\n filename_to_load: String::new(),\n on_colour: ImColor32::from_rgb(0xff, 0xff, 0x00),\n off_colour: ImColor32::from_rgb(0x00, 0xff, 0xff),\n is_running: false,\n frame_time: 16,\n last_frame_instant: Instant::now(),\n target_ips: 20\n }\n }\n}\n","traces":[{"line":19,"address":[3461536],"length":1,"stats":{"Line":0}},{"line":21,"address":[3461565],"length":1,"stats":{"Line":0}},{"line":22,"address":[3461569],"length":1,"stats":{"Line":0}},{"line":23,"address":[3461573],"length":1,"stats":{"Line":0}},{"line":24,"address":[3461577],"length":1,"stats":{"Line":0}},{"line":25,"address":[3461580],"length":1,"stats":{"Line":0}},{"line":26,"address":[3461604],"length":1,"stats":{"Line":0}},{"line":27,"address":[3461608],"length":1,"stats":{"Line":0}},{"line":28,"address":[3461612],"length":1,"stats":{"Line":0}},{"line":29,"address":[3461616],"length":1,"stats":{"Line":0}},{"line":30,"address":[3461620],"length":1,"stats":{"Line":0}},{"line":31,"address":[3461627],"length":1,"stats":{"Line":0}},{"line":37,"address":[3461954,3461728],"length":1,"stats":{"Line":0}},{"line":43,"address":[3461747],"length":1,"stats":{"Line":0}},{"line":44,"address":[3461759],"length":1,"stats":{"Line":0}},{"line":45,"address":[3461814],"length":1,"stats":{"Line":0}},{"line":48,"address":[3461827],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":17},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmasdl2","src","bin","gemmasdl2.rs"],"content":"mod support;\nuse std::{sync::Arc, time::Instant};\nuse anyhow::Context;\nuse egui::TextBuffer;\nuse egui_glow::glow::{HasContext, COLOR_BUFFER_BIT};\nuse egui_sdl2_platform::sdl2;\nuse sdl2::event::{Event, WindowEvent};\nuse gemma::chip8::computer::Chip8Computer;\nuse support::timestep::TimeStep;\nuse crate::support::gemma_egui_support::GemmaEguiSupport;\n\nconst SCREEN_WIDTH: u32 = 800;\nconst SCREEN_HEIGHT: u32 = 480;\n\nasync fn run() -\u003e anyhow::Result\u003cString\u003e {\n // Initialize SDL2 and video subsystem\n let sdl = sdl2::init().map_err(|e| anyhow::anyhow!(\"Failed to create SDL context: {}\", e))?;\n let mut video = sdl.video().map_err(|e| anyhow::anyhow!(\"Failed to initialize SDL video subsystem: {}\", e))?;\n\n // Create SDL2 window and OpenGL context\n let window = video.window(\"Window\", SCREEN_WIDTH, SCREEN_HEIGHT)\n .opengl()\n .position_centered()\n .build()?;\n let _gl_context = window.gl_create_context().expect(\"Failed to create GL context\");\n\n // Load OpenGL functions\n let gl = unsafe {\n egui_glow::painter::Context::from_loader_function(|name| {\n video.gl_get_proc_address(name) as *const _\n })\n };\n let mut painter = egui_glow::Painter::new(Arc::new(gl), \"\", None)?;\n\n // Setup Egui and SDL2 platform\n let mut platform = egui_sdl2_platform::Platform::new(window.size())?;\n let mut event_pump = sdl.event_pump().map_err(|e| anyhow::anyhow!(\"Failed to get SDL event pump: {}\", e))?;\n\n // Initial settings\n let mut color = [0.0, 0.0, 0.0, 1.0]; // Background color\n let start_time = Instant::now();\n let mut timestep = TimeStep::new();\n\n let mut computer = Chip8Computer::new();\n let mut is_running: bool = false;\n computer.load_bytes_to_memory(0x200, \u0026std::fs::read(\"resources/roms/3-corax+.ch8\")?);\n\n // Main loop\n 'main: loop {\n // Update the Egui platform with the current time\n platform.update_time(start_time.elapsed().as_secs_f64());\n\n // Begin Egui frame\n let ctx = platform.context();\n\n if is_running {\n computer.step_system();\n }\n\n egui::Window::new(\"Hello, world!\").show(\u0026ctx, |ui| {\n GemmaEguiSupport::video_view(\u0026computer, ui);\n GemmaEguiSupport::memory_view(\u0026computer, ui);\n GemmaEguiSupport::registers_view(\u0026computer, ui);\n });\n\n // Process Egui frame\n let full_output = platform.end_frame(\u0026mut video)?;\n let paint_jobs = platform.tessellate(\u0026full_output);\n\n // Clear the screen with the current color\n unsafe {\n painter.gl().clear_color(color[0], color[1], color[2], 1.0);\n painter.gl().clear(COLOR_BUFFER_BIT);\n }\n\n // Paint Egui outputs and update textures\n let size = window.size();\n painter.paint_and_update_textures([size.0, size.1], 1.0, paint_jobs.as_slice(), \u0026full_output.textures_delta);\n window.gl_swap_window();\n\n // Run the timestep logic\n timestep.run_this(|_| {});\n\n // Handle SDL2 events\n for event in event_pump.poll_iter() {\n match event {\n Event::Quit { .. }\n | Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::Escape), .. } =\u003e break 'main,\n Event::Window { window_id, win_event, .. } if window_id == window.id() =\u003e {\n if let WindowEvent::Close = win_event {\n break 'main;\n }\n }\n Event::KeyUp { keycode: Some(sdl2::keyboard::Keycode::F3), .. } =\u003e {\n println!(\"USER PRESSED F3 -\u003e running\");\n is_running = true;\n }\n Event::KeyUp { keycode: Some(sdl2::keyboard::Keycode::F4), .. } =\u003e {\n println!(\"USER PRESSED F4 -\u003e stopping\");\n is_running = false;\n }\n Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::F5), .. } =\u003e {\n println!(\"USER PRESSED F5 -\u003e Step\");\n computer.step_system();\n }\n Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::F6), .. } =\u003e {\n println!(\"USER PRESSED F6 -\u003e RESET\");\n computer.reset();\n }\n Event::ControllerButtonDown { which, .. } =\u003e {\n println!(\"PLAYER {which} DOWN\");\n }\n Event::ControllerButtonDown { button, .. } =\u003e {\n println!(\"BUTTON {:?}\", button);\n }\n Event::JoyButtonDown {button_idx, .. } =\u003e {\n println!(\"JoyButtonDown {}\", button_idx);\n }\n Event::JoyAxisMotion { which, axis_idx, .. } =\u003e {\n println!(\"JoyAxismotion {which} {axis_idx}\");\n }\n _ =\u003e platform.handle_event(\u0026event, \u0026sdl, \u0026video),\n }\n }\n\n // Optionally log the frame rate\n if let Some(fps) = timestep.frame_rate() {\n println!(\"{:?} fps\", fps);\n }\n\n let num_js = sdl.joystick().unwrap().num_joysticks().unwrap();\n println!(\"NUM JS = {num_js}\");\n }\n\n Ok((\"\").parse()?)\n}\n\nfn main() -\u003e anyhow::Result\u003c()\u003e {\n pollster::block_on(run())?;\n Ok(())\n}\n","traces":[{"line":15,"address":[738576],"length":1,"stats":{"Line":0}},{"line":17,"address":[745302,745385,752506,752544,752649,752773,745491],"length":1,"stats":{"Line":0}},{"line":18,"address":[745484,745592,752848,752953,752504,753077,745747],"length":1,"stats":{"Line":0}},{"line":21,"address":[745696,745908,745832,746087],"length":1,"stats":{"Line":0}},{"line":25,"address":[746164],"length":1,"stats":{"Line":0}},{"line":29,"address":[753152,746265],"length":1,"stats":{"Line":0}},{"line":30,"address":[753170],"length":1,"stats":{"Line":0}},{"line":33,"address":[746569,746324,752423],"length":1,"stats":{"Line":0}},{"line":36,"address":[746536,752402,746871,746692],"length":1,"stats":{"Line":0}},{"line":37,"address":[753413,752381,753184,746864,747146,746972,753289],"length":1,"stats":{"Line":0}},{"line":40,"address":[747076],"length":1,"stats":{"Line":0}},{"line":41,"address":[747120,747246],"length":1,"stats":{"Line":0}},{"line":42,"address":[747269],"length":1,"stats":{"Line":0}},{"line":44,"address":[747276],"length":1,"stats":{"Line":0}},{"line":45,"address":[747295],"length":1,"stats":{"Line":0}},{"line":46,"address":[747378,752341,747303],"length":1,"stats":{"Line":0}},{"line":51,"address":[747640],"length":1,"stats":{"Line":0}},{"line":54,"address":[747756],"length":1,"stats":{"Line":0}},{"line":56,"address":[747799],"length":1,"stats":{"Line":0}},{"line":57,"address":[747836,747899],"length":1,"stats":{"Line":0}},{"line":60,"address":[747809,753488,747933],"length":1,"stats":{"Line":0}},{"line":61,"address":[753506],"length":1,"stats":{"Line":0}},{"line":62,"address":[753520],"length":1,"stats":{"Line":0}},{"line":63,"address":[753534],"length":1,"stats":{"Line":0}},{"line":67,"address":[747955,748183],"length":1,"stats":{"Line":0}},{"line":68,"address":[748156],"length":1,"stats":{"Line":0}},{"line":72,"address":[748376,748268],"length":1,"stats":{"Line":0}},{"line":73,"address":[748469],"length":1,"stats":{"Line":0}},{"line":77,"address":[748535],"length":1,"stats":{"Line":0}},{"line":78,"address":[748584],"length":1,"stats":{"Line":0}},{"line":79,"address":[748692],"length":1,"stats":{"Line":0}},{"line":82,"address":[748719,753552,753563],"length":1,"stats":{"Line":0}},{"line":85,"address":[748726,748829],"length":1,"stats":{"Line":0}},{"line":86,"address":[750151,750741,751798,748877],"length":1,"stats":{"Line":0}},{"line":89,"address":[750082,750648],"length":1,"stats":{"Line":0}},{"line":90,"address":[750700],"length":1,"stats":{"Line":0}},{"line":94,"address":[751913],"length":1,"stats":{"Line":0}},{"line":95,"address":[751886,751834],"length":1,"stats":{"Line":0}},{"line":96,"address":[751905],"length":1,"stats":{"Line":0}},{"line":98,"address":[751945],"length":1,"stats":{"Line":0}},{"line":99,"address":[751860,751918],"length":1,"stats":{"Line":0}},{"line":100,"address":[751937],"length":1,"stats":{"Line":0}},{"line":102,"address":[751750],"length":1,"stats":{"Line":0}},{"line":103,"address":[751712,750792],"length":1,"stats":{"Line":0}},{"line":104,"address":[751731],"length":1,"stats":{"Line":0}},{"line":106,"address":[751793],"length":1,"stats":{"Line":0}},{"line":107,"address":[750821,751755],"length":1,"stats":{"Line":0}},{"line":108,"address":[751774],"length":1,"stats":{"Line":0}},{"line":110,"address":[750467],"length":1,"stats":{"Line":0}},{"line":111,"address":[752224],"length":1,"stats":{"Line":0}},{"line":116,"address":[750338],"length":1,"stats":{"Line":0}},{"line":117,"address":[752150],"length":1,"stats":{"Line":0}},{"line":119,"address":[750195],"length":1,"stats":{"Line":0}},{"line":120,"address":[752060],"length":1,"stats":{"Line":0}},{"line":122,"address":[750014,752298],"length":1,"stats":{"Line":0}},{"line":127,"address":[748822,748937],"length":1,"stats":{"Line":0}},{"line":128,"address":[749117],"length":1,"stats":{"Line":0}},{"line":131,"address":[749427,749740,749110],"length":1,"stats":{"Line":0}},{"line":132,"address":[749876],"length":1,"stats":{"Line":0}},{"line":135,"address":[750991,750924],"length":1,"stats":{"Line":0}},{"line":138,"address":[738592],"length":1,"stats":{"Line":0}},{"line":139,"address":[738768,738599],"length":1,"stats":{"Line":0}},{"line":140,"address":[738757],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":63},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmasdl2","src","bin","support","gemma_egui_support.rs"],"content":"use std::fs::read_dir;\nuse std::ops::Index;\nuse std::path::{Display, PathBuf};\nuse std::thread;\nuse std::time::Duration;\nuse egui::{Align, Color32, ComboBox, Direction, Pos2, Response, TextBuffer};\nuse egui::Rect;\nuse egui::Vec2;\nuse egui::Ui;\nuse egui::WidgetType::SelectableLabel;\nuse crate::Chip8Computer;\n\nconst CELL_WIDTH: f32 = 5.0;\nconst CELL_HEIGHT: f32 = 5.0;\n\npub struct EGuiFileList {}\nimpl EGuiFileList {\n pub fn display_path(root: PathBuf, selected_filename: \u0026mut String, ui: \u0026mut Ui) {\n let mut working_filename = selected_filename.clone();\n ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {\n // ui.label(format!(\"Displaying {}\", root.to_str().unwrap_or(\"Unable to Load Path\")));\n ComboBox::from_label(\"Select ROM\")\n .selected_text(selected_filename.clone())\n .show_ui(ui, |ui| {\n\n let mut sorted_options = vec![];\n for option in read_dir(root.as_path()).unwrap() {\n let to_push = option.unwrap().file_name().into_string().unwrap_or( String::new());\n sorted_options.push(to_push);\n }\n\n sorted_options.sort();\n for item in sorted_options {\n // Add each option to the ComboBox\n if ui.selectable_label(selected_filename.eq(\u0026item.as_str()), item.clone()).clicked()\n {\n *selected_filename = item;\n }\n }\n });\n // Display the selected option\n });\n }\n}\n\npub struct GemmaEguiSupport {}\n\nimpl GemmaEguiSupport {\n pub fn controls_view(mut system: \u0026mut Chip8Computer, ui: \u0026mut Ui) {\n ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {\n if ui.button(\"Start\").clicked() {\n println!(\"Start\");\n // state.is_running = true;\n }\n if ui.button(\"Step\").clicked() {\n system.step_system();\n }\n\n if ui.button(\"Stop\").clicked() {\n println!(\"STOP\");\n // state.is_running = false;\n }\n if ui.button(\"Reset\").clicked() {\n system.reset();\n // state.is_running = false;\n }\n });\n\n // if ui.button(format!(\"Load {}\", state.selected_rom_filename)).clicked() {\n // load the bin...\n // let read_bin = std::fs::read(PathBuf::from(format!(\"resources/roms/{}\", state.selected_rom_filename))).unwrap();\n // ...then feed the system.\n // system.load_bytes_to_memory(0x200, \u0026read_bin);\n // println!(\"Loaded {}\", state.selected_rom_filename);\n // }\n // EGuiFileList::display_path(PathBuf::from(\"resources/roms\"), \u0026mut state.selected_rom_filename, ui);\n\n\n\n ui.with_layout(egui::Layout::left_to_right(Align::TOP), |ui| {\n // ui.checkbox(\u0026mut state.display_memory, \"Display Memory\");\n // ui.checkbox(\u0026mut state.display_video, \"Display Video\");\n // ui.checkbox(\u0026mut state.display_registers, \"Display Registers\");\n });\n }\n\n pub fn registers_view(system: \u0026Chip8Computer, ui: \u0026mut Ui) {\n ui.label(format!(\"V0-7: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} \",\n system.registers.peek(0x00),\n system.registers.peek(0x01),\n system.registers.peek(0x02),\n system.registers.peek(0x03),\n system.registers.peek(0x04),\n system.registers.peek(0x05),\n system.registers.peek(0x06),\n system.registers.peek(0x07)\n ));\n ui.label(format!(\"V8-F: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} \",\n system.registers.peek(0x08),\n system.registers.peek(0x09),\n system.registers.peek(0x0A),\n system.registers.peek(0x0B),\n system.registers.peek(0x0C),\n system.registers.peek(0x0D),\n system.registers.peek(0x0E),\n system.registers.peek(0x0F)\n ));\n ui.label(format!(\"PC: {:04x}\\tI: {:04x}\", system.registers.peek_pc(), system.registers.peek_i()));\n }\n\n pub fn video_view(system: \u0026Chip8Computer, ui: \u0026mut Ui) {\n let (_resp, painter) = ui.allocate_painter(Vec2::new(350.0, 165.0), egui::Sense::hover());\n for current_row in 0..32 {\n for current_col in 0..64 {\n let data_offset = current_row * 64 + current_col;\n let x_offset = current_col as f32 * CELL_WIDTH;\n let y_offset = current_row as f32 * CELL_HEIGHT;\n let origin = Pos2::new(x_offset, y_offset);\n let colour = if system.video_memory.peek(data_offset) {\n Color32::RED\n } else {\n Color32::WHITE\n };\n let rect = Rect::from_min_size(origin, Vec2::new(CELL_WIDTH, CELL_HEIGHT));\n painter.rect_filled(rect, 0.0, colour);\n // println!(\"Cell {current_col}x{current_row} at {}x{} -\u003e {}\",\n // origin.x, origin.y,\n // system.video_memory.peek(data_offset));\n }\n }\n // thread::sleep(Duration::from_secs(1));\n }\n\n pub fn memory_view(system: \u0026Chip8Computer, ui: \u0026mut Ui) {\n ui.label(\"Memory View\");\n\n for i in (0..=0x200).step_by(16) {\n ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {\n for y in 0..16 {\n ui.label(format!(\"{:02x}\", system.memory.peek((i + y) as u16)).as_str());\n }\n });\n }\n ui.label(\"Should have **something** to adjust the 'memory window'\");\n }\n}\n","traces":[{"line":18,"address":[787872,788303],"length":1,"stats":{"Line":0}},{"line":19,"address":[787902],"length":1,"stats":{"Line":0}},{"line":20,"address":[788131],"length":1,"stats":{"Line":0}},{"line":22,"address":[810940,810765,810875],"length":1,"stats":{"Line":0}},{"line":23,"address":[810922,810810,810990],"length":1,"stats":{"Line":0}},{"line":24,"address":[813212,810930,811024,812807],"length":1,"stats":{"Line":0}},{"line":26,"address":[811060],"length":1,"stats":{"Line":0}},{"line":27,"address":[811447,811582,811117,813167,811221,811611],"length":1,"stats":{"Line":0}},{"line":28,"address":[813202,812838],"length":1,"stats":{"Line":0}},{"line":29,"address":[813096],"length":1,"stats":{"Line":0}},{"line":32,"address":[811853],"length":1,"stats":{"Line":0}},{"line":33,"address":[812077,812127,811887,812783],"length":1,"stats":{"Line":0}},{"line":35,"address":[812167,812277,812478,812770],"length":1,"stats":{"Line":0}},{"line":37,"address":[812589],"length":1,"stats":{"Line":0}},{"line":49,"address":[788336],"length":1,"stats":{"Line":0}},{"line":50,"address":[788466],"length":1,"stats":{"Line":0}},{"line":51,"address":[813384,813273],"length":1,"stats":{"Line":0}},{"line":52,"address":[813459],"length":1,"stats":{"Line":0}},{"line":55,"address":[813499,813622],"length":1,"stats":{"Line":0}},{"line":56,"address":[813706],"length":1,"stats":{"Line":0}},{"line":59,"address":[813722,813845],"length":1,"stats":{"Line":0}},{"line":60,"address":[813929],"length":1,"stats":{"Line":0}},{"line":63,"address":[813969,814092],"length":1,"stats":{"Line":0}},{"line":64,"address":[814173],"length":1,"stats":{"Line":0}},{"line":80,"address":[788681],"length":1,"stats":{"Line":0}},{"line":87,"address":[788816],"length":1,"stats":{"Line":0}},{"line":88,"address":[790696,792465,791856,792088,791624,789976,790928,791160,791392,790464],"length":1,"stats":{"Line":0}},{"line":89,"address":[788864],"length":1,"stats":{"Line":0}},{"line":90,"address":[789001],"length":1,"stats":{"Line":0}},{"line":91,"address":[789141],"length":1,"stats":{"Line":0}},{"line":92,"address":[789281],"length":1,"stats":{"Line":0}},{"line":93,"address":[789421],"length":1,"stats":{"Line":0}},{"line":94,"address":[789561],"length":1,"stats":{"Line":0}},{"line":95,"address":[789701],"length":1,"stats":{"Line":0}},{"line":96,"address":[789841],"length":1,"stats":{"Line":0}},{"line":98,"address":[795028,796104,793612,794564,794796,795260,794332,795724,794100,795492],"length":1,"stats":{"Line":0}},{"line":99,"address":[792497],"length":1,"stats":{"Line":0}},{"line":101,"address":[792777],"length":1,"stats":{"Line":0}},{"line":102,"address":[792917],"length":1,"stats":{"Line":0}},{"line":103,"address":[793057],"length":1,"stats":{"Line":0}},{"line":104,"address":[793197],"length":1,"stats":{"Line":0}},{"line":105,"address":[793337],"length":1,"stats":{"Line":0}},{"line":106,"address":[793477],"length":1,"stats":{"Line":0}},{"line":108,"address":[796412,797123,796708,796281,796145,796940],"length":1,"stats":{"Line":0}},{"line":111,"address":[798540,797168],"length":1,"stats":{"Line":0}},{"line":112,"address":[797223],"length":1,"stats":{"Line":0}},{"line":113,"address":[797601,797705,797519],"length":1,"stats":{"Line":0}},{"line":114,"address":[797726,797824],"length":1,"stats":{"Line":0}},{"line":115,"address":[798108,797939],"length":1,"stats":{"Line":0}},{"line":116,"address":[798028],"length":1,"stats":{"Line":0}},{"line":117,"address":[798062],"length":1,"stats":{"Line":0}},{"line":118,"address":[798148],"length":1,"stats":{"Line":0}},{"line":119,"address":[798184,798225],"length":1,"stats":{"Line":0}},{"line":120,"address":[798227],"length":1,"stats":{"Line":0}},{"line":122,"address":[798212],"length":1,"stats":{"Line":0}},{"line":125,"address":[798454],"length":1,"stats":{"Line":0}},{"line":134,"address":[798576],"length":1,"stats":{"Line":0}},{"line":135,"address":[798609],"length":1,"stats":{"Line":0}},{"line":137,"address":[798643,798856],"length":1,"stats":{"Line":0}},{"line":138,"address":[798969],"length":1,"stats":{"Line":0}},{"line":139,"address":[814328,814270],"length":1,"stats":{"Line":0}},{"line":140,"address":[814717,814899,814469,814339],"length":1,"stats":{"Line":0}},{"line":144,"address":[798798],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":63},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmasdl2","src","bin","support","mod.rs"],"content":"pub mod timestep;\npub mod gemma_egui_support;\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmasdl2","src","bin","support","timestep.rs"],"content":"\n//! Gameplay speed control. It attempts to mimic/limit progression to\n//! the 30 tics per second Doom used.\n\nuse std::{fmt, time::Instant};\n\nconst MS_PER_UPDATE: f32 = 28.57;\n\n#[derive(Debug)]\npub struct TimeStep {\n last_time: Instant,\n delta_time: f32,\n frame_count: u32,\n frame_time: f32,\n run_tics: u32,\n last_tics: u32,\n lag: f32,\n}\n\n#[derive(Debug)]\npub struct FrameData {\n pub tics: u32,\n pub frames: u32,\n}\n\nimpl fmt::Display for FrameData {\n fn fmt(\u0026self, f: \u0026mut fmt::Formatter\u003c'_\u003e) -\u003e fmt::Result {\n f.write_fmt(format_args!(\n \"FrameData (per-second):\\n - tics: {}\\n - fps: {}\",\n self.tics, self.frames\n ))\n }\n}\n\nimpl TimeStep {\n pub fn new() -\u003e TimeStep {\n TimeStep {\n last_time: Instant::now(),\n delta_time: 0.0,\n frame_count: 0,\n frame_time: 0.0,\n run_tics: 0,\n last_tics: 0,\n lag: 0.0,\n }\n }\n\n pub fn delta(\u0026mut self) -\u003e f32 {\n let current_time = Instant::now();\n let delta = current_time.duration_since(self.last_time).as_micros() as f32 * 0.001;\n self.last_time = current_time;\n self.delta_time = delta;\n delta\n }\n\n /// Increments self time and returns current lag. `run_this` is run only for\n /// `n` tics available.\n pub fn run_this(\u0026mut self, mut run_this: impl FnMut(f32)) {\n let dt = self.delta();\n self.lag += dt;\n while self.lag \u003e= MS_PER_UPDATE {\n run_this(dt);\n self.lag -= MS_PER_UPDATE;\n self.run_tics += 1;\n }\n }\n\n pub fn frame_rate(\u0026mut self) -\u003e Option\u003cFrameData\u003e {\n self.frame_count += 1;\n self.frame_time += self.delta_time;\n let tmp;\n let tmp2;\n // per second\n if self.frame_time \u003e= 1000.0 {\n tmp = self.frame_count;\n tmp2 = self.last_tics;\n self.frame_count = 0;\n self.frame_time = 0.0;\n self.last_tics = self.run_tics;\n return Some(FrameData {\n tics: self.run_tics - tmp2,\n frames: tmp,\n });\n }\n\n None\n }\n}\n\nimpl Default for TimeStep {\n // shutup clippy!\n fn default() -\u003e Self {\n Self::new()\n }\n}","traces":[{"line":27,"address":[830752],"length":1,"stats":{"Line":0}},{"line":28,"address":[830940,830856],"length":1,"stats":{"Line":0}},{"line":36,"address":[831040],"length":1,"stats":{"Line":0}},{"line":38,"address":[831054],"length":1,"stats":{"Line":0}},{"line":48,"address":[831136],"length":1,"stats":{"Line":0}},{"line":49,"address":[831149],"length":1,"stats":{"Line":0}},{"line":50,"address":[831171],"length":1,"stats":{"Line":0}},{"line":51,"address":[831247],"length":1,"stats":{"Line":0}},{"line":52,"address":[831262],"length":1,"stats":{"Line":0}},{"line":58,"address":[],"length":0,"stats":{"Line":0}},{"line":59,"address":[],"length":0,"stats":{"Line":0}},{"line":60,"address":[],"length":0,"stats":{"Line":0}},{"line":61,"address":[],"length":0,"stats":{"Line":0}},{"line":62,"address":[],"length":0,"stats":{"Line":0}},{"line":63,"address":[],"length":0,"stats":{"Line":0}},{"line":64,"address":[],"length":0,"stats":{"Line":0}},{"line":68,"address":[831280],"length":1,"stats":{"Line":0}},{"line":69,"address":[831304,831366],"length":1,"stats":{"Line":0}},{"line":70,"address":[831331],"length":1,"stats":{"Line":0}},{"line":74,"address":[831346],"length":1,"stats":{"Line":0}},{"line":75,"address":[831400],"length":1,"stats":{"Line":0}},{"line":76,"address":[831410],"length":1,"stats":{"Line":0}},{"line":77,"address":[831417],"length":1,"stats":{"Line":0}},{"line":78,"address":[831424],"length":1,"stats":{"Line":0}},{"line":79,"address":[831432],"length":1,"stats":{"Line":0}},{"line":80,"address":[831477],"length":1,"stats":{"Line":0}},{"line":81,"address":[831491,831438],"length":1,"stats":{"Line":0}},{"line":86,"address":[831387],"length":1,"stats":{"Line":0}},{"line":92,"address":[831520],"length":1,"stats":{"Line":0}},{"line":93,"address":[831528],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":30},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmatelnet","src","bin","gemmatelnetd.rs"],"content":"fn main() {\n println!(\"Taxation is Theft\");\n}","traces":[{"line":1,"address":[116192,116144],"length":1,"stats":{"Line":1}},{"line":2,"address":[116148],"length":1,"stats":{"Line":0}}],"covered":1,"coverable":2},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmautil","src","bin","bin2hex.rs"],"content":"use std::fs::File;\nuse std::io;\nuse std::io::{BufReader, Read};\nuse clap::{Arg, Command, ArgAction, ValueEnum};\n\n#[derive(Debug)]\nstruct CliArgs {\n input: String,\n}\n\nfn main() {\n println!(\"Taxation is Theft!\");\n // Set up the command line arguments\n let matches = Command::new(\"my_program\")\n .about(\"Processes an input file and outputs it with a specified bit width\")\n .arg(\n Arg::new(\"input\")\n .help(\"The input file to process\")\n .required(true)\n .index(1),\n )\n\n .get_matches();\n\n // Parse the command-line arguments\n let args = CliArgs {\n input: matches.get_one::\u003cString\u003e(\"input\").unwrap().to_string(),\n };\n\n // Use the parsed arguments\n println!(\"Input file: {}\", args.input);\n\n // behave like a shift register and load each character from the file 1 by 1.\n let results = read_file_to_bools(\u0026args.input);\n for result in results.unwrap().bytes() {\n print!(\"0x{:02x}, \", result.unwrap());\n }\n}\nfn read_file_to_bools(file_path: \u0026str) -\u003e io::Result\u003cVec\u003cu8\u003e\u003e {\n // Open the file\n let file = File::open(file_path)?;\n let mut reader = BufReader::new(file);\n\n let mut bytes = Vec::new();\n reader.read_to_end(\u0026mut bytes)?;\n\n let mut output = Vec::new();\n let mut current_byte = 0u8;\n let mut bit_index = 0;\n\n for \u0026byte in \u0026bytes {\n // Convert ASCII character '1' or '0' to boolean, skip any other characters\n let bit = match byte {\n b'1' =\u003e true,\n b'0' =\u003e false,\n _ =\u003e continue, // Skip non-'1' or '0' characters\n };\n\n // Set the appropriate bit in the current byte\n if bit {\n current_byte |= 1 \u003c\u003c (7 - bit_index); // Set the bit at the correct position\n }\n\n bit_index += 1;\n\n // Once we have filled 8 bits, push the byte and reset\n if bit_index == 8 {\n output.push(current_byte);\n current_byte = 0;\n bit_index = 0;\n }\n }\n\n // If there are remaining bits, push the last byte (it will be partially filled)\n if bit_index \u003e 0 {\n output.push(current_byte);\n }\n\n\n\n Ok(output)\n}\n\n","traces":[{"line":11,"address":[250928,253074],"length":1,"stats":{"Line":0}},{"line":12,"address":[250950],"length":1,"stats":{"Line":0}},{"line":14,"address":[251256,251331,251007],"length":1,"stats":{"Line":0}},{"line":17,"address":[251089,251161],"length":1,"stats":{"Line":0}},{"line":27,"address":[251344,251513],"length":1,"stats":{"Line":0}},{"line":31,"address":[251740],"length":1,"stats":{"Line":0}},{"line":34,"address":[251817],"length":1,"stats":{"Line":0}},{"line":35,"address":[252086,252329,252189],"length":1,"stats":{"Line":0}},{"line":36,"address":[252965,252584,252701],"length":1,"stats":{"Line":0}},{"line":39,"address":[254208,254264,253120],"length":1,"stats":{"Line":0}},{"line":41,"address":[253153,253251],"length":1,"stats":{"Line":0}},{"line":42,"address":[253219],"length":1,"stats":{"Line":0}},{"line":44,"address":[253330],"length":1,"stats":{"Line":0}},{"line":45,"address":[253390,253458,253552],"length":1,"stats":{"Line":0}},{"line":47,"address":[253540],"length":1,"stats":{"Line":0}},{"line":48,"address":[253585],"length":1,"stats":{"Line":0}},{"line":49,"address":[253593],"length":1,"stats":{"Line":0}},{"line":51,"address":[253777,253612,253683],"length":1,"stats":{"Line":0}},{"line":53,"address":[253798],"length":1,"stats":{"Line":0}},{"line":54,"address":[253966],"length":1,"stats":{"Line":0}},{"line":55,"address":[253976],"length":1,"stats":{"Line":0}},{"line":60,"address":[254093,253984],"length":1,"stats":{"Line":0}},{"line":61,"address":[254014,254095],"length":1,"stats":{"Line":0}},{"line":64,"address":[253994,254117,254139],"length":1,"stats":{"Line":0}},{"line":67,"address":[254203,254124],"length":1,"stats":{"Line":0}},{"line":68,"address":[254157],"length":1,"stats":{"Line":0}},{"line":69,"address":[254184],"length":1,"stats":{"Line":0}},{"line":70,"address":[254192],"length":1,"stats":{"Line":0}},{"line":75,"address":[253765],"length":1,"stats":{"Line":0}},{"line":76,"address":[253901],"length":1,"stats":{"Line":0}},{"line":81,"address":[253827],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":31},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmautil","src","bin","ch8asm.rs"],"content":"use std::fs;\n// Ch8Asm\n// Converts well formed CH8ASM.\n// no variables.\n// no labels.\n// nothing fun.\nuse pest::Parser;\nuse pest_derive::Parser;\n\n#[derive(Parser)]\n#[grammar = \"chip8_asm.pest\"]\npub struct Chip8AsmParser;\n\nfn main() {\n println!(\"Taxation is Theft\");\n\n\n\n let unparsed = fs::read_to_string(\"resources/test/gemma_disassembler_1_chip_logo_ch8_asm.asc\").expect(\"Unable to read input\");\n\n let file = Chip8AsmParser::parse(Rule::file, \u0026unparsed).expect(\"Unable to parse. Try again.\")\n .next().unwrap();\n\n for record in file.into_inner() {\n match record.as_rule() {\n Rule::instruction =\u003e {\n println!(\"INSTRUCTION = {:?}\", record.into_inner().flatten())\n }\n _ =\u003e {\n println!(\"UNHANDLED PART.\");\n }\n }\n }\n}\n\nmod test {\n use super::*;\n\n #[test]\n fn bits_all_parse() {\n println!(\"PARSED: {:?}\",\n Chip8AsmParser::parse(Rule::instruction, \"CLS\")\n );\n println!(\"PARSED: {:?}\",\n Chip8AsmParser::parse(Rule::parameter, \"0x01\")\n );\n let parsed = Chip8AsmParser::parse(Rule::comment, \"; comment\").unwrap();\n for i in parsed {\n println!(\"PARSED COMMENT -\u003e {:?}\", i);\n }\n\n let parsed =\n Chip8AsmParser::parse(Rule::record, \"CLS ; comment\").unwrap();\n for i in parsed {\n println!(\"RULE PAIR THING: {:?}\", i);\n }\n\n let parsed = Chip8AsmParser::parse(Rule::record, \"ADDI 0x01 ; comment\");\n for i in parsed {\n println!(\"RULE PAIR THING: {:?}\", i);\n }\n\n println!(\"PARSED: {:?}\",\n Chip8AsmParser::parse(Rule::record, \"ADD ADD ADD\")\n );\n\n println!(\"PARSED: {:?}\",\n Chip8AsmParser::parse(Rule::record, \"ADD 0x01 0x02 ; Comment\")\n );\n\n println!(\"PARSED: {:?}\",\n Chip8AsmParser::parse(Rule::record, \"ADD 0x01 0x02 ; Comment\")\n );\n }\n}","traces":[{"line":14,"address":[201921,200576,201827],"length":1,"stats":{"Line":0}},{"line":15,"address":[200583],"length":1,"stats":{"Line":0}},{"line":19,"address":[200639],"length":1,"stats":{"Line":0}},{"line":21,"address":[200710,200786],"length":1,"stats":{"Line":0}},{"line":24,"address":[201280,201865,201236,201045],"length":1,"stats":{"Line":0}},{"line":25,"address":[201344,201427],"length":1,"stats":{"Line":0}},{"line":27,"address":[201572,201448,201699],"length":1,"stats":{"Line":0}},{"line":30,"address":[201836,201527],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":8},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmautil","src","bin","ch8disasm.rs"],"content":"use std::path::Path;\nuse clap::{command, Parser};\nuse gemma::chip8::instructions::Chip8CpuInstructions;\nuse gemma::chip8::instructions::Chip8CpuInstructions::XXXXERRORINSTRUCTION;\nuse gemma::chip8::quirk_modes::QuirkMode::Chip8;\n\n/// ch8disasm\n///\n/// Provide disassembled version of the CH8 file provided.\n#[derive(Parser)]\n#[command(version, about, long_about = None)]\nstruct DisassemblerApp {\n #[arg(short)]\n input_file: Box\u003cPath\u003e,\n #[arg(short)]\n output_file: Option\u003cBox\u003cPath\u003e\u003e,\n}\n\nstruct Disassembler {}\nimpl Disassembler {\n pub fn disassemble(from_data: Vec\u003cu8\u003e) -\u003e String {\n let mut working_instruction: u16 = 0x0000;\n\n // read the input data and loop through it byte by byte.\n let mut output_string = String::new();\n\n for (offset, byte) in from_data.iter().enumerate() {\n working_instruction = (working_instruction \u003c\u003c 8) | (*byte as u16);\n if offset % 2 != 0 {\n let decoded = Chip8CpuInstructions::decode(working_instruction, \u0026Chip8);\n let decoded_string = decoded.to_string();\n let mut current_parts = String::new();\n\n match decoded {\n XXXXERRORINSTRUCTION =\u003e {\n current_parts = format!(\"DW 0x{:04x}\", working_instruction);\n }\n _ =\u003e {\n current_parts = format!(\"{}\", decoded);\n }\n };\n\n let target_length: i32 = 25;\n let spacing_length = target_length.saturating_sub(current_parts.len() as i32);\n\n // now add the rest after the string\n let x = spacing_length as usize;\n current_parts = format!(\"{}{:\u003cx$}; Bytes [0x{:04x}] offset [0x{:04x}]\\n\", current_parts, \" \", working_instruction, offset -1);\n // println!(\"SHOULD OUTPUT: [{current_parts}]\");\n output_string = output_string.to_string() + \u0026*current_parts.to_string();\n\n working_instruction = 0x0000;\n }\n }\n\n output_string\n }\n}\n\nfn main() {\n println!(\"Taxation is Theft\");\n let result = DisassemblerApp::parse();\n println!(\"PREPARING TO DISASSEMBLE {:?}\", result.input_file.file_name());\n\n\n let source_file = result.input_file.to_str().unwrap();\n let decompiled_program = Disassembler::disassemble(\n std::fs::read(source_file).unwrap()\n );\n\n\n match result.output_file {\n None =\u003e {\n println!(\"Output to console.\");\n println!(\"OS: \\n\\n{}\", decompiled_program);\n }\n Some(target) =\u003e {\n println!(\"Output to {:?}\", target);\n std::fs::write(target, decompiled_program).unwrap();\n }\n }\n}\n\nmod test {\n #[test]\n fn smoke() { assert!(true); }\n\n #[test]\n fn assemble_test_file() {\n\n }\n}","traces":[{"line":21,"address":[433120,428704],"length":1,"stats":{"Line":0}},{"line":22,"address":[428746],"length":1,"stats":{"Line":0}},{"line":25,"address":[428772],"length":1,"stats":{"Line":0}},{"line":27,"address":[428903,428831,429185],"length":1,"stats":{"Line":0}},{"line":28,"address":[429227],"length":1,"stats":{"Line":0}},{"line":29,"address":[429273],"length":1,"stats":{"Line":0}},{"line":30,"address":[429287],"length":1,"stats":{"Line":0}},{"line":31,"address":[429358],"length":1,"stats":{"Line":0}},{"line":32,"address":[429373],"length":1,"stats":{"Line":0}},{"line":34,"address":[429424],"length":1,"stats":{"Line":0}},{"line":36,"address":[430130,429712,429976],"length":1,"stats":{"Line":0}},{"line":38,"address":[430558],"length":1,"stats":{"Line":0}},{"line":39,"address":[430295,430416],"length":1,"stats":{"Line":0}},{"line":43,"address":[428735],"length":1,"stats":{"Line":0}},{"line":44,"address":[430280,430568,430636],"length":1,"stats":{"Line":0}},{"line":47,"address":[430643],"length":1,"stats":{"Line":0}},{"line":48,"address":[431224,432547,432300,430985,432068,431604,431836,431128],"length":1,"stats":{"Line":0}},{"line":50,"address":[432689,433079],"length":1,"stats":{"Line":0}},{"line":52,"address":[433028],"length":1,"stats":{"Line":0}},{"line":56,"address":[429128],"length":1,"stats":{"Line":0}},{"line":60,"address":[435019,434949,433152],"length":1,"stats":{"Line":0}},{"line":61,"address":[433159],"length":1,"stats":{"Line":0}},{"line":62,"address":[433223],"length":1,"stats":{"Line":0}},{"line":63,"address":[433351,433244,433477],"length":1,"stats":{"Line":0}},{"line":66,"address":[433546,433698],"length":1,"stats":{"Line":0}},{"line":68,"address":[433714],"length":1,"stats":{"Line":0}},{"line":72,"address":[433991],"length":1,"stats":{"Line":0}},{"line":74,"address":[434020,434253],"length":1,"stats":{"Line":0}},{"line":75,"address":[434382],"length":1,"stats":{"Line":0}},{"line":77,"address":[434049],"length":1,"stats":{"Line":0}},{"line":78,"address":[434533],"length":1,"stats":{"Line":0}},{"line":79,"address":[434602],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":32},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmautil","tests","assmber_tests.rs"],"content":"#[test]\nfn smoke() { assert!(true) }\n\n","traces":[],"covered":0,"coverable":0}]};
|
|
var previousData = {"files":[{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","computer.rs"],"content":"use log::{debug};\nuse crate::chip8::delay_timer::DelayTimer;\nuse crate::chip8::keypad::Keypad;\nuse crate::chip8::quirk_modes::QuirkMode;\nuse crate::chip8::quirk_modes::QuirkMode::Chip8;\nuse crate::chip8::registers::Chip8Registers;\nuse crate::chip8::sound_timer::SoundTimer;\nuse crate::chip8::stack::Chip8Stack;\n\nuse super::{\n cpu_states::Chip8CpuStates, instructions::Chip8CpuInstructions, system_memory::Chip8SystemMemory, video::Chip8Video,\n};\n\n#[derive(Clone)]\npub struct Chip8Computer {\n pub num_cycles: i32,\n pub memory: Chip8SystemMemory,\n pub registers: Chip8Registers,\n pub sound_timer: SoundTimer,\n pub delay_timer: DelayTimer,\n pub video_memory: Chip8Video,\n pub state: Chip8CpuStates,\n pub keypad: Keypad,\n pub stack: Chip8Stack,\n pub quirk_mode: QuirkMode\n}\nimpl Default for Chip8Computer {\n fn default() -\u003e Self {\n Self {\n num_cycles: 0,\n memory: Chip8SystemMemory::default(),\n video_memory: Chip8Video::default(),\n registers: Chip8Registers::default(),\n sound_timer: SoundTimer::new(),\n delay_timer: DelayTimer::new(),\n state: Chip8CpuStates::default(),\n keypad: Keypad::default(),\n stack: Chip8Stack::default(),\n quirk_mode: QuirkMode::default()\n }\n }\n}\n\nimpl Chip8Computer {\n pub fn reset(\u0026mut self) {\n self.video_memory.reset();\n self.num_cycles = 0;\n self.registers.reset();\n self.delay_timer.reset();\n self.sound_timer.reset();\n self.stack.reset();\n self.memory.reset();\n self.quirk_mode = QuirkMode::Chip8;\n }\n\n pub fn dump_keypad_to_string(\u0026self) -\u003e String {\n self.keypad.format_as_string()\n }\n\n pub fn dump_registers_to_string(\u0026self) -\u003e String {\n self.registers.format_as_string()\n }\n\n pub fn dump_video_to_string(\u0026self) -\u003e String {\n self.clone().video_memory.format_as_string()\n }\n\n pub fn new_with_program(new_program: Vec\u003cu16\u003e) -\u003e Self {\n let mut working = Chip8Computer::new();\n\n for (i, \u0026word) in new_program.iter().enumerate() {\n let high = (word \u003e\u003e 8) as u8;\n let low = (word \u0026 0xff) as u8;\n let base_offset = (i * 2) as u16;\n working.memory.poke(base_offset, high);\n working.memory.poke(base_offset + 1, low);\n }\n working\n }\n pub fn new() -\u003e Self {\n Chip8Computer::default()\n }\n\n pub fn load_bytes_to_memory(\u0026mut self, offset: u16, to_load: \u0026Vec\u003cu8\u003e) {\n let total_len = to_load.len() as u16;\n for current_index in 0..total_len {\n let new_value = to_load[current_index as usize];\n let new_location = current_index + offset;\n self.memory.poke(new_location, new_value);\n }\n self.registers.set_pc(offset);\n }\n\n pub fn step_system(\u0026mut self) -\u003e \u0026mut Chip8Computer {\n debug!(\"Stepping System 1 Step\");\n // read the next instruction\n let local_memory = \u0026self.memory;\n\n // let mut working_instruction: u16 = 0b0000000000000000;\n let start_pc = self.registers.peek_pc();\n let high_byte = (local_memory.peek(start_pc) as u16).rotate_left(8);\n let low_byte = local_memory.peek(start_pc + 1) as u16;\n let result = high_byte | low_byte;\n let decoded_instruction =\n Chip8CpuInstructions::decode(result, \u0026self.quirk_mode);\n // todo: THIS IS BAD AND IS A SIDE EFFECT\n decoded_instruction.execute(self);\n\n match self.state {\n Chip8CpuStates::WaitingForInstruction =\u003e {\n self.sound_timer.tick();\n self.delay_timer.tick();\n self.video_memory.tick();\n self.num_cycles += 1;\n }\n Chip8CpuStates::WaitingForKey =\u003e {\n debug!(\"waiting for a key press...\");\n }\n _ =\u003e {}\n }\n self\n }\n}\n","traces":[{"line":27,"address":[841408,841918],"length":1,"stats":{"Line":6}},{"line":30,"address":[3563840],"length":1,"stats":{"Line":5}},{"line":31,"address":[841454],"length":1,"stats":{"Line":4}},{"line":32,"address":[3563871],"length":1,"stats":{"Line":3}},{"line":33,"address":[376350],"length":1,"stats":{"Line":6}},{"line":34,"address":[777997],"length":1,"stats":{"Line":3}},{"line":35,"address":[3563964],"length":1,"stats":{"Line":6}},{"line":36,"address":[42137255],"length":1,"stats":{"Line":4}},{"line":37,"address":[602778],"length":1,"stats":{"Line":7}},{"line":38,"address":[1160237],"length":1,"stats":{"Line":3}},{"line":44,"address":[376736],"length":1,"stats":{"Line":1}},{"line":45,"address":[3564365],"length":1,"stats":{"Line":1}},{"line":46,"address":[778423],"length":1,"stats":{"Line":1}},{"line":47,"address":[376768],"length":1,"stats":{"Line":1}},{"line":48,"address":[778450],"length":1,"stats":{"Line":1}},{"line":49,"address":[3564419],"length":1,"stats":{"Line":1}},{"line":50,"address":[42137716],"length":1,"stats":{"Line":1}},{"line":51,"address":[3564450],"length":1,"stats":{"Line":1}},{"line":52,"address":[376842],"length":1,"stats":{"Line":1}},{"line":55,"address":[42137776],"length":1,"stats":{"Line":0}},{"line":56,"address":[603297],"length":1,"stats":{"Line":0}},{"line":59,"address":[1160768],"length":1,"stats":{"Line":1}},{"line":60,"address":[376929],"length":1,"stats":{"Line":1}},{"line":63,"address":[1160952,1160816],"length":1,"stats":{"Line":2}},{"line":64,"address":[377009],"length":1,"stats":{"Line":2}},{"line":67,"address":[3564752,3565438],"length":1,"stats":{"Line":0}},{"line":68,"address":[778837],"length":1,"stats":{"Line":0}},{"line":70,"address":[842520,842451,842773],"length":1,"stats":{"Line":0}},{"line":71,"address":[42138508],"length":1,"stats":{"Line":0}},{"line":72,"address":[604030],"length":1,"stats":{"Line":0}},{"line":73,"address":[779377,779310],"length":1,"stats":{"Line":0}},{"line":74,"address":[377644],"length":1,"stats":{"Line":0}},{"line":75,"address":[604138],"length":1,"stats":{"Line":0}},{"line":77,"address":[603918],"length":1,"stats":{"Line":0}},{"line":79,"address":[779520],"length":1,"stats":{"Line":5}},{"line":80,"address":[779528],"length":1,"stats":{"Line":5}},{"line":83,"address":[42138784],"length":1,"stats":{"Line":1}},{"line":84,"address":[604333],"length":1,"stats":{"Line":4}},{"line":85,"address":[843160,843249],"length":1,"stats":{"Line":5}},{"line":86,"address":[604448],"length":1,"stats":{"Line":1}},{"line":87,"address":[42139040,42138985],"length":1,"stats":{"Line":4}},{"line":88,"address":[843339],"length":1,"stats":{"Line":1}},{"line":90,"address":[604407],"length":1,"stats":{"Line":4}},{"line":93,"address":[843376],"length":1,"stats":{"Line":1}},{"line":94,"address":[1162035,1162250],"length":1,"stats":{"Line":5}},{"line":96,"address":[42139131],"length":1,"stats":{"Line":4}},{"line":99,"address":[843471],"length":1,"stats":{"Line":1}},{"line":100,"address":[42139245,42139182],"length":1,"stats":{"Line":8}},{"line":101,"address":[843779,843573,843942],"length":1,"stats":{"Line":5}},{"line":102,"address":[780258],"length":1,"stats":{"Line":1}},{"line":103,"address":[42139506],"length":1,"stats":{"Line":4}},{"line":106,"address":[605045],"length":1,"stats":{"Line":1}},{"line":108,"address":[843910],"length":1,"stats":{"Line":1}},{"line":109,"address":[780544],"length":1,"stats":{"Line":1}},{"line":110,"address":[3566376],"length":1,"stats":{"Line":4}},{"line":111,"address":[378694],"length":1,"stats":{"Line":1}},{"line":112,"address":[1162636],"length":1,"stats":{"Line":4}},{"line":113,"address":[378721,378799,378788],"length":1,"stats":{"Line":5}},{"line":116,"address":[3566442,3566545],"length":1,"stats":{"Line":2}}],"covered":48,"coverable":59},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","computer_manager.rs"],"content":"use std::sync::mpsc::{channel, Sender};\nuse std::thread;\nuse std::thread::{sleep, JoinHandle, Thread};\nuse std::time::{Duration, Instant};\nuse crate::chip8::computer::Chip8Computer;\nuse crate::chip8::cpu_states::Chip8CpuStates;\nuse crate::chip8::cpu_states::Chip8CpuStates::WaitingForInstruction;\npub enum ManagerDumpables {\n Video,\n Registers,\n Keyboard\n}\n\npub struct Chip8ComputerManager {\n core_should_run: bool,\n one_step: bool,\n core_cycle_timer: bool,\n core_last_cycle_start: Instant,\n computer: Chip8Computer\n}\n\nimpl Default for Chip8ComputerManager {\n fn default() -\u003e Self {\n Chip8ComputerManager {\n core_should_run: false,\n one_step: false,\n core_cycle_timer: false,\n core_last_cycle_start: Instant::now() ,\n computer: Chip8Computer::new()\n }\n }\n}\n\nimpl Chip8ComputerManager {\n pub fn reset(\u0026mut self) {\n self.one_step = false;\n self.core_should_run = false;\n self.computer.reset();\n }\n pub fn new() -\u003e Chip8ComputerManager {\n let core_handle = thread::spawn(move || {\n loop {\n let start_time = Instant::now();\n let sleep_time = Instant::now().duration_since(start_time).as_millis();\n sleep(Duration::from_millis((16 - sleep_time) as u64));\n }\n });\n\n Chip8ComputerManager::default()\n }\n\n pub fn start(\u0026mut self) {\n self.core_should_run = true;\n }\n\n pub fn stop(\u0026mut self) {\n self.core_should_run = false\n }\n\n pub fn step(\u0026mut self) {\n self.one_step = true;\n }\n\n pub fn state(\u0026mut self) -\u003e \u0026Chip8Computer {\n \u0026self.computer\n }\n\n pub fn tick( \u0026mut self) -\u003e bool {\n // println!(\"STARTING TICK\");\n let mut did_tick: bool = false;\n if self.one_step | self.core_should_run {\n match self.computer.state {\n WaitingForInstruction =\u003e {\n self.core_last_cycle_start = Instant::now();\n self.computer.step_system();\n did_tick = true\n // println!(\"SYSTEM STEP\");\n }\n _ =\u003e {}\n }\n };\n if self.one_step {\n println!(\"SYSTEM HALTED AFTER 1 STEP\");\n // stop the CPU for the next cycle, we are only\n // wanting one step.\n self.one_step = false;\n did_tick = true;\n }\n did_tick\n }\n\n pub fn press_key(\u0026mut self, key_index: u8) {\n self.computer.keypad.push_key(key_index);\n if matches!(self.computer.state, Chip8CpuStates::WaitingForKey) {\n self.computer.state = WaitingForInstruction\n }\n }\n pub fn release_key(\u0026mut self, key_index: u8) {\n self.computer.keypad.release_key(key_index);\n }\n\n pub fn sound(managed: \u0026Chip8ComputerManager) -\u003e bool {\n managed.computer.sound_timer.current() \u003e 0\n }\n\n pub fn wait_for_instruction(\u0026mut self) {\n self.computer.state = WaitingForInstruction;\n }\n\n pub fn is_key_pressed(\u0026self, key_index: u8) -\u003e bool {\n self.computer.keypad.pressed(key_index)\n }\n\n pub fn num_cycles(\u0026self) -\u003e i32 {\n self.computer.num_cycles\n }\n\n pub fn load_bytes_to_system_memory(\u0026mut self, bytes_to_load: Vec\u003cu8\u003e) {\n self.computer.load_bytes_to_memory(0x200, \u0026bytes_to_load);\n }\n\n pub fn dump_to_string(\u0026self, dump_type: ManagerDumpables) -\u003e String {\n match dump_type {\n ManagerDumpables::Video =\u003e {\n self.computer.video_memory.format_as_string()\n }\n ManagerDumpables::Registers =\u003e {\n self.computer.registers.format_as_string()\n }\n ManagerDumpables::Keyboard =\u003e {\n self.computer.keypad.format_as_string()\n }\n }\n }\n}","traces":[{"line":23,"address":[314752],"length":1,"stats":{"Line":0}},{"line":28,"address":[3535296],"length":1,"stats":{"Line":0}},{"line":29,"address":[314798],"length":1,"stats":{"Line":0}},{"line":35,"address":[42109872],"length":1,"stats":{"Line":0}},{"line":36,"address":[42109877],"length":1,"stats":{"Line":0}},{"line":37,"address":[3535420],"length":1,"stats":{"Line":0}},{"line":38,"address":[314915],"length":1,"stats":{"Line":0}},{"line":40,"address":[42109999,42109904],"length":1,"stats":{"Line":0}},{"line":41,"address":[830192],"length":1,"stats":{"Line":0}},{"line":43,"address":[3556340],"length":1,"stats":{"Line":0}},{"line":44,"address":[42132428],"length":1,"stats":{"Line":0}},{"line":45,"address":[3556458],"length":1,"stats":{"Line":0}},{"line":49,"address":[3535472],"length":1,"stats":{"Line":0}},{"line":52,"address":[42110032],"length":1,"stats":{"Line":0}},{"line":53,"address":[42110037],"length":1,"stats":{"Line":0}},{"line":56,"address":[42110048],"length":1,"stats":{"Line":0}},{"line":57,"address":[42110053],"length":1,"stats":{"Line":0}},{"line":60,"address":[3535600],"length":1,"stats":{"Line":0}},{"line":61,"address":[42110069],"length":1,"stats":{"Line":0}},{"line":64,"address":[42110080],"length":1,"stats":{"Line":0}},{"line":68,"address":[3535632],"length":1,"stats":{"Line":0}},{"line":70,"address":[3535645],"length":1,"stats":{"Line":0}},{"line":71,"address":[3535650],"length":1,"stats":{"Line":0}},{"line":72,"address":[315159],"length":1,"stats":{"Line":0}},{"line":74,"address":[3535700],"length":1,"stats":{"Line":0}},{"line":75,"address":[3535723],"length":1,"stats":{"Line":0}},{"line":76,"address":[315200],"length":1,"stats":{"Line":0}},{"line":82,"address":[3535792,3535672],"length":1,"stats":{"Line":0}},{"line":83,"address":[3535747],"length":1,"stats":{"Line":0}},{"line":86,"address":[3535780],"length":1,"stats":{"Line":0}},{"line":87,"address":[42110251],"length":1,"stats":{"Line":0}},{"line":89,"address":[42110200],"length":1,"stats":{"Line":0}},{"line":92,"address":[315280],"length":1,"stats":{"Line":0}},{"line":93,"address":[42110293],"length":1,"stats":{"Line":0}},{"line":94,"address":[42110311],"length":1,"stats":{"Line":0}},{"line":95,"address":[315336],"length":1,"stats":{"Line":0}},{"line":98,"address":[42110352],"length":1,"stats":{"Line":0}},{"line":99,"address":[3535904],"length":1,"stats":{"Line":0}},{"line":102,"address":[42110400],"length":1,"stats":{"Line":0}},{"line":103,"address":[3535941],"length":1,"stats":{"Line":0}},{"line":106,"address":[3535968],"length":1,"stats":{"Line":0}},{"line":107,"address":[315445],"length":1,"stats":{"Line":0}},{"line":110,"address":[3536000],"length":1,"stats":{"Line":0}},{"line":111,"address":[3536016],"length":1,"stats":{"Line":0}},{"line":114,"address":[3536048],"length":1,"stats":{"Line":0}},{"line":115,"address":[3536053],"length":1,"stats":{"Line":0}},{"line":118,"address":[3536145,3536064],"length":1,"stats":{"Line":0}},{"line":119,"address":[3536081],"length":1,"stats":{"Line":0}},{"line":122,"address":[3536176],"length":1,"stats":{"Line":0}},{"line":123,"address":[42110670],"length":1,"stats":{"Line":0}},{"line":125,"address":[3536250],"length":1,"stats":{"Line":0}},{"line":128,"address":[3536268],"length":1,"stats":{"Line":0}},{"line":131,"address":[3536293],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":53},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","cpu_states.rs"],"content":"#[derive(Clone, Copy, Default)]\npub enum Chip8CpuStates {\n #[default]\n WaitingForInstruction,\n WaitingForKey,\n ExecutingInstruction,\n Error,\n}\n\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","delay_timer.rs"],"content":"#[derive(Clone, Copy)]\npub struct DelayTimer {\n counter: u8\n}\n\nimpl DelayTimer {\n pub fn current(\u0026self) -\u003e u8 {\n self.counter\n }\n\n pub fn new() -\u003e Self {\n DelayTimer {\n counter: 0xff\n }\n }\n\n pub fn reset(\u0026mut self) {\n self.counter = 0xff;\n }\n\n pub fn set_timer(\u0026mut self, new_value: u8) {\n self.counter = new_value as u8\n }\n\n pub fn tick(\u0026mut self) {\n if self.counter \u003e 0 {\n self.counter -= 1;\n }\n }\n}\n","traces":[{"line":7,"address":[725344],"length":1,"stats":{"Line":1}},{"line":8,"address":[290229],"length":1,"stats":{"Line":1}},{"line":17,"address":[290256],"length":1,"stats":{"Line":1}},{"line":18,"address":[636437],"length":1,"stats":{"Line":1}},{"line":21,"address":[1185552],"length":1,"stats":{"Line":2}},{"line":22,"address":[1185564],"length":1,"stats":{"Line":2}},{"line":25,"address":[831888],"length":1,"stats":{"Line":6}},{"line":26,"address":[3571111,3571070],"length":1,"stats":{"Line":5}},{"line":27,"address":[3571085,3571113],"length":1,"stats":{"Line":5}}],"covered":9,"coverable":9},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","instructions.rs"],"content":"use std::arch::x86_64::_mm_xor_pd;\nuse std::fmt::{Debug, Display, Formatter};\nuse std::ops::{BitAnd, Deref, Shr};\nuse std::time::Instant;\nuse chrono::ParseMonthError;\nuse log::debug;\nuse rand::{random, Rng};\nuse crate::chip8::computer::{Chip8Computer};\nuse crate::chip8::cpu_states::Chip8CpuStates::WaitingForKey;\nuse crate::chip8::instructions::Chip8CpuInstructions::*;\nuse crate::chip8::quirk_modes::QuirkMode;\nuse crate::chip8::util::InstructionUtil;\nuse crate::constants::{*};\n\n/*\nnnn or addr - A 12-bit value, the lowest 12 bits of the instruction\nn or nibble - A 4-bit value, the lowest 4 bits of the instruction\nx - A 4-bit value, the lower 4 bits of the high byte of the instruction\ny - A 4-bit value, the upper 4 bits of the low byte of the instruction\nkk or byte - An 8-bit value, the lowest 8 bits of the instruction\n */\n\n#[derive(Debug)]\npub enum Chip8CpuInstructions {\n /// 0nnn\n /// Exit to System Call at nnn\n SYS(u16),\n /// 00E0\n /// Clear the display.\n CLS,\n /// 00EE\n /// Return from a subroutine.\n ///\n /// The interpreter sets the program counter to the address at the top of the stack,\n /// then subtracts 1 from the stack pointer.\n RET,\n /// 1nnn\n /// Jump to location nnn.\n ///\n /// The interpreter sets the program counter to nnn.\n JPA(u16),\n /// 2nnn\n /// Call subroutine at nnn.\n ///\n /// The interpreter increments the stack pointer, then puts the current PC on the top\n /// of the stack. The PC is then set to nnn.\n CALL(u16),\n /// 0x3xkk\n /// Skip next instruction if Vx = kk.\n ///\n /// The interpreter compares register Vx to kk, and if they are equal, increments the\n /// program counter by 2.\n SEX(u8, u8),\n /// 4xkk\n /// Skip next instruction if Vx != kk.\n ///\n /// The interpreter compares register Vx to kk, and if they are not equal, increments\n /// the program counter by 2.\n SNEB(u8, u8),\n /// 5xy0\n /// Skip next instruction if Vx = Vy.\n ///\n /// The interpreter compares register Vx to register Vy, and if they are equal, increments\n /// the program counter by 2.\n SEY(u8, u8),\n /// 6xkk\n /// Set Vx = kk\n LDR(u8, u8),\n /// 7xkk\n /// The interpreter puts the value kk into register Vx.\n ADD(u8, u8),\n /// 8xy0\n /// Adds the value kk to the value of register Vx, then stores the result in Vx.\n LDR_Y(u8, u8),\n /// 8xy1\n /// Stores the value of register Vy in register Vx.\n OR(u8, u8),\n /// 8xy2\n /// Set Vx = Vx OR Vy.\n ///\n /// Performs a bitwise OR on the values of Vx and Vy, then stores the result in Vx.\n /// A bitwise OR compares the corrseponding bits from two values, and if either\n /// bit is 1, then the same bit in the result is also 1. Otherwise, it is 0.\n AND(u8, u8),\n /// 8xy3\n /// Set Vx = Vx AND Vy.\n ///\n /// Performs a bitwise AND on the values of Vx and Vy, then stores the result in Vx.\n /// A bitwise AND compares the corrseponding bits from two values, and if both bits\n /// are 1, then the same bit in the result is also 1. Otherwise, it is 0.\n ORY(u8, u8),\n /// 8xy4\n /// Set Vx = Vx XOR Vy.\n ///\n /// Performs a bitwise exclusive OR on the values of Vx and Vy, then stores the\n /// result in Vx. An exclusive OR compares the corrseponding bits from two values,\n /// and if the bits are not both the same, then the corresponding bit in the result\n /// is set to 1. Otherwise, it is 0.\n ADDR(u8, u8),\n /// 8xy5\n /// Set Vx = Vx + Vy, set VF = carry.\n ///\n /// The values of Vx and Vy are added together. If the result is greater than 8 bits\n /// (i.e., \u003e 255,) VF is set to 1, otherwise 0. Only the lowest 8 bits of the result\n /// are kept, and stored in Vx.\n SUB(u8, u8),\n /// 8xy6\n /// Set Vx = Vx - Vy, set VF = NOT borrow.\n ///\n /// If Vx \u003e Vy, then VF is set to 1, otherwise 0. Then Vy is subtracted from Vx, and the\n /// results stored in Vx.\n SHR(u8, u8),\n /// 8xy7\n /// If the least-significant bit of Vx is 1, then VF is set to 1, otherwise 0. Then Vx\n /// is divided by 2.\n SUBC(u8, u8),\n /// 8xye\n /// Set Vx = Vy - Vx, set VF = NOT borrow.\n //\n /// If Vy \u003e Vx, then VF is set to 1, otherwise 0. Then Vx is subtracted from Vy, and the\n /// results stored in Vx.\n SHL(u8, u8),\n /// 9xy0\n /// Skip next instruction if Vx != Vy.\n ///\n /// The values of Vx and Vy are compared, and if they are not equal, the program\n /// counter is increased by 2.\n SNEY(u8, u8),\n /// Annn\n /// Set I = nnn.\n ///\n /// The value of register I is set to nnn\n LDIA(u16),\n /// Bnnn\n /// Jump to location nnn + V0.\n ///\n /// The program counter is set to nnn plus the value of V0.\n JPI(u16),\n /// Cxkk\n /// Set Vx = random byte AND kk.\n ///\n /// The interpreter generates a random number from 0 to 255, which is then\n /// ANDed with the value kk. The results are stored in Vx. See instruction\n /// 8xy2 for more information on AND.\n RND(u8, u8),\n /// Dxyn\n /// Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision.\n ///\n /// In Chip-8,\n ///\n /// The interpreter reads n bytes from memory, starting at the address stored in I.\n /// These bytes are then displayed as sprites on screen at coordinates (Vx, Vy).\n /// Sprites are XORed onto the existing screen. If this causes any pixels to be erased,\n /// VF is set to 1, otherwise it is set to 0. If the sprite is positioned so part of\n /// it is outside the coordinates of the display, it wraps around to the opposite side\n /// of the screen. See instruction 8xy3 for more information on XOR, and section 2.4,\n /// Display, for more information on the Chip-8 screen and sprites.\n ///\n /// In SCHIP\n ///\n /// Show N-byte sprite from M(I) at Coords (VX,VY) VF = Collision.\n /// If N=0 AND ExtendedMode, 16x16 sprite\n DRW(u8, u8, u8),\n /// Ex9E\n /// Skip next instruction if key with the value of Vx is pressed.\n ///\n /// Checks the keyboard, and if the key corresponding to the value of Vx is currently\n /// in the down position, PC is increased by 2.\n SKP(u8),\n /// ExA1\n /// Skip next instruction if key with the value of Vx is not pressed.\n ///\n /// Checks the keyboard, and if the key corresponding to the value of Vx is currently in\n /// the up position, PC is increased by 2.\n SKNP(u8),\n /// Fx07\n /// The value of DT is placed into Vx.\n LDRD(u8),\n /// Fx0A\n /// Wait for a key press, store the value of the key in Vx.\n ///\n /// All execution stops until a key is pressed, then the value of that key is stored in Vx.\n LDRK(u8),\n /// Fx15\n /// Set delay timer = Vx.\n ///\n /// DT is set equal to the value of Vx.\n LDD(u8), // 0xFx15 Set Delay Timer\n /// Fx18\n /// Set sound timer = Vx.\n ///\n /// ST is set equal to the value of Vx.\n LDIS(u8),\n /// Fx1E - ADD I, Vx\n /// Set I = I + Vx.\n ///\n /// The values of I and Vx are added, and the results are stored in I.\n ADDI(u8),\n /// Fx29 - LD F, Vx\n /// Set I = location of sprite for digit Vx.\n ///\n /// The value of I is set to the location for the hexadecimal sprite\n /// corresponding to the value of Vx. See section 2.4, Display, for\n /// more information on the Chip-8 hexadecimal font.\n LDFX(u8),\n /// Fx33 - LD B, Vx\n /// Store BCD representation of Vx in memory locations I, I+1, and I+2.\n ///\n /// The interpreter takes the decimal value of Vx, and places the hundreds\n /// digit in memory at location in I, the tens digit at location I+1, and the\n /// ones digit at location I+2.\n BCD(u8),\n /// Fx55 - LD [I], Vx\n /// Store registers V0 through Vx in memory starting at location I.\n ///\n /// The interpreter copies the values of registers V0 through Vx into memory,\n /// starting at the address in I.\n LDIX(u8),\n /// Fx65 - LD Vx, [I]\n /// Read registers V0 through Vx from memory starting at location I.\n ///\n /// The interpreter reads values from memory starting at location I into registers\n /// V0 through Vx.\n LDRI(u8),\n XXXXERRORINSTRUCTION,\n /* START OF SCHIP-8 */\n /// 00CN\n ///\n /// Scrolll Display N Lines Down\n SDN(u8),\n /// 00FB\n ///\n /// Scroll 4 lines Right\n SRT,\n /// 00FC\n ///\n /// Scroll 4 lines Left\n SLF,\n /// 00FE\n ///\n /// Disable Extended Mode\n DIS,\n /// 00FF\n ///\n /// Enable Extended Mode\n ENA,\n /// 00FD\n ///\n /// Exit App\n EXIT,\n /// FX30\n ///\n /// Point I to 10 yte font sprite for digit VX (0..9)\n LDF2(u8),\n /// FX75\n ///\n /// Store V0..VX in RPL user flags (X \u003c= 7\n STR(u8),\n /// FX85\n ///\n /// Load V0..VX from RPL user flags (X \u003c= 7)\n LIDR(u8),\n}\n\nimpl Chip8CpuInstructions {\n pub fn name(\u0026self) -\u003e \u0026str {\n match self {\n Chip8CpuInstructions::ADDI(_) =\u003e INST_ADDI,\n Chip8CpuInstructions::ADD(_, _) =\u003e INST_ADD,\n Chip8CpuInstructions::ADDR(_, _) =\u003e INST_ADDR,\n Chip8CpuInstructions::AND(_, _) =\u003e INST_AND,\n Chip8CpuInstructions::CLS =\u003e INST_CLS,\n Chip8CpuInstructions::CALL(_) =\u003e INST_CALL,\n Chip8CpuInstructions::DRW(_, _, _) =\u003e INST_DRW,\n Chip8CpuInstructions::EXIT =\u003e INST_EXIT,\n Chip8CpuInstructions::JPA(_) =\u003e INST_JPA,\n Chip8CpuInstructions::JPI(_) =\u003e INST_JPI,\n Chip8CpuInstructions::BCD(_) =\u003e INST_BCD,\n Chip8CpuInstructions::LDD(_) =\u003e INST_LDD,\n Chip8CpuInstructions::LDFX(_) =\u003e INST_LDF,\n Chip8CpuInstructions::LDF2(_) =\u003e INST_LDF2,\n Chip8CpuInstructions::LDIA(_) =\u003e INST_LDIA,\n Chip8CpuInstructions::LDIX(_) =\u003e INST_LDIX,\n Chip8CpuInstructions::LIDR(_) =\u003e INST_LIDR,\n Chip8CpuInstructions::LDIS(_) =\u003e INST_LDIS,\n Chip8CpuInstructions::LDR(_, _) =\u003e INST_LDR,\n Chip8CpuInstructions::LDRD(_) =\u003e INST_LDRD,\n Chip8CpuInstructions::LDRI(_) =\u003e INST_LDRI,\n Chip8CpuInstructions::LDRK(_) =\u003e INST_LDRK,\n Chip8CpuInstructions::LDR_Y(_, _) =\u003e INST_LDRY,\n Chip8CpuInstructions::OR(_, _) =\u003e INST_OR,\n Chip8CpuInstructions::RET =\u003e INST_RET,\n Chip8CpuInstructions::RND(_, _) =\u003e INST_RND,\n Chip8CpuInstructions::SDN(_) =\u003e INST_SDN,\n Chip8CpuInstructions::SLF =\u003e INST_SLF,\n Chip8CpuInstructions::SRT =\u003e INST_SRT,\n Chip8CpuInstructions::SEX(_, _) =\u003e INST_SEX,\n Chip8CpuInstructions::SEY(_, _) =\u003e INST_SEY,\n Chip8CpuInstructions::SHL(_, _) =\u003e INST_SHL,\n Chip8CpuInstructions::SHR(_, _) =\u003e INST_SHR,\n Chip8CpuInstructions::SKP(_) =\u003e INST_SKP,\n Chip8CpuInstructions::SNEB(_, _) =\u003e INST_SNEB,\n Chip8CpuInstructions::SNEY(_, _) =\u003e INST_SNEY,\n Chip8CpuInstructions::SKNP(_) =\u003e INST_SKNP,\n Chip8CpuInstructions::STR(_) =\u003e INST_STR,\n Chip8CpuInstructions::SUB(_, _) =\u003e INST_SUB,\n Chip8CpuInstructions::SUBC(_, _) =\u003e INST_SUBC,\n Chip8CpuInstructions::SYS(_) =\u003e INST_SYS,\n Chip8CpuInstructions::DIS =\u003e INST_DIS,\n Chip8CpuInstructions::ENA =\u003e INST_ENA,\n Chip8CpuInstructions::ORY(_, _) =\u003e INST_ORY,\n XXXXERRORINSTRUCTION =\u003e \"XX ERROR XX\",\n }\n }\n\n pub fn operands(\u0026self) -\u003e String {\n match self {\n Chip8CpuInstructions::SYS(addr) |\n Chip8CpuInstructions::JPI(addr) |\n Chip8CpuInstructions::JPA(addr) |\n Chip8CpuInstructions::LDIA(addr) |\n Chip8CpuInstructions::CALL(addr) =\u003e {\n format!(\"0x{addr:04x}\")\n }\n Chip8CpuInstructions::SEX(x, byte) |\n Chip8CpuInstructions::SNEB(x, byte) |\n Chip8CpuInstructions::LDR(x, byte) |\n Chip8CpuInstructions::RND(x, byte) |\n Chip8CpuInstructions::ADD(x, byte) =\u003e {\n format!(\"0x{x:02x}, 0x{byte:02x}\")\n }\n // Reg, Reg\n SEY(x, y) |\n LDR_Y(x, y) |\n Chip8CpuInstructions::OR(x, y) |\n Chip8CpuInstructions::AND(x, y) |\n Chip8CpuInstructions::ORY(x, y) |\n Chip8CpuInstructions::ADDR(x, y) |\n Chip8CpuInstructions::SUB(x, y) |\n Chip8CpuInstructions::SHR(x, y) |\n Chip8CpuInstructions::SUBC(x, y) |\n Chip8CpuInstructions::SHL(x, y) |\n Chip8CpuInstructions::SNEY(x, y) =\u003e {\n format!(\"0x{x:01x}, 0x{y:01x}\")\n }\n // Reg, Reg, Nibble\n Chip8CpuInstructions::DRW(x, y, nibble) =\u003e {\n format!(\"0x{x:02x}, 0x{y:02x}, 0x{nibble:02x}\")\n }\n // Registers. 0-F\n Chip8CpuInstructions::LDD(x) |\n Chip8CpuInstructions::LDIS(x) |\n Chip8CpuInstructions::ADDI(x) |\n Chip8CpuInstructions::LDFX(x) |\n Chip8CpuInstructions::BCD(x) |\n Chip8CpuInstructions::LDIX(x) |\n Chip8CpuInstructions::LDRD(x) |\n Chip8CpuInstructions::LDRK(x) |\n Chip8CpuInstructions::LDRI(x) |\n Chip8CpuInstructions::LDF2(x) |\n Chip8CpuInstructions::STR(x) |\n Chip8CpuInstructions::LIDR(x) |\n Chip8CpuInstructions::SDN(x) |\n Chip8CpuInstructions::SKNP(x) |\n Chip8CpuInstructions::SKP(x) =\u003e {\n format!(\"0x{x:02x}\")\n }\n Chip8CpuInstructions::EXIT |\n Chip8CpuInstructions::ENA |\n Chip8CpuInstructions::DIS |\n Chip8CpuInstructions::SLF |\n Chip8CpuInstructions::XXXXERRORINSTRUCTION |\n Chip8CpuInstructions::SRT |\n Chip8CpuInstructions::CLS |\n Chip8CpuInstructions::RET =\u003e {\n String::new()\n }\n }\n }\n}\n\nimpl Display for Chip8CpuInstructions {\n fn fmt(\u0026self, f: \u0026mut Formatter\u003c'_\u003e) -\u003e std::fmt::Result {\n let ops = self.operands();\n let space = if ops.is_empty() { \"\" } else { \" \" };\n write!(f, \"{}{}{}\", self.name(), space, ops)\n }\n}\n\nimpl Chip8CpuInstructions {\n pub fn from_str(input: \u0026str) -\u003e Chip8CpuInstructions {\n let mut parts = input.split(\" \");\n // print!(\"THERE ARE {} PARTS\", parts.clone().count());\n let first_part = parts.next().unwrap_or(\"\");\n // take the next value...\n // ...strip off the extra...\n // ...convert it to an integer from base 16\n let param1 = u16::from_str_radix(parts.next().unwrap_or(\"0\").trim_start_matches(\"0x\").trim_end_matches(\",\"), 16).unwrap_or(0);\n let param2 = u16::from_str_radix(parts.next().unwrap_or(\"0\").trim_start_matches(\"0x\").trim_end_matches(\",\"), 16).unwrap_or(0);\n let param3 = u16::from_str_radix(parts.next().unwrap_or(\"0\").trim_start_matches(\"0x\").trim_end_matches(\",\"), 16).unwrap_or(0);\n // println!(\"\\tFirst part is {:?} / {:?} / {:?} / {:?}\", first_part, param1 ,param2 ,param3);\n match first_part {\n INST_CLS =\u003e {\n CLS\n }\n INST_DRW =\u003e {\n DRW(param1 as u8, param2 as u8, param3 as u8)\n }\n INST_ADD =\u003e {\n ADD(param1 as u8, param2 as u8)\n }\n INST_CALL =\u003e {\n CALL(param1)\n }\n INST_SYS =\u003e {\n SYS(param1)\n }\n INST_RET =\u003e {\n RET\n }\n INST_JPA =\u003e {\n JPA(param1)\n }\n INST_JPI =\u003e {\n JPI(param1)\n }\n INST_SEX =\u003e {\n SEX(param1 as u8, param2 as u8)\n }\n INST_SNEB =\u003e {\n SNEB(param1 as u8, param2 as u8)\n }\n INST_SDN =\u003e {\n SDN(param1 as u8)\n }\n INST_SRT =\u003e {\n SRT\n }\n INST_SLF =\u003e {\n SLF\n }\n INST_EXIT =\u003e {\n EXIT\n }\n INST_DIS =\u003e {\n DIS\n }\n INST_ENA =\u003e {\n ENA\n }\n INST_SEY =\u003e {\n SEY(param1 as u8, param2 as u8)\n }\n INST_LDRY =\u003e {\n LDR_Y(param1 as u8, param2 as u8)\n }\n INST_LDR =\u003e {\n LDR(param1 as u8, param2 as u8)\n }\n INST_OR =\u003e {\n OR(param1 as u8, param2 as u8)\n }\n INST_AND =\u003e {\n AND(param1 as u8, param2 as u8)\n }\n INST_ORY =\u003e {\n ORY(param1 as u8, param2 as u8)\n }\n INST_ADDR =\u003e {\n ADDR(param1 as u8, param2 as u8)\n }\n INST_SUB =\u003e {\n SUB(param1 as u8, param2 as u8)\n }\n INST_SHR =\u003e {\n SHR(param1 as u8, param2 as u8)\n }\n INST_SHL =\u003e {\n SHL(param1 as u8, param2 as u8)\n }\n INST_SUBC =\u003e {\n SUBC(param1 as u8, param2 as u8)\n }\n INST_SNEY =\u003e {\n SNEY(param1 as u8, param2 as u8)\n }\n INST_LDIA =\u003e {\n LDIA(param1)\n }\n INST_RND =\u003e {\n RND(param1 as u8, param2 as u8)\n }\n INST_SKP =\u003e {\n SKP(param1 as u8)\n }\n INST_SKNP =\u003e {\n SKNP(param1 as u8)\n }\n INST_LDRD =\u003e {\n LDRD(param1 as u8)\n }\n INST_LDRK =\u003e {\n LDRK(param1 as u8)\n }\n INST_LDRI =\u003e {\n LDRI(param1 as u8)\n }\n INST_BCD =\u003e {\n BCD(param1 as u8)\n }\n INST_LDF =\u003e {\n LDFX(param1 as u8)\n }\n INST_LDF2 =\u003e {\n LDF2(param1 as u8)\n }\n INST_LDIX =\u003e {\n LDIX(param1 as u8)\n }\n INST_LIDR =\u003e {\n LIDR(param1 as u8)\n }\n INST_LDIS =\u003e {\n LDIS(param1 as u8)\n }\n INST_STR =\u003e {\n STR(param1 as u8)\n }\n INST_LDD =\u003e {\n LDD(param1 as u8)\n }\n _ =\u003e {\n XXXXERRORINSTRUCTION\n }\n }\n }\n\n pub fn encode(\u0026self) -\u003e u16 {\n match self {\n Chip8CpuInstructions::SYS(target) =\u003e 0x0000 | (target \u0026 0x0FFF) as u16,\n Chip8CpuInstructions::CLS =\u003e 0x00E0,\n Chip8CpuInstructions::RET =\u003e 0x00EE,\n Chip8CpuInstructions::JPA(new_addr) =\u003e 0x1000 | (new_addr \u0026 0x0FFF) as u16,\n Chip8CpuInstructions::CALL(address) =\u003e 0x2000 | (address \u0026 0x0FFF) as u16,\n Chip8CpuInstructions::SEX(vx_register, byte) =\u003e 0x3000 | ((*vx_register as u16) \u003c\u003c 8) | (*byte as u16),\n Chip8CpuInstructions::SNEB(vx_register, byte) =\u003e 0x4000 | ((*vx_register as u16) \u003c\u003c 8) | (*byte as u16),\n Chip8CpuInstructions::SEY(x_register, y_register) =\u003e 0x5000 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::LDR(x_register, byte) =\u003e 0x6000 | ((*x_register as u16) \u003c\u003c 8) | (*byte as u16),\n Chip8CpuInstructions::ADD(x_register, byte) =\u003e 0x7000 | ((*x_register as u16) \u003c\u003c 8) | (*byte as u16),\n Chip8CpuInstructions::LDR_Y(x_register, y_register) =\u003e 0x8000 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::OR(x_register, y_register) =\u003e 0x8001 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::AND(x_register, y_register) =\u003e 0x8002 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::ORY(x_register, y_register) =\u003e 0x8003 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::ADDR(x_register, y_register) =\u003e 0x8004 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::SUB(x_register, y_register) =\u003e 0x8005 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::SHR(x_register, y_register) =\u003e 0x8006 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::SUBC(x_register, y_register) =\u003e 0x8007 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::SHL(x_register, y_register) =\u003e 0x800E | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::SNEY(x_register, y_register) =\u003e 0x9000 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4),\n Chip8CpuInstructions::LDIA(addr) =\u003e 0xA000 | addr,\n Chip8CpuInstructions::JPI(addr) =\u003e 0xB000 | addr,\n Chip8CpuInstructions::RND(x_register, byte) =\u003e 0xC000 | ((*x_register as u16) \u003c\u003c 8) | (*byte as u16),\n Chip8CpuInstructions::DRW(x_register, y_register, height) =\u003e {\n 0xD000 | ((*x_register as u16) \u003c\u003c 8) | ((*y_register as u16) \u003c\u003c 4) | (*height as u16)\n }\n Chip8CpuInstructions::SKP(x_register) =\u003e 0xE09E | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::SKNP(x_register) =\u003e 0xE0A1 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::LDRD(x_register) =\u003e 0xF007 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::LDRK(x_register) =\u003e 0xF00A | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::LDD(x_register) =\u003e 0xF015 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::LDIS(x_register) =\u003e 0xF018 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::ADDI(x_register) =\u003e 0xF01E | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::LDFX(x_register) =\u003e 0xF029 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::BCD(x_register) =\u003e 0xF033 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::LDIX(x_register) =\u003e 0xF055 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::LDRI(x_register) =\u003e 0xF065 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::SDN(x_register) =\u003e 0x00C0 | (*x_register as u16),\n Chip8CpuInstructions::SRT =\u003e 0x00FB,\n Chip8CpuInstructions::SLF =\u003e 0x00FC,\n Chip8CpuInstructions::DIS =\u003e 0x00FE,\n Chip8CpuInstructions::ENA =\u003e 0x00FF,\n Chip8CpuInstructions::EXIT =\u003e 0x00FD,\n Chip8CpuInstructions::LDF2(x_register) =\u003e 0xF030 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::STR(x_register) =\u003e 0xF075 | ((*x_register as u16) \u003c\u003c 8),\n Chip8CpuInstructions::LIDR(x_register) =\u003e 0xF085 | ((*x_register as u16) \u003c\u003c 8),\n XXXXERRORINSTRUCTION =\u003e 0xFFFF\n }\n }\n pub fn decode(input: u16, quirk_mode: \u0026QuirkMode) -\u003e Chip8CpuInstructions {\n let x_param = InstructionUtil::read_x_from_instruction(input);\n let y_param = InstructionUtil::read_y_from_instruction(input);\n let addr_param = InstructionUtil::read_addr_from_instruction(input);\n let byte_param = InstructionUtil::read_byte_from_instruction(input);\n let nibble_param = InstructionUtil::read_nibble_from_instruction(input);\n let ubln = InstructionUtil::read_upper_byte_lower_nibble(input);\n let last_byte = (input \u0026 0xFF) as u8;\n let last_nibble = (input \u0026 0xF) as u8;\n\n match input {\n 0x00C0..=0x00CF =\u003e {\n match quirk_mode {\n QuirkMode::Chip8 =\u003e {\n XXXXERRORINSTRUCTION\n }\n QuirkMode::XOChip =\u003e {\n SDN(last_nibble)\n }\n QuirkMode::SChipModern =\u003e {\n SDN(last_nibble)\n }\n }\n },\n 0x00E0 =\u003e Chip8CpuInstructions::CLS,\n 0x00EE =\u003e Chip8CpuInstructions::RET,\n 0x00FB =\u003e {\n match quirk_mode {\n QuirkMode::Chip8 =\u003e {\n // does not exist on Chip8\n XXXXERRORINSTRUCTION\n }\n QuirkMode::XOChip =\u003e {\n Chip8CpuInstructions::SRT\n }\n QuirkMode::SChipModern =\u003e {\n Chip8CpuInstructions::SRT\n }\n }\n },\n 0x00FC =\u003e Chip8CpuInstructions::SLF,\n 0x00FD =\u003e Chip8CpuInstructions::EXIT,\n 0x00FE =\u003e Chip8CpuInstructions::DIS,\n 0x00FF =\u003e Chip8CpuInstructions::ENA,\n 0x0000..=0x0FFF =\u003e Chip8CpuInstructions::SYS(addr_param),\n 0x1000..=0x1FFF =\u003e Chip8CpuInstructions::JPA(addr_param),\n 0x2000..=0x2FFF =\u003e Chip8CpuInstructions::CALL(addr_param),\n 0x3000..=0x3FFF =\u003e Chip8CpuInstructions::SEX(x_param, byte_param),\n 0x4000..=0x4FFF =\u003e Chip8CpuInstructions::SNEB(x_param, byte_param),\n 0x5000..=0x5FF0 if input \u0026 0x01 == 0 =\u003e Chip8CpuInstructions::SEY(x_param, y_param),\n 0x6000..=0x6FFF =\u003e Chip8CpuInstructions::LDR(x_param, byte_param),\n 0x7000..=0x7FFF =\u003e Chip8CpuInstructions::ADD(x_param, byte_param),\n 0x8000..=0x8FFE =\u003e match last_nibble {\n 0x0 =\u003e Chip8CpuInstructions::LDR_Y(x_param, y_param),\n 0x1 =\u003e Chip8CpuInstructions::OR(x_param, y_param),\n 0x2 =\u003e Chip8CpuInstructions::AND(x_param, y_param),\n 0x3 =\u003e Chip8CpuInstructions::ORY(x_param, y_param),\n 0x4 =\u003e Chip8CpuInstructions::ADDR(x_param, y_param),\n 0x5 =\u003e Chip8CpuInstructions::SUB(x_param, y_param),\n 0x6 =\u003e Chip8CpuInstructions::SHR(x_param, y_param),\n 0x7 =\u003e Chip8CpuInstructions::SUBC(x_param, y_param),\n 0xE =\u003e Chip8CpuInstructions::SHL(x_param, y_param),\n _ =\u003e XXXXERRORINSTRUCTION\n }\n 0x9000..=0x9FF0 if input \u0026 0x01 == 0 =\u003e Chip8CpuInstructions::SNEY(x_param, y_param),\n 0xA000..=0xAFFF =\u003e Chip8CpuInstructions::LDIA(addr_param),\n 0xB000..=0xBFFF =\u003e Chip8CpuInstructions::JPI(addr_param),\n 0xC000..=0xCFFF =\u003e Chip8CpuInstructions::RND(x_param, byte_param),\n 0xD000..=0xDFFF =\u003e Chip8CpuInstructions::DRW(x_param, y_param, nibble_param),\n 0xE09E..=0xEFA1 =\u003e match last_byte {\n 0x9E =\u003e Chip8CpuInstructions::SKP(ubln),\n 0xA1 =\u003e Chip8CpuInstructions::SKNP(ubln),\n _ =\u003e XXXXERRORINSTRUCTION\n }\n 0xF007..=0xFF65 =\u003e match last_byte {\n 0x07 =\u003e Chip8CpuInstructions::LDRD(ubln),\n 0x0A =\u003e Chip8CpuInstructions::LDRK(ubln),\n 0x15 =\u003e Chip8CpuInstructions::LDD(ubln),\n 0x18 =\u003e Chip8CpuInstructions::LDIS(ubln),\n 0x1E =\u003e Chip8CpuInstructions::ADDI(ubln),\n 0x29 =\u003e Chip8CpuInstructions::LDFX(ubln),\n 0x30 =\u003e Chip8CpuInstructions::LDF2(ubln),\n 0x33 =\u003e Chip8CpuInstructions::BCD(ubln),\n 0x55 =\u003e Chip8CpuInstructions::LDIX(ubln),\n 0x65 =\u003e Chip8CpuInstructions::LDRI(ubln),\n 0x75 =\u003e Chip8CpuInstructions::STR(ubln),\n 0x85 =\u003e Chip8CpuInstructions::LIDR(ubln),\n _ =\u003e XXXXERRORINSTRUCTION\n }\n _ =\u003e XXXXERRORINSTRUCTION\n }\n }\n pub fn execute(\u0026self, input: \u0026mut Chip8Computer) -\u003e Chip8Computer {\n // print!(\"INSTRUCTION {}\", self);\n let start_time = Instant::now();\n let start_pc = input.registers.peek_pc();\n input.registers.poke_pc(start_pc + 2);\n let _ = match self {\n // 0x0nnn Exit to System Call\n Chip8CpuInstructions::SYS(new_address) =\u003e {\n input.registers.poke_pc(*new_address as u16);\n }\n // * 0x00E0 Clear Screen\n Chip8CpuInstructions::CLS =\u003e {\n input.video_memory.cls();\n }\n // 0x00EE Return from Subroutine\n Chip8CpuInstructions::RET =\u003e {\n input.registers.poke_pc(input.stack.pop());\n }\n // 0x1nnn Jump to Address\n Chip8CpuInstructions::JPA(new_address) =\u003e {\n input.registers.poke_pc(*new_address as u16);\n }\n // 0x2nnn Call Subroutine\n Chip8CpuInstructions::CALL(new_address) =\u003e {\n let return_address = input.registers.peek_pc();\n input.registers.poke_pc(*new_address as u16);\n input.stack.push(\u0026return_address);\n }\n // 0x3xkk Skip next instruction if Vx = kk.\n Chip8CpuInstructions::SEX(vx_register, byte) =\u003e {\n if input.registers.peek(*vx_register as u8) == *byte as u8 {\n input.registers.advance_pc();\n }\n }\n // 0x4xkk Skip next instruction if Vx != kk\n Chip8CpuInstructions::SNEB(x, byte) =\u003e {\n // 4xkk - SNE Vx, byte\n // Skip next instruction if Vx != kk.\n //\n // The interpreter compares register Vx to kk, and if they are not equal,\n // increments the program counter by 2.\n if input.registers.peek(*x) != *byte {\n input.registers.advance_pc();\n }\n }\n // 0x5xy0 Skip next instruction if Vx == Vy\n Chip8CpuInstructions::SEY(x, y) =\u003e {\n if input.registers.peek(*x as u8) == input.registers.peek(*y as u8) {\n input.registers.advance_pc();\n }\n }\n // 0x6xkk Set Vx = kk\n Chip8CpuInstructions::LDR(register, byte) =\u003e {\n input.registers.poke(*register, *byte);\n }\n // 0x7xkk Set Vx = Vx + kk\n Chip8CpuInstructions::ADD(vx_register, byte) =\u003e {\n input.registers.poke(*vx_register, (input.registers.peek(*vx_register) as u16 + *byte as u16) as u8);\n }\n // 0x8xy0 Set value of Vy in Vx\n Chip8CpuInstructions::LDR_Y(x, y) =\u003e {\n input.registers.poke(*x as u8, input.registers.peek(*y as u8));\n }\n // 0x8xy1 Set Vx = Vx OR Vy\n Chip8CpuInstructions::OR(x, y) =\u003e {\n // shift them to 16 bit\n let working_16_x = input.registers.peek(*x as u8) as u16;\n let working_16_y = input.registers.peek(*y as u8) as u16;\n // OR them\n let working_16_or = working_16_x | working_16_y;\n // shift them back to 8 bit.\n input.registers.poke(*x as u8, working_16_or as u8);\n debug!(\"OrVxVy [0x{x:1x}] [0x{y:1x}]\")\n }\n // 0x8xy2 Set Vx = Vx AND Vy\n Chip8CpuInstructions::AND(x, y) =\u003e {\n let lhs_16 = input.registers.peek(*x as u8) as u16;\n let rhs_16 = input.registers.peek(*y as u8) as u16;\n input.registers.poke(*x as u8, (lhs_16 \u0026 rhs_16) as u8);\n }\n // 0x8xy3 Set Vx = Vx XOR Vy\n Chip8CpuInstructions::ORY(x, y) =\u003e {\n let lhs_16 = input.registers.peek(*x as u8) as u16;\n let rhs_16 = input.registers.peek(*y as u8) as u16;\n input.registers.poke(*x as u8, (lhs_16 ^ rhs_16) as u8);\n }\n // 0x8xy4 Set Vx = Vx + Vy (SET VF on Carry)\n Chip8CpuInstructions::ADDR(x, y) =\u003e {\n let lhs = input.registers.peek(*x as u8) as i16;\n let rhs = input.registers.peek(*y as u8) as i16;\n let working = lhs + rhs;\n input.registers.poke(*x as u8, working as u8);\n\n if working \u003e= 0x100 {\n input.registers.poke(0xf, 0x01);\n } else {\n input.registers.poke(0x0f, 0x00);\n }\n }\n Chip8CpuInstructions::SUB(x, y) =\u003e {\n // 8xy5 - SUB Vx, Vy\n // Set Vx = Vx - Vy, set VF = NOT borrow.\n //\n // If Vx \u003e Vy, then VF is set to 1, otherwise 0. Then Vy is subtracted from Vx, and the results stored in Vx.\n\n let lhs = input.registers.peek(*x);\n let rhs = input.registers.peek(*y);\n\n let mut result = 0;\n\n let borrow_flag: u8 = if rhs \u003e lhs {\n result = (lhs as u16 + 0x100) - rhs as u16;\n 0\n } else {\n result = lhs as u16 - rhs as u16;\n 1\n };\n\n input.registers.poke(*x as u8, result as u8);\n input.registers.poke(0x0f, borrow_flag);\n }\n Chip8CpuInstructions::SHR(x, _) =\u003e {\n // 8xy6 - SHR Vx {, Vy}\n // Set Vx = Vx SHR 1.\n // SHIFT 1 Bit ----\u003e\n // If the least-significant bit of Vx is 1, then VF is set to 1, otherwise 0. Then Vx is divided by 2.\n let initial_value = input.registers.peek(*x);\n\n // overflow check\n let rotated = initial_value \u003e\u003e 1;\n input.registers.poke(*x as u8, rotated);\n if initial_value.bitand(0b1) == 1 {\n input.registers.poke(0x0f, 0x01);\n } else {\n input.registers.poke(0x0f, 0x00);\n }\n }\n Chip8CpuInstructions::SUBC(x, y) =\u003e {\n // 8xy7 - SUBN Vx, Vy\n // Set Vx = Vy - Vx, set VF = NOT borrow.\n //\n // If Vy \u003e Vx, then VF is set to 1, otherwise 0. Then Vx is subtracted from Vy, and the results stored in Vx.\n let y_register = input.registers.peek(*y as u8);\n let x_register = input.registers.peek(*x as u8);\n let mut value_to_poke = 0;\n\n let new_value = if y_register \u003c x_register {\n value_to_poke = (y_register as u16 + 256) - x_register as u16;\n 0\n } else {\n value_to_poke = (y_register - x_register) as u16;\n 1\n };\n\n debug!(\"SUB CARRY -\u003e REGISTER 1 = [0x{x:02x}] / [{x_register}] REGISTER 2 = [0x{y:02x}] / [{y_register}] SUB = {value_to_poke} CARRY = {new_value}\");\n\n input.registers.poke(*x, value_to_poke as u8);\n input.registers.poke(0xf, new_value);\n }\n\n Chip8CpuInstructions::SHL(x, _) =\u003e {\n // 8xyE - SHL Vx {, Vy}\n // Set Vx = Vx SHL 1.\n //\n // If the most-significant bit of Vx is 1, then VF is set to 1, otherwise to 0. Then Vx is multiplied by 2.\n let initial_value = input.registers.peek(*x);\n\n // overflow check\n let rotated = initial_value \u003c\u003c 1;\n input.registers.poke(*x as u8, rotated);\n if initial_value.bitand(0b10000000) == 0b10000000 {\n input.registers.poke(0x0f, 0x01);\n } else {\n input.registers.poke(0x0f, 0x00);\n }\n }\n Chip8CpuInstructions::SNEY(vx_register, vy_register) =\u003e {\n // 9xy0 - SNE Vx, Vy\n // Skip next instruction if Vx != Vy.\n //\n // The values of Vx and Vy are compared, and if they are not equal, the program counter is increased by 2.\n\n let x_reg_value = input.registers.peek(*vx_register as u8);\n let y_reg_value = input.registers.peek(*vy_register as u8);\n if x_reg_value != y_reg_value {\n input.registers.advance_pc();\n }\n }\n Chip8CpuInstructions::LDIA(new_index) =\u003e {\n // Annn - LD I, addr\n // Set I = nnn.\n //\n // The value of register I is set to nnn.\n // debug!(\"LdiAddr [0x{new_index:3x}]\");\n input.registers.poke_i(*new_index);\n }\n // 0xBnnn Jump to nnn+V0\n Chip8CpuInstructions::JPI(addr) =\u003e {\n // Bnnn - JP V0, addr\n // Jump to location nnn + V0.\n //\n // The program counter is set to nnn plus the value of V0.\n input.registers.poke_pc(input.registers.peek(0) as u16 + addr);\n }\n Chip8CpuInstructions::RND(x, byte) =\u003e {\n // Cxkk - RND Vx, byte\n // Set Vx = random byte AND kk.\n //\n // The interpreter generates a random number from 0 to 255,\n // which is then ANDed with the value kk.\n // The results are stored in Vx.\n let mut rng = rand::thread_rng();\n let new_value: u8 = rng.random();\n let and_value: u8 = *byte;\n let result = new_value \u0026 and_value;\n debug!(\"RANDOM: [{new_value:02x}] AND: [{and_value:02x} Result: [{result:02x}]\");\n input.registers.poke(*x as u8, new_value \u0026 *byte as u8)\n }\n Chip8CpuInstructions::DRW(y, x, n) =\u003e {\n // Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision.\n\n // The interpreter reads n bytes from memory, starting at the address stored in I.\n\n // These bytes are then displayed as sprites on screen at coordinates (Vx, Vy).\n // Sprites are XORed onto the existing screen.\n // If this causes any pixels to be erased, VF is set to 1,\n // otherwise it is set to 0.\n // If the sprite is positioned so part of it is outside the coordinates of the display,\n // it wraps around to the opposite side of the screen.\n\n let source_memory_offset = input.registers.peek_i();\n let x_offset = input.registers.peek(*x) as u16;\n let y_offset = input.registers.peek(*y) as u16;\n if input.video_memory.is_highres() {\n // if n == 0 we have a 16 row sprite (font maybe)\n let actual_num_loops = if *n == 0u8 {\n 16\n } else {\n *n\n };\n for byte_index in 0..actual_num_loops {\n let current_byte = input.memory.peek(byte_index as u16 + source_memory_offset);\n let next_byte = input.memory.peek(byte_index as u16 + 1u16 + source_memory_offset);\n let x_offset = (x_offset + byte_index as u16) * 64;\n for bit_index in 0..8 {\n input.video_memory.poke(x_offset + (y_offset + bit_index as u16), (current_byte \u0026 (0x80 \u003e\u003e bit_index)) != 0);\n input.video_memory.poke(x_offset + (y_offset + bit_index as u16) + 8, (current_byte \u0026 (0x80 \u003e\u003e bit_index)) != 0);\n }\n }\n } else {\n for byte_index in 0..*n {\n let current_byte = input.memory.peek(byte_index as u16 + source_memory_offset);\n let x_offset: u16 = (x_offset + byte_index as u16) * 64;\n for bit_index in 0..8 {\n input.video_memory.poke(x_offset + (y_offset + bit_index as u16), (current_byte \u0026 (0x80 \u003e\u003e bit_index)) != 0);\n }\n }\n }\n\n let target = if input.video_memory.has_frame_changed {\n 1u8\n } else {\n 0u8\n };\n\n input.registers.poke(0xf, target);\n }\n Chip8CpuInstructions::SKP(x) =\u003e {\n // Ex9E - SKP Vx\n // Skip next instruction if key with the value of Vx is pressed.\n //\n // Checks the keyboard, and if the key corresponding to the value of Vx is currently in the down position, PC is increased by 2.\n let key_to_check = input.registers.peek(*x as u8);\n let is_pressed = input.keypad.pressed(key_to_check);\n if is_pressed {\n input.registers.advance_pc();\n }\n }\n Chip8CpuInstructions::SKNP(x) =\u003e {\n // ExA1 - SKNP Vx\n // Skip next instruction if key with the value of Vx is not pressed.\n //\n\n // Checks the keyboard,\n // and if the key corresponding to the value of Vx is currently in the up position,\n // PC is increased by 2.\n let target_key = input.registers.peek(*x as u8);\n let is_pressed = input.keypad.pressed(target_key);\n debug!(\"SnKpVx [{x:1x}]\");\n if !is_pressed {\n input.registers.advance_pc();\n }\n }\n Chip8CpuInstructions::LDRD(x) =\u003e {\n // Fx07 - LD Vx, DT\n // Set Vx = delay timer value.\n //\n // The value of DT is placed into Vx.\n let value_to_set = input.delay_timer.current();\n input.registers.poke(*x as u8, value_to_set as u8);\n }\n Chip8CpuInstructions::LDRK(x) =\u003e {\n // Fx0A - LD Vx, K\n // Wait for a key press, store the value of the key in Vx.\n //\n // All execution stops until a key is pressed, then the value of that key is stored in Vx.\n input.state = WaitingForKey;\n }\n Chip8CpuInstructions::LDD(source_register) =\u003e {\n // Fx15 - LD DT, Vx\n // Set delay timer = Vx.\n //\n // DT is set equal to the value of Vx.\n let new_time = input.registers.peek(*source_register as u8);\n input.delay_timer.set_timer(new_time);\n }\n Chip8CpuInstructions::LDIS(new_time) =\u003e {\n let new_value = input.registers.peek(*new_time as u8);\n input.sound_timer.set_timer(new_value as i32);\n }\n Chip8CpuInstructions::ADDI(x) =\u003e {\n // Fx1E - ADD I, Vx\n // Set I = I + Vx.\n //\n // The values of I and Vx are added, and the results are stored in I.\n let base = input.registers.peek_i();\n let x_value = input.registers.peek(*x as u8);\n input.registers.poke_i(base + x_value as u16);\n }\n Chip8CpuInstructions::LDFX(x) =\u003e {\n // Fx29 - LD F, Vx\n // Set I = location of sprite for digit Vx.\n //\n // The value of I is set to the location for the hexadecimal sprite corresponding\n // to the value of Vx. See section 2.4, Display, for more information on\n // the Chip-8 hexadecimal font.\n\n let x_value: u8 = input.registers.peek(*x);\n\n let real_offset = x_value as u16 * 5;\n input.registers.poke_i(real_offset as u16);\n }\n Chip8CpuInstructions::BCD(x) =\u003e {\n // Fx33 - LD B, Vx\n // Store BCD representation of Vx in memory locations I, I+1, and I+2.\n //\n // The interpreter takes the decimal value of Vx, and places the hundreds\n // digit in memory at location in I, the tens digit at location I+1,\n // and the ones digit at location I+2.\n\n let to_convert = input.registers.peek(*x as u8);\n\n // how many hundreds\n let hundreds = to_convert / 100;\n // how many tens, minus the hundreds\n let tens = (to_convert / 10) - (hundreds * 10);\n // whats the leftover when dividing by 10\n let units = to_convert % 10;\n\n // Convert to BCD\n let result = ((hundreds as u16) \u003c\u003c 8) | units as u16 | ((tens as u16) \u003c\u003c 4) | units as u16;\n // write them to the memory pointed to by I, I+1, and I+2\n let target_start_offset = input.registers.peek_i();\n input.memory.poke(target_start_offset, hundreds);\n input.memory.poke(target_start_offset + 1, tens);\n input.memory.poke(target_start_offset + 2, units);\n }\n Chip8CpuInstructions::LDIX(x) =\u003e {\n // Store registers V0 through Vx in memory starting at location I.\n //\n // The interpreter copies the values of registers V0 through Vx into memory,\n // starting at the address in I.\n let offset = input.registers.peek_i();\n for i in 0..=*x {\n input.memory.poke(offset + i as u16, input.registers.peek(i as u8));\n }\n input.registers.poke_i(offset + 1);\n }\n Chip8CpuInstructions::LDRI(x) =\u003e {\n // Read registers V0 through Vx from memory starting at location I.\n //\n // The interpreter reads values from memory starting at location I into registers V0 through Vx.\n let offset = input.registers.peek_i();\n debug!(\"STARTING TO READ AT {offset:03x}\");\n let num_loops = x + 1;\n debug!(\"WILL READ {num_loops:x} BYTES\");\n for index in 0..num_loops {\n let src_value = input.memory.peek(index as u16 + offset);\n input.registers.poke(index as u8, src_value);\n debug!(\"POKING Register 0x{index:02x} with 0x{src_value:04x} using offset 0x{offset:04x}\");\n }\n input.registers.poke_i(offset + 1);\n }\n Chip8CpuInstructions::XXXXERRORINSTRUCTION =\u003e {}\n Chip8CpuInstructions::SDN(x) =\u003e {\n input.video_memory.scroll_down(*x as i32);\n }\n Chip8CpuInstructions::SRT =\u003e {\n input.video_memory.scroll_right();\n }\n Chip8CpuInstructions::SLF =\u003e {\n input.video_memory.scroll_left();\n }\n Chip8CpuInstructions::DIS =\u003e {\n input.video_memory.set_lowres();\n }\n Chip8CpuInstructions::ENA =\u003e {\n input.video_memory.set_highres();\n }\n Chip8CpuInstructions::EXIT =\u003e {\n println!(\"EXIT INTERPRETER\");\n }\n Chip8CpuInstructions::LDF2(x) =\u003e {\n println!(\"POINTING TO FONT AT {x:02x}\");\n // base = 0x100 + 0x0A*X\n input.registers.poke_i(0x100 + (0xA * x) as u16);\n }\n Chip8CpuInstructions::STR(x) =\u003e {\n println!(\"STORING FROM RPL FOR {x}\");\n }\n Chip8CpuInstructions::LIDR(x) =\u003e {\n println!(\"LOADING FROM RPL FOR {x}\");\n }\n };\n let cycle_time = Instant::now().duration_since(start_time).as_nanos();\n // println!(\"\\t\\tTook {cycle_time}ms\");\n input.to_owned()\n }\n\n pub fn from_string(input: \u0026str) -\u003e Chip8CpuInstructions {\n let parts = input.split(\" \");\n println!(\"Parts -\u003e {:?}\", parts);\n\n Chip8CpuInstructions::XXXXERRORINSTRUCTION\n }\n}\n","traces":[{"line":265,"address":[733568],"length":1,"stats":{"Line":1}},{"line":266,"address":[42143034],"length":1,"stats":{"Line":1}},{"line":267,"address":[734389],"length":1,"stats":{"Line":1}},{"line":268,"address":[733843],"length":1,"stats":{"Line":1}},{"line":269,"address":[330485],"length":1,"stats":{"Line":1}},{"line":270,"address":[755105],"length":1,"stats":{"Line":1}},{"line":271,"address":[330147],"length":1,"stats":{"Line":1}},{"line":272,"address":[3571297],"length":1,"stats":{"Line":1}},{"line":273,"address":[645455],"length":1,"stats":{"Line":1}},{"line":274,"address":[755853],"length":1,"stats":{"Line":1}},{"line":275,"address":[644935],"length":1,"stats":{"Line":1}},{"line":276,"address":[734155],"length":1,"stats":{"Line":1}},{"line":277,"address":[734441],"length":1,"stats":{"Line":0}},{"line":278,"address":[1189777],"length":1,"stats":{"Line":0}},{"line":279,"address":[3571999],"length":1,"stats":{"Line":0}},{"line":280,"address":[42144148],"length":1,"stats":{"Line":0}},{"line":281,"address":[42143585],"length":1,"stats":{"Line":1}},{"line":282,"address":[330979],"length":1,"stats":{"Line":0}},{"line":283,"address":[734752],"length":1,"stats":{"Line":0}},{"line":284,"address":[645611],"length":1,"stats":{"Line":0}},{"line":285,"address":[755001],"length":1,"stats":{"Line":1}},{"line":286,"address":[734285],"length":1,"stats":{"Line":0}},{"line":287,"address":[645741],"length":1,"stats":{"Line":0}},{"line":288,"address":[330823],"length":1,"stats":{"Line":0}},{"line":289,"address":[733869],"length":1,"stats":{"Line":1}},{"line":290,"address":[3571479],"length":1,"stats":{"Line":1}},{"line":291,"address":[644909],"length":1,"stats":{"Line":1}},{"line":292,"address":[645429],"length":1,"stats":{"Line":1}},{"line":293,"address":[645793],"length":1,"stats":{"Line":1}},{"line":294,"address":[42144053],"length":1,"stats":{"Line":1}},{"line":295,"address":[645819],"length":1,"stats":{"Line":1}},{"line":296,"address":[733739],"length":1,"stats":{"Line":1}},{"line":297,"address":[645039],"length":1,"stats":{"Line":1}},{"line":298,"address":[42143533],"length":1,"stats":{"Line":1}},{"line":299,"address":[3571609],"length":1,"stats":{"Line":1}},{"line":300,"address":[1189673],"length":1,"stats":{"Line":0}},{"line":301,"address":[645013],"length":1,"stats":{"Line":1}},{"line":302,"address":[755287],"length":1,"stats":{"Line":1}},{"line":303,"address":[42143715],"length":1,"stats":{"Line":0}},{"line":304,"address":[331232],"length":1,"stats":{"Line":0}},{"line":305,"address":[42143455],"length":1,"stats":{"Line":1}},{"line":306,"address":[1189491],"length":1,"stats":{"Line":1}},{"line":307,"address":[330121],"length":1,"stats":{"Line":1}},{"line":308,"address":[734623],"length":1,"stats":{"Line":1}},{"line":309,"address":[3572230],"length":1,"stats":{"Line":1}},{"line":310,"address":[1189387],"length":1,"stats":{"Line":1}},{"line":311,"address":[645767],"length":1,"stats":{"Line":0}},{"line":315,"address":[331296],"length":1,"stats":{"Line":1}},{"line":316,"address":[646160,646107,646715,646345,648428,648186,648252,648494,646567,646734,646604,646234,646456,646419,646530,648450,648362,648274,648318,646790,648230,646271,648296,646753,646308,648208,648406,646493,646678,646641,648340,648384,646141,646062,646382,648472,646197],"length":1,"stats":{"Line":23}},{"line":317,"address":[756034],"length":1,"stats":{"Line":1}},{"line":322,"address":[1192792,1193172,1193053],"length":1,"stats":{"Line":3}},{"line":324,"address":[3572654],"length":1,"stats":{"Line":1}},{"line":329,"address":[1193693,1193397,1194095,1193925],"length":1,"stats":{"Line":4}},{"line":332,"address":[646614],"length":1,"stats":{"Line":1}},{"line":343,"address":[3576992,3576464,3576760],"length":1,"stats":{"Line":3}},{"line":346,"address":[646800],"length":1,"stats":{"Line":1}},{"line":347,"address":[757108,757436,758100,757668,757900],"length":1,"stats":{"Line":5}},{"line":350,"address":[333702],"length":1,"stats":{"Line":0}},{"line":365,"address":[3577689,3577549,3577285],"length":1,"stats":{"Line":3}},{"line":375,"address":[1190309],"length":1,"stats":{"Line":1}},{"line":382,"address":[651360,652016],"length":1,"stats":{"Line":1}},{"line":383,"address":[651399],"length":1,"stats":{"Line":1}},{"line":384,"address":[1195615,1195671],"length":1,"stats":{"Line":2}},{"line":385,"address":[336792,337147],"length":1,"stats":{"Line":2}},{"line":390,"address":[652048],"length":1,"stats":{"Line":1}},{"line":391,"address":[337325],"length":1,"stats":{"Line":1}},{"line":393,"address":[337348],"length":1,"stats":{"Line":1}},{"line":397,"address":[1196351],"length":1,"stats":{"Line":1}},{"line":398,"address":[42150530],"length":1,"stats":{"Line":1}},{"line":399,"address":[42150693],"length":1,"stats":{"Line":1}},{"line":402,"address":[3578994],"length":1,"stats":{"Line":1}},{"line":403,"address":[337942],"length":1,"stats":{"Line":1}},{"line":405,"address":[741441],"length":1,"stats":{"Line":1}},{"line":406,"address":[652770],"length":1,"stats":{"Line":1}},{"line":408,"address":[741484],"length":1,"stats":{"Line":1}},{"line":409,"address":[741587],"length":1,"stats":{"Line":1}},{"line":411,"address":[338032],"length":1,"stats":{"Line":1}},{"line":412,"address":[338121],"length":1,"stats":{"Line":1}},{"line":414,"address":[741615],"length":1,"stats":{"Line":1}},{"line":415,"address":[652944],"length":1,"stats":{"Line":1}},{"line":417,"address":[338146],"length":1,"stats":{"Line":1}},{"line":418,"address":[762928],"length":1,"stats":{"Line":1}},{"line":420,"address":[42151177],"length":1,"stats":{"Line":1}},{"line":421,"address":[1197232],"length":1,"stats":{"Line":1}},{"line":423,"address":[762948],"length":1,"stats":{"Line":1}},{"line":424,"address":[3579429],"length":1,"stats":{"Line":1}},{"line":426,"address":[741817],"length":1,"stats":{"Line":1}},{"line":427,"address":[1197343],"length":1,"stats":{"Line":1}},{"line":429,"address":[338348],"length":1,"stats":{"Line":1}},{"line":430,"address":[3579548],"length":1,"stats":{"Line":1}},{"line":432,"address":[3579515],"length":1,"stats":{"Line":1}},{"line":433,"address":[42151476],"length":1,"stats":{"Line":1}},{"line":435,"address":[3579576],"length":1,"stats":{"Line":1}},{"line":436,"address":[1197507],"length":1,"stats":{"Line":1}},{"line":438,"address":[338522],"length":1,"stats":{"Line":1}},{"line":439,"address":[742110],"length":1,"stats":{"Line":1}},{"line":441,"address":[3579671],"length":1,"stats":{"Line":1}},{"line":442,"address":[763337],"length":1,"stats":{"Line":1}},{"line":444,"address":[1197570],"length":1,"stats":{"Line":1}},{"line":445,"address":[3579780],"length":1,"stats":{"Line":1}},{"line":447,"address":[742173],"length":1,"stats":{"Line":1}},{"line":448,"address":[338717],"length":1,"stats":{"Line":1}},{"line":450,"address":[338694],"length":1,"stats":{"Line":1}},{"line":451,"address":[1197732],"length":1,"stats":{"Line":1}},{"line":453,"address":[742259],"length":1,"stats":{"Line":1}},{"line":454,"address":[338831],"length":1,"stats":{"Line":1}},{"line":456,"address":[42151776],"length":1,"stats":{"Line":1}},{"line":457,"address":[42151870],"length":1,"stats":{"Line":1}},{"line":459,"address":[742381],"length":1,"stats":{"Line":1}},{"line":460,"address":[653723],"length":1,"stats":{"Line":1}},{"line":462,"address":[338920],"length":1,"stats":{"Line":1}},{"line":463,"address":[3580120],"length":1,"stats":{"Line":1}},{"line":465,"address":[1197943],"length":1,"stats":{"Line":1}},{"line":466,"address":[42152053],"length":1,"stats":{"Line":1}},{"line":468,"address":[339042],"length":1,"stats":{"Line":1}},{"line":469,"address":[3580242],"length":1,"stats":{"Line":1}},{"line":471,"address":[742625],"length":1,"stats":{"Line":1}},{"line":472,"address":[763903],"length":1,"stats":{"Line":1}},{"line":474,"address":[42152142],"length":1,"stats":{"Line":1}},{"line":475,"address":[1198220],"length":1,"stats":{"Line":1}},{"line":477,"address":[763931],"length":1,"stats":{"Line":1}},{"line":478,"address":[764025],"length":1,"stats":{"Line":1}},{"line":480,"address":[3580392],"length":1,"stats":{"Line":1}},{"line":481,"address":[339380],"length":1,"stats":{"Line":1}},{"line":483,"address":[654117],"length":1,"stats":{"Line":1}},{"line":484,"address":[42152419],"length":1,"stats":{"Line":1}},{"line":486,"address":[1198370],"length":1,"stats":{"Line":1}},{"line":487,"address":[1198456],"length":1,"stats":{"Line":1}},{"line":489,"address":[1198428],"length":1,"stats":{"Line":1}},{"line":490,"address":[339523],"length":1,"stats":{"Line":1}},{"line":496,"address":[743028],"length":1,"stats":{"Line":0}},{"line":508,"address":[3580656],"length":1,"stats":{"Line":1}},{"line":509,"address":[42152544],"length":1,"stats":{"Line":1}},{"line":510,"address":[339603],"length":1,"stats":{"Line":1}},{"line":511,"address":[42152619],"length":1,"stats":{"Line":1}},{"line":512,"address":[339655],"length":1,"stats":{"Line":1}},{"line":513,"address":[339671],"length":1,"stats":{"Line":1}},{"line":514,"address":[1198675],"length":1,"stats":{"Line":1}},{"line":515,"address":[1198719],"length":1,"stats":{"Line":1}},{"line":516,"address":[339816],"length":1,"stats":{"Line":1}},{"line":517,"address":[764577],"length":1,"stats":{"Line":1}},{"line":518,"address":[42152910],"length":1,"stats":{"Line":1}},{"line":519,"address":[654759],"length":1,"stats":{"Line":1}},{"line":520,"address":[42153027],"length":1,"stats":{"Line":1}},{"line":521,"address":[1199078],"length":1,"stats":{"Line":1}},{"line":522,"address":[3581289],"length":1,"stats":{"Line":1}},{"line":523,"address":[1199212],"length":1,"stats":{"Line":1}},{"line":524,"address":[42153295],"length":1,"stats":{"Line":1}},{"line":525,"address":[743906],"length":1,"stats":{"Line":1}},{"line":526,"address":[1199413],"length":1,"stats":{"Line":1}},{"line":527,"address":[42153496],"length":1,"stats":{"Line":1}},{"line":528,"address":[744107],"length":1,"stats":{"Line":1}},{"line":529,"address":[765358],"length":1,"stats":{"Line":1}},{"line":530,"address":[340721],"length":1,"stats":{"Line":1}},{"line":531,"address":[655532],"length":1,"stats":{"Line":1}},{"line":532,"address":[655575],"length":1,"stats":{"Line":1}},{"line":533,"address":[655638],"length":1,"stats":{"Line":1}},{"line":534,"address":[1199875],"length":1,"stats":{"Line":1}},{"line":536,"address":[42153935],"length":1,"stats":{"Line":1}},{"line":537,"address":[1199960],"length":1,"stats":{"Line":1}},{"line":538,"address":[3582145],"length":1,"stats":{"Line":1}},{"line":539,"address":[3582186],"length":1,"stats":{"Line":1}},{"line":540,"address":[341123],"length":1,"stats":{"Line":1}},{"line":541,"address":[1200124],"length":1,"stats":{"Line":1}},{"line":542,"address":[655973],"length":1,"stats":{"Line":1}},{"line":543,"address":[42154222],"length":1,"stats":{"Line":1}},{"line":544,"address":[765991],"length":1,"stats":{"Line":1}},{"line":545,"address":[744848],"length":1,"stats":{"Line":1}},{"line":546,"address":[341369],"length":1,"stats":{"Line":1}},{"line":547,"address":[766126],"length":1,"stats":{"Line":1}},{"line":548,"address":[42154431],"length":1,"stats":{"Line":1}},{"line":549,"address":[1200427],"length":1,"stats":{"Line":1}},{"line":550,"address":[341479],"length":1,"stats":{"Line":1}},{"line":551,"address":[745011],"length":1,"stats":{"Line":1}},{"line":552,"address":[341500],"length":1,"stats":{"Line":1}},{"line":553,"address":[766217],"length":1,"stats":{"Line":1}},{"line":554,"address":[1200511],"length":1,"stats":{"Line":1}},{"line":555,"address":[745109],"length":1,"stats":{"Line":1}},{"line":556,"address":[42154382],"length":1,"stats":{"Line":1}},{"line":559,"address":[3582752],"length":1,"stats":{"Line":2}},{"line":560,"address":[42154641],"length":1,"stats":{"Line":5}},{"line":561,"address":[1200649],"length":1,"stats":{"Line":2}},{"line":562,"address":[341711],"length":1,"stats":{"Line":5}},{"line":563,"address":[656508],"length":1,"stats":{"Line":2}},{"line":564,"address":[42154740],"length":1,"stats":{"Line":5}},{"line":565,"address":[42154764],"length":1,"stats":{"Line":2}},{"line":566,"address":[766514],"length":1,"stats":{"Line":5}},{"line":567,"address":[745345],"length":1,"stats":{"Line":2}},{"line":569,"address":[1200814],"length":1,"stats":{"Line":5}},{"line":570,"address":[3583006,3582944],"length":1,"stats":{"Line":7}},{"line":571,"address":[766641],"length":1,"stats":{"Line":2}},{"line":572,"address":[1200904],"length":1,"stats":{"Line":2}},{"line":573,"address":[3583055],"length":1,"stats":{"Line":1}},{"line":574,"address":[42154934],"length":1,"stats":{"Line":1}},{"line":575,"address":[42154941],"length":1,"stats":{"Line":1}},{"line":576,"address":[341966],"length":1,"stats":{"Line":1}},{"line":577,"address":[745499],"length":1,"stats":{"Line":1}},{"line":578,"address":[1200888,1200974],"length":1,"stats":{"Line":8}},{"line":579,"address":[42155034,42154974],"length":1,"stats":{"Line":8}},{"line":580,"address":[745622,745562],"length":1,"stats":{"Line":7}},{"line":581,"address":[656854,656917],"length":1,"stats":{"Line":7}},{"line":582,"address":[42155109,42155178],"length":1,"stats":{"Line":7}},{"line":583,"address":[745706,745775,747035],"length":1,"stats":{"Line":9}},{"line":584,"address":[3583343,3583410],"length":1,"stats":{"Line":7}},{"line":585,"address":[42155266,42155335],"length":1,"stats":{"Line":6}},{"line":586,"address":[657180,657111],"length":1,"stats":{"Line":8}},{"line":587,"address":[746801],"length":1,"stats":{"Line":2}},{"line":588,"address":[746827],"length":1,"stats":{"Line":2}},{"line":589,"address":[1202293],"length":1,"stats":{"Line":2}},{"line":590,"address":[746879],"length":1,"stats":{"Line":2}},{"line":591,"address":[768089],"length":1,"stats":{"Line":3}},{"line":592,"address":[658179],"length":1,"stats":{"Line":3}},{"line":593,"address":[3584541],"length":1,"stats":{"Line":2}},{"line":594,"address":[1202423],"length":1,"stats":{"Line":2}},{"line":595,"address":[3584593],"length":1,"stats":{"Line":2}},{"line":596,"address":[1202223],"length":1,"stats":{"Line":1}},{"line":598,"address":[658013,657164,657248],"length":1,"stats":{"Line":9}},{"line":599,"address":[342458,342525],"length":1,"stats":{"Line":7}},{"line":600,"address":[657346,657283],"length":1,"stats":{"Line":4}},{"line":601,"address":[3583729,3583666],"length":1,"stats":{"Line":7}},{"line":602,"address":[767313,767382],"length":1,"stats":{"Line":6}},{"line":603,"address":[767443,767366],"length":1,"stats":{"Line":6}},{"line":604,"address":[746725],"length":1,"stats":{"Line":1}},{"line":605,"address":[767927],"length":1,"stats":{"Line":1}},{"line":606,"address":[3584295],"length":1,"stats":{"Line":1}},{"line":608,"address":[746311,746243],"length":1,"stats":{"Line":6}},{"line":609,"address":[3584083],"length":1,"stats":{"Line":1}},{"line":610,"address":[746517],"length":1,"stats":{"Line":2}},{"line":611,"address":[767719],"length":1,"stats":{"Line":1}},{"line":612,"address":[767737],"length":1,"stats":{"Line":1}},{"line":613,"address":[767755],"length":1,"stats":{"Line":2}},{"line":614,"address":[1202029],"length":1,"stats":{"Line":1}},{"line":615,"address":[343081],"length":1,"stats":{"Line":1}},{"line":616,"address":[3584209],"length":1,"stats":{"Line":2}},{"line":617,"address":[657891],"length":1,"stats":{"Line":3}},{"line":618,"address":[42156117],"length":1,"stats":{"Line":2}},{"line":619,"address":[746679],"length":1,"stats":{"Line":1}},{"line":620,"address":[1202137],"length":1,"stats":{"Line":1}},{"line":621,"address":[767669],"length":1,"stats":{"Line":1}},{"line":623,"address":[657544],"length":1,"stats":{"Line":1}},{"line":626,"address":[780530,768240],"length":1,"stats":{"Line":2}},{"line":628,"address":[658374],"length":1,"stats":{"Line":2}},{"line":629,"address":[343650],"length":1,"stats":{"Line":3}},{"line":630,"address":[343779,343678],"length":1,"stats":{"Line":2}},{"line":631,"address":[747269],"length":1,"stats":{"Line":3}},{"line":633,"address":[343813],"length":1,"stats":{"Line":1}},{"line":634,"address":[1202793],"length":1,"stats":{"Line":1}},{"line":638,"address":[747383],"length":1,"stats":{"Line":2}},{"line":642,"address":[42156858],"length":1,"stats":{"Line":2}},{"line":645,"address":[343938],"length":1,"stats":{"Line":4}},{"line":646,"address":[747482],"length":1,"stats":{"Line":4}},{"line":649,"address":[1202960],"length":1,"stats":{"Line":3}},{"line":650,"address":[344002],"length":1,"stats":{"Line":3}},{"line":651,"address":[3585156],"length":1,"stats":{"Line":3}},{"line":652,"address":[42157053],"length":1,"stats":{"Line":3}},{"line":655,"address":[768820],"length":1,"stats":{"Line":2}},{"line":656,"address":[747666],"length":1,"stats":{"Line":2}},{"line":657,"address":[1208328],"length":1,"stats":{"Line":2}},{"line":661,"address":[768905],"length":1,"stats":{"Line":2}},{"line":667,"address":[747751],"length":1,"stats":{"Line":2}},{"line":668,"address":[349307],"length":1,"stats":{"Line":3}},{"line":672,"address":[768990],"length":1,"stats":{"Line":2}},{"line":673,"address":[3585420],"length":1,"stats":{"Line":2}},{"line":674,"address":[42162396],"length":1,"stats":{"Line":1}},{"line":678,"address":[1203373],"length":1,"stats":{"Line":3}},{"line":679,"address":[659211],"length":1,"stats":{"Line":2}},{"line":682,"address":[1203447],"length":1,"stats":{"Line":2}},{"line":683,"address":[659285,664229],"length":1,"stats":{"Line":4}},{"line":686,"address":[344601],"length":1,"stats":{"Line":2}},{"line":687,"address":[769354],"length":1,"stats":{"Line":2}},{"line":690,"address":[1203703],"length":1,"stats":{"Line":2}},{"line":692,"address":[1203730],"length":1,"stats":{"Line":2}},{"line":693,"address":[748341],"length":1,"stats":{"Line":2}},{"line":695,"address":[769578],"length":1,"stats":{"Line":2}},{"line":697,"address":[748405],"length":1,"stats":{"Line":2}},{"line":698,"address":[3590885,3586018,3591413,3590626,3591181],"length":1,"stats":{"Line":4}},{"line":701,"address":[769680],"length":1,"stats":{"Line":2}},{"line":702,"address":[659774],"length":1,"stats":{"Line":2}},{"line":703,"address":[42158036],"length":1,"stats":{"Line":2}},{"line":704,"address":[1204074],"length":1,"stats":{"Line":2}},{"line":707,"address":[3586264],"length":1,"stats":{"Line":2}},{"line":708,"address":[345163],"length":1,"stats":{"Line":2}},{"line":709,"address":[345216],"length":1,"stats":{"Line":3}},{"line":710,"address":[3586402],"length":1,"stats":{"Line":3}},{"line":713,"address":[748864],"length":1,"stats":{"Line":3}},{"line":714,"address":[345352],"length":1,"stats":{"Line":3}},{"line":715,"address":[345405],"length":1,"stats":{"Line":3}},{"line":716,"address":[1209559,1209514,1204434],"length":1,"stats":{"Line":6}},{"line":717,"address":[3591666],"length":1,"stats":{"Line":3}},{"line":719,"address":[775295],"length":1,"stats":{"Line":3}},{"line":720,"address":[1209616],"length":1,"stats":{"Line":2}},{"line":722,"address":[1209583],"length":1,"stats":{"Line":2}},{"line":725,"address":[749037],"length":1,"stats":{"Line":3}},{"line":731,"address":[1204515],"length":1,"stats":{"Line":3}},{"line":732,"address":[3586708],"length":1,"stats":{"Line":3}},{"line":734,"address":[3586746],"length":1,"stats":{"Line":3}},{"line":736,"address":[749172,754304,754485],"length":1,"stats":{"Line":6}},{"line":737,"address":[775605,775436,775674],"length":1,"stats":{"Line":2}},{"line":738,"address":[754477],"length":1,"stats":{"Line":1}},{"line":740,"address":[775490,775472,775402],"length":1,"stats":{"Line":4}},{"line":741,"address":[754296],"length":1,"stats":{"Line":2}},{"line":744,"address":[665586],"length":1,"stats":{"Line":3}},{"line":745,"address":[1209815],"length":1,"stats":{"Line":3}},{"line":747,"address":[3586785],"length":1,"stats":{"Line":2}},{"line":752,"address":[345662],"length":1,"stats":{"Line":2}},{"line":755,"address":[345708],"length":1,"stats":{"Line":2}},{"line":756,"address":[749272],"length":1,"stats":{"Line":3}},{"line":757,"address":[660547],"length":1,"stats":{"Line":3}},{"line":758,"address":[3592098],"length":1,"stats":{"Line":2}},{"line":760,"address":[42164006],"length":1,"stats":{"Line":2}},{"line":763,"address":[770525],"length":1,"stats":{"Line":2}},{"line":768,"address":[3586952],"length":1,"stats":{"Line":2}},{"line":769,"address":[749407],"length":1,"stats":{"Line":2}},{"line":770,"address":[1204878],"length":1,"stats":{"Line":2}},{"line":772,"address":[1210239,1204888,1210101],"length":1,"stats":{"Line":6}},{"line":773,"address":[754606,754801,754730],"length":1,"stats":{"Line":4}},{"line":774,"address":[42164247],"length":1,"stats":{"Line":2}},{"line":776,"address":[3592247,3592159,3592226],"length":1,"stats":{"Line":4}},{"line":777,"address":[665901],"length":1,"stats":{"Line":2}},{"line":780,"address":[3593636,3594528,3593212,3592513,3593856,3594088,3594308,3592263,3594748],"length":1,"stats":{"Line":4}},{"line":782,"address":[351207],"length":1,"stats":{"Line":2}},{"line":783,"address":[42164326],"length":1,"stats":{"Line":2}},{"line":786,"address":[770673],"length":1,"stats":{"Line":2}},{"line":791,"address":[3587088],"length":1,"stats":{"Line":2}},{"line":794,"address":[660799],"length":1,"stats":{"Line":2}},{"line":795,"address":[346001],"length":1,"stats":{"Line":2}},{"line":796,"address":[749587],"length":1,"stats":{"Line":2}},{"line":797,"address":[42166976],"length":1,"stats":{"Line":3}},{"line":799,"address":[3595140],"length":1,"stats":{"Line":2}},{"line":802,"address":[346069],"length":1,"stats":{"Line":2}},{"line":808,"address":[42159115],"length":1,"stats":{"Line":2}},{"line":809,"address":[42159164],"length":1,"stats":{"Line":2}},{"line":810,"address":[42159197],"length":1,"stats":{"Line":2}},{"line":811,"address":[778773],"length":1,"stats":{"Line":1}},{"line":814,"address":[42159226],"length":1,"stats":{"Line":2}},{"line":820,"address":[346223],"length":1,"stats":{"Line":4}},{"line":823,"address":[42159279],"length":1,"stats":{"Line":1}},{"line":828,"address":[771027],"length":1,"stats":{"Line":1}},{"line":830,"address":[42159387],"length":1,"stats":{"Line":2}},{"line":837,"address":[346408],"length":1,"stats":{"Line":2}},{"line":838,"address":[354042,346433],"length":1,"stats":{"Line":4}},{"line":839,"address":[668921],"length":1,"stats":{"Line":2}},{"line":840,"address":[1213122],"length":1,"stats":{"Line":2}},{"line":841,"address":[354081,355425,354633,355193,354245,354961],"length":1,"stats":{"Line":4}},{"line":842,"address":[3595371],"length":1,"stats":{"Line":2}},{"line":844,"address":[750035],"length":1,"stats":{"Line":2}},{"line":856,"address":[750085],"length":1,"stats":{"Line":4}},{"line":857,"address":[750133],"length":1,"stats":{"Line":2}},{"line":858,"address":[661435],"length":1,"stats":{"Line":4}},{"line":859,"address":[1205671],"length":1,"stats":{"Line":2}},{"line":861,"address":[3596995,3597619],"length":1,"stats":{"Line":0}},{"line":862,"address":[356386],"length":1,"stats":{"Line":0}},{"line":864,"address":[760045],"length":1,"stats":{"Line":0}},{"line":866,"address":[356413],"length":1,"stats":{"Line":0}},{"line":867,"address":[760173,760285,760361],"length":1,"stats":{"Line":0}},{"line":868,"address":[3597977,3598085,3597909],"length":1,"stats":{"Line":0}},{"line":869,"address":[42169981,42170066,42169934],"length":1,"stats":{"Line":0}},{"line":870,"address":[760626,760581],"length":1,"stats":{"Line":0}},{"line":871,"address":[760697,760870],"length":1,"stats":{"Line":0}},{"line":872,"address":[42170355,42170309],"length":1,"stats":{"Line":0}},{"line":876,"address":[1214865,1214952,1214816],"length":1,"stats":{"Line":10}},{"line":877,"address":[759533,759645],"length":1,"stats":{"Line":2}},{"line":878,"address":[759669,759622,759754],"length":1,"stats":{"Line":6}},{"line":879,"address":[1215210,1215165],"length":1,"stats":{"Line":6}},{"line":880,"address":[42169300],"length":1,"stats":{"Line":4}},{"line":885,"address":[42168937,42169676],"length":1,"stats":{"Line":2}},{"line":886,"address":[356579],"length":1,"stats":{"Line":4}},{"line":888,"address":[3597796],"length":1,"stats":{"Line":0}},{"line":891,"address":[1215678],"length":1,"stats":{"Line":2}},{"line":893,"address":[346693],"length":1,"stats":{"Line":1}},{"line":898,"address":[3587865],"length":1,"stats":{"Line":1}},{"line":899,"address":[771497],"length":1,"stats":{"Line":1}},{"line":900,"address":[1205778],"length":1,"stats":{"Line":1}},{"line":901,"address":[1216523],"length":1,"stats":{"Line":1}},{"line":904,"address":[42159823],"length":1,"stats":{"Line":1}},{"line":912,"address":[346804],"length":1,"stats":{"Line":1}},{"line":913,"address":[42159874],"length":1,"stats":{"Line":1}},{"line":914,"address":[42170751,42170605,42159903,42171015],"length":1,"stats":{"Line":2}},{"line":915,"address":[42170564],"length":1,"stats":{"Line":1}},{"line":916,"address":[3599342],"length":1,"stats":{"Line":1}},{"line":919,"address":[661757],"length":1,"stats":{"Line":0}},{"line":924,"address":[1205961],"length":1,"stats":{"Line":0}},{"line":925,"address":[3588141],"length":1,"stats":{"Line":0}},{"line":927,"address":[750598],"length":1,"stats":{"Line":2}},{"line":932,"address":[661858],"length":1,"stats":{"Line":2}},{"line":934,"address":[661900],"length":1,"stats":{"Line":1}},{"line":939,"address":[771851],"length":1,"stats":{"Line":1}},{"line":940,"address":[42160155],"length":1,"stats":{"Line":1}},{"line":942,"address":[3588320],"length":1,"stats":{"Line":1}},{"line":943,"address":[1206191],"length":1,"stats":{"Line":1}},{"line":944,"address":[771967],"length":1,"stats":{"Line":1}},{"line":946,"address":[42160276],"length":1,"stats":{"Line":2}},{"line":951,"address":[347249],"length":1,"stats":{"Line":2}},{"line":952,"address":[347296],"length":1,"stats":{"Line":2}},{"line":953,"address":[347337,358133],"length":1,"stats":{"Line":4}},{"line":955,"address":[750983],"length":1,"stats":{"Line":1}},{"line":963,"address":[750998],"length":1,"stats":{"Line":1}},{"line":965,"address":[358178,358206,347436],"length":1,"stats":{"Line":2}},{"line":966,"address":[783030],"length":1,"stats":{"Line":1}},{"line":968,"address":[42160528],"length":1,"stats":{"Line":2}},{"line":976,"address":[42160543],"length":1,"stats":{"Line":2}},{"line":979,"address":[1206558],"length":1,"stats":{"Line":2}},{"line":981,"address":[1217337,1206589,1217567],"length":1,"stats":{"Line":4}},{"line":983,"address":[673205],"length":1,"stats":{"Line":2}},{"line":986,"address":[673238],"length":1,"stats":{"Line":2}},{"line":988,"address":[762027],"length":1,"stats":{"Line":2}},{"line":989,"address":[3599655],"length":1,"stats":{"Line":2}},{"line":990,"address":[358545,358494,358437],"length":1,"stats":{"Line":4}},{"line":991,"address":[1217622,1217679],"length":1,"stats":{"Line":4}},{"line":993,"address":[3588800],"length":1,"stats":{"Line":3}},{"line":998,"address":[751227],"length":1,"stats":{"Line":3}},{"line":999,"address":[1217712,1217822,1206713],"length":1,"stats":{"Line":9}},{"line":1000,"address":[1217921,1217840],"length":1,"stats":{"Line":6}},{"line":1002,"address":[42171895,42171792],"length":1,"stats":{"Line":6}},{"line":1004,"address":[347902],"length":1,"stats":{"Line":2}},{"line":1008,"address":[751521],"length":1,"stats":{"Line":2}},{"line":1009,"address":[1218235,1218499,1218086,1206982],"length":1,"stats":{"Line":4}},{"line":1010,"address":[762548],"length":1,"stats":{"Line":2}},{"line":1011,"address":[784641,784495,783756],"length":1,"stats":{"Line":4}},{"line":1012,"address":[763628,763729,763248],"length":1,"stats":{"Line":6}},{"line":1013,"address":[360070,360162,360257],"length":1,"stats":{"Line":4}},{"line":1014,"address":[785044],"length":1,"stats":{"Line":2}},{"line":1015,"address":[3601561,3602722,3601930,3602490,3602258,3601475],"length":1,"stats":{"Line":4}},{"line":1017,"address":[1219124,1219236],"length":1,"stats":{"Line":4}},{"line":1020,"address":[662995],"length":1,"stats":{"Line":1}},{"line":1021,"address":[751762],"length":1,"stats":{"Line":1}},{"line":1024,"address":[42161241],"length":1,"stats":{"Line":1}},{"line":1027,"address":[1207244],"length":1,"stats":{"Line":1}},{"line":1030,"address":[751823],"length":1,"stats":{"Line":1}},{"line":1033,"address":[42161298],"length":1,"stats":{"Line":1}},{"line":1036,"address":[773037],"length":1,"stats":{"Line":0}},{"line":1038,"address":[42161357],"length":1,"stats":{"Line":0}},{"line":1039,"address":[773471,773207],"length":1,"stats":{"Line":0}},{"line":1041,"address":[663638,676651],"length":1,"stats":{"Line":0}},{"line":1043,"address":[42161924],"length":1,"stats":{"Line":0}},{"line":1044,"address":[3590174],"length":1,"stats":{"Line":0}},{"line":1046,"address":[773862],"length":1,"stats":{"Line":0}},{"line":1047,"address":[664048],"length":1,"stats":{"Line":0}},{"line":1050,"address":[347988],"length":1,"stats":{"Line":2}},{"line":1052,"address":[42161165],"length":1,"stats":{"Line":2}},{"line":1055,"address":[1220880],"length":1,"stats":{"Line":0}},{"line":1056,"address":[3603053],"length":1,"stats":{"Line":0}},{"line":1057,"address":[786778],"length":1,"stats":{"Line":0}},{"line":1059,"address":[3603253],"length":1,"stats":{"Line":0}}],"covered":402,"coverable":444},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","keypad.rs"],"content":"use crate::constants::CHIP8_KEYBOARD;\n\n#[derive(Clone, Copy)]\npub struct Keypad {\n keys: [bool; 0x10],\n}\n\nimpl Keypad {\n pub fn format_as_string(\u0026self) -\u003e String {\n let mut return_value = String::new();\n // draw a 4x4 grid showing the keys with * filling the cells that are depressed\n for row in CHIP8_KEYBOARD.iter() {\n for (index, key) in row.iter().enumerate() {\n let is_lit = if self.keys[*key as usize] {\n \"*\".to_string()\n } else {\n char::from_digit(*key as u32, 16).unwrap_or(' ').to_string()\n };\n\n if index == 3 {\n return_value += format!(\"|{}|\\n\", is_lit).as_str();\n\n } else {\n return_value += format!(\"|{}\", is_lit).as_str();\n }\n }\n }\n\n return_value\n }\n}\n\nimpl Default for Keypad {\n fn default() -\u003e Self {\n Keypad {\n keys: [ false; 16]\n }\n }\n}\n\nimpl Keypad {\n pub fn push_key(\u0026mut self, key_index: u8) {\n self.keys[key_index as usize] = true;\n }\n\n pub fn release_key(\u0026mut self, key_index: u8) {\n self.keys[key_index as usize] = false;\n }\n\n pub fn key_state(\u0026self, key_index: u8) -\u003e bool {\n self.keys[key_index as usize]\n }\n\n pub fn new() -\u003e Keypad {\n Keypad::default()\n }\n\n pub fn pressed(\u0026self, key: u8) -\u003e bool {\n self.key_state(key)\n }\n pub fn released(\u0026self, key: u8) -\u003e bool {\n !self.key_state(key)\n }\n}\n","traces":[{"line":9,"address":[770424,769104,770670],"length":1,"stats":{"Line":1}},{"line":10,"address":[790143],"length":1,"stats":{"Line":1}},{"line":12,"address":[1224867,1224695,1224596],"length":1,"stats":{"Line":3}},{"line":13,"address":[1224883],"length":1,"stats":{"Line":1}},{"line":14,"address":[769703],"length":1,"stats":{"Line":1}},{"line":15,"address":[790784,790884],"length":1,"stats":{"Line":0}},{"line":17,"address":[380277,380332],"length":1,"stats":{"Line":2}},{"line":20,"address":[790876],"length":1,"stats":{"Line":1}},{"line":21,"address":[1225737,1225608],"length":1,"stats":{"Line":2}},{"line":24,"address":[596194,596065],"length":1,"stats":{"Line":2}},{"line":29,"address":[595016],"length":1,"stats":{"Line":1}},{"line":34,"address":[42103296],"length":1,"stats":{"Line":6}},{"line":36,"address":[3562974],"length":1,"stats":{"Line":3}},{"line":42,"address":[770752],"length":1,"stats":{"Line":2}},{"line":43,"address":[42103419,42103381],"length":1,"stats":{"Line":2}},{"line":46,"address":[791824],"length":1,"stats":{"Line":1}},{"line":47,"address":[1226293,1226331],"length":1,"stats":{"Line":1}},{"line":50,"address":[770912],"length":1,"stats":{"Line":1}},{"line":51,"address":[1226412,1226373],"length":1,"stats":{"Line":1}},{"line":54,"address":[3563280],"length":1,"stats":{"Line":1}},{"line":55,"address":[381512],"length":1,"stats":{"Line":1}},{"line":58,"address":[381536],"length":1,"stats":{"Line":1}},{"line":59,"address":[792048],"length":1,"stats":{"Line":1}},{"line":61,"address":[1226512],"length":1,"stats":{"Line":1}},{"line":62,"address":[3563360],"length":1,"stats":{"Line":1}}],"covered":24,"coverable":25},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","quirk_modes.rs"],"content":"#[derive(Default, Clone)]\npub enum QuirkMode {\n #[default]\n Chip8,\n XOChip,\n SChipModern\n}\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","registers.rs"],"content":"/// Registers. numbered 1-16 publicly.\n/// Privately using zero base array so -1 to shift from pub to priv.\n#[derive(Clone, Copy)]\npub struct Chip8Registers {\n pub registers: [u8; 16],\n pub i_register: u16,\n pub pc: u16,\n}\n\nimpl Chip8Registers {\n pub fn advance_pc(\u0026mut self) {\n self.pc += 2;\n }\n}\n\nimpl Default for Chip8Registers {\n fn default() -\u003e Self {\n Chip8Registers {\n registers: [0x00; 16],\n i_register: 0x00,\n pc: 0x200,\n }\n }\n}\n\nimpl Chip8Registers {\n pub fn reset(\u0026mut self) {\n self.registers = [0x00; 16];\n self.i_register = 0x00;\n self.pc = 0x200;\n }\n\n pub fn poke_pc(\u0026mut self, new_pc: u16) {\n self.pc = new_pc\n }\n pub fn peek_i(\u0026self) -\u003e u16 {\n self.i_register\n }\n\n pub fn poke_i(\u0026mut self, new_value: u16) {\n self.i_register = new_value;\n }\n pub fn peek(\u0026self, register_number: u8) -\u003e u8 {\n self.registers[register_number as usize]\n }\n\n pub fn poke(\u0026mut self, register_number: u8, value: u8) {\n if register_number \u003e 0xf {\n panic!(\"INVALID REGISTER\");\n }\n self.registers[register_number as usize] = value;\n }\n\n pub fn peek_pc(\u0026self) -\u003e u16 {\n self.pc\n }\n\n pub fn set_pc(\u0026mut self, new_pc: u16) {\n self.pc = new_pc\n }\n\n pub fn format_as_string(\u0026self) -\u003e String {\n format!(\"Vx: 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x}\\n 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x}\\nI: 0x{:04x}\\tPC: 0x{:04x}\",\n self.registers[0x0],\n self.registers[0x1],\n self.registers[0x2],\n self.registers[0x3],\n self.registers[0x4],\n self.registers[0x5],\n self.registers[0x6],\n self.registers[0x7],\n self.registers[0x8],\n self.registers[0x9],\n self.registers[0xa],\n self.registers[0xb],\n self.registers[0xc],\n self.registers[0xd],\n self.registers[0xe],\n self.registers[0xf],\n self.i_register,\n self.pc\n )\n }\n}\n","traces":[{"line":11,"address":[626912],"length":1,"stats":{"Line":2}},{"line":12,"address":[292787,292749],"length":1,"stats":{"Line":2}},{"line":17,"address":[42086528],"length":1,"stats":{"Line":6}},{"line":19,"address":[717454],"length":1,"stats":{"Line":4}},{"line":27,"address":[42086608],"length":1,"stats":{"Line":2}},{"line":28,"address":[822286],"length":1,"stats":{"Line":2}},{"line":29,"address":[822303],"length":1,"stats":{"Line":2}},{"line":30,"address":[42086645],"length":1,"stats":{"Line":2}},{"line":33,"address":[717568],"length":1,"stats":{"Line":3}},{"line":34,"address":[822333],"length":1,"stats":{"Line":2}},{"line":36,"address":[1139616],"length":1,"stats":{"Line":2}},{"line":37,"address":[42086693],"length":1,"stats":{"Line":4}},{"line":40,"address":[1139632],"length":1,"stats":{"Line":2}},{"line":41,"address":[42086717],"length":1,"stats":{"Line":4}},{"line":43,"address":[717648],"length":1,"stats":{"Line":4}},{"line":44,"address":[822458,822421],"length":1,"stats":{"Line":2}},{"line":47,"address":[822480],"length":1,"stats":{"Line":3}},{"line":48,"address":[293139],"length":1,"stats":{"Line":2}},{"line":49,"address":[627339],"length":1,"stats":{"Line":1}},{"line":51,"address":[627413,627323,627400],"length":1,"stats":{"Line":5}},{"line":54,"address":[717888],"length":1,"stats":{"Line":5}},{"line":55,"address":[627445],"length":1,"stats":{"Line":3}},{"line":58,"address":[627456],"length":1,"stats":{"Line":2}},{"line":59,"address":[3515469],"length":1,"stats":{"Line":5}},{"line":62,"address":[42087024],"length":1,"stats":{"Line":1}},{"line":63,"address":[3519612,3515986,3518916,3520540,3520772,3517102,3521932,3516730,3516451,3519148,3516079,3517988,3516544,3515707,3521004,3520308,3521700,3517192,3516172,3521468,3520076,3516916,3518452,3518220,3516637,3519380,3516823,3515800,3515614,3516265,3517009,3516358,3518684,3521236,3519844,3515893],"length":1,"stats":{"Line":62}}],"covered":26,"coverable":26},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","sound_timer.rs"],"content":"use log::trace;\n\n#[derive(Clone, Copy)]\npub struct SoundTimer {\n counter: i32\n}\n\nimpl SoundTimer {\n pub fn current(\u0026self) -\u003e i32 {\n self.counter\n }\n pub fn new() -\u003e Self {\n SoundTimer {\n counter: 0\n }\n }\n pub fn set_timer(\u0026mut self, new_value: i32) {\n trace!(\"SETTING SOUND TIMER TO {new_value}\");\n self.counter = new_value\n }\n\n pub fn tick(\u0026mut self) {\n trace!(\"TICKING SOUND FROM {} to {}\", self.counter, self.counter - 1);\n if self.counter \u003e 0 {\n self.counter -= 1;\n /*\n todo: this breaks tests. maybe its wrong?\n if let good_thread = thread::spawn(|| {\n beep(440).expect(\"Unable to beep\");\n thread::sleep(time::Duration::from_millis(500));\n }).join().unwrap().\n */\n }\n }\n\n pub fn reset(\u0026mut self) {\n self.counter = 0x00;\n }\n}\n","traces":[{"line":9,"address":[385312],"length":1,"stats":{"Line":1}},{"line":10,"address":[625877],"length":1,"stats":{"Line":1}},{"line":17,"address":[821104],"length":1,"stats":{"Line":1}},{"line":18,"address":[3555216,3555016,3555094],"length":1,"stats":{"Line":2}},{"line":19,"address":[42131100],"length":1,"stats":{"Line":1}},{"line":22,"address":[1183328],"length":1,"stats":{"Line":2}},{"line":23,"address":[1183541,1183426,1183348,1183679],"length":1,"stats":{"Line":7}},{"line":24,"address":[626328,626852],"length":1,"stats":{"Line":6}},{"line":25,"address":[822054,822028],"length":1,"stats":{"Line":1}},{"line":36,"address":[386320],"length":1,"stats":{"Line":1}},{"line":37,"address":[3555973],"length":1,"stats":{"Line":1}}],"covered":11,"coverable":11},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","stack.rs"],"content":"#[derive(Clone)]\npub struct Chip8Stack {\n items: Vec\u003cu16\u003e\n}\n\nimpl Default for Chip8Stack {\n fn default() -\u003e Self {\n Chip8Stack {\n items: vec![],\n }\n }\n}\n\nimpl Chip8Stack {\n pub fn push(\u0026mut self, new_value: \u0026u16) {\n if self.depth() == 16 {\n // println!(\"Deep deep stack?\");\n panic!(\"Stack Overflow\");\n }\n self.items.push(*new_value );\n }\n pub fn pop(\u0026mut self) -\u003e u16 {\n if self.items.is_empty() {\n panic!(\"Stack Underflow\");\n }\n self.items.pop().unwrap()\n }\n pub fn depth(\u0026self) -\u003e u16 {\n self.items.len() as u16\n }\n\n pub fn new() -\u003e Self {\n Chip8Stack {\n items: vec![]\n }\n }\n\n pub fn reset(\u0026mut self) {\n self.items = vec![]\n }\n}\n","traces":[{"line":7,"address":[792720],"length":1,"stats":{"Line":3}},{"line":9,"address":[809453],"length":1,"stats":{"Line":7}},{"line":15,"address":[809504],"length":1,"stats":{"Line":3}},{"line":16,"address":[1174008],"length":1,"stats":{"Line":3}},{"line":18,"address":[307363],"length":1,"stats":{"Line":1}},{"line":20,"address":[42122187],"length":1,"stats":{"Line":3}},{"line":22,"address":[1174096],"length":1,"stats":{"Line":2}},{"line":23,"address":[42122222],"length":1,"stats":{"Line":2}},{"line":24,"address":[3569303],"length":1,"stats":{"Line":1}},{"line":26,"address":[1174125],"length":1,"stats":{"Line":2}},{"line":28,"address":[42122352],"length":1,"stats":{"Line":3}},{"line":29,"address":[793045],"length":1,"stats":{"Line":3}},{"line":32,"address":[42122368],"length":1,"stats":{"Line":1}},{"line":34,"address":[42122381],"length":1,"stats":{"Line":1}},{"line":38,"address":[809840,809903],"length":1,"stats":{"Line":1}},{"line":39,"address":[3569533,3569453],"length":1,"stats":{"Line":2}}],"covered":16,"coverable":16},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","system_memory.rs"],"content":"use log::{trace};\n\nuse crate::constants::*;\n\n#[derive(Clone, Copy)]\npub struct Chip8SystemMemory {\n memory: [u8; CHIP8_MEMORY_SIZE as usize],\n}\n\nimpl Default for Chip8SystemMemory {\n fn default() -\u003e Self {\n\n let mut x = Chip8SystemMemory {\n memory: [0x00; CHIP8_MEMORY_SIZE as usize],\n };\n\n x.load_fonts_to_memory();\n x.load_schip_fonts_to_memory();\n x\n }\n}\nimpl Chip8SystemMemory {\n\n pub fn reset(\u0026mut self){\n self.memory = [0x00; CHIP8_MEMORY_SIZE as usize];\n self.load_fonts_to_memory();\n self.load_schip_fonts_to_memory();\n }\n \n pub fn new() -\u003e Self {\n Chip8SystemMemory {\n memory: [0x00; CHIP8_MEMORY_SIZE as usize],\n }\n }\n\n pub fn peek(\u0026self, address: u16) -\u003e u8 {\n trace!(\"PEEK: {} / {}\", address, self.memory[address as usize].clone());\n self.memory[address as usize]\n }\n\n pub fn poke(\u0026mut self, address: u16, value: u8) {\n trace!(\"POKE: {} / {} to {}\", address, self.memory[address as usize], value);\n self.memory[address as usize] = value;\n }\n\n pub fn load_program(\u0026mut self, program_to_load: Box\u003cVec\u003cu8\u003e\u003e) {\n for load_index in 0..program_to_load.len() {\n self.poke((load_index + 0x200) as u16, program_to_load[load_index]);\n }\n }\n\n pub fn load_fonts_to_memory(\u0026mut self) {\n let all_font_characters = [\n CHIP8FONT_0,\n CHIP8FONT_1,\n CHIP8FONT_2,\n CHIP8FONT_3,\n CHIP8FONT_4,\n CHIP8FONT_5,\n CHIP8FONT_6,\n CHIP8FONT_7,\n CHIP8FONT_8,\n CHIP8FONT_9,\n CHIP8FONT_A,\n CHIP8FONT_B,\n CHIP8FONT_C,\n CHIP8FONT_D,\n CHIP8FONT_E,\n CHIP8FONT_F,\n ];\n\n for (font_index, current_font) in all_font_characters.iter().enumerate() {\n for font_mem_offset in 0..=4 {\n let real_offset = font_index * 5 + font_mem_offset;\n self.poke(real_offset as u16, current_font[font_mem_offset]);\n }\n }\n }\n\n pub fn load_schip_fonts_to_memory(\u0026mut self) {\n let all_font_characters = [\n SCHIPFONT_0, SCHIPFONT_1, SCHIPFONT_2, SCHIPFONT_3,\n SCHIPFONT_4, SCHIPFONT_5, SCHIPFONT_6, SCHIPFONT_7,\n SCHIPFONT_8, SCHIPFONT_9, SCHIPFONT_A, SCHIPFONT_B,\n SCHIPFONT_C, SCHIPFONT_D, SCHIPFONT_E, SCHIPFONT_F\n ];\n for (font_index, current_font) in all_font_characters.iter().enumerate() {\n let base_offset = 0x100;\n for font_mem_offset in 0..=4 {\n let real_offset = base_offset + font_index * 0x10 + font_mem_offset;\n self.poke(real_offset as u16, current_font[font_mem_offset]);\n }\n }\n }\n}","traces":[{"line":11,"address":[1149456],"length":1,"stats":{"Line":8}},{"line":14,"address":[42097148],"length":1,"stats":{"Line":4}},{"line":17,"address":[322647],"length":1,"stats":{"Line":8}},{"line":18,"address":[835970],"length":1,"stats":{"Line":2}},{"line":19,"address":[640178],"length":1,"stats":{"Line":6}},{"line":24,"address":[42097248],"length":1,"stats":{"Line":1}},{"line":25,"address":[836030],"length":1,"stats":{"Line":1}},{"line":26,"address":[42097279],"length":1,"stats":{"Line":1}},{"line":27,"address":[836058],"length":1,"stats":{"Line":1}},{"line":30,"address":[729168],"length":1,"stats":{"Line":0}},{"line":32,"address":[836109],"length":1,"stats":{"Line":0}},{"line":36,"address":[640352],"length":1,"stats":{"Line":2}},{"line":37,"address":[729642,729490,729276,729362],"length":1,"stats":{"Line":7}},{"line":38,"address":[729876,729860,729307],"length":1,"stats":{"Line":7}},{"line":41,"address":[729904],"length":1,"stats":{"Line":8}},{"line":42,"address":[1150520,1150870,1150434,1150648],"length":1,"stats":{"Line":9}},{"line":43,"address":[1151120,1151140,1150465],"length":1,"stats":{"Line":14}},{"line":46,"address":[324272,324588],"length":1,"stats":{"Line":0}},{"line":47,"address":[837791,837606,837673],"length":1,"stats":{"Line":0}},{"line":48,"address":[42099041],"length":1,"stats":{"Line":0}},{"line":52,"address":[731040],"length":1,"stats":{"Line":6}},{"line":53,"address":[324644],"length":1,"stats":{"Line":6}},{"line":72,"address":[1151897,1152067],"length":1,"stats":{"Line":15}},{"line":73,"address":[838525],"length":1,"stats":{"Line":3}},{"line":74,"address":[325445,325355],"length":1,"stats":{"Line":9}},{"line":75,"address":[325437,325481],"length":1,"stats":{"Line":9}},{"line":80,"address":[3527680],"length":1,"stats":{"Line":7}},{"line":81,"address":[838893],"length":1,"stats":{"Line":4}},{"line":87,"address":[732923,733093],"length":1,"stats":{"Line":13}},{"line":88,"address":[1152460],"length":1,"stats":{"Line":6}},{"line":89,"address":[3528863],"length":1,"stats":{"Line":2}},{"line":90,"address":[3529027,3529156],"length":1,"stats":{"Line":8}},{"line":91,"address":[3529148,3529192],"length":1,"stats":{"Line":9}}],"covered":28,"coverable":33},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","util.rs"],"content":"pub struct InstructionUtil {}\n\nimpl InstructionUtil {\n pub fn byte_to_bools(to_convert: u8) -\u003e [bool; 8] {\n let mut return_values = [false; 8];\n for i in 0..8 {\n let new_value = to_convert \u003e\u003e i \u0026 0x1 == 1;\n return_values[i as usize] = new_value;\n }\n return_values\n }\n\n pub fn bools_to_byte(to_convert: [bool; 8]) -\u003e u8 {\n let mut return_value = 0u8;\n for i in 0..to_convert.len() {\n let new_bit = 0x1 \u003c\u003c i;\n if to_convert[i] {\n return_value = return_value | new_bit\n }\n }\n return_value\n }\n\n pub fn split_bytes(to_split: u16) -\u003e (u8, u8) {\n let high = to_split.rotate_left(8) as u8;\n let low = (to_split \u0026 0xff) as u8;\n\n (high, low)\n }\n\n pub fn join_bytes(high: u8, low: u8) -\u003e u16 {\n let result = (high as u16) \u003c\u003c 8 | low as u16;\n result\n }\n\n // nnn or addr - A 12-bit value, the lowest 12 bits of the instruction\n pub fn read_addr_from_instruction(instruction_to_read_from: u16) -\u003e u16 {\n instruction_to_read_from \u0026 0x0FFF\n }\n\n // n or nibble - A 4-bit value, the lowest 4 bits of the instruction\n pub fn read_nibble_from_instruction(instruction_to_read_from: u16) -\u003e u8 {\n ( instruction_to_read_from \u0026 0x000F )as u8\n }\n\n // x - A 4-bit value, the lower 4 bits of the high byte of the instruction\n pub fn read_x_from_instruction(instruction_to_read_from: u16) -\u003e u8 {\n (instruction_to_read_from \u0026 0x0F00).rotate_right(8) as u8\n }\n\n // y - A 4-bit value, the upper 4 bits of the low byte of the instruction\n pub fn read_y_from_instruction(instruction_to_read_from: u16) -\u003e u8 {\n (instruction_to_read_from \u0026 0x00F0).rotate_right(4) as u8\n }\n\n // kk or byte - An 8-bit value, the lowest 8 bits of the instruction\n pub fn read_byte_from_instruction(instruction_to_read_from: u16) -\u003e u8 {\n (instruction_to_read_from \u0026 0x00FF) as u8\n }\n\n pub fn read_upper_byte_lower_nibble(to_read_from: u16) -\u003e u8 {\n ((to_read_from \u0026 0x0f00) \u003e\u003e 8) as u8\n }\n}\n","traces":[{"line":4,"address":[792304],"length":1,"stats":{"Line":1}},{"line":5,"address":[42178383],"length":1,"stats":{"Line":1}},{"line":6,"address":[42178400,42178470,42178571],"length":1,"stats":{"Line":3}},{"line":7,"address":[3606667,3606610],"length":1,"stats":{"Line":1}},{"line":8,"address":[1226868,1226828,1226885],"length":1,"stats":{"Line":2}},{"line":10,"address":[42178450],"length":1,"stats":{"Line":1}},{"line":13,"address":[1226912],"length":1,"stats":{"Line":1}},{"line":14,"address":[42178627],"length":1,"stats":{"Line":1}},{"line":15,"address":[680856,680919],"length":1,"stats":{"Line":2}},{"line":16,"address":[771654,771694],"length":1,"stats":{"Line":1}},{"line":17,"address":[3606946,3606870,3606899],"length":1,"stats":{"Line":3}},{"line":18,"address":[3606938],"length":1,"stats":{"Line":1}},{"line":21,"address":[792622],"length":1,"stats":{"Line":1}},{"line":24,"address":[771776],"length":1,"stats":{"Line":1}},{"line":25,"address":[42178869],"length":1,"stats":{"Line":1}},{"line":26,"address":[1227177],"length":1,"stats":{"Line":1}},{"line":31,"address":[681104],"length":1,"stats":{"Line":1}},{"line":32,"address":[771838],"length":1,"stats":{"Line":1}},{"line":37,"address":[792864],"length":1,"stats":{"Line":2}},{"line":38,"address":[42178936],"length":1,"stats":{"Line":5}},{"line":42,"address":[372960],"length":1,"stats":{"Line":2}},{"line":43,"address":[792888],"length":1,"stats":{"Line":5}},{"line":47,"address":[792896],"length":1,"stats":{"Line":2}},{"line":48,"address":[372984],"length":1,"stats":{"Line":5}},{"line":52,"address":[771952],"length":1,"stats":{"Line":5}},{"line":53,"address":[792952],"length":1,"stats":{"Line":2}},{"line":57,"address":[42179056],"length":1,"stats":{"Line":5}},{"line":58,"address":[772008],"length":1,"stats":{"Line":2}},{"line":61,"address":[1227376],"length":1,"stats":{"Line":5}},{"line":62,"address":[3607208],"length":1,"stats":{"Line":2}}],"covered":30,"coverable":30},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","chip8","video.rs"],"content":"use log::{debug};\nuse crate::chip8::util::InstructionUtil;\nuse crate::chip8::video::Chip8VideoModes::{HighRes, LowRes};\nuse crate::constants::{CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_MEMORY, CHIP8_VIDEO_WIDTH, SCHIP_VIDE_MEMORY, SCHIP_VIDEO_HEIGHT, SCHIP_VIDEO_WIDTH};\n\n#[derive(Clone, Copy)]\nenum Chip8VideoModes {\n LowRes,\n HighRes,\n}\n\n#[derive(Clone)]\npub struct Chip8Video {\n memory: Vec\u003cbool\u003e,\n pub has_frame_changed: bool,\n current_res: Chip8VideoModes,\n}\n\nimpl Chip8Video {\n pub fn reset(\u0026mut self) {\n self.cls();\n self.start_frame();\n }\n\n pub fn is_highres(\u0026self) -\u003e bool {\n matches!(self.current_res, HighRes)\n }\n\n pub fn set_highres(\u0026mut self) {\n self.current_res = HighRes;\n self.cls();\n }\n\n pub fn set_lowres(\u0026mut self) {\n self.current_res = LowRes\n }\n\n pub fn get_screen_resolution(\u0026mut self) -\u003e Chip8VideoModes {\n self.current_res\n }\n\n pub fn cls(\u0026mut self) {\n self.memory.clear();\n let num_loops = match self.current_res {\n LowRes =\u003e {\n CHIP8_VIDEO_MEMORY\n }\n HighRes =\u003e {\n SCHIP_VIDE_MEMORY\n }\n };\n for i in 0..num_loops {\n self.memory.push(false);\n }\n }\n\n pub fn start_frame(\u0026mut self) {\n self.has_frame_changed = false;\n }\n\n pub fn new(initial_configuration: Box\u003cVec\u003cbool\u003e\u003e) -\u003e Self {\n Self {\n memory: *initial_configuration,\n has_frame_changed: false,\n current_res: Chip8VideoModes::LowRes,\n }\n }\n\n pub fn peek(\u0026self, address: u16) -\u003e bool {\n let loop_value: u16 = if self.is_highres() {\n SCHIP_VIDE_MEMORY as u16\n } else {\n CHIP8_VIDEO_MEMORY as u16\n };\n let effective_address = if address \u003e= loop_value {\n address % loop_value\n } else { address };\n self.memory[effective_address as usize]\n }\n\n pub fn poke(\u0026mut self, address: u16, new_value: bool) {\n let loop_value: u16 = self.get_memory_size() as u16;\n // Loop the address\n let effective_address = address % loop_value;\n\n let old_value = self.memory[effective_address as usize];\n let xored_value = new_value ^ old_value; // XOR of the video\n // if the frame has already changed we dont care if it changed again.\n if !self.has_frame_changed {\n if old_value != xored_value {\n self.has_frame_changed = true\n };\n }\n\n // println!(\"VIDEO POKE COMPLETE WITH {effective_address} SET TO {xored_value}\");\n self.memory[effective_address as usize] = xored_value;\n }\n\n pub fn poke_byte(\u0026mut self, first_address: u16, to_write: u8) {\n for i in (0..8).rev() {\n self.poke(first_address + (7 - i), (to_write \u0026 (1 \u003c\u003c i)) != 0);\n }\n }\n\n pub fn poke_2byte(\u0026mut self, first_address: u16, to_write: [u8; 2]) {\n for (idx, _) in to_write.iter().enumerate() {\n for i in (0..8).rev() {\n self.poke(first_address + (idx * 8) as u16 + (7 - i), (to_write[idx] \u0026 (1 \u003c\u003c i)) != 0);\n }\n }\n }\n\n pub fn format_as_string(\u0026self) -\u003e String {\n let (width, height) = self.get_resolution();\n println!(\"FORMATTING {width}x{height}\");\n let mut output = String::new();\n for row in 0..height {\n for column in 0..width {\n let data_offset = row * width + column;\n debug!(\"Rendering {data_offset} with value {}\", self.memory[data_offset as usize]);\n if self.memory[data_offset as usize] {\n output += \"*\"\n } else {\n output += \" \"\n }\n }\n output += \"\\n\";\n }\n output\n }\n\n pub fn get_resolution(\u0026self) -\u003e (i32, i32) {\n if self.is_highres() {\n (SCHIP_VIDEO_WIDTH, SCHIP_VIDEO_HEIGHT)\n } else {\n (CHIP8_VIDEO_WIDTH, CHIP8_VIDEO_HEIGHT)\n }\n }\n fn get_memory_size(\u0026self) -\u003e i32 {\n let (width, height) = self.get_resolution();\n width * height\n }\n\n pub fn tick(\u0026mut self) {\n self.has_frame_changed = false;\n }\n\n pub fn scroll_right(\u0026mut self) {\n let (width, height) = self.get_resolution();\n\n for current_row in 0..height {\n let row_offset: usize = (current_row * width) as usize;\n for current_column in (0..(width - 4)).rev() {\n let source_address = row_offset + current_column as usize;\n let target_address = source_address + 4;\n self.memory[target_address] = self.memory[source_address];\n }\n self.memory[row_offset..row_offset + 4].fill(false);\n }\n }\n\n pub fn scroll_left(\u0026mut self) {\n let (width, height) = self.get_resolution();\n\n for current_row in 0..height {\n let row_offset = current_row * width;\n for current_column in (0..width - 4) {\n let source: usize = (row_offset + current_column) as usize;\n let target: usize = source + 4;\n self.memory[target] = self.memory[source];\n }\n\n let clear_start: usize = (row_offset + width - 4) as usize;\n let clear_end: usize = clear_start + 4;\n\n self.memory[clear_start..clear_end].fill(false);\n }\n }\n\n pub fn scroll_down(\u0026mut self, how_far: i32) {\n let (width, height) = self.get_resolution();\n let row_shift = how_far * width;\n\n let max_source_row = height - how_far;\n for current_source_row in (0..max_source_row).rev() {\n let current_source_offset = current_source_row * width;\n for current_source_column in (0..width) {\n let base_offset: usize = (current_source_offset + current_source_column) as usize;\n let extended_offset: usize = base_offset + row_shift as usize;\n self.memory[extended_offset] = self.memory[base_offset];\n };\n }\n\n // Clear the new top rows after shifting\n let clear_end = (how_far * width) as usize;\n self.memory[0..clear_end].fill(false);\n }\n}\n\nimpl Default for Chip8Video {\n fn default() -\u003e Self {\n let mut mem = vec![];\n for _ in 0..CHIP8_VIDEO_MEMORY { mem.push(false); }\n Chip8Video { memory: mem, has_frame_changed: false, current_res: Chip8VideoModes::LowRes }\n }\n}\n","traces":[{"line":20,"address":[772048],"length":1,"stats":{"Line":2}},{"line":21,"address":[42103934],"length":1,"stats":{"Line":2}},{"line":22,"address":[1154249],"length":1,"stats":{"Line":2}},{"line":25,"address":[793088],"length":1,"stats":{"Line":2}},{"line":26,"address":[3529509],"length":1,"stats":{"Line":2}},{"line":29,"address":[42104016],"length":1,"stats":{"Line":1}},{"line":30,"address":[42104025],"length":1,"stats":{"Line":1}},{"line":31,"address":[1154343],"length":1,"stats":{"Line":1}},{"line":34,"address":[42104064],"length":1,"stats":{"Line":1}},{"line":35,"address":[596933],"length":1,"stats":{"Line":1}},{"line":38,"address":[42104096],"length":1,"stats":{"Line":0}},{"line":39,"address":[301781],"length":1,"stats":{"Line":0}},{"line":42,"address":[3529648],"length":1,"stats":{"Line":2}},{"line":43,"address":[42104126],"length":1,"stats":{"Line":2}},{"line":44,"address":[42104137],"length":1,"stats":{"Line":2}},{"line":46,"address":[597015],"length":1,"stats":{"Line":2}},{"line":49,"address":[1154466],"length":1,"stats":{"Line":1}},{"line":52,"address":[793291,793355],"length":1,"stats":{"Line":4}},{"line":53,"address":[301922],"length":1,"stats":{"Line":2}},{"line":57,"address":[597120],"length":1,"stats":{"Line":2}},{"line":58,"address":[597125],"length":1,"stats":{"Line":2}},{"line":61,"address":[42104272],"length":1,"stats":{"Line":1}},{"line":63,"address":[301971,302097],"length":1,"stats":{"Line":1}},{"line":69,"address":[302128],"length":1,"stats":{"Line":2}},{"line":70,"address":[772603,772620],"length":1,"stats":{"Line":4}},{"line":71,"address":[1154798],"length":1,"stats":{"Line":0}},{"line":73,"address":[772613],"length":1,"stats":{"Line":2}},{"line":75,"address":[597370,597387,597461],"length":1,"stats":{"Line":5}},{"line":76,"address":[793645,793719,793707],"length":1,"stats":{"Line":2}},{"line":77,"address":[3530054],"length":1,"stats":{"Line":2}},{"line":78,"address":[3530084],"length":1,"stats":{"Line":2}},{"line":81,"address":[1154928],"length":1,"stats":{"Line":2}},{"line":82,"address":[302343],"length":1,"stats":{"Line":2}},{"line":84,"address":[3530214,3530319],"length":1,"stats":{"Line":2}},{"line":86,"address":[302394],"length":1,"stats":{"Line":2}},{"line":87,"address":[302441],"length":1,"stats":{"Line":2}},{"line":89,"address":[42104775],"length":1,"stats":{"Line":2}},{"line":90,"address":[42104869,42104807],"length":1,"stats":{"Line":4}},{"line":91,"address":[772993],"length":1,"stats":{"Line":2}},{"line":96,"address":[772956],"length":1,"stats":{"Line":2}},{"line":99,"address":[1155184],"length":1,"stats":{"Line":4}},{"line":100,"address":[1155221,1155293],"length":1,"stats":{"Line":6}},{"line":101,"address":[773132],"length":1,"stats":{"Line":2}},{"line":105,"address":[598048],"length":1,"stats":{"Line":1}},{"line":106,"address":[42105238,42105378],"length":1,"stats":{"Line":2}},{"line":107,"address":[3530935],"length":1,"stats":{"Line":1}},{"line":108,"address":[3531050],"length":1,"stats":{"Line":1}},{"line":113,"address":[3532847,3531360],"length":1,"stats":{"Line":2}},{"line":114,"address":[773990],"length":1,"stats":{"Line":2}},{"line":115,"address":[42106020],"length":1,"stats":{"Line":2}},{"line":116,"address":[303751],"length":1,"stats":{"Line":2}},{"line":117,"address":[599201,598980,599072],"length":1,"stats":{"Line":6}},{"line":118,"address":[3532034,3531891],"length":1,"stats":{"Line":4}},{"line":119,"address":[42106634,42106516,42106548],"length":1,"stats":{"Line":4}},{"line":120,"address":[42106954,42107048,42106592,42106743,42106656],"length":1,"stats":{"Line":6}},{"line":121,"address":[1156971,1157546],"length":1,"stats":{"Line":4}},{"line":122,"address":[1157610,1157578],"length":1,"stats":{"Line":4}},{"line":124,"address":[3532837,3532783],"length":1,"stats":{"Line":5}},{"line":127,"address":[3532003,3532071],"length":1,"stats":{"Line":5}},{"line":129,"address":[599158],"length":1,"stats":{"Line":2}},{"line":132,"address":[775472],"length":1,"stats":{"Line":2}},{"line":133,"address":[796499,796473],"length":1,"stats":{"Line":4}},{"line":134,"address":[42107381],"length":1,"stats":{"Line":1}},{"line":136,"address":[304962],"length":1,"stats":{"Line":2}},{"line":139,"address":[3532960],"length":1,"stats":{"Line":2}},{"line":140,"address":[1157737],"length":1,"stats":{"Line":2}},{"line":141,"address":[796588,796567],"length":1,"stats":{"Line":2}},{"line":144,"address":[1157792],"length":1,"stats":{"Line":3}},{"line":145,"address":[1157797],"length":1,"stats":{"Line":6}},{"line":148,"address":[3533040],"length":1,"stats":{"Line":1}},{"line":149,"address":[42107521],"length":1,"stats":{"Line":1}},{"line":151,"address":[3533077,3533134],"length":1,"stats":{"Line":2}},{"line":152,"address":[1157957,1157910],"length":1,"stats":{"Line":1}},{"line":153,"address":[776111,775900,775801,775767],"length":1,"stats":{"Line":4}},{"line":154,"address":[1158197,1158173,1158087],"length":1,"stats":{"Line":2}},{"line":155,"address":[776116,776005,776052],"length":1,"stats":{"Line":2}},{"line":156,"address":[305524],"length":1,"stats":{"Line":1}},{"line":158,"address":[600615,600680],"length":1,"stats":{"Line":2}},{"line":162,"address":[797136],"length":1,"stats":{"Line":1}},{"line":163,"address":[797153],"length":1,"stats":{"Line":1}},{"line":165,"address":[305642,305697],"length":1,"stats":{"Line":2}},{"line":166,"address":[1158431,1158472],"length":1,"stats":{"Line":1}},{"line":167,"address":[305769,305735,305855,306163],"length":1,"stats":{"Line":4}},{"line":168,"address":[42108287,42108467,42108498],"length":1,"stats":{"Line":2}},{"line":169,"address":[42108593,42108529,42108482],"length":1,"stats":{"Line":2}},{"line":170,"address":[42108537],"length":1,"stats":{"Line":1}},{"line":173,"address":[776439,776504,776387],"length":1,"stats":{"Line":2}},{"line":174,"address":[601311,601271,601224],"length":1,"stats":{"Line":2}},{"line":176,"address":[42108415],"length":1,"stats":{"Line":1}},{"line":180,"address":[776752],"length":1,"stats":{"Line":1}},{"line":181,"address":[776777],"length":1,"stats":{"Line":1}},{"line":182,"address":[42108675,42108716],"length":1,"stats":{"Line":1}},{"line":184,"address":[797823,797888,797856],"length":1,"stats":{"Line":2}},{"line":185,"address":[797860,797959,797904],"length":1,"stats":{"Line":3}},{"line":186,"address":[42108972,42108850,42108947],"length":1,"stats":{"Line":2}},{"line":187,"address":[306549,306736,306516],"length":1,"stats":{"Line":3}},{"line":188,"address":[3534624,3534572],"length":1,"stats":{"Line":1}},{"line":189,"address":[306630,306741,306679],"length":1,"stats":{"Line":2}},{"line":190,"address":[306687],"length":1,"stats":{"Line":1}},{"line":195,"address":[601737,601787,601685],"length":1,"stats":{"Line":2}},{"line":196,"address":[42108884],"length":1,"stats":{"Line":1}},{"line":201,"address":[306768,307044],"length":1,"stats":{"Line":6}},{"line":202,"address":[798337],"length":1,"stats":{"Line":3}},{"line":203,"address":[3534767,3535009,3534848],"length":1,"stats":{"Line":16}}],"covered":101,"coverable":104},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","constants.rs"],"content":"pub const CHIP8_REGISTER_COUNT: i32 = 16;\npub const CHIP8_MEMORY_SIZE: i32 = 4096i32;\npub const CHIP8_VIDEO_WIDTH: i32 = 64i32;\npub const CHIP8_VIDEO_HEIGHT: i32 = 32i32;\npub const CHIP8_VIDEO_MEMORY: usize = (CHIP8_VIDEO_HEIGHT * CHIP8_VIDEO_WIDTH) as usize;\npub const CHIP8_ROM_SIZE: usize = 512;\n\npub const RESOURCES_ROOT: \u0026str = \"../resources\";\npub const TESTS_ROOT: \u0026str = \"../resources/tests/\";\n\npub const CHIP8_KEYBOARD: [[u8; 4]; 4] = [\n [0x01, 0x02, 0x03, 0x0C],\n [0x04, 0x05, 0x06, 0x0D],\n [0x07, 0x08, 0x09, 0x0E],\n [0x0A, 0x00, 0x0B, 0x0F]\n];\n\npub const SCHIP_VIDEO_HEIGHT: i32 = 64;\npub const SCHIP_VIDEO_WIDTH: i32 = 128;\npub const SCHIP_VIDE_MEMORY: usize = (SCHIP_VIDEO_HEIGHT * SCHIP_VIDEO_WIDTH) as usize;\n\npub const INST_ADDI: \u0026str = \"ADDI\";\npub const INST_ADD: \u0026str = \"ADD\";\npub const INST_ADDR: \u0026str = \"ADDR\";\npub const INST_AND: \u0026str = \"AND\";\npub const INST_CLS: \u0026str = \"CLS\";\npub const INST_CALL: \u0026str = \"CALL\";\npub const INST_DRW: \u0026str = \"DRW\";\npub const INST_EXIT: \u0026str = \"EXIT\";\npub const INST_JPA: \u0026str = \"JPA\";\npub const INST_JPI: \u0026str = \"JPI\";\npub const INST_BCD: \u0026str = \"BCD\";\npub const INST_LDD: \u0026str = \"LDD\";\npub const INST_LDF: \u0026str = \"LDF\";\npub const INST_LDF2: \u0026str = \"LDF2\";\npub const INST_LDIA: \u0026str = \"LDIA\";\npub const INST_LDIX: \u0026str = \"LDIX\";\npub const INST_LIDR: \u0026str = \"LIDR\";\npub const INST_LDIS: \u0026str = \"LDIS\";\npub const INST_LDR: \u0026str = \"LDR\";\npub const INST_LDRD: \u0026str = \"LDRD\";\npub const INST_LDRI: \u0026str = \"LDRI\";\npub const INST_LDRK: \u0026str = \"LDRK\";\npub const INST_LDRY: \u0026str = \"LDRY\";\npub const INST_OR: \u0026str = \"OR\";\npub const INST_RET: \u0026str = \"RET\";\npub const INST_RND: \u0026str = \"RND\";\npub const INST_SDN: \u0026str = \"SDN\";\npub const INST_SRT: \u0026str = \"SRT\";\npub const INST_SLF: \u0026str = \"SLF\";\npub const INST_SEX: \u0026str = \"SEX\";\npub const INST_SEY: \u0026str = \"SEY\";\npub const INST_SHL: \u0026str = \"SHL\";\npub const INST_SHR: \u0026str = \"SHR\";\npub const INST_SKP: \u0026str = \"SKP\";\npub const INST_SKNP: \u0026str = \"SKNP\";\npub const INST_SNEB: \u0026str = \"SNEB\";\npub const INST_SNEY: \u0026str = \"SNEY\";\npub const INST_STR: \u0026str = \"STR\";\npub const INST_SUB: \u0026str = \"SUB\";\npub const INST_SUBC: \u0026str = \"SUBC\";\npub const INST_SYS: \u0026str = \"SYS\";\npub const INST_DIS: \u0026str = \"DIS\";\npub const INST_ENA: \u0026str = \"ENA\";\npub const INST_ORY: \u0026str = \"ORY\";\n\npub const CHIP8_PROGRAM_LOAD_OFFSET: i32 = 0x200;\npub const CHIP8FONT_0: [u8; 5] = [0xF0, 0x90, 0x90, 0x90, 0xF0];\npub const CHIP8FONT_1: [u8; 5] = [0x20, 0x60, 0x20, 0x20, 0x70];\npub const CHIP8FONT_2: [u8; 5] = [0xF0, 0x10, 0xF0, 0x80, 0xF0];\npub const CHIP8FONT_3: [u8; 5] = [0xF0, 0x10, 0xF0, 0x10, 0xF0];\npub const CHIP8FONT_4: [u8; 5] = [0x90, 0x90, 0xF0, 0x10, 0x10];\npub const CHIP8FONT_5: [u8; 5] = [0xF0, 0x80, 0xF0, 0x10, 0xF0];\npub const CHIP8FONT_6: [u8; 5] = [0xF0, 0x80, 0xF0, 0x90, 0xF0];\npub const CHIP8FONT_7: [u8; 5] = [0xF0, 0x10, 0x20, 0x40, 0x40];\npub const CHIP8FONT_8: [u8; 5] = [0xF0, 0x90, 0xF0, 0x90, 0xF0];\npub const CHIP8FONT_9: [u8; 5] = [0xF0, 0x90, 0xF0, 0x10, 0xF0];\npub const CHIP8FONT_A: [u8; 5] = [0xF0, 0x90, 0xF0, 0x90, 0x90];\npub const CHIP8FONT_B: [u8; 5] = [0xE0, 0x90, 0xE0, 0x90, 0xE0];\npub const CHIP8FONT_C: [u8; 5] = [0xF0, 0x80, 0x80, 0x80, 0xF0];\npub const CHIP8FONT_D: [u8; 5] = [0xE0, 0x90, 0x90, 0x90, 0xE0];\npub const CHIP8FONT_E: [u8; 5] = [0xF0, 0x80, 0xF0, 0x80, 0xF0];\npub const CHIP8FONT_F: [u8; 5] = [0xF0, 0x80, 0xF0, 0x80, 0x80];\n\npub const SCHIPFONT_0: [u8; 0x20] = [\n 0x00, 0x00,\n 0x01, 0x80,\n 0x03, 0xc0,\n 0x06, 0x60,\n 0x0c, 0x30,\n 0x0c, 0x30,\n 0x18, 0x18,\n 0x18, 0x18,\n 0x18, 0x18,\n 0x18, 0x18,\n 0x0c, 0x30,\n 0x0c, 0x30,\n 0x06, 0x60,\n 0x03, 0xc0, // 0b0000001111000000\n 0x01, 0x80, // 0b0000000110000000\n 0x00, 0x00 // 0b0000000000000000\n];\npub const SCHIPFONT_1: [u8; 0x20] = [\n 0x00, 0x00,\n 0x03, 0xc0,\n 0x02, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x00, 0xc0,\n 0x03, 0xf0,\n 0x00, 0x00\n];\npub const SCHIPFONT_2: [u8; 0x20] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC7, 0xC3, 0xC0, 0xE0,\n 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0xFF, 0xFF,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78];\npub const SCHIPFONT_3: [u8; 0x20] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC7, 0xC3, 0xC0, 0xE0,\n 0xF0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0xFF, 0xFF,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78];\npub const SCHIPFONT_4: [u8; 0x20] = [0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xF7, 0xF3, 0xF1,\n 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78];\npub const SCHIPFONT_5: [u8; 0x20] = [0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x3F, 0x7F, 0x7F,\n 0x01, 0x01, 0xC1, 0xE3, 0xFF, 0xFE, 0xFC, 0x78,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78];\npub const SCHIPFONT_6: [u8; 0x20] = [0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78\n];\npub const SCHIPFONT_7: [u8; 0x20] = [0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0x78, 0x3C,\n 0x1E, 0x0F, 0x07, 0x03, 0x01, 0x01, 0x01, 0x01,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78\n];\npub const SCHIPFONT_8: [u8; 0x20] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF,\n 0x7E, 0xFE, 0xC3, 0xC3, 0xFF, 0xFF, 0xFE, 0x7C,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78\n];\npub const SCHIPFONT_9: [u8; 0x20] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF,\n 0xFF, 0x7F, 0x03, 0x03, 0xC7, 0xFF, 0xFE, 0x7C,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78\n];\npub const SCHIPFONT_A: [u8; 0x20] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78\n];\npub const SCHIPFONT_B: [u8; 0x20] = [0xFE, 0xFF, 0xFF, 0xFF, 0xC3, 0xC3, 0xFE, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xFE,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78\n];\npub const SCHIPFONT_C: [u8; 0x20] = [0x7C, 0xFE, 0xFF, 0xFF, 0xC3, 0xC3, 0x01, 0x01,\n 0x01, 0x01, 0xC3, 0xC3, 0xFF, 0xFE, 0xFC, 0x78,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78\n];\npub const SCHIPFONT_D: [u8; 0x20] = [0xFE, 0xFF, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3,\n 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xFE, 0x7C, 0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78\n];\npub const SCHIPFONT_E: [u8; 0x20] = [0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x03, 0xFF,\n 0xFF, 0xFF, 0x03, 0x03, 0xFF, 0xFF, 0xFF, 0xFF,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78\n];\npub const SCHIPFONT_F: [u8; 0x20] = [0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x03, 0xFF,\n 0xFF, 0xFF, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,0x78, 0xFE, 0xFF, 0xFF, 0x83, 0x01, 0x01, 0xFF,\n 0xFF, 0xFF, 0xC3, 0xE3, 0xFF, 0xFE, 0xFC, 0x78];\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","src","lib.rs"],"content":"pub mod chip8 {\n pub mod video;\n pub mod sound_timer;\n pub mod delay_timer;\n pub mod keypad;\n pub mod computer;\n pub mod system_memory;\n pub mod instructions;\n pub mod cpu_states;\n pub mod util;\n pub mod registers;\n\n pub mod stack;\n pub mod computer_manager;\n pub mod quirk_modes;\n}\n\npub mod constants;","traces":[],"covered":0,"coverable":0},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","tests","computer_tests.rs"],"content":"use gemma::chip8::computer::Chip8Computer;\nuse gemma::constants::CHIP8_VIDEO_MEMORY;\n\n#[test]\nfn smoke() { assert!(true) }\n\nfn load_result(to_load: \u0026str) -\u003e String {\n std::fs::read_to_string(format!(\"../resources/test/{}\", to_load)).unwrap()\n}\n\nfn load_rom(to_load: \u0026str) -\u003e Vec\u003cu8\u003e {\n std::fs::read(format!(\"../resources/roms/{}\", to_load)).unwrap()\n}\n\n#[test]\nfn reset_clears_video() {\n let mut x = Chip8Computer::new();\n\n for i in 0..CHIP8_VIDEO_MEMORY {\n x.video_memory.poke(i as u16, i % 2 == 0);\n }\n\n x.reset();\n x.video_memory.reset();\n\n assert_eq!(x.dump_video_to_string(), x.video_memory.format_as_string());\n\n for i in 0..CHIP8_VIDEO_MEMORY {\n assert!(!x.video_memory.peek(i as u16));\n }\n}\n\n#[test]\nfn level1_test() {\n let mut x = Chip8Computer::new();\n let level_1_rom = load_rom(\"1-chip8-logo.ch8\");\n x.load_bytes_to_memory(0x200, (\u0026level_1_rom).into());\n\n // run for 0x40 cycles\n while x.num_cycles \u003c 0x40 {\n x.step_system();\n }\n assert_eq!(x.dump_video_to_string(), load_result(\"gemma_integration_level_1_test.asc\"));\n}\n\n#[test]\nfn level2_test() {\n let mut x = Chip8Computer::new();\n // Load the IBM rom and run it.\n // it takes 39 cycles to get to the end so lets run it 40.\n let test_rom_to_run = load_rom(\"2-ibm-logo.ch8\");\n x.load_bytes_to_memory(0x200, (\u0026test_rom_to_run).into());\n for _ in 0..40 {\n x.step_system();\n }\n // ...then verify that the current video memory of the chip-8\n // simulator matches what we expect it to be\n\n assert_eq!(x.dump_video_to_string(), load_result(\"gemma_integration_ibm_rom_output.asc\"));\n}\n\n#[test]\nfn level3_test() {\n let mut x = Chip8Computer::new();\n\n x.load_bytes_to_memory(\n 0x200, (\u0026load_rom(\"3-corax+.ch8\")).into()\n );\n for i in 0..0x180 {\n x.step_system();\n }\n\n assert_eq!(x.dump_video_to_string(), load_result(\"gemma_integration_corax_plus.asc\"));\n}\n\n#[test]\nfn rps_test() {\n let mut x = Chip8Computer::new();\n x.load_bytes_to_memory(0x200, \u0026load_rom(\"RPS.ch8\").into());\n for _ in 0..0xF0 {\n x.step_system();\n }\n assert_eq!(x.dump_video_to_string(), load_result(\"gemma_integration_rps_stage1.asc\"));\n x.keypad.push_key(0x01);\n for _ in 0..0x200 {\n x.step_system();\n }\n assert_eq!(x.dump_video_to_string(), load_result(\"gemma_integration_rps_stage2.asc\"));\n}\n\n#[test]\nfn level4_test() {\n // flags\n let mut x = Chip8Computer::new();\n x.load_bytes_to_memory(0x200, \u0026load_rom(\"4-flags.ch8\").into());\n for _ in 0..0x400 {\n x.step_system();\n }\n\n assert_eq!(x.dump_video_to_string(), load_result(\"gemma_integration_flags.asc\"));\n}\n","traces":[{"line":7,"address":[299120],"length":1,"stats":{"Line":1}},{"line":8,"address":[299247,299350],"length":1,"stats":{"Line":2}},{"line":11,"address":[299568],"length":1,"stats":{"Line":4}},{"line":12,"address":[299695,299798],"length":1,"stats":{"Line":5}}],"covered":4,"coverable":4},{"path":["/","home","tmerritt","Projects","chip8_toy","gemma","tests","unit_tests.rs"],"content":"use std::collections::{BTreeMap, BTreeSet};\nuse log::debug;\nuse rand::random;\nuse gemma::chip8::computer::Chip8Computer;\nuse gemma::chip8::delay_timer::DelayTimer;\nuse gemma::chip8::instructions::Chip8CpuInstructions;\nuse gemma::chip8::instructions::Chip8CpuInstructions::JPA;\nuse gemma::chip8::keypad::Keypad;\nuse gemma::chip8::quirk_modes::QuirkMode::{Chip8, SChipModern, XOChip};\nuse gemma::chip8::registers::Chip8Registers;\nuse gemma::chip8::sound_timer::SoundTimer;\nuse gemma::chip8::stack::Chip8Stack;\nuse gemma::chip8::util::InstructionUtil;\nuse gemma::chip8::video::Chip8Video;\nuse gemma::constants::*;\n\nconst TEST_OUTPUT_SAMPLE_DIR: \u0026str = \"../resources/test/\";\n\nfn read_test_result(suffix: \u0026str) -\u003e String {\n std::fs::read_to_string(TEST_OUTPUT_SAMPLE_DIR.to_owned() + suffix)\n .unwrap()\n}\n\n#[test]\nfn smoke() {\n assert!(true)\n}\n\n#[test]\nfn encode_decode_test() {\n assert_eq!(Chip8CpuInstructions::CLS.encode(), 0x00E0);\n assert_eq!(Chip8CpuInstructions::RET.encode(), 0x00EE);\n assert_eq!(Chip8CpuInstructions::SYS(0x123).encode(), 0x0123);\n assert_eq!(Chip8CpuInstructions::JPA(0x234).encode(), 0x1234);\n assert_eq!(Chip8CpuInstructions::CALL(0x345).encode(), 0x2345);\n assert_eq!(Chip8CpuInstructions::SEX(0x4, 0x56).encode(), 0x3456);\n assert_eq!(Chip8CpuInstructions::SNEB(0xa, 0xbc).encode(), 0x4abc);\n assert_eq!(Chip8CpuInstructions::SEY(0xa, 0xb).encode(), 0x5ab0);\n assert_eq!(Chip8CpuInstructions::LDR(0xa, 0xff).encode(), 0x6aff);\n assert_eq!(Chip8CpuInstructions::ADD(0xa, 0xbc).encode(), 0x7abc);\n assert_eq!(Chip8CpuInstructions::LDR_Y(0xa, 0xb).encode(), 0x8ab0);\n assert_eq!(Chip8CpuInstructions::OR(0xb, 0xa).encode(), 0x8ba1);\n assert_eq!(Chip8CpuInstructions::AND(0xc, 0xd).encode(), 0x8cd2);\n assert_eq!(Chip8CpuInstructions::ORY(0xd, 0xe).encode(), 0x8de3);\n assert_eq!(Chip8CpuInstructions::ADDR(0xe, 0xf).encode(), 0x8ef4);\n assert_eq!(Chip8CpuInstructions::SUB(0xf, 0x0).encode(), 0x8f05);\n assert_eq!(Chip8CpuInstructions::SHR(0x0, 0x1).encode(), 0x8016);\n assert_eq!(Chip8CpuInstructions::SUBC(0x1, 0x2).encode(), 0x8127);\n assert_eq!(Chip8CpuInstructions::SHL(0x3, 0x4).encode(), 0x834e);\n assert_eq!(Chip8CpuInstructions::SNEY(0xa, 0xb).encode(), 0x9ab0);\n assert_eq!(Chip8CpuInstructions::LDIA(0x123).encode(), 0xa123);\n assert_eq!(Chip8CpuInstructions::JPI(0x234).encode(), 0xb234);\n assert_eq!(Chip8CpuInstructions::RND(0xa, 0xca).encode(), 0xcaca);\n assert_eq!(Chip8CpuInstructions::DRW(0xa, 0xb, 0x4).encode(), 0xdab4);\n assert_eq!(Chip8CpuInstructions::SKP(0x1).encode(), 0xe19e);\n assert_eq!(Chip8CpuInstructions::SKNP(0x2).encode(), 0xe2a1);\n assert_eq!(Chip8CpuInstructions::LDRD(0x1).encode(), 0xf107);\n assert_eq!(Chip8CpuInstructions::LDRK(0x4).encode(), 0xf40a);\n assert_eq!(Chip8CpuInstructions::LDD(0x6).encode(), 0xf615);\n assert_eq!(Chip8CpuInstructions::LDIS(0xb).encode(), 0xfb18);\n assert_eq!(Chip8CpuInstructions::ADDI(0xd).encode(), 0xfd1e);\n assert_eq!(Chip8CpuInstructions::LDFX(0xc).encode(), 0xfc29);\n assert_eq!(Chip8CpuInstructions::BCD(0xd).encode(), 0xfd33);\n assert_eq!(Chip8CpuInstructions::LDIX(0xe).encode(), 0xfe55);\n assert_eq!(Chip8CpuInstructions::LDRI(0x3).encode(), 0xf365);\n assert_eq!(Chip8CpuInstructions::SDN(0x1).encode(), 0x00C1);\n assert_eq!(Chip8CpuInstructions::SLF.encode(), 0x00FC);\n assert_eq!(Chip8CpuInstructions::SRT.encode(), 0x00FB);\n assert_eq!(Chip8CpuInstructions::EXIT.encode(), 0x00FD);\n assert_eq!(Chip8CpuInstructions::ENA.encode(), 0x00FF);\n assert_eq!(Chip8CpuInstructions::DIS.encode(), 0x00FE);\n assert_eq!(Chip8CpuInstructions::LDF2(0).encode(), 0xF030);\n assert_eq!(Chip8CpuInstructions::STR(1).encode(), 0xF175);\n assert_eq!(Chip8CpuInstructions::LIDR(1).encode(), 0xF185);\n\n\n/*\n assert!(matches!(Chip8CpuInstructions::decode(0xF175), Chip8CpuInstructions::STR(1)));\n assert!(matches!(Chip8CpuInstructions::decode(0xF185), Chip8CpuInstructions::LIDR(1)));\n assert!(matches!(Chip8CpuInstructions::decode(0x00C1u16), Chip8CpuInstructions::SDN(0x01)));\n assert!(matches!(Chip8CpuInstructions::decode(0x00FCu16), Chip8CpuInstructions::SLF));\n assert!(matches!(Chip8CpuInstructions::decode(0x00FBu16), Chip8CpuInstructions::SRT));\n assert!(matches!(Chip8CpuInstructions::decode(0x00FDu16), Chip8CpuInstructions::EXIT));\n assert!(matches!(Chip8CpuInstructions::decode(0x00FEu16), Chip8CpuInstructions::DIS));\n assert!(matches!(Chip8CpuInstructions::decode(0x00FFu16), Chip8CpuInstructions::ENA));\n assert!(matches!(Chip8CpuInstructions::decode(0xF030u16), Chip8CpuInstructions::LDF2(0)));\n assert!(matches!(Chip8CpuInstructions::decode(0x00E0u16), Chip8CpuInstructions::CLS));\n assert!(matches!(Chip8CpuInstructions::decode(0x00EEu16), Chip8CpuInstructions::RET));\n assert!(matches!(Chip8CpuInstructions::decode(0x0123), Chip8CpuInstructions::SYS(0x123)));\n assert!(matches!(Chip8CpuInstructions::decode(0x0FFF), Chip8CpuInstructions::SYS(0xfff)));\n assert!(matches!(Chip8CpuInstructions::decode(0x1002), Chip8CpuInstructions::JPA(0x2)));\n assert!(matches!(Chip8CpuInstructions::decode(0x1FF0), Chip8CpuInstructions::JPA(0xFF0)));\n assert!(matches!(Chip8CpuInstructions::decode(0x2002), Chip8CpuInstructions::CALL(0x2)));\n assert!(matches!(Chip8CpuInstructions::decode(0x3123), Chip8CpuInstructions::SEX(0x1, 0x23)));\n assert!(matches!(Chip8CpuInstructions::decode(0x4abc), Chip8CpuInstructions::SNEB(0xa, 0xbc)));\n assert!(matches!(Chip8CpuInstructions::decode(0x5ab0), Chip8CpuInstructions::SEY(0xa, 0xb)));\n assert!(matches!(Chip8CpuInstructions::decode(0x6aff), Chip8CpuInstructions::LDR(0xa, 0xff)));\n assert!(matches!(Chip8CpuInstructions::decode(0x7abc), Chip8CpuInstructions::ADD(0xa, 0xbc)));\n assert!(matches!(Chip8CpuInstructions::decode(0x8ab0), Chip8CpuInstructions::LDR_Y(0xa, 0xb)));\n assert!(matches!(Chip8CpuInstructions::decode(0x8ba1), Chip8CpuInstructions::OR(0xb, 0xa)));\n assert!(matches!(Chip8CpuInstructions::decode(0x8cd2), Chip8CpuInstructions::AND(0xc, 0xd)));\n assert!(matches!(Chip8CpuInstructions::decode(0x8de3), Chip8CpuInstructions::ORY(0xd, 0xe)));\n assert!(matches!(Chip8CpuInstructions::decode(0x8ef4), Chip8CpuInstructions::ADDR(0xe, 0xf)));\n assert!(matches!(Chip8CpuInstructions::decode(0x8f05), Chip8CpuInstructions::SUB(0xf, 0x0)));\n assert!(matches!(Chip8CpuInstructions::decode(0x8016), Chip8CpuInstructions::SHR(0x0, 0x1)));\n assert!(matches!(Chip8CpuInstructions::decode(0x8127), Chip8CpuInstructions::SUBC(0x1, 0x2)));\n assert!(matches!(Chip8CpuInstructions::decode(0x834e), Chip8CpuInstructions::SHL(0x3, 0x4)));\n assert!(matches!(Chip8CpuInstructions::decode(0x9ab0), Chip8CpuInstructions::SNEY(0xa, 0xb)));\n assert!(matches!(Chip8CpuInstructions::decode(0xa123), Chip8CpuInstructions::LDIA(0x123)));\n assert!(matches!(Chip8CpuInstructions::decode(0xb234), Chip8CpuInstructions::JPI(0x234)));\n assert!(matches!(Chip8CpuInstructions::decode(0xcaca), Chip8CpuInstructions::RND(0xa, 0xca)));\n assert!(matches!(Chip8CpuInstructions::decode(0xdab4), Chip8CpuInstructions::DRW(0xa, 0xb, 0x4)));\n assert!(matches!(Chip8CpuInstructions::decode(0xe19e), Chip8CpuInstructions::SKP(0x1)));\n assert!(matches!(Chip8CpuInstructions::decode(0xe2a1), Chip8CpuInstructions::SKNP(0x2)));\n assert!(matches!(Chip8CpuInstructions::decode(0xf107), Chip8CpuInstructions::LDRD(0x1)));\n assert!(matches!(Chip8CpuInstructions::decode(0xf40a), Chip8CpuInstructions::LDRK(0x4)));\n assert!(matches!(Chip8CpuInstructions::decode(0xf615), Chip8CpuInstructions::LDD(0x6)));\n assert!(matches!(Chip8CpuInstructions::decode(0xfb18), Chip8CpuInstructions::LDIS(0xb)));\n assert!(matches!(Chip8CpuInstructions::decode(0xfd1e), Chip8CpuInstructions::ADDI(0xd)));\n assert!(matches!(Chip8CpuInstructions::decode(0xfc29), Chip8CpuInstructions::LDFX(0xc)));\n assert!(matches!(Chip8CpuInstructions::decode(0xfd33), Chip8CpuInstructions::BCD(0xd)));\n assert!(matches!(Chip8CpuInstructions::decode(0xfe55), Chip8CpuInstructions::LDIX(0xe)));\n assert!(matches!(Chip8CpuInstructions::decode(0xf365), Chip8CpuInstructions::LDRI(0x3)));\n*/\n}\n\n#[test]\nfn decoder_test_invalid_instructions() {\n let invalid_to_encode = [\n 0x5ab1, 0x5abf, 0x8ab8, 0x8abd, 0x8abf,\n 0x9ab1, 0x9abf, 0xea9d, 0xea9f, 0xeaa0,\n 0xeaa2, 0xf006, 0xf008\n ];\n\n for i in invalid_to_encode {\n assert_eq!(Chip8CpuInstructions::decode(i, \u0026Chip8).encode(), 0xffff);\n assert!(matches!(Chip8CpuInstructions::decode(i, \u0026Chip8), Chip8CpuInstructions::XXXXERRORINSTRUCTION));\n }\n}\n\n/// START OF THE EXECUTION TESTS\n#[test]\nfn instruction_tests() {\n // 0x0nnn Exit to System Call\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::SYS(0).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0);\n\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::SYS(0xFA0).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0xFA0);\n\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::SYS(0x0AF).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x0AF);\n\n // 0x1nnn Jump to Address\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::JPA(0).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0);\n\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::JPA(0xABC).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0xABC);\n\n // 0x6xkk Set Vx = kk\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::LDR(1, 0x12).execute(\u0026mut x);\n assert_eq!(x.registers.peek(1), 0x12);\n\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::LDR(2, 0x21).execute(\u0026mut x);\n assert_eq!(x.registers.peek(2), 0x21);\n\n // 0x3xkk Skip next instruction if Vx = kk.\n // The interpreter compares register Vx to kk,\n // and if they are equal, increments the program counter by 2.\n\n // test setup: Load value 0x84 into V1\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0x84);\n Chip8CpuInstructions::SEX(1, 0x48).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x202);\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0x84);\n Chip8CpuInstructions::SEX(1, 0x84).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x204);\n\n // 0x4xkk Skip next instruction if Vx != kk\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0x84);\n x.registers.poke(0x2, 0x84);\n // skip, compare 0x84 to 0x84\n Chip8CpuInstructions::SEY(0x1, 0x2).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x204);\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0x84);\n x.registers.poke(0x2, 0x48);\n Chip8CpuInstructions::SEY(0x01, 0x02).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x202);\n\n // 0x8xy0 Set value of Vy in Vx\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0x01);\n x.registers.poke(0x02, 0x02);\n Chip8CpuInstructions::LDR_Y(0x01, 0x02).execute(\u0026mut x);\n assert_eq!(x.registers.peek(1), 0x02);\n\n // 0x8xy1 Set Vx = Vx OR Vy\n // 0b0101 0000 (0x50)\n // | 0b0000 1010 (0x0A)\n // 0b0101 1010 (0x5A)\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0b01010000);\n x.registers.poke(0x02, 0b00001010);\n Chip8CpuInstructions::OR(1, 2).execute(\u0026mut x);\n assert_eq!(x.registers.peek(1), 0b01011010);\n\n // 0x8xy2 Set Vx = Vx AND Vy\n // 0b1111 1100 (0xFC)\n // \u0026 0b1100 1010 (0xCA)\n // 0b1100 1000 (0xC8)\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0xFC);\n x.registers.poke(0x02, 0xCA);\n Chip8CpuInstructions::AND(1, 2).execute(\u0026mut x);\n assert_eq!(x.registers.peek(1), 0xC8);\n\n // 0x8xy3 Set Vx = Vx XOR Vy\n // 0b1111 1100 (0xFC)\n // ^ 0b1100 1010 (0xCA)\n // 0b0011 0110 (0x36)\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0b11111100);\n x.registers.poke(0x02, 0b11001010);\n Chip8CpuInstructions::ORY(1, 2).execute(\u0026mut x);\n assert_eq!(x.registers.peek(1), 0b00110110);\n\n // 0x8xy4 Set Vx = Vx + Vy (SET VF on Carry)\n // T1 T2: Judgement Test\n // 0x01 0xFF\n // + 0x01 0x01\n // 0x02 F0 0x00 F1\n let mut x = Chip8Computer::new();\n x.registers.poke(0x0f, 00);\n x.registers.poke(0x01, 0x01);\n x.registers.poke(0x02, 0x01);\n Chip8CpuInstructions::ADDR(0x01, 0x02).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0xf), 0x00);\n assert_eq!(x.registers.peek(0x01), 0x02);\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x0f, 0x00);\n x.registers.poke(0x01, 0xff);\n x.registers.poke(0x02, 0x01);\n Chip8CpuInstructions::ADDR(1, 2).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0xf), 1);\n assert_eq!(x.registers.peek(1), 0);\n\n /*\n Set Vx = Vx SHR 1.\n\n If the least-significant bit of Vx is 1, then VF is set to 1, otherwise 0. Then Vx is divided by 2.\n */\n let mut x = Chip8Computer::new();\n x.registers.poke(0x0f, 0x00);\n x.registers.poke(0x01, 0b00001000);\n x.registers.poke(0x02, 0b00000000);\n Chip8CpuInstructions::SHR(0x1, 0x2).execute(\u0026mut x); // 0b0000 0010 (0x02) (Not Set)\n assert_eq!(x.registers.peek(1), 0b00000100);\n assert_eq!(x.registers.peek(0xf), 0);\n\n x = Chip8Computer::new();\n x.registers.poke(0x0f, 0x00);\n x.registers.poke(0x01, 0b00001001);\n Chip8CpuInstructions::SHR(0x1, 0x2).execute(\u0026mut x);\n assert_eq!(x.registers.peek(1), 0b00000100);\n assert_eq!(x.registers.peek(0xf), 1);\n\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::LDIA(0x123).execute(\u0026mut x);\n assert_eq!(x.registers.peek_i(), 0x123);\n assert_eq!(x.registers.peek_pc(), 0x202);\n}\n\n#[test]\nfn jp_v0addr_test() {\n let mut x = Chip8Computer::new();\n /// jump to I + nnn\n x.registers.poke(0x0, 0xff);\n Chip8CpuInstructions::JPI(0x100).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x1FF);\n}\n\n#[test]\nfn cls_test() {\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::CLS.execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x202);\n for i in 0..CHIP8_VIDEO_MEMORY {\n assert_eq!(x.video_memory.peek(i as u16), false);\n }\n // draw some thing to the video memory\n x.video_memory.poke(0x01, true);\n x.video_memory.poke(0x03, true);\n x.video_memory.poke(0x05, true);\n\n Chip8CpuInstructions::CLS.execute(\u0026mut x);\n\n for i in 0..CHIP8_VIDEO_MEMORY {\n assert_eq!(x.video_memory.peek(i as u16), false);\n }\n}\n\n#[test]\nfn skip_next_instruction_ne_text() {\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0xf0);\n Chip8CpuInstructions::SNEB(0x1, 0x0f).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x204);\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0xf0);\n Chip8CpuInstructions::SNEB(0x1, 0xf0).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x202);\n}\n\n#[test]\nfn addivx_test() {\n let mut x = Chip8Computer::new();\n x.registers.poke_i(0xabc);\n x.registers.poke(0x0, 0x10);\n Chip8CpuInstructions::ADDI(0x0).execute(\u0026mut x);\n assert_eq!(x.registers.peek_i(), 0xacc);\n}\n\n#[test]\nfn ldstvt_test() {\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0xf0);\n Chip8CpuInstructions::LDIS(0x01).execute(\u0026mut x);\n assert_eq!(x.sound_timer.current(), 0xf0);\n x.sound_timer.tick();\n x.sound_timer.tick();\n x.sound_timer.tick();\n assert_eq!(x.sound_timer.current(), 0xed);\n}\n\n#[test]\nfn rnd_vx_byte_text() {\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::RND(0x1, 0x0f).execute(\u0026mut x);\n let new_value = x.registers.peek(0x1);\n assert!(new_value \u003c 0x10);\n}\n\n#[test]\nfn add_vx_byte_test() {\n let mut x = Chip8Computer::new();\n // set a value in the register\n x.registers.poke(0x01, 0xab);\n // add 0x10 to register\n Chip8CpuInstructions::ADD(0x1, 0x10).execute(\u0026mut x);\n assert_eq!(x.registers.peek(1), 0xbb);\n}\n\n#[test]\nfn sub_vx_vy_test() {\n let mut x = Chip8Computer::new();\n // load values in 2 registers\n x.registers.poke(0x1, 0x10);\n x.registers.poke(0x2, 0x08);\n Chip8CpuInstructions::SUB(0x1, 0x02).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0xf), 1);\n assert_eq!(x.registers.peek(0x1), 0x8);\n assert_eq!(x.registers.peek_pc(), 0x202);\n}\n\n#[test]\nfn sne_vx_vy_test() {\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0x10);\n x.registers.poke(0x2, 0x10);\n Chip8CpuInstructions::SNEY(0x1, 0x2).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x202);\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0x10);\n x.registers.poke(0x2, 0x00);\n Chip8CpuInstructions::SNEY(0x01, 0x02).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x204)\n}\n\n#[test]\nfn ld_dt_vx_test() {\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0x10);\n Chip8CpuInstructions::LDD(0x1).execute(\u0026mut x);\n assert_eq!(x.delay_timer.current(), 0x10);\n for i in 0..0x20 {\n x.delay_timer.tick();\n }\n assert_eq!(x.delay_timer.current(), 0);\n}\n\n#[test]\nfn ld_vx_dt_test() {\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0xf0);\n Chip8CpuInstructions::LDD(0x1).execute(\u0026mut x);\n x.delay_timer.tick();\n x.delay_timer.tick();\n x.delay_timer.tick();\n assert_eq!(x.delay_timer.current(), 0xed);\n}\n\n#[test]\nfn subn_vx_vy_test() {\n // This instruction subtracts the value in\n // register Vx from the value in register Vy and stores the result in register Vx.\n // The subtraction is performed as follows: Vx = Vy - Vx. If Vy is less than Vx,\n // the result will wrap around (due to the 8-bit nature of the registers).\n // The carry flag (VF) is set to 1 if there is no borrow (i.e., Vy is greater\n // than or equal to Vx), and it is set to 0 if there is a borrow.\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0xa0);\n x.registers.poke(0x2, 0xab);\n Chip8CpuInstructions::SUBC(0x1, 0x2).execute(\u0026mut x);\n // expect the result to be 0x0b\n assert_eq!(x.registers.peek(0x1), 0x0b);\n // expect the vf register to be set to 1 as there was overflow\n assert_eq!(x.registers.peek(0xf), 0x1);\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0xab);\n x.registers.poke(0x02, 0xa0);\n Chip8CpuInstructions::SUBC(0x1, 0x2).execute(\u0026mut x);\n\n // expect the result to be 11110101, -0xB, -11, 245, 0xF5\n assert_eq!(x.registers.peek(0x1), 0xf5);\n assert_eq!(x.registers.peek(0xf), 0x0);\n\n // 8xyE - SHL Vx {, Vy}\n // Set Vx = Vx SHL 1.\n //\n // If the most-significant bit of Vx is 1, then VF is set to 1, otherwise to 0. Then Vx is multiplied by 2.\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0b00100000);\n Chip8CpuInstructions::SHL(0x1, 0x1).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x1), 0b01000000);\n assert_eq!(x.registers.peek(0xf), 0x0);\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x1, 0b10101010);\n Chip8CpuInstructions::SHL(0x1, 0x1).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x1), 0b01010100);\n assert_eq!(x.registers.peek(0xf), 0x1);\n\n // Fx29 - LD F, Vx\n // Set I = location of sprite for digit Vx.\n //\n // 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.\n let mut x = Chip8Computer::new();\n // target_sprite = 2\n // target_offset = 0x5\n x.registers.poke(0x1, 0x2);\n Chip8CpuInstructions::LDFX(0x1).execute(\u0026mut x);\n\n assert_eq!(x.registers.peek_i(), 10);\n\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0x06);\n Chip8CpuInstructions::LDFX(0x1).execute(\u0026mut x);\n assert_eq!(x.registers.peek_i(), 30);\n\n // Fx33 - LD B, Vx\n // Store BCD representation of Vx in memory locations I, I+1, and I+2.\n //\n // The interpreter takes the decimal value of Vx, and places the hundreds digit\n // in memory at location in I, the tens digit at location I+1,\n // and the ones digit at location I+2.\n let mut x = Chip8Computer::new();\n\n // load the value 123 (0x7b)\n x.registers.poke(0x1, 0x7b);\n x.registers.poke_i(0x500);\n Chip8CpuInstructions::BCD(0x1).execute(\u0026mut x);\n assert_eq!(x.memory.peek(0x500), 0x1);\n assert_eq!(x.memory.peek(0x501), 0x2);\n assert_eq!(x.memory.peek(0x502), 0x3);\n\n // Store registers V0 through Vx in memory starting at location I.\n //\n // The interpreter copies the values of registers V0 through Vx into memory,\n // starting at the address in I.\n let mut x = Chip8Computer::new();\n\n // Load Registers.\n let to_load = [0xab, 0xba, 0xca, 0xca, 0xbe, 0xef];\n for (idx, val) in to_load.iter().enumerate() {\n x.registers.poke(idx as u8, *val);\n }\n x.registers.poke_i(0x500);\n\n Chip8CpuInstructions::LDIX(to_load.len() as u8).execute(\u0026mut x);\n\n // Verify the values are in memory from 0x500 to 0x507\n for (idx, value) in to_load.iter().enumerate() {\n assert_eq!(x.memory.peek(0x500 + idx as u16), *value);\n }\n\n // Read registers V0 through Vx from memory starting at location I.\n //\n // The interpreter reads values from memory starting at location I into registers V0 through Vx.\n\n let mut x = Chip8Computer::new();\n\n let base_offset = 0x500;\n let to_load = [0xab, 0xba, 0xca, 0xca, 0xbe, 0xef];\n\n // start by setting values in memory\n for (idx, memory) in to_load.iter().enumerate() {\n let target_address = base_offset + idx;\n let target_value = *memory;\n x.memory.poke(target_address as u16, target_value);\n }\n // where to load from\n x.registers.poke_i(0x500);\n // how much to load\n x.registers.poke(0x6, to_load.len() as u8);\n\n // then copying them values memory to registers\n Chip8CpuInstructions::LDRI(0x6).execute(\u0026mut x);\n\n // now check that we have the right values in our registers\n for (idx, value) in to_load.iter().enumerate() {\n assert_eq!(x.registers.peek(idx as u8), *value);\n }\n\n // ExA1 - SKNP Vx\n // Skip next instruction if key with the value of Vx is not pressed.\n //\n // Checks the keyboard,\n // and if the key corresponding to the value of Vx is currently in the up position,\n // PC is increased by 2.\n let mut x = Chip8Computer::new();\n x.keypad.push_key(0x5);\n x.registers.poke(0x1, 0x5);\n Chip8CpuInstructions::SKNP(0x1).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x202);\n x.keypad.release_key(0x5);\n Chip8CpuInstructions::SKNP(0x1).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x206);\n\n // Ex9E - SKP Vx\n // Skip next instruction if key with the value of Vx is pressed.\n //\n // Checks the keyboard, and if the key corresponding to the value of Vx is currently in the down position, PC is increased by 2.\n let mut x = Chip8Computer::new();\n x.keypad.push_key(0x5);\n x.registers.poke(0x1, 0x5);\n Chip8CpuInstructions::SKP(0x1).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x204);\n\n x.keypad.release_key(0x5);\n Chip8CpuInstructions::SKP(0x1).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x206);\n}\n\nfn draw_nibble_vx_vy_n_test_hd() {\n let mut x = Chip8Computer::new();\n\n let x_register = 0x01;\n let x_offset = 0x03;\n let y_register = 0x02;\n let y_offset = 0x04;\n let char_offset = 0x100;\n x.registers.poke(x_register, x_offset);\n x.registers.poke(y_register, y_offset);\n x.video_memory.set_highres();\n x.registers.poke_i(char_offset);\n Chip8CpuInstructions::DRW(x_register, y_register, 0).execute(\u0026mut x);\n\n println!(\"[[{}]]\", x.video_memory.format_as_string());\n\n assert_eq!(read_test_result(\"\"), x.video_memory.format_as_string());\n}\n\n#[test]\nfn draw_nibble_vx_vy_n_test_sd() {\n let mut x = Chip8Computer::new();\n let x_register = 0x1;\n let y_register = 0x2;\n let x_offset = 1;\n let y_offset = 2;\n let char_offset = 0x0A;\n\n // now lets set the X and Y to 1,2\n x.registers.poke(x_register, x_offset);\n x.registers.poke(y_register, y_offset);\n x.registers.poke_i(char_offset);\n // we are using 5 rows.\n Chip8CpuInstructions::DRW(x_register, y_register, 5).execute(\u0026mut x);\n\n // now check that video memory has the values at\n // 1,2-\u003e1,9\n // 2,2-\u003e2,9\n // 3,2-\u003e3,9\n // 4,2-\u003e4,9\n // 5,2-\u003e5,9\n // let byte_to_check = CHIP8FONT_0[0];\n for row_in_sprite in 0..5 {\n let row_data = CHIP8FONT_2[row_in_sprite];\n for bit_in_byte in 0..8 {\n let data_offset = (x_offset\n as u16 + row_in_sprite as u16) * 64 + (bit_in_byte + y_offset) as u16;\n let real_bit_in_byte = 7 - bit_in_byte;\n let shifted_one = 0x01 \u003c\u003c real_bit_in_byte;\n let one_shift_set = (shifted_one \u0026 row_data) \u003e 0;\n 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}]\");\n debug!(\"DATA_OFFSET FOR SOURCE DATA {}x{} is {} / offset by {}x{} and should be {} working with byte {:08b}\",\n bit_in_byte, row_in_sprite, data_offset, x_offset, y_offset, one_shift_set, row_data);\n }\n }\n}\n\n#[test]\nfn sub_test() {\n // 2nnn\n // Call a subroutine at 2nnn\n let mut x = Chip8Computer::new();\n Chip8CpuInstructions::CALL(0x124).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x124);\n assert_eq!(x.stack.depth(), 1);\n Chip8CpuInstructions::CALL(0x564).execute(\u0026mut x);\n assert_eq!(x.registers.peek_pc(), 0x564);\n assert_eq!(x.stack.depth(), 2);\n\n // SETUP\n // Return from a subroutine.\n let mut x = Chip8Computer::new();\n x.stack.push(\u00260x132);\n x.stack.push(\u00260xabc);\n // EXECUTE\n Chip8CpuInstructions::RET.execute(\u0026mut x);\n // VERIFY\n assert_eq!(x.registers.peek_pc(), 0xabc);\n assert_eq!(x.stack.depth(), 1);\n // EXECUTE\n Chip8CpuInstructions::RET.execute(\u0026mut x);\n // VERIFY\n assert_eq!(x.registers.peek_pc(), 0x132);\n assert_eq!(x.stack.depth(), 0);\n}\n\n\n#[test]\nfn ldvxk_test() {\n // SETUP\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0x01);\n Chip8CpuInstructions::LDRK(0x1).execute(\u0026mut x);\n assert!(matches!(x.state, gemma::chip8::cpu_states::Chip8CpuStates::WaitingForKey));\n}\n\n#[test]\nfn series8xy4_corex_tests() {\n /// 8xy4\n /// Set Vx = Vx + Vy\n /// Set VF=1 if Carry\n ///\n\n // 1 + 1\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0x01);\n x.registers.poke(0x02, 0x01);\n Chip8CpuInstructions::ADDR(0x01, 0x02).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x01), 0x02);\n assert_eq!(x.registers.peek(0x0f), 0x00);\n\n // 255+1\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0xff);\n x.registers.poke(0x02, 0x01);\n Chip8CpuInstructions::ADDR(0x01, 0x02).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x01), 0x00);\n assert_eq!(x.registers.peek(0x0f), 0x01);\n\n // 128+192\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 128);\n x.registers.poke(0x02, 192);\n Chip8CpuInstructions::ADDR(0x01, 0x02).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x01), 64);\n assert_eq!(x.registers.peek(0x0f), 1);\n\n // 8xy6 - SHR Vx {, Vy}\n // Set Vx = Vx SHR 1.\n //\n // If the least-significant bit of Vx is 1, then VF is set to 1,\n // otherwise 0. Then Vx is divided by 2.\n let mut x = Chip8Computer::new();\n // 0b10101010 -\u003e 0b01010101\n x.registers.poke(0x01, 0b10101010);\n x.registers.poke(0x0f, 0x0);\n\n Chip8CpuInstructions::SHL(0x01, 0x00).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x01), 0b01010100);\n assert_eq!(x.registers.peek(0x0f), 1);\n\n Chip8CpuInstructions::SHL(0x01, 0x00).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x01), 0b10101000);\n assert_eq!(x.registers.peek(0x0f), 0x00);\n\n Chip8CpuInstructions::SHL(0x01, 0x00).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x01), 0b01010000);\n assert_eq!(x.registers.peek(0x0f), 0x01);\n\n Chip8CpuInstructions::SHL(0x01, 0x00).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x01), 0b10100000);\n assert_eq!(x.registers.peek(0x0f), 0x00);\n\n Chip8CpuInstructions::SHL(0x01, 0x00).execute(\u0026mut x);\n assert_eq!(x.registers.peek(0x01), 0b01000000);\n assert_eq!(x.registers.peek(0x0f), 0x01);\n}\n\n#[test]\nfn random_produces_different_numbers() {\n let mut x = Chip8Computer::new();\n x.registers.poke(0x01, 0x00);\n let first_number = Chip8CpuInstructions::RND(0x01, 0xff).execute(\u0026mut x).registers.peek(0x01);\n let second_number = Chip8CpuInstructions::RND(0x01, 0xff).execute(\u0026mut x).registers.peek(0x01);\n assert_ne!(first_number, second_number);\n}\n\n#[test]\nfn delay_timer_ticks_reduce_time() {\n let mut st = DelayTimer::new();\n st.set_timer(100);\n st.tick();\n st.tick();\n st.tick();\n assert_eq!(st.current(), 97);\n}\n\n#[test]\nfn delay_timer_out_of_ticks_works() {\n let mut st = DelayTimer::new();\n st.set_timer(0);\n st.tick();\n st.tick();\n st.tick();\n assert_eq!(st.current(), 0);\n}\n\n#[test]\nfn keypad_keys_check() {\n let mut k = Keypad::new();\n\n for i in 0..16 {\n assert!(!k.key_state(i));\n }\n\n // press a key\n k.push_key(1);\n k.push_key(2);\n assert!(k.pressed(1));\n assert!(k.pressed(2));\n k.release_key(1);\n assert!(k.released(1));\n}\n\n\n#[test]\nfn keypad_string_format_test() {\n let mut k = Keypad::new();\n\n\n assert_eq!(k.format_as_string(), read_test_result(\"gemma_keypad_string_result.asc\"));\n}\n\n#[test]\nfn register_rw_test() {\n let mut x = Chip8Registers::default();\n x.poke(0x0, 0xff);\n x.poke(0x1, 0xab);\n assert_eq!(x.peek(0x0), 0xff);\n assert_eq!(x.peek(0x1), 0xab);\n}\n\n#[test]\nfn pc_test() {\n let mut x = Chip8Registers::default();\n x.set_pc(0x300);\n assert_eq!(x.peek_pc(), 0x300);\n}\n\n#[test]\n#[should_panic]\nfn invalid_register() {\n let mut x = Chip8Registers::default();\n x.poke(0x10, 0xff);\n}\n\n#[test]\nfn format_as_string_looks_right() {\n let mut x = Chip8Registers::default();\n for i in 0..0x10 {\n x.registers[i] = i as u8;\n }\n x.pc = 0xabc;\n x.i_register = 0xcab;\n let result_string = x.format_as_string();\n 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\"));\n}\n\n#[test]\nfn reset_clears_registers() {\n let mut x = Chip8Registers::default();\n\n for register in 0..0x10 {\n x.poke(register, random::\u003cu8\u003e());\n }\n x.reset();\n for register in 0..0x10 {\n assert_eq!(x.peek(register), 0x00);\n }\n}\n\n#[test]\nfn sound_timer_ticks_reduce_time() {\n let mut st = SoundTimer::new();\n st.set_timer(100);\n st.tick();\n st.tick();\n st.tick();\n assert_eq!(st.current(), 97);\n}\n\n#[test]\nfn sound_timer_out_of_ticks_works() {\n let mut st = SoundTimer::new();\n st.set_timer(0);\n st.tick();\n st.tick();\n st.tick();\n assert_eq!(st.current(), 0);\n}\n\n#[test]\nfn stack_push_pop_test() {\n let mut x = Chip8Stack::new();\n\n // lets see if we can push and pop a bunch\n x.push(\u00260xabcu16);\n x.push(\u00260xcdeu16);\n x.pop();\n assert_eq!(x.depth(), 1);\n}\n\n#[test]\n#[should_panic]\nfn stack_overflow_test() {\n let mut x = Chip8Stack::new();\n for i in 0..17 {\n x.push(\u0026i);\n }\n}\n\n#[test]\n#[should_panic]\nfn stack_underflow_test() {\n let mut x = Chip8Stack::new();\n x.pop();\n}\n\n#[test]\nfn stack_lots_of_subs() {\n let mut x = Chip8Stack::new();\n let stack_contents = [0x123, 0x321, 0xabc, 0xdef,\n 0xbad, 0xbef, 0xfed, 0xcab,\n 0xbed, 0xcad, 0xfeb, 0xcab,\n 0xfff, 0x000, 0x001];\n for i in stack_contents {\n x.push(\u0026i);\n }\n\n assert_eq!(x.depth(), 15);\n\n // up to 50 random loops\n let num_loops: u8 = random::\u003cu8\u003e() % 50;\n for i in 0..num_loops {\n let start_count = x.depth();\n let num_pop = random::\u003cu8\u003e() % x.depth() as u8;\n for current_pop in 0..num_pop {\n x.pop();\n }\n\n let post_pop_count = x.depth();\n assert_eq!(post_pop_count as u8, start_count as u8 - num_pop);\n for current_push in 0..num_pop {\n x.push(\u0026stack_contents[(current_push + post_pop_count as u8) as usize]);\n }\n assert_eq!(x.depth(), 15);\n }\n}\n\n\n#[test]\nfn video_split_bytes() {\n // from 0xABCD we should have AB high, CD low\n let (low, high) = InstructionUtil::split_bytes(0xabcd);\n assert_eq!(low, 0xAB);\n assert_eq!(high, 0xCD);\n}\n\n#[test]\nfn video_join_bytes() {\n // from 0xAB low and 0xCD high we get 0xABCD\n let merged = InstructionUtil::join_bytes(0xcd, 0xab);\n assert_eq!(merged, 0xcdab);\n}\n\n#[test]\nfn instruction_read_from_instruction() {\n // from 0xABCD\n let source = 0xABCD;\n assert_eq!(InstructionUtil::read_addr_from_instruction(source), 0xBCD);\n assert_eq!(InstructionUtil::read_nibble_from_instruction(source), 0xD);\n assert_eq!(InstructionUtil::read_x_from_instruction(source), 0xB);\n assert_eq!(InstructionUtil::read_y_from_instruction(source), 0xC);\n assert_eq!(InstructionUtil::read_byte_from_instruction(source), 0xCD);\n}\n\n#[test]\nfn instruction_ubln() {\n // from 0xABCD we should see B\n assert_eq!(InstructionUtil::read_upper_byte_lower_nibble(0xABCD), 0xB);\n assert_eq!(InstructionUtil::read_upper_byte_lower_nibble(0x0123), 0x1);\n assert_eq!(InstructionUtil::read_upper_byte_lower_nibble(0x0000), 0x0);\n}\n\n#[test]\nfn instruction_byte_to_bool_changes() {\n assert_eq!(InstructionUtil::byte_to_bools(0b00000000), [false, false, false, false, false, false, false, false]);\n assert_eq!(InstructionUtil::byte_to_bools(0b11111111), [true, true, true, true, true, true, true, true]);\n assert_eq!(InstructionUtil::byte_to_bools(0b11001100), [false, false, true, true, false, false, true, true]);\n assert_eq!(InstructionUtil::byte_to_bools(0b11110000), [false, false, false, false, true, true, true, true]);\n assert_eq!(InstructionUtil::bools_to_byte([false, false, false, false, false, false, false, false]), 0b00000000);\n assert_eq!(InstructionUtil::bools_to_byte([true, true, true, true, true, true, true, true]), 0b11111111);\n assert_eq!(InstructionUtil::bools_to_byte([false, false, true, true, false, false, true, true]), 0b11001100);\n assert_eq!(InstructionUtil::bools_to_byte([false, false, false, false, true, true, true, true]), 0b11110000);\n}\n\n\nfn real_build_checkboard(in_hd: bool) -\u003e Chip8Video {\n let mut r = Chip8Video::default();\n let (width, height) = if in_hd {\n r.set_highres();\n (SCHIP_VIDEO_WIDTH, SCHIP_VIDEO_HEIGHT)\n } else {\n (CHIP8_VIDEO_WIDTH, CHIP8_VIDEO_HEIGHT)\n };\n\n println!(\"BUILDING BOARD WITH SIZE OF {width}x{height}\");\n\n for row in 0..height {\n let data_offset = row * width;\n\n for col in 0..width {\n // XOR row and column indices to alternate in a checkerboard pattern\n let to_poke = (row % 2) ^ (col % 2) == 1;\n let local_offset: u16 = (data_offset + col) as u16;\n\n r.poke(local_offset, to_poke);\n }\n }\n r\n}\n\nfn build_checkboard_hd() -\u003e Chip8Video {\n real_build_checkboard(true)\n}\n\nfn build_checkerboard() -\u003e Chip8Video {\n real_build_checkboard(false)\n}\n\n#[test]\nfn video_default_test() {\n let mut x = Chip8Video::default();\n\n for i in 0..CHIP8_VIDEO_MEMORY {\n assert!(!x.clone().peek(i as u16));\n // then flip the value and test again.\n \u0026x.poke(i as u16, true);\n assert!(x.clone().peek(i as u16));\n }\n}\n\n#[test]\nfn video_set_initial_memory_sd() {\n let mut x = Chip8Video::default();\n // let mut initial_memory = [false; CHIP8_VIDEO_MEMORY];\n let mut ws = String::new();\n // set our checkerboard\n for cbr in 0..32 {\n for cbc in 0..64 {\n let dof = cbr * 64 + cbc;\n if (dof as i32 % 2) == 0 {\n x.poke(dof, true);\n ws += \"*\";\n } else {\n ws += \" \";\n }\n }\n ws += \"\\n\";\n }\n assert_eq!(x.format_as_string(), ws);\n}\n\n#[test]\nfn video_poke_byte_test() {\n let to_poke = 0b11001111;\n let mut x = Chip8Video::default();\n x.poke_byte(0x05, to_poke);\n let mut expected = String::new();\n expected = \" ** **** \\n\".to_string();\n for i in 0..31 {\n expected += \u0026*(\" \".repeat(64) + \"\\n\");\n }\n assert_eq!(x.format_as_string(), expected);\n}\n\n#[test]\nfn video_poke_2byte_test() {\n let to_poke: [u8; 2] = [\n 0b11001111,\n 0b00111100\n ];\n\n let mut x = Chip8Video::default();\n x.poke_2byte(0x00, to_poke);\n\n let mut expected = String::new();\n expected = \"** **** **** \".to_string() + \u0026*\" \".repeat(64 - 16).to_string() + \"\\n\";\n for i in 0..31 {\n expected += \u0026*((\u0026*\" \".repeat(64)).to_string() + \"\\n\");\n }\n\n assert_eq!(expected, x.format_as_string());\n}\n\n#[test]\nfn video_poke_multirow_2_byte_sprite() {\n // take 2 rows of 16bits and write them to memory\n}\n\n#[test]\nfn video_cls_stddef() {\n let width = 64;\n let height = 32;\n let mut initial_memory = vec![];\n let mut ws = String::new();\n let mut set_x = Chip8Video::new(initial_memory.into());\n for cbr in 0..32 {\n ws += \u0026*\" \".repeat(width);\n ws += \"\\n\";\n }\n set_x.cls();\n\n assert_eq!(set_x.format_as_string(), ws);\n}\n\n#[test]\nfn video_poke_byte_test_2() {\n let to_poke = 0b10101010;\n let mut v = Chip8Video::default();\n v.poke_byte(0x00, to_poke);\n assert!(v.clone().peek(0x00));\n assert!(!v.clone().peek(0x01));\n assert!(v.clone().peek(0x02));\n assert!(!v.clone().peek(0x03));\n assert!(v.clone().peek(0x04));\n assert!(!v.clone().peek(0x05));\n assert!(v.clone().peek(0x06));\n assert!(!v.clone().peek(0x07));\n for i in 0x8..CHIP8_VIDEO_MEMORY {\n assert!(!v.clone().peek(i as u16));\n }\n}\n\n#[test]\nfn video_poke_multi_line_test() {\n let mut v = Chip8Video::default();\n let to_poke = [\n 0b00000000,\n 0b11111111,\n 0b10101010,\n 0b01010101\n ];\n\n for (byte_in_set, byte_to_poke) in to_poke.iter().enumerate() {\n let base_offset = byte_in_set * 64;\n v.poke_byte(base_offset as u16, *byte_to_poke);\n }\n\n // row 2 column 1\n {\n assert!(v.clone().peek(0x40));\n assert!(v.clone().peek(0x41));\n assert!(v.clone().peek(0x42));\n assert!(v.clone().peek(0x43));\n assert!(v.clone().peek(0x44));\n assert!(v.clone().peek(0x45));\n assert!(v.clone().peek(0x46));\n assert!(v.clone().peek(0x47));\n\n // row 3 column 1\n assert!(!v.clone().peek(0xC0));\n assert!(v.clone().peek(0xC1));\n assert!(!v.clone().peek(0xC2));\n assert!(v.clone().peek(0xC3));\n assert!(!v.clone().peek(0xC4));\n assert!(v.clone().peek(0xC5));\n assert!(!v.clone().peek(0xC6));\n assert!(v.clone().peek(0xC7));\n }\n}\n\n#[test]\nfn video_moved_poke_test() {\n let mut v = Chip8Video::default();\n let to_poke = [\n 0b00000000,\n 0b11111111,\n 0b10101010,\n 0b01010101\n ];\n\n let x_offset = 20;\n let y_offset = 5;\n\n\n for (byte_in_set, byte_to_poke) in to_poke.iter().enumerate() {\n let base_offset = (x_offset + byte_in_set) * 64 + y_offset;\n v.poke_byte(base_offset as u16, *byte_to_poke);\n }\n\n let test_offset = (x_offset * 64 + y_offset) as u16;\n assert!(!v.clone().peek(test_offset));\n assert!(!v.clone().peek(test_offset + 1));\n assert!(!v.clone().peek(test_offset + 2));\n assert!(!v.clone().peek(test_offset + 3));\n assert!(!v.clone().peek(test_offset + 4));\n assert!(!v.clone().peek(test_offset + 5));\n assert!(!v.clone().peek(test_offset + 6));\n assert!(!v.clone().peek(test_offset + 7));\n\n let test_offset = test_offset + 0x40;\n assert!(v.clone().peek(test_offset));\n assert!(v.clone().peek(test_offset + 1));\n assert!(v.clone().peek(test_offset + 2));\n assert!(v.clone().peek(test_offset + 3));\n assert!(v.clone().peek(test_offset + 4));\n assert!(v.clone().peek(test_offset + 5));\n assert!(v.clone().peek(test_offset + 6));\n assert!(v.clone().peek(test_offset + 7));\n}\n\n#[test]\nfn video_verify_change_registered() {\n let mut v = Chip8Video::default();\n v.poke(0x01, true);\n v.poke(0x01, true);\n assert!(v.has_frame_changed);\n\n v.start_frame();\n assert!(!v.has_frame_changed);\n}\n\n#[test]\nfn video_write_checkboard() {\n let mut v = build_checkerboard();\n assert_eq!(v.clone().format_as_string(), read_test_result(\"test_video_write_checkerboard.asc\"));\n}\n\n#[test]\nfn video_zero_test() {\n let mut x = Chip8Video::default();\n\n for (byte_index, data_offset) in (0..=0x100).step_by(0x40).enumerate() {\n x.poke_byte(data_offset as u16, CHIP8FONT_0[byte_index]);\n }\n\n assert_eq!(read_test_result(\"test_video_zero.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_multi_sprite_test() {\n let mut x = Chip8Video::default();\n // draw a row of digits 01234567\n let to_draw = [CHIP8FONT_0, CHIP8FONT_1, CHIP8FONT_2, CHIP8FONT_3, CHIP8FONT_4, CHIP8FONT_5, CHIP8FONT_6, CHIP8FONT_7];\n for (index, sprite) in to_draw.iter().enumerate() {\n let data_base_offset = index * 0x8;\n for (index, offset) in (0..=0x100).step_by(0x40).enumerate() {\n x.poke_byte((data_base_offset + offset) as u16, sprite[index]);\n }\n }\n\n assert_eq!(read_test_result(\"test_multi_sprite.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_reset_test() {\n let mut x = build_checkerboard();\n x.reset();\n assert_eq!(x.format_as_string(), read_test_result(\"test_reset_clears_video.asc\"));\n}\n\n#[test]\nfn video_collision_test() {\n // Setup: Set 0xFF to 0x00 with a new frame ready\n // Action: Run Poke to the same area\n // Test: Verify the 'changed' flag is tripped\n let mut x = Chip8Video::default();\n x.poke_byte(0x00, 0xff);\n x.tick();\n // set the cell thats already set...\n x.poke(0x00, true);\n // it becomes unset and theres a frame changed\n assert_eq!(false, x.peek(0x00));\n\n assert_eq!(true, x.clone().has_frame_changed);\n}\n\n#[test]\nfn video_collision_test2() {\n let mut x = Chip8Video::default();\n x.poke_byte(0x00, 0b11110000);\n assert_eq!(true, x.has_frame_changed);\n x.tick();\n assert_eq!(false, x.has_frame_changed);\n // clear the 'has changed' flag\n\n // now set a no-collision value\n x.poke_byte(0x00, 0b00001111);\n assert_eq!(true, x.has_frame_changed);\n}\n\n#[test]\nfn video_peek_out_of_bounds_doesnt_panic() {\n let x = Chip8Video::default();\n\n let y = x.clone().peek(2049);\n let y = x.clone().peek(0);\n\n // if we got here we didn't panic\n assert!(true);\n}\n\n#[test]\nfn video_scroll_down_1_row_test() {\n let mut x = build_checkerboard();\n x.scroll_down(1);\n assert_eq!(read_test_result(\"test_video_scroll_down_1.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_scroll_down_10_row_test() {\n let mut x = build_checkerboard();\n x.scroll_down(10);\n assert_eq!(read_test_result(\"test_video_scroll_down_10.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_high_res_has_right_resolution() {\n let mut x = build_checkboard_hd();\n println!(\"[{}]\", x.format_as_string());\n assert_eq!(read_test_result(\"test_video_highdef.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_scroll_down_1_row_test_schip() {\n let mut x = build_checkboard_hd();\n x.scroll_down(1);\n\n println!(\"[{}]\", x.format_as_string());\n println!(\"[{}]\", read_test_result(\"test_scroll_down_1_hd.asc\"));\n\n assert_eq!(read_test_result(\"test_scroll_down_1_hd.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_scroll_down_10_row_test_schip() {\n let mut x = build_checkboard_hd();\n x.scroll_down(10);\n assert_eq!(read_test_result(\"test_scroll_down_10_hd.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_scroll_left_4_row_test_std_def() {\n let mut x = build_checkerboard();\n x.scroll_left();\n assert_eq!(read_test_result(\"test_scroll_left_4.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_scroll_left_4_row_test_high_def() {\n let mut x = build_checkboard_hd();\n x.scroll_left();\n assert_eq!(read_test_result(\"test_scroll_left_4_hd.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_scroll_right_4_row_test_std_def() {\n let mut x = build_checkerboard();\n x.scroll_right();\n assert_eq!(read_test_result(\"test_scroll_right_4.asc\"), x.format_as_string());\n}\n\n#[test]\nfn video_scroll_right_4_row_test_high_def() {\n let mut x = build_checkboard_hd();\n x.scroll_right();\n assert_eq!(read_test_result(\"test_scroll_right_4_hd.asc\"), x.format_as_string());\n}\n\n\n#[test]\nfn instructions_operands_tests() {\n assert_eq!(Chip8CpuInstructions::SYS(0x000).operands(), \"0x0000\");\n assert_eq!(Chip8CpuInstructions::JPI(0x123).operands(), \"0x0123\");\n assert_eq!(Chip8CpuInstructions::JPA(0x234).operands(), \"0x0234\");\n assert_eq!(Chip8CpuInstructions::LDIA(0x345).operands(), \"0x0345\");\n assert_eq!(Chip8CpuInstructions::CALL(0x456).operands(), \"0x0456\");\n}\n\n#[test]\nfn instruction_ena_dis_tests() {\n let mut x = Chip8Computer::new();\n assert!(!x.video_memory.is_highres());\n Chip8CpuInstructions::ENA.execute(\u0026mut x);\n assert!(x.video_memory.is_highres());\n Chip8CpuInstructions::ENA.execute(\u0026mut x);\n assert!(x.video_memory.is_highres());\n Chip8CpuInstructions::DIS.execute(\u0026mut x);\n assert!(!x.video_memory.is_highres());\n}\n\n#[test]\nfn instruction_test_scrolling_lowres() {\n let mut x = Chip8Computer::new();\n x.video_memory = build_checkerboard();\n Chip8CpuInstructions::SRT.execute(\u0026mut x);\n\n assert_eq!(read_test_result(\"test_scroll_right_4.asc\"), x.dump_video_to_string());\n\n x = Chip8Computer::new();\n x.video_memory = build_checkerboard();\n Chip8CpuInstructions::SLF.execute(\u0026mut x);\n\n assert_eq!(read_test_result(\"test_scroll_left_4.asc\"), x.dump_video_to_string());\n\n x = Chip8Computer::new();\n x.video_memory = build_checkerboard();\n Chip8CpuInstructions::SDN(0x01).execute(\u0026mut x);\n assert_eq!(read_test_result(\"test_video_scroll_down_1.asc\"), x.dump_video_to_string());\n\n x = Chip8Computer::new();\n x.video_memory = build_checkerboard();\n Chip8CpuInstructions::SDN(0xA).execute(\u0026mut x);\n assert_eq!(read_test_result(\"test_video_scroll_down_10.asc\"), x.dump_video_to_string());\n}\n\n#[test]\nfn computer_dump_keypad_to_string() {\n let mut x = Chip8Computer::new();\n x.keypad.push_key(0x1);\n x.keypad.push_key(0x2);\n assert_eq!(read_test_result(\"test_keypad_to_string.asc\"), x.dump_keypad_to_string());\n}\n\n#[test]\nfn computer_dump_registers_to_string() {\n let mut x = Chip8Computer::new();\n let values_to_set = [0x0b, 0xad, 0xbe, 0xef,\n 0xca, 0xb0,\n 0x7a, 0xc0, 0xca, 0x70,\n 0xba, 0xdb, 0xed, 0x00,\n 0x00, 0x00\n ];\n let expected_value = \"Vx: 0x0b 0xad 0xbe 0xef 0xca 0xb0 0x7a 0xc0\\n 0xca 0x70 0xba 0xdb 0xed 0x00 0x00 0x00\\nI: 0x0000\\tPC: 0x0200\";\n\n for i in 0..16 {\n x.registers.poke(i, values_to_set[i as usize]);\n }\n\n // now verify.\n assert_eq!(expected_value, x.dump_registers_to_string());\n}\n","traces":[{"line":18,"address":[322048],"length":1,"stats":{"Line":1}},{"line":19,"address":[322085],"length":1,"stats":{"Line":1}},{"line":570,"address":[323237,322352],"length":1,"stats":{"Line":0}},{"line":571,"address":[322406],"length":1,"stats":{"Line":0}},{"line":573,"address":[322420],"length":1,"stats":{"Line":0}},{"line":574,"address":[322389],"length":1,"stats":{"Line":0}},{"line":575,"address":[322428],"length":1,"stats":{"Line":0}},{"line":576,"address":[322394],"length":1,"stats":{"Line":0}},{"line":577,"address":[322399],"length":1,"stats":{"Line":0}},{"line":578,"address":[322436],"length":1,"stats":{"Line":0}},{"line":579,"address":[322506],"length":1,"stats":{"Line":0}},{"line":580,"address":[322535],"length":1,"stats":{"Line":0}},{"line":581,"address":[322551],"length":1,"stats":{"Line":0}},{"line":582,"address":[322575],"length":1,"stats":{"Line":0}},{"line":584,"address":[322794,322658],"length":1,"stats":{"Line":0}},{"line":586,"address":[322943],"length":1,"stats":{"Line":0}},{"line":957,"address":[324298,323264],"length":1,"stats":{"Line":1}},{"line":958,"address":[323297],"length":1,"stats":{"Line":1}},{"line":959,"address":[323353,323332,323529,323312],"length":1,"stats":{"Line":4}},{"line":960,"address":[323334],"length":1,"stats":{"Line":1}},{"line":961,"address":[323513],"length":1,"stats":{"Line":1}},{"line":963,"address":[323316],"length":1,"stats":{"Line":1}},{"line":966,"address":[323635],"length":1,"stats":{"Line":1}},{"line":968,"address":[323882,323720],"length":1,"stats":{"Line":2}},{"line":969,"address":[323950,323900],"length":1,"stats":{"Line":1}},{"line":971,"address":[323978,323925],"length":1,"stats":{"Line":2}},{"line":973,"address":[324210,324080],"length":1,"stats":{"Line":1}},{"line":974,"address":[324272,324197,324239],"length":1,"stats":{"Line":2}},{"line":976,"address":[324293,324250],"length":1,"stats":{"Line":2}},{"line":979,"address":[323839],"length":1,"stats":{"Line":1}},{"line":982,"address":[324320],"length":1,"stats":{"Line":1}},{"line":983,"address":[324328],"length":1,"stats":{"Line":1}},{"line":986,"address":[324352],"length":1,"stats":{"Line":1}},{"line":987,"address":[324360],"length":1,"stats":{"Line":1}},{"line":1640,"address":[324384],"length":1,"stats":{"Line":0}},{"line":1644,"address":[324403],"length":1,"stats":{"Line":0}}],"covered":20,"coverable":36},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmaegui","src","bin","gemmaegui.rs"],"content":"use std::path::PathBuf;\nuse std::time::Instant;\nuse crate::support::gemma_egui_support::{EGuiFileList, GemmaEguiSupport};\nuse crate::support::gemma_egui_state::GemmaEGuiState;\nuse eframe::egui;\nuse egui::{Key, Ui};\nuse gemma::chip8::computer::Chip8Computer;\nuse gemma::chip8::computer_manager::Chip8ComputerManager;\n\nmod support;\n\nconst LIN_KEYS: [[(Key, u8); 4]; 4] = [\n [(Key::Num1, 0x01), (Key::Num2, 0x02), (Key::Num3, 0x03), (Key::Num4, 0x0c)],\n [(Key::Q, 0x04), (Key::W, 0x05), (Key::E, 0x06), (Key::R, 0x0d)],\n [(Key::A, 0x07), (Key::S, 0x08), (Key::D, 0x09), (Key::F, 0x0e)],\n [(Key::Z, 0x0a), (Key::X, 0x00), (Key::C, 0x0b), (Key::V, 0x0F)]\n];\n\n#[derive(Default)]\nstruct DisplayOptions {\n pub video: bool,\n pub registers: bool,\n pub memory: bool,\n}\npub struct GemmaViewerState {\n pub selected_file_index: i32,\n pub selected_filename: String,\n pub display_options: DisplayOptions,\n}\n\nimpl Default for GemmaViewerState {\n fn default() -\u003e Self {\n GemmaViewerState {\n selected_file_index: -1,\n selected_filename: String::new(),\n display_options: Default::default(),\n }\n }\n}\n\nimpl GemmaViewerState {\n pub fn new() -\u003e GemmaViewerState {\n GemmaViewerState {\n ..Default::default()\n }\n }\n}\n\nfn main() -\u003e eframe::Result {\n println!(\"Taxation is Theft\");\n\n let mut computer = Chip8ComputerManager::new();\n let mut state = GemmaViewerState::new();\n\n let options = eframe::NativeOptions {\n viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]),\n ..Default::default()\n };\n\n eframe::run_simple_native(\"EGUI Gemma\", options, move |ctx, _frame| {\n catppuccin_egui::set_theme(\u0026ctx, catppuccin_egui::MOCHA);\n egui::CentralPanel::default().show(ctx, |ui| {\n let frame_start_time = Instant::now();\n\n let local_computer = computer.state();\n //if state.display_video {\n GemmaEguiSupport::video_view(local_computer, ui);\n // }\n\n ui.heading(\"EGUI Gemma\");\n\n // if state.display_memory {\n GemmaEguiSupport::memory_view(\u0026local_computer, ui);\n // }\n\n // if state.display_registers {\n GemmaEguiSupport::registers_view(\u0026local_computer, ui);\n // }\n ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {\n if ui.button(\"Start\").clicked() {\n computer.start();\n }\n if ui.button(\"Step\").clicked() {\n computer.step();\n }\n\n if ui.button(\"Stop\").clicked() {\n computer.stop();\n // state.is_running = false;\n }\n if ui.button(\"Reset\").clicked() {\n computer.reset();\n // state.is_running = false;\n }\n });\n\n if ui.button(format!(\"Load {}\", state.selected_filename)).clicked() {\n // println!(\"Should load the bin now\");\n let read_bin = std::fs::read(PathBuf::from(format!(\"resources/roms/{}\", state.selected_filename))).unwrap();\n computer.load_bytes_to_system_memory(read_bin);\n };\n EGuiFileList::display_path(PathBuf::from(\"resources/roms\"), \u0026mut state.selected_filename, ui);\n let input = ctx.input(|input| {\n // loop through the keys we are checking...\n for row in LIN_KEYS {\n for (keyboard_key, keypad_key) in row {\n if input.key_pressed(keyboard_key) {\n computer.press_key(keypad_key);\n // println!(\"KEY {keypad_key:02x} DOWN\");\n } else {\n // release it if the user just did\n if computer.is_key_pressed(keypad_key) {\n computer.release_key(keypad_key);\n // println!(\"KEY {keypad_key:02x} up\");\n }\n }\n }\n }\n });\n\n // run our target number of ticks in the amount of available time.\n let time_consumed = Instant::now().duration_since(frame_start_time).as_millis();\n let mut num_ticks = 0;\n while num_ticks \u003c 1000 {\n computer.tick();\n num_ticks += 1;\n }\n ctx.request_repaint();\n });\n })\n}\n","traces":[{"line":32,"address":[3199832,3199664],"length":1,"stats":{"Line":0}},{"line":35,"address":[3199683],"length":1,"stats":{"Line":0}},{"line":36,"address":[3199745,3199688],"length":1,"stats":{"Line":0}},{"line":42,"address":[3199856],"length":1,"stats":{"Line":0}},{"line":49,"address":[3201026,3199952,3200995],"length":1,"stats":{"Line":0}},{"line":50,"address":[3199999],"length":1,"stats":{"Line":0}},{"line":52,"address":[3200063],"length":1,"stats":{"Line":0}},{"line":53,"address":[3200093],"length":1,"stats":{"Line":0}},{"line":56,"address":[3200157,3200202],"length":1,"stats":{"Line":0}},{"line":60,"address":[3157424],"length":1,"stats":{"Line":0}},{"line":61,"address":[3157457],"length":1,"stats":{"Line":0}},{"line":62,"address":[3159257,3157509,3157616],"length":1,"stats":{"Line":0}},{"line":63,"address":[3157641],"length":1,"stats":{"Line":0}},{"line":65,"address":[3157684],"length":1,"stats":{"Line":0}},{"line":67,"address":[3157706],"length":1,"stats":{"Line":0}},{"line":70,"address":[3157721],"length":1,"stats":{"Line":0}},{"line":73,"address":[3157767],"length":1,"stats":{"Line":0}},{"line":77,"address":[3157782],"length":1,"stats":{"Line":0}},{"line":79,"address":[3157901,3159296,3160195],"length":1,"stats":{"Line":0}},{"line":80,"address":[3159435,3159321],"length":1,"stats":{"Line":0}},{"line":81,"address":[3159510],"length":1,"stats":{"Line":0}},{"line":83,"address":[3159526,3159649],"length":1,"stats":{"Line":0}},{"line":84,"address":[3159733],"length":1,"stats":{"Line":0}},{"line":87,"address":[3159749,3159872],"length":1,"stats":{"Line":0}},{"line":88,"address":[3159956],"length":1,"stats":{"Line":0}},{"line":91,"address":[3159972,3160095],"length":1,"stats":{"Line":0}},{"line":92,"address":[3160176],"length":1,"stats":{"Line":0}},{"line":97,"address":[3158376,3158122,3158032,3158257],"length":1,"stats":{"Line":0}},{"line":99,"address":[3158558,3158688,3158468],"length":1,"stats":{"Line":0}},{"line":100,"address":[3158951],"length":1,"stats":{"Line":0}},{"line":102,"address":[3158968],"length":1,"stats":{"Line":0}},{"line":103,"address":[3160224,3159031,3157633,3160882],"length":1,"stats":{"Line":0}},{"line":105,"address":[3160406,3160249,3160473],"length":1,"stats":{"Line":0}},{"line":106,"address":[3160733,3160663,3160489],"length":1,"stats":{"Line":0}},{"line":107,"address":[3160761,3160725],"length":1,"stats":{"Line":0}},{"line":108,"address":[3160877,3160817],"length":1,"stats":{"Line":0}},{"line":112,"address":[3160840,3160790],"length":1,"stats":{"Line":0}},{"line":113,"address":[3160853],"length":1,"stats":{"Line":0}},{"line":122,"address":[3159043],"length":1,"stats":{"Line":0}},{"line":123,"address":[3159142],"length":1,"stats":{"Line":0}},{"line":124,"address":[3159153,3159239],"length":1,"stats":{"Line":0}},{"line":125,"address":[3159201],"length":1,"stats":{"Line":0}},{"line":126,"address":[3159241,3159210],"length":1,"stats":{"Line":0}},{"line":128,"address":[3159171],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":44},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmaegui","src","bin","support","gemma_egui_state.rs"],"content":"use std::ops::Range;\nuse gemma::chip8::computer_manager::Chip8ComputerManager;\n\npub struct GemmaEGuiState {\n pub display_video: bool,\n pub display_memory: bool,\n pub display_registers: bool,\n pub memory_view: Range\u003ci32\u003e,\n pub computer: Chip8ComputerManager,\n pub selected_rom_filename: String\n}\n\nimpl Default for GemmaEGuiState {\n fn default() -\u003e Self {\n Self {\n display_video: true,\n display_memory: true,\n display_registers: true,\n memory_view: 0x00..0x200,\n computer: Chip8ComputerManager::new(),\n selected_rom_filename: String::new()\n }\n }\n}\n","traces":[{"line":14,"address":[3182160,3182383],"length":1,"stats":{"Line":0}},{"line":20,"address":[3182191],"length":1,"stats":{"Line":0}},{"line":21,"address":[3182213],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":3},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmaegui","src","bin","support","gemma_egui_support.rs"],"content":"use std::fs::read_dir;\nuse std::ops::Index;\nuse std::path::{Display, PathBuf};\nuse std::thread;\nuse std::time::Duration;\nuse egui::{Align, Color32, ComboBox, Direction, Pos2, Response, TextBuffer};\nuse egui::Rect;\nuse egui::Vec2;\nuse egui::Ui;\nuse egui::WidgetType::SelectableLabel;\nuse crate::Chip8Computer;\n\nconst CELL_WIDTH: f32 = 5.0;\nconst CELL_HEIGHT: f32 = 5.0;\n\npub struct EGuiFileList {}\nimpl EGuiFileList {\n pub fn display_path(root: PathBuf, selected_filename: \u0026mut String, ui: \u0026mut Ui) {\n let mut working_filename = selected_filename.clone();\n ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {\n // ui.label(format!(\"Displaying {}\", root.to_str().unwrap_or(\"Unable to Load Path\")));\n ComboBox::from_label(\"Select ROM\")\n .selected_text(selected_filename.clone())\n .show_ui(ui, |ui| {\n\n let mut sorted_options = vec![];\n for option in read_dir(root.as_path()).unwrap() {\n let to_push = option.unwrap().file_name().into_string().unwrap_or( String::new());\n sorted_options.push(to_push);\n }\n\n sorted_options.sort();\n for item in sorted_options {\n // Add each option to the ComboBox\n if ui.selectable_label(selected_filename.eq(\u0026item.as_str()), item.clone()).clicked()\n {\n *selected_filename = item;\n }\n }\n });\n // Display the selected option\n });\n }\n}\n\npub struct GemmaEguiSupport {}\n\nimpl GemmaEguiSupport {\n pub fn controls_view(system: \u0026mut Chip8Computer, ui: \u0026mut Ui) {\n\n ui.with_layout(egui::Layout::left_to_right(Align::TOP), |ui| {\n // ui.checkbox(\u0026mut state.display_memory, \"Display Memory\");\n // ui.checkbox(\u0026mut state.display_video, \"Display Video\");\n // ui.checkbox(\u0026mut state.display_registers, \"Display Registers\");\n });\n }\n\n pub fn registers_view(system: \u0026Chip8Computer, ui: \u0026mut Ui) {\n ui.label(format!(\"V0-7: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} \",\n system.registers.peek(0x00),\n system.registers.peek(0x01),\n system.registers.peek(0x02),\n system.registers.peek(0x03),\n system.registers.peek(0x04),\n system.registers.peek(0x05),\n system.registers.peek(0x06),\n system.registers.peek(0x07)\n ));\n ui.label(format!(\"V8-F: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} \",\n system.registers.peek(0x08),\n system.registers.peek(0x09),\n system.registers.peek(0x0A),\n system.registers.peek(0x0B),\n system.registers.peek(0x0C),\n system.registers.peek(0x0D),\n system.registers.peek(0x0E),\n system.registers.peek(0x0F)\n ));\n ui.label(format!(\"PC: {:04x}\\tI: {:04x}\", system.registers.peek_pc(), system.registers.peek_i()));\n }\n\n pub fn video_view(system: \u0026Chip8Computer, ui: \u0026mut Ui) {\n let (_resp, painter) = ui.allocate_painter(Vec2::new(350.0, 165.0), egui::Sense::hover());\n for current_row in 0..32 {\n for current_col in 0..64 {\n let data_offset = current_row * 64 + current_col;\n let x_offset = current_col as f32 * CELL_WIDTH;\n let y_offset = current_row as f32 * CELL_HEIGHT;\n let origin = Pos2::new(x_offset, y_offset);\n let colour = if system.video_memory.peek(data_offset) {\n Color32::RED\n } else {\n Color32::WHITE\n };\n let rect = Rect::from_min_size(origin, Vec2::new(CELL_WIDTH, CELL_HEIGHT));\n painter.rect_filled(rect, 0.0, colour);\n // println!(\"Cell {current_col}x{current_row} at {}x{} -\u003e {}\",\n // origin.x, origin.y,\n // system.video_memory.peek(data_offset));\n }\n }\n // thread::sleep(Duration::from_secs(1));\n }\n\n pub fn memory_view(system: \u0026Chip8Computer, ui: \u0026mut Ui) {\n ui.label(\"Memory View\");\n\n for i in (0..=0x200).step_by(16) {\n ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {\n for y in 0..16 {\n ui.label(format!(\"{:02x}\", system.memory.peek((i + y) as u16)).as_str());\n }\n });\n }\n ui.label(\"Should have **something** to adjust the 'memory window'\");\n }\n}\n","traces":[{"line":18,"address":[3164097,3163664],"length":1,"stats":{"Line":0}},{"line":19,"address":[3163694],"length":1,"stats":{"Line":0}},{"line":20,"address":[3163925],"length":1,"stats":{"Line":0}},{"line":22,"address":[3186846,3186670,3186780],"length":1,"stats":{"Line":0}},{"line":23,"address":[3186828,3186896,3186715],"length":1,"stats":{"Line":0}},{"line":24,"address":[3186836,3188719,3186928,3189140],"length":1,"stats":{"Line":0}},{"line":26,"address":[3186964],"length":1,"stats":{"Line":0}},{"line":27,"address":[3187351,3187125,3187021,3189091,3187490,3187523],"length":1,"stats":{"Line":0}},{"line":28,"address":[3188750,3189118],"length":1,"stats":{"Line":0}},{"line":29,"address":[3189016],"length":1,"stats":{"Line":0}},{"line":32,"address":[3187765],"length":1,"stats":{"Line":0}},{"line":33,"address":[3187799,3188695,3188039,3187989],"length":1,"stats":{"Line":0}},{"line":35,"address":[3188189,3188682,3188079,3188390],"length":1,"stats":{"Line":0}},{"line":37,"address":[3188501],"length":1,"stats":{"Line":0}},{"line":49,"address":[3164128],"length":1,"stats":{"Line":0}},{"line":51,"address":[3164247],"length":1,"stats":{"Line":0}},{"line":58,"address":[3164368],"length":1,"stats":{"Line":0}},{"line":59,"address":[3166712,3168020,3166944,3167640,3167408,3166016,3166480,3166248,3167176,3165528],"length":1,"stats":{"Line":0}},{"line":60,"address":[3164416],"length":1,"stats":{"Line":0}},{"line":61,"address":[3164553],"length":1,"stats":{"Line":0}},{"line":62,"address":[3164693],"length":1,"stats":{"Line":0}},{"line":63,"address":[3164833],"length":1,"stats":{"Line":0}},{"line":64,"address":[3164973],"length":1,"stats":{"Line":0}},{"line":65,"address":[3165113],"length":1,"stats":{"Line":0}},{"line":66,"address":[3165253],"length":1,"stats":{"Line":0}},{"line":67,"address":[3165393],"length":1,"stats":{"Line":0}},{"line":69,"address":[3170818,3170586,3169658,3170354,3171282,3169170,3171662,3169890,3170122,3171050],"length":1,"stats":{"Line":0}},{"line":70,"address":[3168055],"length":1,"stats":{"Line":0}},{"line":71,"address":[3168195],"length":1,"stats":{"Line":0}},{"line":72,"address":[3168335],"length":1,"stats":{"Line":0}},{"line":73,"address":[3168475],"length":1,"stats":{"Line":0}},{"line":74,"address":[3168615],"length":1,"stats":{"Line":0}},{"line":75,"address":[3168755],"length":1,"stats":{"Line":0}},{"line":76,"address":[3168895],"length":1,"stats":{"Line":0}},{"line":77,"address":[3169035],"length":1,"stats":{"Line":0}},{"line":79,"address":[3171839,3172266,3171703,3172498,3171970,3172681],"length":1,"stats":{"Line":0}},{"line":82,"address":[3172736,3174124],"length":1,"stats":{"Line":0}},{"line":83,"address":[3172791],"length":1,"stats":{"Line":0}},{"line":84,"address":[3173289,3173103,3173185],"length":1,"stats":{"Line":0}},{"line":85,"address":[3173408,3173310],"length":1,"stats":{"Line":0}},{"line":86,"address":[3173523,3173692],"length":1,"stats":{"Line":0}},{"line":87,"address":[3173612],"length":1,"stats":{"Line":0}},{"line":88,"address":[3173646],"length":1,"stats":{"Line":0}},{"line":89,"address":[3173732],"length":1,"stats":{"Line":0}},{"line":90,"address":[3173809,3173768],"length":1,"stats":{"Line":0}},{"line":91,"address":[3173811],"length":1,"stats":{"Line":0}},{"line":93,"address":[3173796],"length":1,"stats":{"Line":0}},{"line":96,"address":[3174038],"length":1,"stats":{"Line":0}},{"line":105,"address":[3174160],"length":1,"stats":{"Line":0}},{"line":106,"address":[3174192],"length":1,"stats":{"Line":0}},{"line":108,"address":[3174438,3174226],"length":1,"stats":{"Line":0}},{"line":109,"address":[3174551],"length":1,"stats":{"Line":0}},{"line":110,"address":[3189230,3189288],"length":1,"stats":{"Line":0}},{"line":111,"address":[3189299,3189859,3189677,3189429],"length":1,"stats":{"Line":0}},{"line":115,"address":[3174381],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":55},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmaegui","src","bin","support","mod.rs"],"content":"pub mod gemma_egui_state;\npub mod gemma_egui_support;\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmaimgui","src","bin","gemmaimgui.rs"],"content":"use std::default::Default;\nuse std::fs::DirEntry;\nuse std::time::Instant;\nuse gemma::{\n chip8::computer::Chip8Computer,\n constants::{CHIP8_MEMORY_SIZE, CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH},\n};\nuse imgui::*;\nuse sys::{ImColor, ImVec2, ImVector_ImU32};\nuse rand::random;\nuse gemma::chip8::computer_manager::Chip8ComputerManager;\nuse gemma::chip8::cpu_states::Chip8CpuStates::WaitingForInstruction;\nuse gemma::chip8::system_memory::Chip8SystemMemory;\nuse support::{emmagui_support::GemmaImguiSupport, ui_state::ImGuiUiState};\nuse clap::{Parser, Subcommand};\nuse gemma::chip8::quirk_modes::QuirkMode;\nuse gemma::chip8::quirk_modes::QuirkMode::Chip8;\n\n\nmod support;\n\n/// Keypad Mappings for my Linux box\n/// 1 2 3 C\n/// 4 5 6 D\n/// 7 8 9 E\n/// A 0 B F\n\nconst LIN_KEYS: [(u16, u8); 0x10] = [(537, 0x01),(538, 0x02),(539, 0x03),(540, 0x0c),\n (562, 0x04),(568, 0x05),(550, 0x06),(563, 0x0d),\n (546, 7),(564, 8),(549, 9),(551, 0xe),\n (571, 0xa),(569, 0),(548, 0xb),(567, 0xf)];\n\nfn main() {\n pretty_env_logger::init();\n\n let mut system = Chip8ComputerManager::default();\n let mut ui_state = ImGuiUiState::default();\n let target_ips = ui_state.target_ips;\n\n support::simple_init(file!(), move |_, ui| {\n let current_time = Instant::now();\n let mut num_cycles = 0;\n\n // Key Checks\n let down_keys = ui.io().keys_down;\n\n // START DEBUG CODE TO DISPLAY WHAT KEYS WE TRAPPED\n for (idx, val) in down_keys.iter().enumerate() {\n if *val {\n println!(\"{idx} = {val}\");\n }\n }\n // END DEBUG CODE\n\n for (key_code, key_reg) in LIN_KEYS {\n if down_keys[key_code as usize] {\n system.press_key(key_reg);\n system.wait_for_instruction();\n } else {\n // do we need to release it?\n\n if system.is_key_pressed(key_reg) {\n system.release_key(key_reg);\n }\n }\n }\n\n let target_ms = ui_state.frame_time;\n let loop_start_time = Instant::now();\n while Instant::now().duration_since(current_time).as_millis() \u003c target_ms as u128 \u0026\u0026 num_cycles \u003c target_ips {\n if system.tick() {\n num_cycles += 1;\n }\n }\n let cycles_time = Instant::now().duration_since(loop_start_time);\n if num_cycles \u003e 0 {\n println!(\"Ran for {}ms and executed {}/{} cycles.\", cycles_time.as_millis(), num_cycles, target_ips);\n }\n // GUI Parts\n if ui_state.show_video {\n GemmaImguiSupport::video_display(\u0026system.state(), \u0026ui_state, ui);\n }\n\n GemmaImguiSupport::system_controls(\u0026mut system, \u0026mut ui_state, ui);\n\n if ui_state.show_registers {\n GemmaImguiSupport::registers_view(\u0026system.state(), ui);\n }\n\n if ui_state.show_memory {\n let active_instruction = system.state().registers.peek_pc();\n GemmaImguiSupport::hex_memory_display(system.state().memory.clone(), (0x100, 0x10), active_instruction as i16, ui);\n }\n\n if ui_state.show_keypad {\n GemmaImguiSupport::keypad_display(\u0026system.state(), ui);\n }\n });\n}\n","traces":[{"line":33,"address":[4072911,4072940,4072608],"length":1,"stats":{"Line":0}},{"line":34,"address":[4072645],"length":1,"stats":{"Line":0}},{"line":36,"address":[4072662],"length":1,"stats":{"Line":0}},{"line":37,"address":[4072692],"length":1,"stats":{"Line":0}},{"line":38,"address":[4072740],"length":1,"stats":{"Line":0}},{"line":40,"address":[4072758],"length":1,"stats":{"Line":0}},{"line":41,"address":[4175144],"length":1,"stats":{"Line":0}},{"line":42,"address":[4175179],"length":1,"stats":{"Line":0}},{"line":45,"address":[4175187],"length":1,"stats":{"Line":0}},{"line":48,"address":[4175218,4175453],"length":1,"stats":{"Line":0}},{"line":49,"address":[4175485],"length":1,"stats":{"Line":0}},{"line":50,"address":[4177245],"length":1,"stats":{"Line":0}},{"line":55,"address":[4175379,4175704,4175515,4175572],"length":1,"stats":{"Line":0}},{"line":56,"address":[4175738,4176852],"length":1,"stats":{"Line":0}},{"line":57,"address":[4176927],"length":1,"stats":{"Line":0}},{"line":58,"address":[4176987],"length":1,"stats":{"Line":0}},{"line":62,"address":[4176900,4176945],"length":1,"stats":{"Line":0}},{"line":63,"address":[4176963],"length":1,"stats":{"Line":0}},{"line":68,"address":[4175655],"length":1,"stats":{"Line":0}},{"line":69,"address":[4175672],"length":1,"stats":{"Line":0}},{"line":70,"address":[4175763,4175941],"length":1,"stats":{"Line":0}},{"line":71,"address":[4176826,4175958],"length":1,"stats":{"Line":0}},{"line":72,"address":[4176803,4176831],"length":1,"stats":{"Line":0}},{"line":75,"address":[4175863],"length":1,"stats":{"Line":0}},{"line":76,"address":[4175927],"length":1,"stats":{"Line":0}},{"line":77,"address":[4176008,4176340,4176248],"length":1,"stats":{"Line":0}},{"line":80,"address":[4175982],"length":1,"stats":{"Line":0}},{"line":81,"address":[4176530],"length":1,"stats":{"Line":0}},{"line":84,"address":[4176494],"length":1,"stats":{"Line":0}},{"line":86,"address":[4176514],"length":1,"stats":{"Line":0}},{"line":87,"address":[4176597],"length":1,"stats":{"Line":0}},{"line":90,"address":[4176581],"length":1,"stats":{"Line":0}},{"line":91,"address":[4176652],"length":1,"stats":{"Line":0}},{"line":92,"address":[4176692],"length":1,"stats":{"Line":0}},{"line":95,"address":[4176636],"length":1,"stats":{"Line":0}},{"line":96,"address":[4176769],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":36},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmaimgui","src","bin","support","emmagui_support.rs"],"content":"use std::ffi::OsString;\nuse gemma::constants::CHIP8_KEYBOARD;\nuse std::fs::{File, read_dir};\nuse std::io::Read;\nuse std::path::{Path, PathBuf};\nuse std::time::Duration;\nuse imgui::{Condition, ImColor32, Ui};\nuse log::debug;\nuse gemma::chip8::computer::Chip8Computer;\nuse gemma::chip8::computer_manager::Chip8ComputerManager;\nuse gemma::chip8::computer_manager::ManagerDumpables::{Keyboard, Registers, Video};\nuse gemma::chip8::keypad::Keypad;\nuse gemma::chip8::system_memory::Chip8SystemMemory;\nuse gemma::constants::{CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_WIDTH};\nuse crate::ImGuiUiState;\nuse crate::support::gui_file_list::GuiFileList;\nuse super::ui_state;\n\nconst ROM_ROOT: \u0026str = \"/home/tmerritt/Projects/chip8_toy/resources/roms\";\n\npub struct GemmaImguiSupport {}\n\nconst CELL_WIDTH: i32 = 5i32;\nconst CELL_HEIGHT: i32 = 5i32;\n\nimpl GemmaImguiSupport {\n pub fn keypad_display(system_to_display: \u0026Chip8Computer, ui: \u0026Ui) {\n ui.window(format!(\"Keypad\"))\n .size([100.0, 100.0], Condition::FirstUseEver)\n .build(|| {\n for row in CHIP8_KEYBOARD {\n for key in row {\n let label = if system_to_display.keypad.pressed(key) {\n format!(\"*{:1x}*\", key)\n } else {\n format!(\"{:1x}\", key)\n };\n ui.text(format!(\"{}\", label));\n ui.same_line();\n }\n ui.text(\"\");\n }\n });\n }\n\n pub fn video_display(system_to_control: \u0026Chip8Computer, gui_state: \u0026ImGuiUiState, ui: \u0026Ui) {\n // draw area size\n let (width, height) = system_to_control.video_memory.get_resolution();\n let draw_area_size = ui.io().display_size;\n // println!(\"DRAW_AREA_SIZE = {}x{}\", draw_area_size[0], draw_area_size[1]);\n let cell_width = ((draw_area_size[0] as i32 / width) * 6) / 10;\n let cell_height = ((draw_area_size[1] as i32 / height) * 6) / 10;\n\n ui.window(format!(\"Display {cell_width}x{cell_height}\"))\n .size([300.0, 300.0], Condition::Once)\n .build(|| {\n let origin = ui.cursor_pos();\n let fg = ui.get_window_draw_list();\n if system_to_control.video_memory.is_highres() {\n // ui.text(\"High Def Video here\");\n for current_row in 0..=height {\n let y_offset = origin[1] as i32 + (current_row * cell_height);\n for current_column in 0..=width {\n let x_offset = origin[0] as i32 + (current_column * cell_width);\n let current_origin = [x_offset as f32, y_offset as f32];\n let current_limit = [(x_offset + cell_width) as f32, (y_offset + cell_height) as f32];\n let memory_offset = (current_row * width + current_column) as u16;\n let to_render = system_to_control.video_memory.peek(memory_offset);\n let color: ImColor32 = if to_render {\n gui_state.on_colour\n } else {\n gui_state.off_colour\n };\n fg.add_rect_filled_multicolor(current_origin, current_limit, color, color, color, color);\n }\n }\n } else {\n for current_row in 0..height {\n let y_offset = origin[1] as i32 + (current_row * cell_height);\n for current_column in 0..width {\n let x_offset = origin[0] as i32 + (current_column * cell_width);\n let current_origin = [x_offset as f32, y_offset as f32];\n let current_limit = [(x_offset + cell_width) as f32, (y_offset + cell_height) as f32];\n let memory_offset = (current_row * width + current_column) as u16;\n let to_render = system_to_control.video_memory.peek(memory_offset);\n let color: ImColor32 = if to_render {\n gui_state.on_colour\n } else {\n gui_state.off_colour\n };\n fg.add_rect_filled_multicolor(current_origin, current_limit, color, color, color, color);\n }\n }\n }\n });\n }\n pub fn system_controls(system_to_control: \u0026mut Chip8ComputerManager, gui_state: \u0026mut ImGuiUiState, ui: \u0026Ui) {\n // let mut state: Chip8Computer = system_to_control;\n ui.window(\"!!!! CONTROLS !!!!\")\n .size([345.0, 200.0], Condition::FirstUseEver)\n .build(|| {\n /* System Step Counter */\n ui.text(format!(\"Step {:04x}\", system_to_control.num_cycles()).as_str());\n\n /* ROM Lister */\n let new_filename = GuiFileList::display_path(PathBuf::from(ROM_ROOT), \u0026gui_state.filename_to_load, ui);\n if !new_filename.is_empty() {\n if new_filename != gui_state.filename_to_load {\n debug!(\"NEW FILENAME SELECTED -\u003e {new_filename}\");\n gui_state.filename_to_load = new_filename;\n }\n if ui.button(\"Load Program\") {\n let mut buffer = Vec::new();\n debug!(\"PREPARING TO LOAD {}\", gui_state.filename_to_load);\n // let mut input_file = File::open(Path::new(\"./1-chip8-logo.ch8\")).expect(\"put 1-chip8-logo.ch8 in this directory\");\n let mut input_file = File::open(Path::new(\u0026(ROM_ROOT.to_string() + \"/\" + \u0026gui_state.filename_to_load))).expect(\"put 1-chip8-logo.ch8 in this directory\");\n input_file.read_to_end(\u0026mut buffer).expect(\"unable to read file\");\n system_to_control.load_bytes_to_system_memory((\u0026*buffer).into());\n }\n }\n ui.separator();\n // if the system has no program loaded hide the buttons.\n if system_to_control.state().memory.peek(0x200) != 0x00 {\n if ui.button(\"Step\") {\n system_to_control.step();\n };\n ui.same_line();\n if ui.button(\"Run\") {\n system_to_control.start();\n }\n }\n ui.same_line();\n if ui.button(\"Stop\") {\n system_to_control.stop();\n }\n ui.same_line();\n if ui.button(\"Reset\") {\n system_to_control.reset();\n }\n if ui.button(\"Dump Video Memory\") {\n println!(\"{}\", system_to_control.dump_to_string(Video));\n }\n ui.same_line();\n if ui.button(\"Dump Keypad State\") {\n debug!(\"{}\", system_to_control.dump_to_string(Keyboard));\n }\n ui.same_line();\n if ui.button(\"Dump Registers\") {\n debug!(\"{}\", system_to_control.dump_to_string(Registers));\n }\n ui.separator();\n\n ui.checkbox(\"Show Memory\", \u0026mut gui_state.show_memory);\n ui.same_line();\n ui.checkbox(\"Show Video\", \u0026mut gui_state.show_video);\n ui.same_line();\n ui.checkbox(\"Show Registers\", \u0026mut gui_state.show_registers);\n });\n }\n\n pub fn registers_view(system: \u0026Chip8Computer, ui: \u0026Ui) {\n ui.window(\"Registers\")\n .size([400.0, 500.0], Condition::FirstUseEver)\n .build(|| {\n ui.text(\"Registers\");\n for i in 1..0x10 {\n ui.text(format!(\"V{:X}: {}\", i, system.registers.peek(i)));\n if i != 7 {\n ui.same_line();\n }\n }\n ui.text(\"\");\n ui.text(format!(\"I: {:03X}\", system.registers.peek_i()));\n ui.same_line();\n ui.text(format!(\"ST: {:02X}\", system.sound_timer.current()));\n ui.same_line();\n ui.text(format!(\"DT: {:02X}\", system.delay_timer.current()));\n ui.text(format!(\"PC: {:02X}\", system.registers.peek_pc()));\n ui.text(format!(\"SP: {:02X}\", system.stack.depth()));\n });\n }\n\n pub fn hex_memory_display(bytes: Chip8SystemMemory, position: (i32, i32), active: i16, ui: \u0026Ui) {\n let rows = position.0;\n let cols = position.1;\n ui.window(\"System Memory\")\n .size([400.0, 300.0], Condition::FirstUseEver)\n .build(|| {\n let mut current_x_hover: i32 = 0;\n let mut current_y_hover: i32 = 0;\n // display a block of data\n for current_row in 0..rows {\n ui.text(format!(\"{:02x}\", current_row * cols));\n ui.same_line();\n for current_column in 0..cols {\n let data_offset = current_row * cols + current_column;\n let formatted_text = format!(\"{:02x}\", bytes.peek(data_offset as u16));\n let text_location = ui.cursor_screen_pos();\n let text_size = ui.calc_text_size(formatted_text.clone());\n let bounding_box = imgui::sys::ImVec2 {\n x: text_location[0] + text_size[0],\n y: text_location[1] + text_size[1],\n };\n\n let hovering = ui.is_mouse_hovering_rect(text_location, [bounding_box.x, bounding_box.y]);\n let is_active = data_offset == active as i32;\n\n ui.text_colored(if hovering {\n [0., 1., 1., 1.]\n } else if is_active {\n [1., 0., 1., 1.]\n } else {\n [1., 1., 0., 1.]\n }, formatted_text.clone());\n\n // if we are hovering show that at the bottom...\n if hovering {\n // Optionally change the text color to indicate it's interactable\n current_x_hover = current_column;\n current_y_hover = current_row;\n\n // Check if the left mouse button is clicked while hovering over the text\n if ui.is_mouse_clicked(imgui::MouseButton::Left) {\n debug!(\"Offset: [{}] [0x{:02x}] Value: [{}]\", data_offset, data_offset, formatted_text.clone());\n // Perform any action here, e.g., call a function, trigger an event, etc.\n }\n }\n\n // are we on the same line?\n if current_column != (cols - 1) {\n ui.same_line();\n }\n }\n }\n ui.text(format!(\"Offset 0x{:03x}\", current_x_hover * cols + current_y_hover));\n });\n }\n}","traces":[{"line":27,"address":[4022816],"length":1,"stats":{"Line":0}},{"line":28,"address":[4022848,4023006,4022943],"length":1,"stats":{"Line":0}},{"line":29,"address":[4022964],"length":1,"stats":{"Line":0}},{"line":30,"address":[4194493,4192528],"length":1,"stats":{"Line":0}},{"line":31,"address":[4192545,4192767,4192692],"length":1,"stats":{"Line":0}},{"line":32,"address":[4192991,4192941,4192775],"length":1,"stats":{"Line":0}},{"line":33,"address":[4193005,4193067],"length":1,"stats":{"Line":0}},{"line":34,"address":[4194265,4193845,4194109],"length":1,"stats":{"Line":0}},{"line":36,"address":[4193300,4193564,4193718],"length":1,"stats":{"Line":0}},{"line":38,"address":[4194448,4194314,4193720],"length":1,"stats":{"Line":0}},{"line":39,"address":[4194455],"length":1,"stats":{"Line":0}},{"line":41,"address":[4193037],"length":1,"stats":{"Line":0}},{"line":46,"address":[4023088],"length":1,"stats":{"Line":0}},{"line":48,"address":[4023134],"length":1,"stats":{"Line":0}},{"line":49,"address":[4023153],"length":1,"stats":{"Line":0}},{"line":51,"address":[4023168,4023407],"length":1,"stats":{"Line":0}},{"line":52,"address":[4024167,4023357,4023427],"length":1,"stats":{"Line":0}},{"line":54,"address":[4024000,4024141,4023770,4023937],"length":1,"stats":{"Line":0}},{"line":55,"address":[4023958],"length":1,"stats":{"Line":0}},{"line":56,"address":[4024065],"length":1,"stats":{"Line":0}},{"line":57,"address":[4194543],"length":1,"stats":{"Line":0}},{"line":58,"address":[4194587],"length":1,"stats":{"Line":0}},{"line":59,"address":[4194622,4194691],"length":1,"stats":{"Line":0}},{"line":61,"address":[4194746,4195896],"length":1,"stats":{"Line":0}},{"line":62,"address":[4196025,4196169],"length":1,"stats":{"Line":0}},{"line":63,"address":[4196206,4196146],"length":1,"stats":{"Line":0}},{"line":64,"address":[4196335,4196503],"length":1,"stats":{"Line":0}},{"line":65,"address":[4196460],"length":1,"stats":{"Line":0}},{"line":66,"address":[4196650,4196486,4196540],"length":1,"stats":{"Line":0}},{"line":67,"address":[4196632,4196755,4196679],"length":1,"stats":{"Line":0}},{"line":68,"address":[4196736,4196780],"length":1,"stats":{"Line":0}},{"line":69,"address":[4196818,4196792],"length":1,"stats":{"Line":0}},{"line":70,"address":[4196828],"length":1,"stats":{"Line":0}},{"line":72,"address":[4196804],"length":1,"stats":{"Line":0}},{"line":74,"address":[4196842],"length":1,"stats":{"Line":0}},{"line":78,"address":[4194895,4194786,4194705],"length":1,"stats":{"Line":0}},{"line":79,"address":[4194931,4195102],"length":1,"stats":{"Line":0}},{"line":80,"address":[4195069,4195134],"length":1,"stats":{"Line":0}},{"line":81,"address":[4195415,4195244],"length":1,"stats":{"Line":0}},{"line":82,"address":[4195372],"length":1,"stats":{"Line":0}},{"line":83,"address":[4195568,4195398,4195455],"length":1,"stats":{"Line":0}},{"line":84,"address":[4195597,4195673,4195550],"length":1,"stats":{"Line":0}},{"line":85,"address":[4195654,4195698],"length":1,"stats":{"Line":0}},{"line":86,"address":[4195710,4195736],"length":1,"stats":{"Line":0}},{"line":87,"address":[4195746],"length":1,"stats":{"Line":0}},{"line":89,"address":[4195722],"length":1,"stats":{"Line":0}},{"line":91,"address":[4195760],"length":1,"stats":{"Line":0}},{"line":97,"address":[4024192],"length":1,"stats":{"Line":0}},{"line":99,"address":[4024251,4024318,4024452],"length":1,"stats":{"Line":0}},{"line":100,"address":[4024276],"length":1,"stats":{"Line":0}},{"line":101,"address":[4024383],"length":1,"stats":{"Line":0}},{"line":103,"address":[4197373,4197561,4197125,4197007],"length":1,"stats":{"Line":0}},{"line":106,"address":[4197676],"length":1,"stats":{"Line":0}},{"line":107,"address":[4197773,4197835],"length":1,"stats":{"Line":0}},{"line":108,"address":[4198597,4197849,4197911],"length":1,"stats":{"Line":0}},{"line":109,"address":[4198129,4198297,4197957],"length":1,"stats":{"Line":0}},{"line":110,"address":[4198023,4198484],"length":1,"stats":{"Line":0}},{"line":112,"address":[4197925,4198609],"length":1,"stats":{"Line":0}},{"line":113,"address":[4198618],"length":1,"stats":{"Line":0}},{"line":114,"address":[4198733,4198817,4198973,4198637],"length":1,"stats":{"Line":0}},{"line":116,"address":[4199152,4199781,4198739],"length":1,"stats":{"Line":0}},{"line":117,"address":[4199552],"length":1,"stats":{"Line":0}},{"line":118,"address":[4199633],"length":1,"stats":{"Line":0}},{"line":121,"address":[4197887],"length":1,"stats":{"Line":0}},{"line":123,"address":[4199811],"length":1,"stats":{"Line":0}},{"line":124,"address":[4199901],"length":1,"stats":{"Line":0}},{"line":125,"address":[4199967],"length":1,"stats":{"Line":0}},{"line":127,"address":[4199945],"length":1,"stats":{"Line":0}},{"line":128,"address":[4199992],"length":1,"stats":{"Line":0}},{"line":129,"address":[4200039],"length":1,"stats":{"Line":0}},{"line":132,"address":[4199876],"length":1,"stats":{"Line":0}},{"line":133,"address":[4200067],"length":1,"stats":{"Line":0}},{"line":134,"address":[4200133],"length":1,"stats":{"Line":0}},{"line":136,"address":[4200111],"length":1,"stats":{"Line":0}},{"line":137,"address":[4200158],"length":1,"stats":{"Line":0}},{"line":138,"address":[4200236],"length":1,"stats":{"Line":0}},{"line":140,"address":[4200257,4200202],"length":1,"stats":{"Line":0}},{"line":141,"address":[4200296,4200447],"length":1,"stats":{"Line":0}},{"line":143,"address":[4200271],"length":1,"stats":{"Line":0}},{"line":144,"address":[4200590],"length":1,"stats":{"Line":0}},{"line":145,"address":[4200745,4200651,4200956],"length":1,"stats":{"Line":0}},{"line":147,"address":[4200634],"length":1,"stats":{"Line":0}},{"line":148,"address":[4201198],"length":1,"stats":{"Line":0}},{"line":149,"address":[4201564,4201353,4201259],"length":1,"stats":{"Line":0}},{"line":151,"address":[4201242],"length":1,"stats":{"Line":0}},{"line":153,"address":[4201806],"length":1,"stats":{"Line":0}},{"line":154,"address":[4201840],"length":1,"stats":{"Line":0}},{"line":155,"address":[4201862],"length":1,"stats":{"Line":0}},{"line":156,"address":[4201896],"length":1,"stats":{"Line":0}},{"line":157,"address":[4201918],"length":1,"stats":{"Line":0}},{"line":161,"address":[4024480],"length":1,"stats":{"Line":0}},{"line":162,"address":[4024512,4024576],"length":1,"stats":{"Line":0}},{"line":163,"address":[4024534],"length":1,"stats":{"Line":0}},{"line":164,"address":[4202032],"length":1,"stats":{"Line":0}},{"line":165,"address":[4202049],"length":1,"stats":{"Line":0}},{"line":166,"address":[4205059,4202071],"length":1,"stats":{"Line":0}},{"line":167,"address":[4205067,4205464,4205178,4205318],"length":1,"stats":{"Line":0}},{"line":168,"address":[4205474],"length":1,"stats":{"Line":0}},{"line":169,"address":[4205485],"length":1,"stats":{"Line":0}},{"line":172,"address":[4202135],"length":1,"stats":{"Line":0}},{"line":173,"address":[4202154,4202717,4202564,4202300],"length":1,"stats":{"Line":0}},{"line":174,"address":[4202730],"length":1,"stats":{"Line":0}},{"line":175,"address":[4202886,4203150,4202741,4203303],"length":1,"stats":{"Line":0}},{"line":176,"address":[4203316],"length":1,"stats":{"Line":0}},{"line":177,"address":[4203472,4203889,4203736,4203327],"length":1,"stats":{"Line":0}},{"line":178,"address":[4204312,4204048,4203902,4204465],"length":1,"stats":{"Line":0}},{"line":179,"address":[4204621,4204885,4204478,4205038],"length":1,"stats":{"Line":0}},{"line":183,"address":[4024656],"length":1,"stats":{"Line":0}},{"line":184,"address":[4024707],"length":1,"stats":{"Line":0}},{"line":185,"address":[4024711],"length":1,"stats":{"Line":0}},{"line":186,"address":[4024897,4024715,4024782],"length":1,"stats":{"Line":0}},{"line":187,"address":[4024740],"length":1,"stats":{"Line":0}},{"line":188,"address":[4024842],"length":1,"stats":{"Line":0}},{"line":189,"address":[4205519],"length":1,"stats":{"Line":0}},{"line":190,"address":[4205530],"length":1,"stats":{"Line":0}},{"line":192,"address":[4205541,4205665],"length":1,"stats":{"Line":0}},{"line":193,"address":[4206479,4206968,4206899,4206743,4206362,4205686],"length":1,"stats":{"Line":0}},{"line":194,"address":[4206920],"length":1,"stats":{"Line":0}},{"line":195,"address":[4206938,4206984],"length":1,"stats":{"Line":0}},{"line":196,"address":[4207062,4207686],"length":1,"stats":{"Line":0}},{"line":197,"address":[4207484,4207138,4207236],"length":1,"stats":{"Line":0}},{"line":198,"address":[4207666,4207759],"length":1,"stats":{"Line":0}},{"line":199,"address":[4207783],"length":1,"stats":{"Line":0}},{"line":200,"address":[4207957],"length":1,"stats":{"Line":0}},{"line":201,"address":[4207873],"length":1,"stats":{"Line":0}},{"line":202,"address":[4207909],"length":1,"stats":{"Line":0}},{"line":205,"address":[4207975],"length":1,"stats":{"Line":0}},{"line":206,"address":[4208096],"length":1,"stats":{"Line":0}},{"line":208,"address":[4208217,4208127,4208398],"length":1,"stats":{"Line":0}},{"line":209,"address":[4208154],"length":1,"stats":{"Line":0}},{"line":210,"address":[4208144,4208285],"length":1,"stats":{"Line":0}},{"line":211,"address":[4208287],"length":1,"stats":{"Line":0}},{"line":213,"address":[4208222],"length":1,"stats":{"Line":0}},{"line":214,"address":[4208350],"length":1,"stats":{"Line":0}},{"line":217,"address":[4208409],"length":1,"stats":{"Line":0}},{"line":219,"address":[4208468],"length":1,"stats":{"Line":0}},{"line":220,"address":[4208475],"length":1,"stats":{"Line":0}},{"line":223,"address":[4208482],"length":1,"stats":{"Line":0}},{"line":224,"address":[4208896,4209847,4208527,4209395,4209627,4208624,4209035],"length":1,"stats":{"Line":0}},{"line":230,"address":[4210140,4208423],"length":1,"stats":{"Line":0}},{"line":231,"address":[4210193],"length":1,"stats":{"Line":0}},{"line":235,"address":[4205898,4206318,4206339,4205733,4206162,4205617],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":142},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmaimgui","src","bin","support","gui_file_list.rs"],"content":"use std::ffi::OsString;\nuse std::fs::read_dir;\nuse std::path::PathBuf;\nuse imgui::Ui;\nuse log::debug;\n\npub struct GuiFileList {}\n\nimpl GuiFileList {\n pub fn display_path(root: PathBuf, selected_filename: \u0026String, ui: \u0026Ui) -\u003e String {\n let mut working_filename = selected_filename.clone();\n ui.text(format!(\"Displaying {}\", root.to_str().unwrap_or(\"Unable to parse path\")));\n\n let mut known_files: Vec\u003cOsString\u003e = vec![];\n\n for entry in read_dir(root.as_path()).unwrap() {\n known_files.push(entry.unwrap().file_name());\n }\n\n known_files.sort();\n\n for (index, entry) in known_files.iter().enumerate() {\n let mut working_select = ui.selectable_config(format!(\"{}\", entry.clone().into_string().unwrap()));\n if entry.to_str().unwrap().to_string() == selected_filename.as_str().to_string() {\n working_select = working_select.selected(true);\n }\n if working_select.build() {\n debug!(\"SELECTED {index} / {entry:?}\");\n working_filename = entry.clone().into_string().unwrap();\n };\n }\n working_filename\n }\n}\n","traces":[{"line":10,"address":[3557436,3553120,3557597],"length":1,"stats":{"Line":0}},{"line":11,"address":[3553281,3553194],"length":1,"stats":{"Line":0}},{"line":12,"address":[3553366,3553586,3553723,3553289],"length":1,"stats":{"Line":0}},{"line":14,"address":[3553730],"length":1,"stats":{"Line":0}},{"line":16,"address":[3554156,3554344,3553912,3553757,3554315],"length":1,"stats":{"Line":0}},{"line":17,"address":[3557463],"length":1,"stats":{"Line":0}},{"line":20,"address":[3554592],"length":1,"stats":{"Line":0}},{"line":22,"address":[3554966,3556448,3554638],"length":1,"stats":{"Line":0}},{"line":23,"address":[3555419,3555719,3555075,3554998],"length":1,"stats":{"Line":0}},{"line":24,"address":[3555734,3555830,3556425,3556288,3555974],"length":1,"stats":{"Line":0}},{"line":25,"address":[3556307],"length":1,"stats":{"Line":0}},{"line":27,"address":[3556434,3557431,3556210],"length":1,"stats":{"Line":0}},{"line":28,"address":[3556573,3556842,3556453],"length":1,"stats":{"Line":0}},{"line":29,"address":[3557047,3557273,3556505],"length":1,"stats":{"Line":0}},{"line":32,"address":[3554916],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":15},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmaimgui","src","bin","support","mod.rs"],"content":"use glium::glutin::surface::WindowSurface;\nuse glium::{Display, Surface};\nuse imgui::{Context, FontConfig, FontGlyphRanges, FontSource, Ui};\nuse imgui_glium_renderer::Renderer;\nuse imgui_winit_support::winit::event::{Event, WindowEvent};\nuse imgui_winit_support::winit::event_loop::EventLoop;\nuse imgui_winit_support::winit::window::WindowBuilder;\nuse imgui_winit_support::{HiDpiMode, WinitPlatform};\nuse std::path::Path;\nuse std::time::Instant;\n\npub mod ui_state;\npub mod emmagui_support;\nmod gui_file_list;\n\nuse copypasta::{ClipboardContext, ClipboardProvider};\nuse imgui::ClipboardBackend;\n\npub struct ClipboardSupport(pub ClipboardContext);\n\npub fn clipboard_init() -\u003e Option\u003cClipboardSupport\u003e {\n ClipboardContext::new().ok().map(ClipboardSupport)\n}\n\nimpl ClipboardBackend for ClipboardSupport {\n fn get(\u0026mut self) -\u003e Option\u003cString\u003e {\n self.0.get_contents().ok()\n }\n fn set(\u0026mut self, text: \u0026str) {\n // ignore errors?\n let _ = self.0.set_contents(text.to_owned());\n }\n}\n\npub const FONT_SIZE: f32 = 13.0;\n\n#[allow(dead_code)] // annoyingly, RA yells that this is unusued\npub fn simple_init\u003cF: FnMut(\u0026mut bool, \u0026mut Ui) + 'static\u003e(title: \u0026str, run_ui: F) {\n init_with_startup(title, |_, _, _| {}, run_ui);\n}\n\npub fn init_with_startup\u003cFInit, FUi\u003e(title: \u0026str, mut startup: FInit, mut run_ui: FUi)\nwhere\n FInit: FnMut(\u0026mut Context, \u0026mut Renderer, \u0026Display\u003cWindowSurface\u003e) + 'static,\n FUi: FnMut(\u0026mut bool, \u0026mut Ui) + 'static,\n{\n let mut imgui = create_context();\n\n let title = match Path::new(\u0026title).file_name() {\n Some(file_name) =\u003e file_name.to_str().unwrap(),\n None =\u003e title,\n };\n let event_loop = EventLoop::new().expect(\"Failed to create EventLoop\");\n\n let builder = WindowBuilder::new()\n .with_maximized(true)\n .with_title(title);\n // .with_inner_size(LogicalSize::new(1024, 768));\n let (window, display) = glium::backend::glutin::SimpleWindowBuilder::new()\n .set_window_builder(builder)\n .build(\u0026event_loop);\n let mut renderer = Renderer::init(\u0026mut imgui, \u0026display).expect(\"Failed to initialize renderer\");\n\n if let Some(backend) = clipboard_init() {\n imgui.set_clipboard_backend(backend);\n } else {\n eprintln!(\"Failed to initialize clipboard\");\n }\n\n let mut platform = WinitPlatform::init(\u0026mut imgui);\n {\n let dpi_mode = if let Ok(factor) = std::env::var(\"IMGUI_EXAMPLE_FORCE_DPI_FACTOR\") {\n // Allow forcing of HiDPI factor for debugging purposes\n match factor.parse::\u003cf64\u003e() {\n Ok(f) =\u003e HiDpiMode::Locked(f),\n Err(e) =\u003e panic!(\"Invalid scaling factor: {}\", e),\n }\n } else {\n HiDpiMode::Default\n };\n\n platform.attach_window(imgui.io_mut(), \u0026window, dpi_mode);\n }\n\n let mut last_frame = Instant::now();\n\n startup(\u0026mut imgui, \u0026mut renderer, \u0026display);\n\n event_loop\n .run(move |event, window_target| match event {\n Event::NewEvents(_) =\u003e {\n let now = Instant::now();\n imgui.io_mut().update_delta_time(now - last_frame);\n last_frame = now;\n }\n Event::AboutToWait =\u003e {\n platform\n .prepare_frame(imgui.io_mut(), \u0026window)\n .expect(\"Failed to prepare frame\");\n window.request_redraw();\n }\n Event::WindowEvent {\n event: WindowEvent::RedrawRequested,\n ..\n } =\u003e {\n let ui = imgui.frame();\n\n let mut run = true;\n run_ui(\u0026mut run, ui);\n if !run {\n window_target.exit();\n }\n\n let mut target = display.draw();\n target.clear_color_srgb(1.0, 1.0, 1.0, 1.0);\n platform.prepare_render(ui, \u0026window);\n let draw_data = imgui.render();\n renderer\n .render(\u0026mut target, draw_data)\n .expect(\"Rendering failed\");\n target.finish().expect(\"Failed to swap buffers\");\n }\n Event::WindowEvent {\n event: WindowEvent::Resized(new_size),\n ..\n } =\u003e {\n if new_size.width \u003e 0 \u0026\u0026 new_size.height \u003e 0 {\n display.resize((new_size.width, new_size.height));\n }\n platform.handle_event(imgui.io_mut(), \u0026window, \u0026event);\n }\n Event::WindowEvent {\n event: WindowEvent::CloseRequested,\n ..\n } =\u003e window_target.exit(),\n event =\u003e {\n platform.handle_event(imgui.io_mut(), \u0026window, \u0026event);\n }\n })\n .expect(\"EventLoop error\");\n}\n\n/// Creates the imgui context\npub fn create_context() -\u003e imgui::Context {\n let mut imgui = Context::create();\n // Fixed font size. Note imgui_winit_support uses \"logical\n // pixels\", which are physical pixels scaled by the devices\n // scaling factor. Meaning, 13.0 pixels should look the same size\n // on two different screens, and thus we do not need to scale this\n // value (as the scaling is handled by winit)\n imgui.fonts().add_font(\u0026[\n FontSource::TtfData {\n data: include_bytes!(\"../../../../resources/Roboto-Regular.ttf\"),\n size_pixels: FONT_SIZE,\n config: Some(FontConfig {\n // As imgui-glium-renderer isn't gamma-correct with\n // it's font rendering, we apply an arbitrary\n // multiplier to make the font a bit \"heavier\". With\n // default imgui-glow-renderer this is unnecessary.\n rasterizer_multiply: 1.5,\n // Oversampling font helps improve text rendering at\n // expense of larger font atlas texture.\n oversample_h: 4,\n oversample_v: 4,\n ..FontConfig::default()\n }),\n },\n FontSource::TtfData {\n data: include_bytes!(\"../../../../resources/mplus-1p-regular.ttf\"),\n size_pixels: FONT_SIZE,\n config: Some(FontConfig {\n // Oversampling font helps improve text rendering at\n // expense of larger font atlas texture.\n oversample_h: 4,\n oversample_v: 4,\n // Range of glyphs to rasterize\n glyph_ranges: FontGlyphRanges::japanese(),\n ..FontConfig::default()\n }),\n },\n ]);\n imgui.set_ini_filename(None);\n\n imgui\n}\n","traces":[{"line":21,"address":[3981264],"length":1,"stats":{"Line":0}},{"line":22,"address":[3981281],"length":1,"stats":{"Line":0}},{"line":26,"address":[3981344],"length":1,"stats":{"Line":0}},{"line":27,"address":[3981363],"length":1,"stats":{"Line":0}},{"line":29,"address":[3981408],"length":1,"stats":{"Line":0}},{"line":31,"address":[3981431],"length":1,"stats":{"Line":0}},{"line":38,"address":[],"length":0,"stats":{"Line":0}},{"line":39,"address":[],"length":0,"stats":{"Line":0}},{"line":42,"address":[3445718,3446701,3443632],"length":1,"stats":{"Line":0}},{"line":47,"address":[],"length":0,"stats":{"Line":0}},{"line":49,"address":[3443859,3443952],"length":1,"stats":{"Line":0}},{"line":50,"address":[3444074,3444260],"length":1,"stats":{"Line":0}},{"line":51,"address":[],"length":0,"stats":{"Line":0}},{"line":53,"address":[],"length":0,"stats":{"Line":0}},{"line":55,"address":[],"length":0,"stats":{"Line":0}},{"line":57,"address":[3444415,3444458],"length":1,"stats":{"Line":0}},{"line":59,"address":[],"length":0,"stats":{"Line":0}},{"line":60,"address":[],"length":0,"stats":{"Line":0}},{"line":61,"address":[],"length":0,"stats":{"Line":0}},{"line":62,"address":[3444782,3444734],"length":1,"stats":{"Line":0}},{"line":64,"address":[],"length":0,"stats":{"Line":0}},{"line":65,"address":[],"length":0,"stats":{"Line":0}},{"line":67,"address":[],"length":0,"stats":{"Line":0}},{"line":70,"address":[],"length":0,"stats":{"Line":0}},{"line":72,"address":[],"length":0,"stats":{"Line":0}},{"line":74,"address":[],"length":0,"stats":{"Line":0}},{"line":75,"address":[],"length":0,"stats":{"Line":0}},{"line":76,"address":[3445640,3445460],"length":1,"stats":{"Line":0}},{"line":79,"address":[],"length":0,"stats":{"Line":0}},{"line":82,"address":[],"length":0,"stats":{"Line":0}},{"line":85,"address":[],"length":0,"stats":{"Line":0}},{"line":87,"address":[],"length":0,"stats":{"Line":0}},{"line":89,"address":[],"length":0,"stats":{"Line":0}},{"line":90,"address":[],"length":0,"stats":{"Line":0}},{"line":91,"address":[],"length":0,"stats":{"Line":0}},{"line":92,"address":[],"length":0,"stats":{"Line":0}},{"line":93,"address":[3447228],"length":1,"stats":{"Line":0}},{"line":94,"address":[3447343],"length":1,"stats":{"Line":0}},{"line":96,"address":[],"length":0,"stats":{"Line":0}},{"line":97,"address":[],"length":0,"stats":{"Line":0}},{"line":98,"address":[],"length":0,"stats":{"Line":0}},{"line":99,"address":[],"length":0,"stats":{"Line":0}},{"line":100,"address":[],"length":0,"stats":{"Line":0}},{"line":102,"address":[],"length":0,"stats":{"Line":0}},{"line":103,"address":[],"length":0,"stats":{"Line":0}},{"line":104,"address":[],"length":0,"stats":{"Line":0}},{"line":105,"address":[],"length":0,"stats":{"Line":0}},{"line":106,"address":[],"length":0,"stats":{"Line":0}},{"line":108,"address":[],"length":0,"stats":{"Line":0}},{"line":109,"address":[],"length":0,"stats":{"Line":0}},{"line":110,"address":[],"length":0,"stats":{"Line":0}},{"line":111,"address":[],"length":0,"stats":{"Line":0}},{"line":114,"address":[],"length":0,"stats":{"Line":0}},{"line":115,"address":[3447715],"length":1,"stats":{"Line":0}},{"line":116,"address":[],"length":0,"stats":{"Line":0}},{"line":117,"address":[],"length":0,"stats":{"Line":0}},{"line":118,"address":[3447885],"length":1,"stats":{"Line":0}},{"line":119,"address":[],"length":0,"stats":{"Line":0}},{"line":120,"address":[],"length":0,"stats":{"Line":0}},{"line":121,"address":[3447949],"length":1,"stats":{"Line":0}},{"line":123,"address":[],"length":0,"stats":{"Line":0}},{"line":124,"address":[],"length":0,"stats":{"Line":0}},{"line":125,"address":[],"length":0,"stats":{"Line":0}},{"line":126,"address":[],"length":0,"stats":{"Line":0}},{"line":127,"address":[],"length":0,"stats":{"Line":0}},{"line":128,"address":[],"length":0,"stats":{"Line":0}},{"line":130,"address":[3447478,3447582],"length":1,"stats":{"Line":0}},{"line":132,"address":[],"length":0,"stats":{"Line":0}},{"line":133,"address":[],"length":0,"stats":{"Line":0}},{"line":134,"address":[],"length":0,"stats":{"Line":0}},{"line":135,"address":[],"length":0,"stats":{"Line":0}},{"line":136,"address":[],"length":0,"stats":{"Line":0}},{"line":137,"address":[],"length":0,"stats":{"Line":0}},{"line":144,"address":[3983036,3981488],"length":1,"stats":{"Line":0}},{"line":145,"address":[3981505],"length":1,"stats":{"Line":0}},{"line":151,"address":[3982630,3981529],"length":1,"stats":{"Line":0}},{"line":152,"address":[3981928],"length":1,"stats":{"Line":0}},{"line":155,"address":[3981605],"length":1,"stats":{"Line":0}},{"line":165,"address":[3981586],"length":1,"stats":{"Line":0}},{"line":168,"address":[3982496],"length":1,"stats":{"Line":0}},{"line":171,"address":[3982181],"length":1,"stats":{"Line":0}},{"line":177,"address":[3982062],"length":1,"stats":{"Line":0}},{"line":178,"address":[3982147],"length":1,"stats":{"Line":0}},{"line":182,"address":[3982975],"length":1,"stats":{"Line":0}},{"line":184,"address":[3983008],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":85},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmaimgui","src","bin","support","ui_state.rs"],"content":"use std::time::Instant;\nuse imgui::ImColor32;\n\npub struct ImGuiUiState {\n pub show_registers: bool,\n pub show_memory: bool,\n pub show_video: bool,\n pub show_keypad: bool,\n pub filename_to_load: String,\n pub on_colour: ImColor32,\n pub off_colour: ImColor32,\n pub is_running: bool,\n pub frame_time: u32,\n pub last_frame_instant: Instant,\n pub target_ips: i32\n}\n\nimpl Clone for ImGuiUiState {\n fn clone(\u0026self) -\u003e Self {\n ImGuiUiState {\n show_registers: self.show_registers,\n show_memory: self.show_memory,\n show_video: self.show_video,\n show_keypad: self.show_keypad,\n filename_to_load: self.filename_to_load.to_string(),\n on_colour: self.on_colour,\n off_colour: self.off_colour,\n is_running: self.is_running,\n frame_time: self.frame_time,\n last_frame_instant: self.last_frame_instant,\n target_ips: self.target_ips\n }\n }\n}\n\nimpl Default for ImGuiUiState {\n fn default() -\u003e Self {\n ImGuiUiState {\n show_registers: false,\n show_memory: false,\n show_video: true,\n show_keypad: true,\n filename_to_load: String::new(),\n on_colour: ImColor32::from_rgb(0xff, 0xff, 0x00),\n off_colour: ImColor32::from_rgb(0x00, 0xff, 0xff),\n is_running: false,\n frame_time: 16,\n last_frame_instant: Instant::now(),\n target_ips: 20\n }\n }\n}\n","traces":[{"line":19,"address":[3461536],"length":1,"stats":{"Line":0}},{"line":21,"address":[3461565],"length":1,"stats":{"Line":0}},{"line":22,"address":[3461569],"length":1,"stats":{"Line":0}},{"line":23,"address":[3461573],"length":1,"stats":{"Line":0}},{"line":24,"address":[3461577],"length":1,"stats":{"Line":0}},{"line":25,"address":[3461580],"length":1,"stats":{"Line":0}},{"line":26,"address":[3461604],"length":1,"stats":{"Line":0}},{"line":27,"address":[3461608],"length":1,"stats":{"Line":0}},{"line":28,"address":[3461612],"length":1,"stats":{"Line":0}},{"line":29,"address":[3461616],"length":1,"stats":{"Line":0}},{"line":30,"address":[3461620],"length":1,"stats":{"Line":0}},{"line":31,"address":[3461627],"length":1,"stats":{"Line":0}},{"line":37,"address":[3461728,3461954],"length":1,"stats":{"Line":0}},{"line":43,"address":[3461747],"length":1,"stats":{"Line":0}},{"line":44,"address":[3461759],"length":1,"stats":{"Line":0}},{"line":45,"address":[3461814],"length":1,"stats":{"Line":0}},{"line":48,"address":[3461827],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":17},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmasdl2","src","bin","gemmasdl2.rs"],"content":"mod support;\nuse std::{sync::Arc, time::Instant};\nuse anyhow::Context;\nuse egui::TextBuffer;\nuse egui_glow::glow::{HasContext, COLOR_BUFFER_BIT};\nuse egui_sdl2_platform::sdl2;\nuse sdl2::event::{Event, WindowEvent};\nuse gemma::chip8::computer::Chip8Computer;\nuse support::timestep::TimeStep;\nuse crate::support::gemma_egui_support::GemmaEguiSupport;\n\nconst SCREEN_WIDTH: u32 = 800;\nconst SCREEN_HEIGHT: u32 = 480;\n\nasync fn run() -\u003e anyhow::Result\u003cString\u003e {\n // Initialize SDL2 and video subsystem\n let sdl = sdl2::init().map_err(|e| anyhow::anyhow!(\"Failed to create SDL context: {}\", e))?;\n let mut video = sdl.video().map_err(|e| anyhow::anyhow!(\"Failed to initialize SDL video subsystem: {}\", e))?;\n\n // Create SDL2 window and OpenGL context\n let window = video.window(\"Window\", SCREEN_WIDTH, SCREEN_HEIGHT)\n .opengl()\n .position_centered()\n .build()?;\n let _gl_context = window.gl_create_context().expect(\"Failed to create GL context\");\n\n // Load OpenGL functions\n let gl = unsafe {\n egui_glow::painter::Context::from_loader_function(|name| {\n video.gl_get_proc_address(name) as *const _\n })\n };\n let mut painter = egui_glow::Painter::new(Arc::new(gl), \"\", None)?;\n\n // Setup Egui and SDL2 platform\n let mut platform = egui_sdl2_platform::Platform::new(window.size())?;\n let mut event_pump = sdl.event_pump().map_err(|e| anyhow::anyhow!(\"Failed to get SDL event pump: {}\", e))?;\n\n // Initial settings\n let mut color = [0.0, 0.0, 0.0, 1.0]; // Background color\n let start_time = Instant::now();\n let mut timestep = TimeStep::new();\n\n let mut computer = Chip8Computer::new();\n let mut is_running: bool = false;\n computer.load_bytes_to_memory(0x200, \u0026std::fs::read(\"resources/roms/3-corax+.ch8\")?);\n\n // Main loop\n 'main: loop {\n // Update the Egui platform with the current time\n platform.update_time(start_time.elapsed().as_secs_f64());\n\n // Begin Egui frame\n let ctx = platform.context();\n\n if is_running {\n computer.step_system();\n }\n\n egui::Window::new(\"Hello, world!\").show(\u0026ctx, |ui| {\n GemmaEguiSupport::video_view(\u0026computer, ui);\n GemmaEguiSupport::memory_view(\u0026computer, ui);\n GemmaEguiSupport::registers_view(\u0026computer, ui);\n });\n\n // Process Egui frame\n let full_output = platform.end_frame(\u0026mut video)?;\n let paint_jobs = platform.tessellate(\u0026full_output);\n\n // Clear the screen with the current color\n unsafe {\n painter.gl().clear_color(color[0], color[1], color[2], 1.0);\n painter.gl().clear(COLOR_BUFFER_BIT);\n }\n\n // Paint Egui outputs and update textures\n let size = window.size();\n painter.paint_and_update_textures([size.0, size.1], 1.0, paint_jobs.as_slice(), \u0026full_output.textures_delta);\n window.gl_swap_window();\n\n // Run the timestep logic\n timestep.run_this(|_| {});\n\n // Handle SDL2 events\n for event in event_pump.poll_iter() {\n match event {\n Event::Quit { .. }\n | Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::Escape), .. } =\u003e break 'main,\n Event::Window { window_id, win_event, .. } if window_id == window.id() =\u003e {\n if let WindowEvent::Close = win_event {\n break 'main;\n }\n }\n Event::KeyUp { keycode: Some(sdl2::keyboard::Keycode::F3), .. } =\u003e {\n println!(\"USER PRESSED F3 -\u003e running\");\n is_running = true;\n }\n Event::KeyUp { keycode: Some(sdl2::keyboard::Keycode::F4), .. } =\u003e {\n println!(\"USER PRESSED F4 -\u003e stopping\");\n is_running = false;\n }\n Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::F5), .. } =\u003e {\n println!(\"USER PRESSED F5 -\u003e Step\");\n computer.step_system();\n }\n Event::KeyDown { keycode: Some(sdl2::keyboard::Keycode::F6), .. } =\u003e {\n println!(\"USER PRESSED F6 -\u003e RESET\");\n computer.reset();\n }\n Event::ControllerButtonDown { which, .. } =\u003e {\n println!(\"PLAYER {which} DOWN\");\n }\n Event::ControllerButtonDown { button, .. } =\u003e {\n println!(\"BUTTON {:?}\", button);\n }\n Event::JoyButtonDown {button_idx, .. } =\u003e {\n println!(\"JoyButtonDown {}\", button_idx);\n }\n Event::JoyAxisMotion { which, axis_idx, .. } =\u003e {\n println!(\"JoyAxismotion {which} {axis_idx}\");\n }\n _ =\u003e platform.handle_event(\u0026event, \u0026sdl, \u0026video),\n }\n }\n\n // Optionally log the frame rate\n if let Some(fps) = timestep.frame_rate() {\n println!(\"{:?} fps\", fps);\n }\n\n let num_js = sdl.joystick().unwrap().num_joysticks().unwrap();\n println!(\"NUM JS = {num_js}\");\n }\n\n Ok((\"\").parse()?)\n}\n\nfn main() -\u003e anyhow::Result\u003c()\u003e {\n pollster::block_on(run())?;\n Ok(())\n}\n","traces":[{"line":15,"address":[738576],"length":1,"stats":{"Line":0}},{"line":17,"address":[752773,745491,752506,745302,752544,745385,752649],"length":1,"stats":{"Line":0}},{"line":18,"address":[745592,752504,745484,753077,752848,752953,745747],"length":1,"stats":{"Line":0}},{"line":21,"address":[745696,745908,746087,745832],"length":1,"stats":{"Line":0}},{"line":25,"address":[746164],"length":1,"stats":{"Line":0}},{"line":29,"address":[746265,753152],"length":1,"stats":{"Line":0}},{"line":30,"address":[753170],"length":1,"stats":{"Line":0}},{"line":33,"address":[752423,746569,746324],"length":1,"stats":{"Line":0}},{"line":36,"address":[746871,746692,746536,752402],"length":1,"stats":{"Line":0}},{"line":37,"address":[753289,746972,752381,746864,747146,753184,753413],"length":1,"stats":{"Line":0}},{"line":40,"address":[747076],"length":1,"stats":{"Line":0}},{"line":41,"address":[747246,747120],"length":1,"stats":{"Line":0}},{"line":42,"address":[747269],"length":1,"stats":{"Line":0}},{"line":44,"address":[747276],"length":1,"stats":{"Line":0}},{"line":45,"address":[747295],"length":1,"stats":{"Line":0}},{"line":46,"address":[752341,747378,747303],"length":1,"stats":{"Line":0}},{"line":51,"address":[747640],"length":1,"stats":{"Line":0}},{"line":54,"address":[747756],"length":1,"stats":{"Line":0}},{"line":56,"address":[747799],"length":1,"stats":{"Line":0}},{"line":57,"address":[747899,747836],"length":1,"stats":{"Line":0}},{"line":60,"address":[747933,753488,747809],"length":1,"stats":{"Line":0}},{"line":61,"address":[753506],"length":1,"stats":{"Line":0}},{"line":62,"address":[753520],"length":1,"stats":{"Line":0}},{"line":63,"address":[753534],"length":1,"stats":{"Line":0}},{"line":67,"address":[747955,748183],"length":1,"stats":{"Line":0}},{"line":68,"address":[748156],"length":1,"stats":{"Line":0}},{"line":72,"address":[748376,748268],"length":1,"stats":{"Line":0}},{"line":73,"address":[748469],"length":1,"stats":{"Line":0}},{"line":77,"address":[748535],"length":1,"stats":{"Line":0}},{"line":78,"address":[748584],"length":1,"stats":{"Line":0}},{"line":79,"address":[748692],"length":1,"stats":{"Line":0}},{"line":82,"address":[753563,753552,748719],"length":1,"stats":{"Line":0}},{"line":85,"address":[748829,748726],"length":1,"stats":{"Line":0}},{"line":86,"address":[748877,750151,751798,750741],"length":1,"stats":{"Line":0}},{"line":89,"address":[750082,750648],"length":1,"stats":{"Line":0}},{"line":90,"address":[750700],"length":1,"stats":{"Line":0}},{"line":94,"address":[751913],"length":1,"stats":{"Line":0}},{"line":95,"address":[751834,751886],"length":1,"stats":{"Line":0}},{"line":96,"address":[751905],"length":1,"stats":{"Line":0}},{"line":98,"address":[751945],"length":1,"stats":{"Line":0}},{"line":99,"address":[751860,751918],"length":1,"stats":{"Line":0}},{"line":100,"address":[751937],"length":1,"stats":{"Line":0}},{"line":102,"address":[751750],"length":1,"stats":{"Line":0}},{"line":103,"address":[751712,750792],"length":1,"stats":{"Line":0}},{"line":104,"address":[751731],"length":1,"stats":{"Line":0}},{"line":106,"address":[751793],"length":1,"stats":{"Line":0}},{"line":107,"address":[751755,750821],"length":1,"stats":{"Line":0}},{"line":108,"address":[751774],"length":1,"stats":{"Line":0}},{"line":110,"address":[750467],"length":1,"stats":{"Line":0}},{"line":111,"address":[752224],"length":1,"stats":{"Line":0}},{"line":116,"address":[750338],"length":1,"stats":{"Line":0}},{"line":117,"address":[752150],"length":1,"stats":{"Line":0}},{"line":119,"address":[750195],"length":1,"stats":{"Line":0}},{"line":120,"address":[752060],"length":1,"stats":{"Line":0}},{"line":122,"address":[750014,752298],"length":1,"stats":{"Line":0}},{"line":127,"address":[748937,748822],"length":1,"stats":{"Line":0}},{"line":128,"address":[749117],"length":1,"stats":{"Line":0}},{"line":131,"address":[749740,749110,749427],"length":1,"stats":{"Line":0}},{"line":132,"address":[749876],"length":1,"stats":{"Line":0}},{"line":135,"address":[750991,750924],"length":1,"stats":{"Line":0}},{"line":138,"address":[738592],"length":1,"stats":{"Line":0}},{"line":139,"address":[738768,738599],"length":1,"stats":{"Line":0}},{"line":140,"address":[738757],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":63},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmasdl2","src","bin","support","gemma_egui_support.rs"],"content":"use std::fs::read_dir;\nuse std::ops::Index;\nuse std::path::{Display, PathBuf};\nuse std::thread;\nuse std::time::Duration;\nuse egui::{Align, Color32, ComboBox, Direction, Pos2, Response, TextBuffer};\nuse egui::Rect;\nuse egui::Vec2;\nuse egui::Ui;\nuse egui::WidgetType::SelectableLabel;\nuse crate::Chip8Computer;\n\nconst CELL_WIDTH: f32 = 5.0;\nconst CELL_HEIGHT: f32 = 5.0;\n\npub struct EGuiFileList {}\nimpl EGuiFileList {\n pub fn display_path(root: PathBuf, selected_filename: \u0026mut String, ui: \u0026mut Ui) {\n let mut working_filename = selected_filename.clone();\n ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {\n // ui.label(format!(\"Displaying {}\", root.to_str().unwrap_or(\"Unable to Load Path\")));\n ComboBox::from_label(\"Select ROM\")\n .selected_text(selected_filename.clone())\n .show_ui(ui, |ui| {\n\n let mut sorted_options = vec![];\n for option in read_dir(root.as_path()).unwrap() {\n let to_push = option.unwrap().file_name().into_string().unwrap_or( String::new());\n sorted_options.push(to_push);\n }\n\n sorted_options.sort();\n for item in sorted_options {\n // Add each option to the ComboBox\n if ui.selectable_label(selected_filename.eq(\u0026item.as_str()), item.clone()).clicked()\n {\n *selected_filename = item;\n }\n }\n });\n // Display the selected option\n });\n }\n}\n\npub struct GemmaEguiSupport {}\n\nimpl GemmaEguiSupport {\n pub fn controls_view(mut system: \u0026mut Chip8Computer, ui: \u0026mut Ui) {\n ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {\n if ui.button(\"Start\").clicked() {\n println!(\"Start\");\n // state.is_running = true;\n }\n if ui.button(\"Step\").clicked() {\n system.step_system();\n }\n\n if ui.button(\"Stop\").clicked() {\n println!(\"STOP\");\n // state.is_running = false;\n }\n if ui.button(\"Reset\").clicked() {\n system.reset();\n // state.is_running = false;\n }\n });\n\n // if ui.button(format!(\"Load {}\", state.selected_rom_filename)).clicked() {\n // load the bin...\n // let read_bin = std::fs::read(PathBuf::from(format!(\"resources/roms/{}\", state.selected_rom_filename))).unwrap();\n // ...then feed the system.\n // system.load_bytes_to_memory(0x200, \u0026read_bin);\n // println!(\"Loaded {}\", state.selected_rom_filename);\n // }\n // EGuiFileList::display_path(PathBuf::from(\"resources/roms\"), \u0026mut state.selected_rom_filename, ui);\n\n\n\n ui.with_layout(egui::Layout::left_to_right(Align::TOP), |ui| {\n // ui.checkbox(\u0026mut state.display_memory, \"Display Memory\");\n // ui.checkbox(\u0026mut state.display_video, \"Display Video\");\n // ui.checkbox(\u0026mut state.display_registers, \"Display Registers\");\n });\n }\n\n pub fn registers_view(system: \u0026Chip8Computer, ui: \u0026mut Ui) {\n ui.label(format!(\"V0-7: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} \",\n system.registers.peek(0x00),\n system.registers.peek(0x01),\n system.registers.peek(0x02),\n system.registers.peek(0x03),\n system.registers.peek(0x04),\n system.registers.peek(0x05),\n system.registers.peek(0x06),\n system.registers.peek(0x07)\n ));\n ui.label(format!(\"V8-F: {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} \",\n system.registers.peek(0x08),\n system.registers.peek(0x09),\n system.registers.peek(0x0A),\n system.registers.peek(0x0B),\n system.registers.peek(0x0C),\n system.registers.peek(0x0D),\n system.registers.peek(0x0E),\n system.registers.peek(0x0F)\n ));\n ui.label(format!(\"PC: {:04x}\\tI: {:04x}\", system.registers.peek_pc(), system.registers.peek_i()));\n }\n\n pub fn video_view(system: \u0026Chip8Computer, ui: \u0026mut Ui) {\n let (_resp, painter) = ui.allocate_painter(Vec2::new(350.0, 165.0), egui::Sense::hover());\n for current_row in 0..32 {\n for current_col in 0..64 {\n let data_offset = current_row * 64 + current_col;\n let x_offset = current_col as f32 * CELL_WIDTH;\n let y_offset = current_row as f32 * CELL_HEIGHT;\n let origin = Pos2::new(x_offset, y_offset);\n let colour = if system.video_memory.peek(data_offset) {\n Color32::RED\n } else {\n Color32::WHITE\n };\n let rect = Rect::from_min_size(origin, Vec2::new(CELL_WIDTH, CELL_HEIGHT));\n painter.rect_filled(rect, 0.0, colour);\n // println!(\"Cell {current_col}x{current_row} at {}x{} -\u003e {}\",\n // origin.x, origin.y,\n // system.video_memory.peek(data_offset));\n }\n }\n // thread::sleep(Duration::from_secs(1));\n }\n\n pub fn memory_view(system: \u0026Chip8Computer, ui: \u0026mut Ui) {\n ui.label(\"Memory View\");\n\n for i in (0..=0x200).step_by(16) {\n ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {\n for y in 0..16 {\n ui.label(format!(\"{:02x}\", system.memory.peek((i + y) as u16)).as_str());\n }\n });\n }\n ui.label(\"Should have **something** to adjust the 'memory window'\");\n }\n}\n","traces":[{"line":18,"address":[787872,788303],"length":1,"stats":{"Line":0}},{"line":19,"address":[787902],"length":1,"stats":{"Line":0}},{"line":20,"address":[788131],"length":1,"stats":{"Line":0}},{"line":22,"address":[810765,810875,810940],"length":1,"stats":{"Line":0}},{"line":23,"address":[810990,810810,810922],"length":1,"stats":{"Line":0}},{"line":24,"address":[811024,810930,813212,812807],"length":1,"stats":{"Line":0}},{"line":26,"address":[811060],"length":1,"stats":{"Line":0}},{"line":27,"address":[811447,811117,813167,811611,811582,811221],"length":1,"stats":{"Line":0}},{"line":28,"address":[812838,813202],"length":1,"stats":{"Line":0}},{"line":29,"address":[813096],"length":1,"stats":{"Line":0}},{"line":32,"address":[811853],"length":1,"stats":{"Line":0}},{"line":33,"address":[812077,812127,811887,812783],"length":1,"stats":{"Line":0}},{"line":35,"address":[812770,812167,812277,812478],"length":1,"stats":{"Line":0}},{"line":37,"address":[812589],"length":1,"stats":{"Line":0}},{"line":49,"address":[788336],"length":1,"stats":{"Line":0}},{"line":50,"address":[788466],"length":1,"stats":{"Line":0}},{"line":51,"address":[813384,813273],"length":1,"stats":{"Line":0}},{"line":52,"address":[813459],"length":1,"stats":{"Line":0}},{"line":55,"address":[813499,813622],"length":1,"stats":{"Line":0}},{"line":56,"address":[813706],"length":1,"stats":{"Line":0}},{"line":59,"address":[813845,813722],"length":1,"stats":{"Line":0}},{"line":60,"address":[813929],"length":1,"stats":{"Line":0}},{"line":63,"address":[814092,813969],"length":1,"stats":{"Line":0}},{"line":64,"address":[814173],"length":1,"stats":{"Line":0}},{"line":80,"address":[788681],"length":1,"stats":{"Line":0}},{"line":87,"address":[788816],"length":1,"stats":{"Line":0}},{"line":88,"address":[792088,790928,791160,791392,792465,789976,791624,791856,790696,790464],"length":1,"stats":{"Line":0}},{"line":89,"address":[788864],"length":1,"stats":{"Line":0}},{"line":90,"address":[789001],"length":1,"stats":{"Line":0}},{"line":91,"address":[789141],"length":1,"stats":{"Line":0}},{"line":92,"address":[789281],"length":1,"stats":{"Line":0}},{"line":93,"address":[789421],"length":1,"stats":{"Line":0}},{"line":94,"address":[789561],"length":1,"stats":{"Line":0}},{"line":95,"address":[789701],"length":1,"stats":{"Line":0}},{"line":96,"address":[789841],"length":1,"stats":{"Line":0}},{"line":98,"address":[795028,794100,794796,793612,794332,794564,795260,795492,795724,796104],"length":1,"stats":{"Line":0}},{"line":99,"address":[792497],"length":1,"stats":{"Line":0}},{"line":101,"address":[792777],"length":1,"stats":{"Line":0}},{"line":102,"address":[792917],"length":1,"stats":{"Line":0}},{"line":103,"address":[793057],"length":1,"stats":{"Line":0}},{"line":104,"address":[793197],"length":1,"stats":{"Line":0}},{"line":105,"address":[793337],"length":1,"stats":{"Line":0}},{"line":106,"address":[793477],"length":1,"stats":{"Line":0}},{"line":108,"address":[797123,796145,796940,796412,796708,796281],"length":1,"stats":{"Line":0}},{"line":111,"address":[798540,797168],"length":1,"stats":{"Line":0}},{"line":112,"address":[797223],"length":1,"stats":{"Line":0}},{"line":113,"address":[797519,797705,797601],"length":1,"stats":{"Line":0}},{"line":114,"address":[797824,797726],"length":1,"stats":{"Line":0}},{"line":115,"address":[797939,798108],"length":1,"stats":{"Line":0}},{"line":116,"address":[798028],"length":1,"stats":{"Line":0}},{"line":117,"address":[798062],"length":1,"stats":{"Line":0}},{"line":118,"address":[798148],"length":1,"stats":{"Line":0}},{"line":119,"address":[798225,798184],"length":1,"stats":{"Line":0}},{"line":120,"address":[798227],"length":1,"stats":{"Line":0}},{"line":122,"address":[798212],"length":1,"stats":{"Line":0}},{"line":125,"address":[798454],"length":1,"stats":{"Line":0}},{"line":134,"address":[798576],"length":1,"stats":{"Line":0}},{"line":135,"address":[798609],"length":1,"stats":{"Line":0}},{"line":137,"address":[798643,798856],"length":1,"stats":{"Line":0}},{"line":138,"address":[798969],"length":1,"stats":{"Line":0}},{"line":139,"address":[814328,814270],"length":1,"stats":{"Line":0}},{"line":140,"address":[814339,814899,814717,814469],"length":1,"stats":{"Line":0}},{"line":144,"address":[798798],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":63},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmasdl2","src","bin","support","mod.rs"],"content":"pub mod timestep;\npub mod gemma_egui_support;\n","traces":[],"covered":0,"coverable":0},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmasdl2","src","bin","support","timestep.rs"],"content":"\n//! Gameplay speed control. It attempts to mimic/limit progression to\n//! the 30 tics per second Doom used.\n\nuse std::{fmt, time::Instant};\n\nconst MS_PER_UPDATE: f32 = 28.57;\n\n#[derive(Debug)]\npub struct TimeStep {\n last_time: Instant,\n delta_time: f32,\n frame_count: u32,\n frame_time: f32,\n run_tics: u32,\n last_tics: u32,\n lag: f32,\n}\n\n#[derive(Debug)]\npub struct FrameData {\n pub tics: u32,\n pub frames: u32,\n}\n\nimpl fmt::Display for FrameData {\n fn fmt(\u0026self, f: \u0026mut fmt::Formatter\u003c'_\u003e) -\u003e fmt::Result {\n f.write_fmt(format_args!(\n \"FrameData (per-second):\\n - tics: {}\\n - fps: {}\",\n self.tics, self.frames\n ))\n }\n}\n\nimpl TimeStep {\n pub fn new() -\u003e TimeStep {\n TimeStep {\n last_time: Instant::now(),\n delta_time: 0.0,\n frame_count: 0,\n frame_time: 0.0,\n run_tics: 0,\n last_tics: 0,\n lag: 0.0,\n }\n }\n\n pub fn delta(\u0026mut self) -\u003e f32 {\n let current_time = Instant::now();\n let delta = current_time.duration_since(self.last_time).as_micros() as f32 * 0.001;\n self.last_time = current_time;\n self.delta_time = delta;\n delta\n }\n\n /// Increments self time and returns current lag. `run_this` is run only for\n /// `n` tics available.\n pub fn run_this(\u0026mut self, mut run_this: impl FnMut(f32)) {\n let dt = self.delta();\n self.lag += dt;\n while self.lag \u003e= MS_PER_UPDATE {\n run_this(dt);\n self.lag -= MS_PER_UPDATE;\n self.run_tics += 1;\n }\n }\n\n pub fn frame_rate(\u0026mut self) -\u003e Option\u003cFrameData\u003e {\n self.frame_count += 1;\n self.frame_time += self.delta_time;\n let tmp;\n let tmp2;\n // per second\n if self.frame_time \u003e= 1000.0 {\n tmp = self.frame_count;\n tmp2 = self.last_tics;\n self.frame_count = 0;\n self.frame_time = 0.0;\n self.last_tics = self.run_tics;\n return Some(FrameData {\n tics: self.run_tics - tmp2,\n frames: tmp,\n });\n }\n\n None\n }\n}\n\nimpl Default for TimeStep {\n // shutup clippy!\n fn default() -\u003e Self {\n Self::new()\n }\n}","traces":[{"line":27,"address":[830752],"length":1,"stats":{"Line":0}},{"line":28,"address":[830940,830856],"length":1,"stats":{"Line":0}},{"line":36,"address":[831040],"length":1,"stats":{"Line":0}},{"line":38,"address":[831054],"length":1,"stats":{"Line":0}},{"line":48,"address":[831136],"length":1,"stats":{"Line":0}},{"line":49,"address":[831149],"length":1,"stats":{"Line":0}},{"line":50,"address":[831171],"length":1,"stats":{"Line":0}},{"line":51,"address":[831247],"length":1,"stats":{"Line":0}},{"line":52,"address":[831262],"length":1,"stats":{"Line":0}},{"line":58,"address":[],"length":0,"stats":{"Line":0}},{"line":59,"address":[],"length":0,"stats":{"Line":0}},{"line":60,"address":[],"length":0,"stats":{"Line":0}},{"line":61,"address":[],"length":0,"stats":{"Line":0}},{"line":62,"address":[],"length":0,"stats":{"Line":0}},{"line":63,"address":[],"length":0,"stats":{"Line":0}},{"line":64,"address":[],"length":0,"stats":{"Line":0}},{"line":68,"address":[831280],"length":1,"stats":{"Line":0}},{"line":69,"address":[831366,831304],"length":1,"stats":{"Line":0}},{"line":70,"address":[831331],"length":1,"stats":{"Line":0}},{"line":74,"address":[831346],"length":1,"stats":{"Line":0}},{"line":75,"address":[831400],"length":1,"stats":{"Line":0}},{"line":76,"address":[831410],"length":1,"stats":{"Line":0}},{"line":77,"address":[831417],"length":1,"stats":{"Line":0}},{"line":78,"address":[831424],"length":1,"stats":{"Line":0}},{"line":79,"address":[831432],"length":1,"stats":{"Line":0}},{"line":80,"address":[831477],"length":1,"stats":{"Line":0}},{"line":81,"address":[831491,831438],"length":1,"stats":{"Line":0}},{"line":86,"address":[831387],"length":1,"stats":{"Line":0}},{"line":92,"address":[831520],"length":1,"stats":{"Line":0}},{"line":93,"address":[831528],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":30},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmatelnet","src","bin","gemmatelnetd.rs"],"content":"fn main() {\n println!(\"Taxation is Theft\");\n}","traces":[{"line":1,"address":[116144,116192],"length":1,"stats":{"Line":1}},{"line":2,"address":[116148],"length":1,"stats":{"Line":0}}],"covered":1,"coverable":2},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmautil","src","bin","bin2hex.rs"],"content":"use std::fs::File;\nuse std::io;\nuse std::io::{BufReader, Read};\nuse clap::{Arg, Command, ArgAction, ValueEnum};\n\n#[derive(Debug)]\nstruct CliArgs {\n input: String,\n}\n\nfn main() {\n println!(\"Taxation is Theft!\");\n // Set up the command line arguments\n let matches = Command::new(\"my_program\")\n .about(\"Processes an input file and outputs it with a specified bit width\")\n .arg(\n Arg::new(\"input\")\n .help(\"The input file to process\")\n .required(true)\n .index(1),\n )\n\n .get_matches();\n\n // Parse the command-line arguments\n let args = CliArgs {\n input: matches.get_one::\u003cString\u003e(\"input\").unwrap().to_string(),\n };\n\n // Use the parsed arguments\n println!(\"Input file: {}\", args.input);\n\n // behave like a shift register and load each character from the file 1 by 1.\n let results = read_file_to_bools(\u0026args.input);\n for result in results.unwrap().bytes() {\n print!(\"0x{:02x}, \", result.unwrap());\n }\n}\nfn read_file_to_bools(file_path: \u0026str) -\u003e io::Result\u003cVec\u003cu8\u003e\u003e {\n // Open the file\n let file = File::open(file_path)?;\n let mut reader = BufReader::new(file);\n\n let mut bytes = Vec::new();\n reader.read_to_end(\u0026mut bytes)?;\n\n let mut output = Vec::new();\n let mut current_byte = 0u8;\n let mut bit_index = 0;\n\n for \u0026byte in \u0026bytes {\n // Convert ASCII character '1' or '0' to boolean, skip any other characters\n let bit = match byte {\n b'1' =\u003e true,\n b'0' =\u003e false,\n _ =\u003e continue, // Skip non-'1' or '0' characters\n };\n\n // Set the appropriate bit in the current byte\n if bit {\n current_byte |= 1 \u003c\u003c (7 - bit_index); // Set the bit at the correct position\n }\n\n bit_index += 1;\n\n // Once we have filled 8 bits, push the byte and reset\n if bit_index == 8 {\n output.push(current_byte);\n current_byte = 0;\n bit_index = 0;\n }\n }\n\n // If there are remaining bits, push the last byte (it will be partially filled)\n if bit_index \u003e 0 {\n output.push(current_byte);\n }\n\n\n\n Ok(output)\n}\n\n","traces":[{"line":11,"address":[253074,250928],"length":1,"stats":{"Line":0}},{"line":12,"address":[250950],"length":1,"stats":{"Line":0}},{"line":14,"address":[251256,251331,251007],"length":1,"stats":{"Line":0}},{"line":17,"address":[251161,251089],"length":1,"stats":{"Line":0}},{"line":27,"address":[251513,251344],"length":1,"stats":{"Line":0}},{"line":31,"address":[251740],"length":1,"stats":{"Line":0}},{"line":34,"address":[251817],"length":1,"stats":{"Line":0}},{"line":35,"address":[252329,252189,252086],"length":1,"stats":{"Line":0}},{"line":36,"address":[252701,252965,252584],"length":1,"stats":{"Line":0}},{"line":39,"address":[253120,254208,254264],"length":1,"stats":{"Line":0}},{"line":41,"address":[253251,253153],"length":1,"stats":{"Line":0}},{"line":42,"address":[253219],"length":1,"stats":{"Line":0}},{"line":44,"address":[253330],"length":1,"stats":{"Line":0}},{"line":45,"address":[253552,253458,253390],"length":1,"stats":{"Line":0}},{"line":47,"address":[253540],"length":1,"stats":{"Line":0}},{"line":48,"address":[253585],"length":1,"stats":{"Line":0}},{"line":49,"address":[253593],"length":1,"stats":{"Line":0}},{"line":51,"address":[253612,253777,253683],"length":1,"stats":{"Line":0}},{"line":53,"address":[253798],"length":1,"stats":{"Line":0}},{"line":54,"address":[253966],"length":1,"stats":{"Line":0}},{"line":55,"address":[253976],"length":1,"stats":{"Line":0}},{"line":60,"address":[254093,253984],"length":1,"stats":{"Line":0}},{"line":61,"address":[254095,254014],"length":1,"stats":{"Line":0}},{"line":64,"address":[254139,254117,253994],"length":1,"stats":{"Line":0}},{"line":67,"address":[254203,254124],"length":1,"stats":{"Line":0}},{"line":68,"address":[254157],"length":1,"stats":{"Line":0}},{"line":69,"address":[254184],"length":1,"stats":{"Line":0}},{"line":70,"address":[254192],"length":1,"stats":{"Line":0}},{"line":75,"address":[253765],"length":1,"stats":{"Line":0}},{"line":76,"address":[253901],"length":1,"stats":{"Line":0}},{"line":81,"address":[253827],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":31},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmautil","src","bin","ch8asm.rs"],"content":"use std::fs;\n// Ch8Asm\n// Converts well formed CH8ASM.\n// no variables.\n// no labels.\n// nothing fun.\nuse pest::Parser;\nuse pest_derive::Parser;\n\n#[derive(Parser)]\n#[grammar = \"chip8_asm.pest\"]\npub struct Chip8AsmParser;\n\nfn main() {\n println!(\"Taxation is Theft\");\n\n\n\n let unparsed = fs::read_to_string(\"resources/test/gemma_disassembler_1_chip_logo_ch8_asm.asc\").expect(\"Unable to read input\");\n\n let file = Chip8AsmParser::parse(Rule::file, \u0026unparsed).expect(\"Unable to parse. Try again.\")\n .next().unwrap();\n\n for record in file.into_inner() {\n match record.as_rule() {\n Rule::instruction =\u003e {\n println!(\"INSTRUCTION = {:?}\", record.into_inner().flatten())\n }\n _ =\u003e {\n println!(\"UNHANDLED PART.\");\n }\n }\n }\n}\n\nmod test {\n use super::*;\n\n #[test]\n fn bits_all_parse() {\n println!(\"PARSED: {:?}\",\n Chip8AsmParser::parse(Rule::instruction, \"CLS\")\n );\n println!(\"PARSED: {:?}\",\n Chip8AsmParser::parse(Rule::parameter, \"0x01\")\n );\n let parsed = Chip8AsmParser::parse(Rule::comment, \"; comment\").unwrap();\n for i in parsed {\n println!(\"PARSED COMMENT -\u003e {:?}\", i);\n }\n\n let parsed =\n Chip8AsmParser::parse(Rule::record, \"CLS ; comment\").unwrap();\n for i in parsed {\n println!(\"RULE PAIR THING: {:?}\", i);\n }\n\n let parsed = Chip8AsmParser::parse(Rule::record, \"ADDI 0x01 ; comment\");\n for i in parsed {\n println!(\"RULE PAIR THING: {:?}\", i);\n }\n\n println!(\"PARSED: {:?}\",\n Chip8AsmParser::parse(Rule::record, \"ADD ADD ADD\")\n );\n\n println!(\"PARSED: {:?}\",\n Chip8AsmParser::parse(Rule::record, \"ADD 0x01 0x02 ; Comment\")\n );\n\n println!(\"PARSED: {:?}\",\n Chip8AsmParser::parse(Rule::record, \"ADD 0x01 0x02 ; Comment\")\n );\n }\n}","traces":[{"line":14,"address":[200576,201827,201921],"length":1,"stats":{"Line":0}},{"line":15,"address":[200583],"length":1,"stats":{"Line":0}},{"line":19,"address":[200639],"length":1,"stats":{"Line":0}},{"line":21,"address":[200710,200786],"length":1,"stats":{"Line":0}},{"line":24,"address":[201045,201280,201236,201865],"length":1,"stats":{"Line":0}},{"line":25,"address":[201427,201344],"length":1,"stats":{"Line":0}},{"line":27,"address":[201699,201448,201572],"length":1,"stats":{"Line":0}},{"line":30,"address":[201836,201527],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":8},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmautil","src","bin","ch8disasm.rs"],"content":"use std::path::Path;\nuse clap::{command, Parser};\nuse gemma::chip8::instructions::Chip8CpuInstructions;\nuse gemma::chip8::instructions::Chip8CpuInstructions::XXXXERRORINSTRUCTION;\nuse gemma::chip8::quirk_modes::QuirkMode::Chip8;\n\n/// ch8disasm\n///\n/// Provide disassembled version of the CH8 file provided.\n#[derive(Parser)]\n#[command(version, about, long_about = None)]\nstruct DisassemblerApp {\n #[arg(short)]\n input_file: Box\u003cPath\u003e,\n #[arg(short)]\n output_file: Option\u003cBox\u003cPath\u003e\u003e,\n}\n\nstruct Disassembler {}\nimpl Disassembler {\n pub fn disassemble(from_data: Vec\u003cu8\u003e) -\u003e String {\n let mut working_instruction: u16 = 0x0000;\n\n // read the input data and loop through it byte by byte.\n let mut output_string = String::new();\n\n for (offset, byte) in from_data.iter().enumerate() {\n working_instruction = (working_instruction \u003c\u003c 8) | (*byte as u16);\n if offset % 2 != 0 {\n let decoded = Chip8CpuInstructions::decode(working_instruction, \u0026Chip8);\n let decoded_string = decoded.to_string();\n let mut current_parts = String::new();\n\n match decoded {\n XXXXERRORINSTRUCTION =\u003e {\n current_parts = format!(\"DW 0x{:04x}\", working_instruction);\n }\n _ =\u003e {\n current_parts = format!(\"{}\", decoded);\n }\n };\n\n let target_length: i32 = 25;\n let spacing_length = target_length.saturating_sub(current_parts.len() as i32);\n\n // now add the rest after the string\n let x = spacing_length as usize;\n current_parts = format!(\"{}{:\u003cx$}; Bytes [0x{:04x}] offset [0x{:04x}]\\n\", current_parts, \" \", working_instruction, offset -1);\n // println!(\"SHOULD OUTPUT: [{current_parts}]\");\n output_string = output_string.to_string() + \u0026*current_parts.to_string();\n\n working_instruction = 0x0000;\n }\n }\n\n output_string\n }\n}\n\nfn main() {\n println!(\"Taxation is Theft\");\n let result = DisassemblerApp::parse();\n println!(\"PREPARING TO DISASSEMBLE {:?}\", result.input_file.file_name());\n\n\n let source_file = result.input_file.to_str().unwrap();\n let decompiled_program = Disassembler::disassemble(\n std::fs::read(source_file).unwrap()\n );\n\n\n match result.output_file {\n None =\u003e {\n println!(\"Output to console.\");\n println!(\"OS: \\n\\n{}\", decompiled_program);\n }\n Some(target) =\u003e {\n println!(\"Output to {:?}\", target);\n std::fs::write(target, decompiled_program).unwrap();\n }\n }\n}\n\nmod test {\n #[test]\n fn smoke() { assert!(true); }\n\n #[test]\n fn assemble_test_file() {\n\n }\n}","traces":[{"line":20,"address":[433113,428704],"length":1,"stats":{"Line":0}},{"line":21,"address":[428746],"length":1,"stats":{"Line":0}},{"line":24,"address":[428772],"length":1,"stats":{"Line":0}},{"line":26,"address":[428831,429185,428903],"length":1,"stats":{"Line":0}},{"line":27,"address":[429227],"length":1,"stats":{"Line":0}},{"line":28,"address":[429273],"length":1,"stats":{"Line":0}},{"line":29,"address":[429287],"length":1,"stats":{"Line":0}},{"line":30,"address":[429351],"length":1,"stats":{"Line":0}},{"line":31,"address":[429366],"length":1,"stats":{"Line":0}},{"line":33,"address":[429417],"length":1,"stats":{"Line":0}},{"line":35,"address":[429705,429969,430123],"length":1,"stats":{"Line":0}},{"line":37,"address":[430551],"length":1,"stats":{"Line":0}},{"line":38,"address":[430409,430288],"length":1,"stats":{"Line":0}},{"line":42,"address":[428735],"length":1,"stats":{"Line":0}},{"line":43,"address":[430629,430561,430273],"length":1,"stats":{"Line":0}},{"line":46,"address":[430636],"length":1,"stats":{"Line":0}},{"line":47,"address":[432293,431829,431121,430978,432061,432540,431597,431217],"length":1,"stats":{"Line":0}},{"line":49,"address":[433072,432682],"length":1,"stats":{"Line":0}},{"line":51,"address":[433021],"length":1,"stats":{"Line":0}},{"line":55,"address":[429128],"length":1,"stats":{"Line":0}},{"line":59,"address":[433136,435003,434933],"length":1,"stats":{"Line":0}},{"line":60,"address":[433143],"length":1,"stats":{"Line":0}},{"line":61,"address":[433207],"length":1,"stats":{"Line":0}},{"line":62,"address":[433461,433335,433228],"length":1,"stats":{"Line":0}},{"line":65,"address":[433530,433682],"length":1,"stats":{"Line":0}},{"line":67,"address":[433698],"length":1,"stats":{"Line":0}},{"line":71,"address":[433975],"length":1,"stats":{"Line":0}},{"line":73,"address":[434237,434004],"length":1,"stats":{"Line":0}},{"line":74,"address":[434366],"length":1,"stats":{"Line":0}},{"line":76,"address":[434033],"length":1,"stats":{"Line":0}},{"line":77,"address":[434517],"length":1,"stats":{"Line":0}},{"line":78,"address":[434586],"length":1,"stats":{"Line":0}}],"covered":0,"coverable":32},{"path":["/","home","tmerritt","Projects","chip8_toy","gemmautil","tests","assmber_tests.rs"],"content":"#[test]\nfn smoke() { assert!(true) }\n\n","traces":[],"covered":0,"coverable":0}]};
|
|
</script>
|
|
<script crossorigin>/** @license React v16.13.1
|
|
* react.production.min.js
|
|
*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
'use strict';(function(d,r){"object"===typeof exports&&"undefined"!==typeof module?r(exports):"function"===typeof define&&define.amd?define(["exports"],r):(d=d||self,r(d.React={}))})(this,function(d){function r(a){for(var b="https://reactjs.org/docs/error-decoder.html?invariant="+a,c=1;c<arguments.length;c++)b+="&args[]="+encodeURIComponent(arguments[c]);return"Minified React error #"+a+"; visit "+b+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}
|
|
function w(a,b,c){this.props=a;this.context=b;this.refs=ba;this.updater=c||ca}function da(){}function L(a,b,c){this.props=a;this.context=b;this.refs=ba;this.updater=c||ca}function ea(a,b,c){var g,e={},fa=null,d=null;if(null!=b)for(g in void 0!==b.ref&&(d=b.ref),void 0!==b.key&&(fa=""+b.key),b)ha.call(b,g)&&!ia.hasOwnProperty(g)&&(e[g]=b[g]);var h=arguments.length-2;if(1===h)e.children=c;else if(1<h){for(var k=Array(h),f=0;f<h;f++)k[f]=arguments[f+2];e.children=k}if(a&&a.defaultProps)for(g in h=a.defaultProps,
|
|
h)void 0===e[g]&&(e[g]=h[g]);return{$$typeof:x,type:a,key:fa,ref:d,props:e,_owner:M.current}}function va(a,b){return{$$typeof:x,type:a.type,key:b,ref:a.ref,props:a.props,_owner:a._owner}}function N(a){return"object"===typeof a&&null!==a&&a.$$typeof===x}function wa(a){var b={"=":"=0",":":"=2"};return"$"+(""+a).replace(/[=:]/g,function(a){return b[a]})}function ja(a,b,c,g){if(C.length){var e=C.pop();e.result=a;e.keyPrefix=b;e.func=c;e.context=g;e.count=0;return e}return{result:a,keyPrefix:b,func:c,
|
|
context:g,count:0}}function ka(a){a.result=null;a.keyPrefix=null;a.func=null;a.context=null;a.count=0;10>C.length&&C.push(a)}function O(a,b,c,g){var e=typeof a;if("undefined"===e||"boolean"===e)a=null;var d=!1;if(null===a)d=!0;else switch(e){case "string":case "number":d=!0;break;case "object":switch(a.$$typeof){case x:case xa:d=!0}}if(d)return c(g,a,""===b?"."+P(a,0):b),1;d=0;b=""===b?".":b+":";if(Array.isArray(a))for(var f=0;f<a.length;f++){e=a[f];var h=b+P(e,f);d+=O(e,h,c,g)}else if(null===a||
|
|
"object"!==typeof a?h=null:(h=la&&a[la]||a["@@iterator"],h="function"===typeof h?h:null),"function"===typeof h)for(a=h.call(a),f=0;!(e=a.next()).done;)e=e.value,h=b+P(e,f++),d+=O(e,h,c,g);else if("object"===e)throw c=""+a,Error(r(31,"[object Object]"===c?"object with keys {"+Object.keys(a).join(", ")+"}":c,""));return d}function Q(a,b,c){return null==a?0:O(a,"",b,c)}function P(a,b){return"object"===typeof a&&null!==a&&null!=a.key?wa(a.key):b.toString(36)}function ya(a,b,c){a.func.call(a.context,b,
|
|
a.count++)}function za(a,b,c){var g=a.result,e=a.keyPrefix;a=a.func.call(a.context,b,a.count++);Array.isArray(a)?R(a,g,c,function(a){return a}):null!=a&&(N(a)&&(a=va(a,e+(!a.key||b&&b.key===a.key?"":(""+a.key).replace(ma,"$&/")+"/")+c)),g.push(a))}function R(a,b,c,g,e){var d="";null!=c&&(d=(""+c).replace(ma,"$&/")+"/");b=ja(b,d,g,e);Q(a,za,b);ka(b)}function t(){var a=na.current;if(null===a)throw Error(r(321));return a}function S(a,b){var c=a.length;a.push(b);a:for(;;){var g=c-1>>>1,e=a[g];if(void 0!==
|
|
e&&0<D(e,b))a[g]=b,a[c]=e,c=g;else break a}}function n(a){a=a[0];return void 0===a?null:a}function E(a){var b=a[0];if(void 0!==b){var c=a.pop();if(c!==b){a[0]=c;a:for(var g=0,e=a.length;g<e;){var d=2*(g+1)-1,f=a[d],h=d+1,k=a[h];if(void 0!==f&&0>D(f,c))void 0!==k&&0>D(k,f)?(a[g]=k,a[h]=c,g=h):(a[g]=f,a[d]=c,g=d);else if(void 0!==k&&0>D(k,c))a[g]=k,a[h]=c,g=h;else break a}}return b}return null}function D(a,b){var c=a.sortIndex-b.sortIndex;return 0!==c?c:a.id-b.id}function F(a){for(var b=n(u);null!==
|
|
b;){if(null===b.callback)E(u);else if(b.startTime<=a)E(u),b.sortIndex=b.expirationTime,S(p,b);else break;b=n(u)}}function T(a){y=!1;F(a);if(!v)if(null!==n(p))v=!0,z(U);else{var b=n(u);null!==b&&G(T,b.startTime-a)}}function U(a,b){v=!1;y&&(y=!1,V());H=!0;var c=m;try{F(b);for(l=n(p);null!==l&&(!(l.expirationTime>b)||a&&!W());){var g=l.callback;if(null!==g){l.callback=null;m=l.priorityLevel;var e=g(l.expirationTime<=b);b=q();"function"===typeof e?l.callback=e:l===n(p)&&E(p);F(b)}else E(p);l=n(p)}if(null!==
|
|
l)var d=!0;else{var f=n(u);null!==f&&G(T,f.startTime-b);d=!1}return d}finally{l=null,m=c,H=!1}}function oa(a){switch(a){case 1:return-1;case 2:return 250;case 5:return 1073741823;case 4:return 1E4;default:return 5E3}}var f="function"===typeof Symbol&&Symbol.for,x=f?Symbol.for("react.element"):60103,xa=f?Symbol.for("react.portal"):60106,Aa=f?Symbol.for("react.fragment"):60107,Ba=f?Symbol.for("react.strict_mode"):60108,Ca=f?Symbol.for("react.profiler"):60114,Da=f?Symbol.for("react.provider"):60109,
|
|
Ea=f?Symbol.for("react.context"):60110,Fa=f?Symbol.for("react.forward_ref"):60112,Ga=f?Symbol.for("react.suspense"):60113,Ha=f?Symbol.for("react.memo"):60115,Ia=f?Symbol.for("react.lazy"):60116,la="function"===typeof Symbol&&Symbol.iterator,pa=Object.getOwnPropertySymbols,Ja=Object.prototype.hasOwnProperty,Ka=Object.prototype.propertyIsEnumerable,I=function(){try{if(!Object.assign)return!1;var a=new String("abc");a[5]="de";if("5"===Object.getOwnPropertyNames(a)[0])return!1;var b={};for(a=0;10>a;a++)b["_"+
|
|
String.fromCharCode(a)]=a;if("0123456789"!==Object.getOwnPropertyNames(b).map(function(a){return b[a]}).join(""))return!1;var c={};"abcdefghijklmnopqrst".split("").forEach(function(a){c[a]=a});return"abcdefghijklmnopqrst"!==Object.keys(Object.assign({},c)).join("")?!1:!0}catch(g){return!1}}()?Object.assign:function(a,b){if(null===a||void 0===a)throw new TypeError("Object.assign cannot be called with null or undefined");var c=Object(a);for(var g,e=1;e<arguments.length;e++){var d=Object(arguments[e]);
|
|
for(var f in d)Ja.call(d,f)&&(c[f]=d[f]);if(pa){g=pa(d);for(var h=0;h<g.length;h++)Ka.call(d,g[h])&&(c[g[h]]=d[g[h]])}}return c},ca={isMounted:function(a){return!1},enqueueForceUpdate:function(a,b,c){},enqueueReplaceState:function(a,b,c,d){},enqueueSetState:function(a,b,c,d){}},ba={};w.prototype.isReactComponent={};w.prototype.setState=function(a,b){if("object"!==typeof a&&"function"!==typeof a&&null!=a)throw Error(r(85));this.updater.enqueueSetState(this,a,b,"setState")};w.prototype.forceUpdate=
|
|
function(a){this.updater.enqueueForceUpdate(this,a,"forceUpdate")};da.prototype=w.prototype;f=L.prototype=new da;f.constructor=L;I(f,w.prototype);f.isPureReactComponent=!0;var M={current:null},ha=Object.prototype.hasOwnProperty,ia={key:!0,ref:!0,__self:!0,__source:!0},ma=/\/+/g,C=[],na={current:null},X;if("undefined"===typeof window||"function"!==typeof MessageChannel){var A=null,qa=null,ra=function(){if(null!==A)try{var a=q();A(!0,a);A=null}catch(b){throw setTimeout(ra,0),b;}},La=Date.now();var q=
|
|
function(){return Date.now()-La};var z=function(a){null!==A?setTimeout(z,0,a):(A=a,setTimeout(ra,0))};var G=function(a,b){qa=setTimeout(a,b)};var V=function(){clearTimeout(qa)};var W=function(){return!1};f=X=function(){}}else{var Y=window.performance,sa=window.Date,Ma=window.setTimeout,Na=window.clearTimeout;"undefined"!==typeof console&&(f=window.cancelAnimationFrame,"function"!==typeof window.requestAnimationFrame&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"),
|
|
"function"!==typeof f&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"));if("object"===typeof Y&&"function"===typeof Y.now)q=function(){return Y.now()};else{var Oa=sa.now();q=function(){return sa.now()-Oa}}var J=!1,K=null,Z=-1,ta=5,ua=0;W=function(){return q()>=ua};f=function(){};X=function(a){0>a||125<a?console.error("forceFrameRate takes a positive int between 0 and 125, forcing framerates higher than 125 fps is not unsupported"):
|
|
ta=0<a?Math.floor(1E3/a):5};var B=new MessageChannel,aa=B.port2;B.port1.onmessage=function(){if(null!==K){var a=q();ua=a+ta;try{K(!0,a)?aa.postMessage(null):(J=!1,K=null)}catch(b){throw aa.postMessage(null),b;}}else J=!1};z=function(a){K=a;J||(J=!0,aa.postMessage(null))};G=function(a,b){Z=Ma(function(){a(q())},b)};V=function(){Na(Z);Z=-1}}var p=[],u=[],Pa=1,l=null,m=3,H=!1,v=!1,y=!1,Qa=0;B={ReactCurrentDispatcher:na,ReactCurrentOwner:M,IsSomeRendererActing:{current:!1},assign:I};I(B,{Scheduler:{__proto__:null,
|
|
unstable_ImmediatePriority:1,unstable_UserBlockingPriority:2,unstable_NormalPriority:3,unstable_IdlePriority:5,unstable_LowPriority:4,unstable_runWithPriority:function(a,b){switch(a){case 1:case 2:case 3:case 4:case 5:break;default:a=3}var c=m;m=a;try{return b()}finally{m=c}},unstable_next:function(a){switch(m){case 1:case 2:case 3:var b=3;break;default:b=m}var c=m;m=b;try{return a()}finally{m=c}},unstable_scheduleCallback:function(a,b,c){var d=q();if("object"===typeof c&&null!==c){var e=c.delay;
|
|
e="number"===typeof e&&0<e?d+e:d;c="number"===typeof c.timeout?c.timeout:oa(a)}else c=oa(a),e=d;c=e+c;a={id:Pa++,callback:b,priorityLevel:a,startTime:e,expirationTime:c,sortIndex:-1};e>d?(a.sortIndex=e,S(u,a),null===n(p)&&a===n(u)&&(y?V():y=!0,G(T,e-d))):(a.sortIndex=c,S(p,a),v||H||(v=!0,z(U)));return a},unstable_cancelCallback:function(a){a.callback=null},unstable_wrapCallback:function(a){var b=m;return function(){var c=m;m=b;try{return a.apply(this,arguments)}finally{m=c}}},unstable_getCurrentPriorityLevel:function(){return m},
|
|
unstable_shouldYield:function(){var a=q();F(a);var b=n(p);return b!==l&&null!==l&&null!==b&&null!==b.callback&&b.startTime<=a&&b.expirationTime<l.expirationTime||W()},unstable_requestPaint:f,unstable_continueExecution:function(){v||H||(v=!0,z(U))},unstable_pauseExecution:function(){},unstable_getFirstCallbackNode:function(){return n(p)},get unstable_now(){return q},get unstable_forceFrameRate(){return X},unstable_Profiling:null},SchedulerTracing:{__proto__:null,__interactionsRef:null,__subscriberRef:null,
|
|
unstable_clear:function(a){return a()},unstable_getCurrent:function(){return null},unstable_getThreadID:function(){return++Qa},unstable_trace:function(a,b,c){return c()},unstable_wrap:function(a){return a},unstable_subscribe:function(a){},unstable_unsubscribe:function(a){}}});d.Children={map:function(a,b,c){if(null==a)return a;var d=[];R(a,d,null,b,c);return d},forEach:function(a,b,c){if(null==a)return a;b=ja(null,null,b,c);Q(a,ya,b);ka(b)},count:function(a){return Q(a,function(){return null},null)},
|
|
toArray:function(a){var b=[];R(a,b,null,function(a){return a});return b},only:function(a){if(!N(a))throw Error(r(143));return a}};d.Component=w;d.Fragment=Aa;d.Profiler=Ca;d.PureComponent=L;d.StrictMode=Ba;d.Suspense=Ga;d.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=B;d.cloneElement=function(a,b,c){if(null===a||void 0===a)throw Error(r(267,a));var d=I({},a.props),e=a.key,f=a.ref,m=a._owner;if(null!=b){void 0!==b.ref&&(f=b.ref,m=M.current);void 0!==b.key&&(e=""+b.key);if(a.type&&a.type.defaultProps)var h=
|
|
a.type.defaultProps;for(k in b)ha.call(b,k)&&!ia.hasOwnProperty(k)&&(d[k]=void 0===b[k]&&void 0!==h?h[k]:b[k])}var k=arguments.length-2;if(1===k)d.children=c;else if(1<k){h=Array(k);for(var l=0;l<k;l++)h[l]=arguments[l+2];d.children=h}return{$$typeof:x,type:a.type,key:e,ref:f,props:d,_owner:m}};d.createContext=function(a,b){void 0===b&&(b=null);a={$$typeof:Ea,_calculateChangedBits:b,_currentValue:a,_currentValue2:a,_threadCount:0,Provider:null,Consumer:null};a.Provider={$$typeof:Da,_context:a};return a.Consumer=
|
|
a};d.createElement=ea;d.createFactory=function(a){var b=ea.bind(null,a);b.type=a;return b};d.createRef=function(){return{current:null}};d.forwardRef=function(a){return{$$typeof:Fa,render:a}};d.isValidElement=N;d.lazy=function(a){return{$$typeof:Ia,_ctor:a,_status:-1,_result:null}};d.memo=function(a,b){return{$$typeof:Ha,type:a,compare:void 0===b?null:b}};d.useCallback=function(a,b){return t().useCallback(a,b)};d.useContext=function(a,b){return t().useContext(a,b)};d.useDebugValue=function(a,b){};
|
|
d.useEffect=function(a,b){return t().useEffect(a,b)};d.useImperativeHandle=function(a,b,c){return t().useImperativeHandle(a,b,c)};d.useLayoutEffect=function(a,b){return t().useLayoutEffect(a,b)};d.useMemo=function(a,b){return t().useMemo(a,b)};d.useReducer=function(a,b,c){return t().useReducer(a,b,c)};d.useRef=function(a){return t().useRef(a)};d.useState=function(a){return t().useState(a)};d.version="16.13.1"});
|
|
</script>
|
|
<script crossorigin>/** @license React v16.13.1
|
|
* react-dom.production.min.js
|
|
*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
/*
|
|
Modernizr 3.0.0pre (Custom Build) | MIT
|
|
*/
|
|
'use strict';(function(I,ea){"object"===typeof exports&&"undefined"!==typeof module?ea(exports,require("react")):"function"===typeof define&&define.amd?define(["exports","react"],ea):(I=I||self,ea(I.ReactDOM={},I.React))})(this,function(I,ea){function k(a){for(var b="https://reactjs.org/docs/error-decoder.html?invariant="+a,c=1;c<arguments.length;c++)b+="&args[]="+encodeURIComponent(arguments[c]);return"Minified React error #"+a+"; visit "+b+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}
|
|
function ji(a,b,c,d,e,f,g,h,m){yb=!1;gc=null;ki.apply(li,arguments)}function mi(a,b,c,d,e,f,g,h,m){ji.apply(this,arguments);if(yb){if(yb){var n=gc;yb=!1;gc=null}else throw Error(k(198));hc||(hc=!0,pd=n)}}function lf(a,b,c){var d=a.type||"unknown-event";a.currentTarget=mf(c);mi(d,b,void 0,a);a.currentTarget=null}function nf(){if(ic)for(var a in cb){var b=cb[a],c=ic.indexOf(a);if(!(-1<c))throw Error(k(96,a));if(!jc[c]){if(!b.extractEvents)throw Error(k(97,a));jc[c]=b;c=b.eventTypes;for(var d in c){var e=
|
|
void 0;var f=c[d],g=b,h=d;if(qd.hasOwnProperty(h))throw Error(k(99,h));qd[h]=f;var m=f.phasedRegistrationNames;if(m){for(e in m)m.hasOwnProperty(e)&&of(m[e],g,h);e=!0}else f.registrationName?(of(f.registrationName,g,h),e=!0):e=!1;if(!e)throw Error(k(98,d,a));}}}}function of(a,b,c){if(db[a])throw Error(k(100,a));db[a]=b;rd[a]=b.eventTypes[c].dependencies}function pf(a){var b=!1,c;for(c in a)if(a.hasOwnProperty(c)){var d=a[c];if(!cb.hasOwnProperty(c)||cb[c]!==d){if(cb[c])throw Error(k(102,c));cb[c]=
|
|
d;b=!0}}b&&nf()}function qf(a){if(a=rf(a)){if("function"!==typeof sd)throw Error(k(280));var b=a.stateNode;b&&(b=td(b),sd(a.stateNode,a.type,b))}}function sf(a){eb?fb?fb.push(a):fb=[a]:eb=a}function tf(){if(eb){var a=eb,b=fb;fb=eb=null;qf(a);if(b)for(a=0;a<b.length;a++)qf(b[a])}}function ud(){if(null!==eb||null!==fb)vd(),tf()}function uf(a,b,c){if(wd)return a(b,c);wd=!0;try{return vf(a,b,c)}finally{wd=!1,ud()}}function ni(a){if(wf.call(xf,a))return!0;if(wf.call(yf,a))return!1;if(oi.test(a))return xf[a]=
|
|
!0;yf[a]=!0;return!1}function pi(a,b,c,d){if(null!==c&&0===c.type)return!1;switch(typeof b){case "function":case "symbol":return!0;case "boolean":if(d)return!1;if(null!==c)return!c.acceptsBooleans;a=a.toLowerCase().slice(0,5);return"data-"!==a&&"aria-"!==a;default:return!1}}function qi(a,b,c,d){if(null===b||"undefined"===typeof b||pi(a,b,c,d))return!0;if(d)return!1;if(null!==c)switch(c.type){case 3:return!b;case 4:return!1===b;case 5:return isNaN(b);case 6:return isNaN(b)||1>b}return!1}function L(a,
|
|
b,c,d,e,f){this.acceptsBooleans=2===b||3===b||4===b;this.attributeName=d;this.attributeNamespace=e;this.mustUseProperty=c;this.propertyName=a;this.type=b;this.sanitizeURL=f}function xd(a,b,c,d){var e=E.hasOwnProperty(b)?E[b]:null;var f=null!==e?0===e.type:d?!1:!(2<b.length)||"o"!==b[0]&&"O"!==b[0]||"n"!==b[1]&&"N"!==b[1]?!1:!0;f||(qi(b,c,e,d)&&(c=null),d||null===e?ni(b)&&(null===c?a.removeAttribute(b):a.setAttribute(b,""+c)):e.mustUseProperty?a[e.propertyName]=null===c?3===e.type?!1:"":c:(b=e.attributeName,
|
|
d=e.attributeNamespace,null===c?a.removeAttribute(b):(e=e.type,c=3===e||4===e&&!0===c?"":""+c,d?a.setAttributeNS(d,b,c):a.setAttribute(b,c))))}function zb(a){if(null===a||"object"!==typeof a)return null;a=zf&&a[zf]||a["@@iterator"];return"function"===typeof a?a:null}function ri(a){if(-1===a._status){a._status=0;var b=a._ctor;b=b();a._result=b;b.then(function(b){0===a._status&&(b=b.default,a._status=1,a._result=b)},function(b){0===a._status&&(a._status=2,a._result=b)})}}function na(a){if(null==a)return null;
|
|
if("function"===typeof a)return a.displayName||a.name||null;if("string"===typeof a)return a;switch(a){case Ma:return"Fragment";case gb:return"Portal";case kc:return"Profiler";case Af:return"StrictMode";case lc:return"Suspense";case yd:return"SuspenseList"}if("object"===typeof a)switch(a.$$typeof){case Bf:return"Context.Consumer";case Cf:return"Context.Provider";case zd:var b=a.render;b=b.displayName||b.name||"";return a.displayName||(""!==b?"ForwardRef("+b+")":"ForwardRef");case Ad:return na(a.type);
|
|
case Df:return na(a.render);case Ef:if(a=1===a._status?a._result:null)return na(a)}return null}function Bd(a){var b="";do{a:switch(a.tag){case 3:case 4:case 6:case 7:case 10:case 9:var c="";break a;default:var d=a._debugOwner,e=a._debugSource,f=na(a.type);c=null;d&&(c=na(d.type));d=f;f="";e?f=" (at "+e.fileName.replace(si,"")+":"+e.lineNumber+")":c&&(f=" (created by "+c+")");c="\n in "+(d||"Unknown")+f}b+=c;a=a.return}while(a);return b}function va(a){switch(typeof a){case "boolean":case "number":case "object":case "string":case "undefined":return a;
|
|
default:return""}}function Ff(a){var b=a.type;return(a=a.nodeName)&&"input"===a.toLowerCase()&&("checkbox"===b||"radio"===b)}function ti(a){var b=Ff(a)?"checked":"value",c=Object.getOwnPropertyDescriptor(a.constructor.prototype,b),d=""+a[b];if(!a.hasOwnProperty(b)&&"undefined"!==typeof c&&"function"===typeof c.get&&"function"===typeof c.set){var e=c.get,f=c.set;Object.defineProperty(a,b,{configurable:!0,get:function(){return e.call(this)},set:function(a){d=""+a;f.call(this,a)}});Object.defineProperty(a,
|
|
b,{enumerable:c.enumerable});return{getValue:function(){return d},setValue:function(a){d=""+a},stopTracking:function(){a._valueTracker=null;delete a[b]}}}}function mc(a){a._valueTracker||(a._valueTracker=ti(a))}function Gf(a){if(!a)return!1;var b=a._valueTracker;if(!b)return!0;var c=b.getValue();var d="";a&&(d=Ff(a)?a.checked?"true":"false":a.value);a=d;return a!==c?(b.setValue(a),!0):!1}function Cd(a,b){var c=b.checked;return M({},b,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:null!=
|
|
c?c:a._wrapperState.initialChecked})}function Hf(a,b){var c=null==b.defaultValue?"":b.defaultValue,d=null!=b.checked?b.checked:b.defaultChecked;c=va(null!=b.value?b.value:c);a._wrapperState={initialChecked:d,initialValue:c,controlled:"checkbox"===b.type||"radio"===b.type?null!=b.checked:null!=b.value}}function If(a,b){b=b.checked;null!=b&&xd(a,"checked",b,!1)}function Dd(a,b){If(a,b);var c=va(b.value),d=b.type;if(null!=c)if("number"===d){if(0===c&&""===a.value||a.value!=c)a.value=""+c}else a.value!==
|
|
""+c&&(a.value=""+c);else if("submit"===d||"reset"===d){a.removeAttribute("value");return}b.hasOwnProperty("value")?Ed(a,b.type,c):b.hasOwnProperty("defaultValue")&&Ed(a,b.type,va(b.defaultValue));null==b.checked&&null!=b.defaultChecked&&(a.defaultChecked=!!b.defaultChecked)}function Jf(a,b,c){if(b.hasOwnProperty("value")||b.hasOwnProperty("defaultValue")){var d=b.type;if(!("submit"!==d&&"reset"!==d||void 0!==b.value&&null!==b.value))return;b=""+a._wrapperState.initialValue;c||b===a.value||(a.value=
|
|
b);a.defaultValue=b}c=a.name;""!==c&&(a.name="");a.defaultChecked=!!a._wrapperState.initialChecked;""!==c&&(a.name=c)}function Ed(a,b,c){if("number"!==b||a.ownerDocument.activeElement!==a)null==c?a.defaultValue=""+a._wrapperState.initialValue:a.defaultValue!==""+c&&(a.defaultValue=""+c)}function ui(a){var b="";ea.Children.forEach(a,function(a){null!=a&&(b+=a)});return b}function Fd(a,b){a=M({children:void 0},b);if(b=ui(b.children))a.children=b;return a}function hb(a,b,c,d){a=a.options;if(b){b={};
|
|
for(var e=0;e<c.length;e++)b["$"+c[e]]=!0;for(c=0;c<a.length;c++)e=b.hasOwnProperty("$"+a[c].value),a[c].selected!==e&&(a[c].selected=e),e&&d&&(a[c].defaultSelected=!0)}else{c=""+va(c);b=null;for(e=0;e<a.length;e++){if(a[e].value===c){a[e].selected=!0;d&&(a[e].defaultSelected=!0);return}null!==b||a[e].disabled||(b=a[e])}null!==b&&(b.selected=!0)}}function Gd(a,b){if(null!=b.dangerouslySetInnerHTML)throw Error(k(91));return M({},b,{value:void 0,defaultValue:void 0,children:""+a._wrapperState.initialValue})}
|
|
function Kf(a,b){var c=b.value;if(null==c){c=b.children;b=b.defaultValue;if(null!=c){if(null!=b)throw Error(k(92));if(Array.isArray(c)){if(!(1>=c.length))throw Error(k(93));c=c[0]}b=c}null==b&&(b="");c=b}a._wrapperState={initialValue:va(c)}}function Lf(a,b){var c=va(b.value),d=va(b.defaultValue);null!=c&&(c=""+c,c!==a.value&&(a.value=c),null==b.defaultValue&&a.defaultValue!==c&&(a.defaultValue=c));null!=d&&(a.defaultValue=""+d)}function Mf(a,b){b=a.textContent;b===a._wrapperState.initialValue&&""!==
|
|
b&&null!==b&&(a.value=b)}function Nf(a){switch(a){case "svg":return"http://www.w3.org/2000/svg";case "math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function Hd(a,b){return null==a||"http://www.w3.org/1999/xhtml"===a?Nf(b):"http://www.w3.org/2000/svg"===a&&"foreignObject"===b?"http://www.w3.org/1999/xhtml":a}function nc(a,b){var c={};c[a.toLowerCase()]=b.toLowerCase();c["Webkit"+a]="webkit"+b;c["Moz"+a]="moz"+b;return c}function oc(a){if(Id[a])return Id[a];
|
|
if(!ib[a])return a;var b=ib[a],c;for(c in b)if(b.hasOwnProperty(c)&&c in Of)return Id[a]=b[c];return a}function Jd(a){var b=Pf.get(a);void 0===b&&(b=new Map,Pf.set(a,b));return b}function Na(a){var b=a,c=a;if(a.alternate)for(;b.return;)b=b.return;else{a=b;do b=a,0!==(b.effectTag&1026)&&(c=b.return),a=b.return;while(a)}return 3===b.tag?c:null}function Qf(a){if(13===a.tag){var b=a.memoizedState;null===b&&(a=a.alternate,null!==a&&(b=a.memoizedState));if(null!==b)return b.dehydrated}return null}function Rf(a){if(Na(a)!==
|
|
a)throw Error(k(188));}function vi(a){var b=a.alternate;if(!b){b=Na(a);if(null===b)throw Error(k(188));return b!==a?null:a}for(var c=a,d=b;;){var e=c.return;if(null===e)break;var f=e.alternate;if(null===f){d=e.return;if(null!==d){c=d;continue}break}if(e.child===f.child){for(f=e.child;f;){if(f===c)return Rf(e),a;if(f===d)return Rf(e),b;f=f.sibling}throw Error(k(188));}if(c.return!==d.return)c=e,d=f;else{for(var g=!1,h=e.child;h;){if(h===c){g=!0;c=e;d=f;break}if(h===d){g=!0;d=e;c=f;break}h=h.sibling}if(!g){for(h=
|
|
f.child;h;){if(h===c){g=!0;c=f;d=e;break}if(h===d){g=!0;d=f;c=e;break}h=h.sibling}if(!g)throw Error(k(189));}}if(c.alternate!==d)throw Error(k(190));}if(3!==c.tag)throw Error(k(188));return c.stateNode.current===c?a:b}function Sf(a){a=vi(a);if(!a)return null;for(var b=a;;){if(5===b.tag||6===b.tag)return b;if(b.child)b.child.return=b,b=b.child;else{if(b===a)break;for(;!b.sibling;){if(!b.return||b.return===a)return null;b=b.return}b.sibling.return=b.return;b=b.sibling}}return null}function jb(a,b){if(null==
|
|
b)throw Error(k(30));if(null==a)return b;if(Array.isArray(a)){if(Array.isArray(b))return a.push.apply(a,b),a;a.push(b);return a}return Array.isArray(b)?[a].concat(b):[a,b]}function Kd(a,b,c){Array.isArray(a)?a.forEach(b,c):a&&b.call(c,a)}function pc(a){null!==a&&(Ab=jb(Ab,a));a=Ab;Ab=null;if(a){Kd(a,wi);if(Ab)throw Error(k(95));if(hc)throw a=pd,hc=!1,pd=null,a;}}function Ld(a){a=a.target||a.srcElement||window;a.correspondingUseElement&&(a=a.correspondingUseElement);return 3===a.nodeType?a.parentNode:
|
|
a}function Tf(a){if(!wa)return!1;a="on"+a;var b=a in document;b||(b=document.createElement("div"),b.setAttribute(a,"return;"),b="function"===typeof b[a]);return b}function Uf(a){a.topLevelType=null;a.nativeEvent=null;a.targetInst=null;a.ancestors.length=0;10>qc.length&&qc.push(a)}function Vf(a,b,c,d){if(qc.length){var e=qc.pop();e.topLevelType=a;e.eventSystemFlags=d;e.nativeEvent=b;e.targetInst=c;return e}return{topLevelType:a,eventSystemFlags:d,nativeEvent:b,targetInst:c,ancestors:[]}}function Wf(a){var b=
|
|
a.targetInst,c=b;do{if(!c){a.ancestors.push(c);break}var d=c;if(3===d.tag)d=d.stateNode.containerInfo;else{for(;d.return;)d=d.return;d=3!==d.tag?null:d.stateNode.containerInfo}if(!d)break;b=c.tag;5!==b&&6!==b||a.ancestors.push(c);c=Bb(d)}while(c);for(c=0;c<a.ancestors.length;c++){b=a.ancestors[c];var e=Ld(a.nativeEvent);d=a.topLevelType;var f=a.nativeEvent,g=a.eventSystemFlags;0===c&&(g|=64);for(var h=null,m=0;m<jc.length;m++){var n=jc[m];n&&(n=n.extractEvents(d,b,f,e,g))&&(h=jb(h,n))}pc(h)}}function Md(a,
|
|
b,c){if(!c.has(a)){switch(a){case "scroll":Cb(b,"scroll",!0);break;case "focus":case "blur":Cb(b,"focus",!0);Cb(b,"blur",!0);c.set("blur",null);c.set("focus",null);break;case "cancel":case "close":Tf(a)&&Cb(b,a,!0);break;case "invalid":case "submit":case "reset":break;default:-1===Db.indexOf(a)&&w(a,b)}c.set(a,null)}}function xi(a,b){var c=Jd(b);Nd.forEach(function(a){Md(a,b,c)});yi.forEach(function(a){Md(a,b,c)})}function Od(a,b,c,d,e){return{blockedOn:a,topLevelType:b,eventSystemFlags:c|32,nativeEvent:e,
|
|
container:d}}function Xf(a,b){switch(a){case "focus":case "blur":xa=null;break;case "dragenter":case "dragleave":ya=null;break;case "mouseover":case "mouseout":za=null;break;case "pointerover":case "pointerout":Eb.delete(b.pointerId);break;case "gotpointercapture":case "lostpointercapture":Fb.delete(b.pointerId)}}function Gb(a,b,c,d,e,f){if(null===a||a.nativeEvent!==f)return a=Od(b,c,d,e,f),null!==b&&(b=Hb(b),null!==b&&Yf(b)),a;a.eventSystemFlags|=d;return a}function zi(a,b,c,d,e){switch(b){case "focus":return xa=
|
|
Gb(xa,a,b,c,d,e),!0;case "dragenter":return ya=Gb(ya,a,b,c,d,e),!0;case "mouseover":return za=Gb(za,a,b,c,d,e),!0;case "pointerover":var f=e.pointerId;Eb.set(f,Gb(Eb.get(f)||null,a,b,c,d,e));return!0;case "gotpointercapture":return f=e.pointerId,Fb.set(f,Gb(Fb.get(f)||null,a,b,c,d,e)),!0}return!1}function Ai(a){var b=Bb(a.target);if(null!==b){var c=Na(b);if(null!==c)if(b=c.tag,13===b){if(b=Qf(c),null!==b){a.blockedOn=b;Pd(a.priority,function(){Bi(c)});return}}else if(3===b&&c.stateNode.hydrate){a.blockedOn=
|
|
3===c.tag?c.stateNode.containerInfo:null;return}}a.blockedOn=null}function rc(a){if(null!==a.blockedOn)return!1;var b=Qd(a.topLevelType,a.eventSystemFlags,a.container,a.nativeEvent);if(null!==b){var c=Hb(b);null!==c&&Yf(c);a.blockedOn=b;return!1}return!0}function Zf(a,b,c){rc(a)&&c.delete(b)}function Ci(){for(Rd=!1;0<fa.length;){var a=fa[0];if(null!==a.blockedOn){a=Hb(a.blockedOn);null!==a&&Di(a);break}var b=Qd(a.topLevelType,a.eventSystemFlags,a.container,a.nativeEvent);null!==b?a.blockedOn=b:fa.shift()}null!==
|
|
xa&&rc(xa)&&(xa=null);null!==ya&&rc(ya)&&(ya=null);null!==za&&rc(za)&&(za=null);Eb.forEach(Zf);Fb.forEach(Zf)}function Ib(a,b){a.blockedOn===b&&(a.blockedOn=null,Rd||(Rd=!0,$f(ag,Ci)))}function bg(a){if(0<fa.length){Ib(fa[0],a);for(var b=1;b<fa.length;b++){var c=fa[b];c.blockedOn===a&&(c.blockedOn=null)}}null!==xa&&Ib(xa,a);null!==ya&&Ib(ya,a);null!==za&&Ib(za,a);b=function(b){return Ib(b,a)};Eb.forEach(b);Fb.forEach(b);for(b=0;b<Jb.length;b++)c=Jb[b],c.blockedOn===a&&(c.blockedOn=null);for(;0<Jb.length&&
|
|
(b=Jb[0],null===b.blockedOn);)Ai(b),null===b.blockedOn&&Jb.shift()}function Sd(a,b){for(var c=0;c<a.length;c+=2){var d=a[c],e=a[c+1],f="on"+(e[0].toUpperCase()+e.slice(1));f={phasedRegistrationNames:{bubbled:f,captured:f+"Capture"},dependencies:[d],eventPriority:b};Td.set(d,b);cg.set(d,f);dg[e]=f}}function w(a,b){Cb(b,a,!1)}function Cb(a,b,c){var d=Td.get(b);switch(void 0===d?2:d){case 0:d=Ei.bind(null,b,1,a);break;case 1:d=Fi.bind(null,b,1,a);break;default:d=sc.bind(null,b,1,a)}c?a.addEventListener(b,
|
|
d,!0):a.addEventListener(b,d,!1)}function Ei(a,b,c,d){Oa||vd();var e=sc,f=Oa;Oa=!0;try{eg(e,a,b,c,d)}finally{(Oa=f)||ud()}}function Fi(a,b,c,d){Gi(Hi,sc.bind(null,a,b,c,d))}function sc(a,b,c,d){if(tc)if(0<fa.length&&-1<Nd.indexOf(a))a=Od(null,a,b,c,d),fa.push(a);else{var e=Qd(a,b,c,d);if(null===e)Xf(a,d);else if(-1<Nd.indexOf(a))a=Od(e,a,b,c,d),fa.push(a);else if(!zi(e,a,b,c,d)){Xf(a,d);a=Vf(a,d,null,b);try{uf(Wf,a)}finally{Uf(a)}}}}function Qd(a,b,c,d){c=Ld(d);c=Bb(c);if(null!==c){var e=Na(c);if(null===
|
|
e)c=null;else{var f=e.tag;if(13===f){c=Qf(e);if(null!==c)return c;c=null}else if(3===f){if(e.stateNode.hydrate)return 3===e.tag?e.stateNode.containerInfo:null;c=null}else e!==c&&(c=null)}}a=Vf(a,d,c,b);try{uf(Wf,a)}finally{Uf(a)}return null}function fg(a,b,c){return null==b||"boolean"===typeof b||""===b?"":c||"number"!==typeof b||0===b||Kb.hasOwnProperty(a)&&Kb[a]?(""+b).trim():b+"px"}function gg(a,b){a=a.style;for(var c in b)if(b.hasOwnProperty(c)){var d=0===c.indexOf("--"),e=fg(c,b[c],d);"float"===
|
|
c&&(c="cssFloat");d?a.setProperty(c,e):a[c]=e}}function Ud(a,b){if(b){if(Ii[a]&&(null!=b.children||null!=b.dangerouslySetInnerHTML))throw Error(k(137,a,""));if(null!=b.dangerouslySetInnerHTML){if(null!=b.children)throw Error(k(60));if(!("object"===typeof b.dangerouslySetInnerHTML&&"__html"in b.dangerouslySetInnerHTML))throw Error(k(61));}if(null!=b.style&&"object"!==typeof b.style)throw Error(k(62,""));}}function Vd(a,b){if(-1===a.indexOf("-"))return"string"===typeof b.is;switch(a){case "annotation-xml":case "color-profile":case "font-face":case "font-face-src":case "font-face-uri":case "font-face-format":case "font-face-name":case "missing-glyph":return!1;
|
|
default:return!0}}function oa(a,b){a=9===a.nodeType||11===a.nodeType?a:a.ownerDocument;var c=Jd(a);b=rd[b];for(var d=0;d<b.length;d++)Md(b[d],a,c)}function uc(){}function Wd(a){a=a||("undefined"!==typeof document?document:void 0);if("undefined"===typeof a)return null;try{return a.activeElement||a.body}catch(b){return a.body}}function hg(a){for(;a&&a.firstChild;)a=a.firstChild;return a}function ig(a,b){var c=hg(a);a=0;for(var d;c;){if(3===c.nodeType){d=a+c.textContent.length;if(a<=b&&d>=b)return{node:c,
|
|
offset:b-a};a=d}a:{for(;c;){if(c.nextSibling){c=c.nextSibling;break a}c=c.parentNode}c=void 0}c=hg(c)}}function jg(a,b){return a&&b?a===b?!0:a&&3===a.nodeType?!1:b&&3===b.nodeType?jg(a,b.parentNode):"contains"in a?a.contains(b):a.compareDocumentPosition?!!(a.compareDocumentPosition(b)&16):!1:!1}function kg(){for(var a=window,b=Wd();b instanceof a.HTMLIFrameElement;){try{var c="string"===typeof b.contentWindow.location.href}catch(d){c=!1}if(c)a=b.contentWindow;else break;b=Wd(a.document)}return b}
|
|
function Xd(a){var b=a&&a.nodeName&&a.nodeName.toLowerCase();return b&&("input"===b&&("text"===a.type||"search"===a.type||"tel"===a.type||"url"===a.type||"password"===a.type)||"textarea"===b||"true"===a.contentEditable)}function lg(a,b){switch(a){case "button":case "input":case "select":case "textarea":return!!b.autoFocus}return!1}function Yd(a,b){return"textarea"===a||"option"===a||"noscript"===a||"string"===typeof b.children||"number"===typeof b.children||"object"===typeof b.dangerouslySetInnerHTML&&
|
|
null!==b.dangerouslySetInnerHTML&&null!=b.dangerouslySetInnerHTML.__html}function kb(a){for(;null!=a;a=a.nextSibling){var b=a.nodeType;if(1===b||3===b)break}return a}function mg(a){a=a.previousSibling;for(var b=0;a;){if(8===a.nodeType){var c=a.data;if(c===ng||c===Zd||c===$d){if(0===b)return a;b--}else c===og&&b++}a=a.previousSibling}return null}function Bb(a){var b=a[Aa];if(b)return b;for(var c=a.parentNode;c;){if(b=c[Lb]||c[Aa]){c=b.alternate;if(null!==b.child||null!==c&&null!==c.child)for(a=mg(a);null!==
|
|
a;){if(c=a[Aa])return c;a=mg(a)}return b}a=c;c=a.parentNode}return null}function Hb(a){a=a[Aa]||a[Lb];return!a||5!==a.tag&&6!==a.tag&&13!==a.tag&&3!==a.tag?null:a}function Pa(a){if(5===a.tag||6===a.tag)return a.stateNode;throw Error(k(33));}function ae(a){return a[vc]||null}function pa(a){do a=a.return;while(a&&5!==a.tag);return a?a:null}function pg(a,b){var c=a.stateNode;if(!c)return null;var d=td(c);if(!d)return null;c=d[b];a:switch(b){case "onClick":case "onClickCapture":case "onDoubleClick":case "onDoubleClickCapture":case "onMouseDown":case "onMouseDownCapture":case "onMouseMove":case "onMouseMoveCapture":case "onMouseUp":case "onMouseUpCapture":case "onMouseEnter":(d=
|
|
!d.disabled)||(a=a.type,d=!("button"===a||"input"===a||"select"===a||"textarea"===a));a=!d;break a;default:a=!1}if(a)return null;if(c&&"function"!==typeof c)throw Error(k(231,b,typeof c));return c}function qg(a,b,c){if(b=pg(a,c.dispatchConfig.phasedRegistrationNames[b]))c._dispatchListeners=jb(c._dispatchListeners,b),c._dispatchInstances=jb(c._dispatchInstances,a)}function Ji(a){if(a&&a.dispatchConfig.phasedRegistrationNames){for(var b=a._targetInst,c=[];b;)c.push(b),b=pa(b);for(b=c.length;0<b--;)qg(c[b],
|
|
"captured",a);for(b=0;b<c.length;b++)qg(c[b],"bubbled",a)}}function be(a,b,c){a&&c&&c.dispatchConfig.registrationName&&(b=pg(a,c.dispatchConfig.registrationName))&&(c._dispatchListeners=jb(c._dispatchListeners,b),c._dispatchInstances=jb(c._dispatchInstances,a))}function Ki(a){a&&a.dispatchConfig.registrationName&&be(a._targetInst,null,a)}function lb(a){Kd(a,Ji)}function rg(){if(wc)return wc;var a,b=ce,c=b.length,d,e="value"in Ba?Ba.value:Ba.textContent,f=e.length;for(a=0;a<c&&b[a]===e[a];a++);var g=
|
|
c-a;for(d=1;d<=g&&b[c-d]===e[f-d];d++);return wc=e.slice(a,1<d?1-d:void 0)}function xc(){return!0}function yc(){return!1}function R(a,b,c,d){this.dispatchConfig=a;this._targetInst=b;this.nativeEvent=c;a=this.constructor.Interface;for(var e in a)a.hasOwnProperty(e)&&((b=a[e])?this[e]=b(c):"target"===e?this.target=d:this[e]=c[e]);this.isDefaultPrevented=(null!=c.defaultPrevented?c.defaultPrevented:!1===c.returnValue)?xc:yc;this.isPropagationStopped=yc;return this}function Li(a,b,c,d){if(this.eventPool.length){var e=
|
|
this.eventPool.pop();this.call(e,a,b,c,d);return e}return new this(a,b,c,d)}function Mi(a){if(!(a instanceof this))throw Error(k(279));a.destructor();10>this.eventPool.length&&this.eventPool.push(a)}function sg(a){a.eventPool=[];a.getPooled=Li;a.release=Mi}function tg(a,b){switch(a){case "keyup":return-1!==Ni.indexOf(b.keyCode);case "keydown":return 229!==b.keyCode;case "keypress":case "mousedown":case "blur":return!0;default:return!1}}function ug(a){a=a.detail;return"object"===typeof a&&"data"in
|
|
a?a.data:null}function Oi(a,b){switch(a){case "compositionend":return ug(b);case "keypress":if(32!==b.which)return null;vg=!0;return wg;case "textInput":return a=b.data,a===wg&&vg?null:a;default:return null}}function Pi(a,b){if(mb)return"compositionend"===a||!de&&tg(a,b)?(a=rg(),wc=ce=Ba=null,mb=!1,a):null;switch(a){case "paste":return null;case "keypress":if(!(b.ctrlKey||b.altKey||b.metaKey)||b.ctrlKey&&b.altKey){if(b.char&&1<b.char.length)return b.char;if(b.which)return String.fromCharCode(b.which)}return null;
|
|
case "compositionend":return xg&&"ko"!==b.locale?null:b.data;default:return null}}function yg(a){var b=a&&a.nodeName&&a.nodeName.toLowerCase();return"input"===b?!!Qi[a.type]:"textarea"===b?!0:!1}function zg(a,b,c){a=R.getPooled(Ag.change,a,b,c);a.type="change";sf(c);lb(a);return a}function Ri(a){pc(a)}function zc(a){var b=Pa(a);if(Gf(b))return a}function Si(a,b){if("change"===a)return b}function Bg(){Mb&&(Mb.detachEvent("onpropertychange",Cg),Nb=Mb=null)}function Cg(a){if("value"===a.propertyName&&
|
|
zc(Nb))if(a=zg(Nb,a,Ld(a)),Oa)pc(a);else{Oa=!0;try{ee(Ri,a)}finally{Oa=!1,ud()}}}function Ti(a,b,c){"focus"===a?(Bg(),Mb=b,Nb=c,Mb.attachEvent("onpropertychange",Cg)):"blur"===a&&Bg()}function Ui(a,b){if("selectionchange"===a||"keyup"===a||"keydown"===a)return zc(Nb)}function Vi(a,b){if("click"===a)return zc(b)}function Wi(a,b){if("input"===a||"change"===a)return zc(b)}function Xi(a){var b=this.nativeEvent;return b.getModifierState?b.getModifierState(a):(a=Yi[a])?!!b[a]:!1}function fe(a){return Xi}
|
|
function Zi(a,b){return a===b&&(0!==a||1/a===1/b)||a!==a&&b!==b}function Ob(a,b){if(Qa(a,b))return!0;if("object"!==typeof a||null===a||"object"!==typeof b||null===b)return!1;var c=Object.keys(a),d=Object.keys(b);if(c.length!==d.length)return!1;for(d=0;d<c.length;d++)if(!$i.call(b,c[d])||!Qa(a[c[d]],b[c[d]]))return!1;return!0}function Dg(a,b){var c=b.window===b?b.document:9===b.nodeType?b:b.ownerDocument;if(ge||null==nb||nb!==Wd(c))return null;c=nb;"selectionStart"in c&&Xd(c)?c={start:c.selectionStart,
|
|
end:c.selectionEnd}:(c=(c.ownerDocument&&c.ownerDocument.defaultView||window).getSelection(),c={anchorNode:c.anchorNode,anchorOffset:c.anchorOffset,focusNode:c.focusNode,focusOffset:c.focusOffset});return Pb&&Ob(Pb,c)?null:(Pb=c,a=R.getPooled(Eg.select,he,a,b),a.type="select",a.target=nb,lb(a),a)}function Ac(a){var b=a.keyCode;"charCode"in a?(a=a.charCode,0===a&&13===b&&(a=13)):a=b;10===a&&(a=13);return 32<=a||13===a?a:0}function q(a,b){0>ob||(a.current=ie[ob],ie[ob]=null,ob--)}function y(a,b,c){ob++;
|
|
ie[ob]=a.current;a.current=b}function pb(a,b){var c=a.type.contextTypes;if(!c)return Ca;var d=a.stateNode;if(d&&d.__reactInternalMemoizedUnmaskedChildContext===b)return d.__reactInternalMemoizedMaskedChildContext;var e={},f;for(f in c)e[f]=b[f];d&&(a=a.stateNode,a.__reactInternalMemoizedUnmaskedChildContext=b,a.__reactInternalMemoizedMaskedChildContext=e);return e}function N(a){a=a.childContextTypes;return null!==a&&void 0!==a}function Fg(a,b,c){if(B.current!==Ca)throw Error(k(168));y(B,b);y(G,c)}
|
|
function Gg(a,b,c){var d=a.stateNode;a=b.childContextTypes;if("function"!==typeof d.getChildContext)return c;d=d.getChildContext();for(var e in d)if(!(e in a))throw Error(k(108,na(b)||"Unknown",e));return M({},c,{},d)}function Bc(a){a=(a=a.stateNode)&&a.__reactInternalMemoizedMergedChildContext||Ca;Ra=B.current;y(B,a);y(G,G.current);return!0}function Hg(a,b,c){var d=a.stateNode;if(!d)throw Error(k(169));c?(a=Gg(a,b,Ra),d.__reactInternalMemoizedMergedChildContext=a,q(G),q(B),y(B,a)):q(G);y(G,c)}function Cc(){switch(aj()){case Dc:return 99;
|
|
case Ig:return 98;case Jg:return 97;case Kg:return 96;case Lg:return 95;default:throw Error(k(332));}}function Mg(a){switch(a){case 99:return Dc;case 98:return Ig;case 97:return Jg;case 96:return Kg;case 95:return Lg;default:throw Error(k(332));}}function Da(a,b){a=Mg(a);return bj(a,b)}function Ng(a,b,c){a=Mg(a);return je(a,b,c)}function Og(a){null===qa?(qa=[a],Ec=je(Dc,Pg)):qa.push(a);return Qg}function ha(){if(null!==Ec){var a=Ec;Ec=null;Rg(a)}Pg()}function Pg(){if(!ke&&null!==qa){ke=!0;var a=0;
|
|
try{var b=qa;Da(99,function(){for(;a<b.length;a++){var c=b[a];do c=c(!0);while(null!==c)}});qa=null}catch(c){throw null!==qa&&(qa=qa.slice(a+1)),je(Dc,ha),c;}finally{ke=!1}}}function Fc(a,b,c){c/=10;return 1073741821-(((1073741821-a+b/10)/c|0)+1)*c}function aa(a,b){if(a&&a.defaultProps){b=M({},b);a=a.defaultProps;for(var c in a)void 0===b[c]&&(b[c]=a[c])}return b}function le(){Gc=qb=Hc=null}function me(a){var b=Ic.current;q(Ic);a.type._context._currentValue=b}function Sg(a,b){for(;null!==a;){var c=
|
|
a.alternate;if(a.childExpirationTime<b)a.childExpirationTime=b,null!==c&&c.childExpirationTime<b&&(c.childExpirationTime=b);else if(null!==c&&c.childExpirationTime<b)c.childExpirationTime=b;else break;a=a.return}}function rb(a,b){Hc=a;Gc=qb=null;a=a.dependencies;null!==a&&null!==a.firstContext&&(a.expirationTime>=b&&(ia=!0),a.firstContext=null)}function W(a,b){if(Gc!==a&&!1!==b&&0!==b){if("number"!==typeof b||1073741823===b)Gc=a,b=1073741823;b={context:a,observedBits:b,next:null};if(null===qb){if(null===
|
|
Hc)throw Error(k(308));qb=b;Hc.dependencies={expirationTime:0,firstContext:b,responders:null}}else qb=qb.next=b}return a._currentValue}function ne(a){a.updateQueue={baseState:a.memoizedState,baseQueue:null,shared:{pending:null},effects:null}}function oe(a,b){a=a.updateQueue;b.updateQueue===a&&(b.updateQueue={baseState:a.baseState,baseQueue:a.baseQueue,shared:a.shared,effects:a.effects})}function Ea(a,b){a={expirationTime:a,suspenseConfig:b,tag:Tg,payload:null,callback:null,next:null};return a.next=
|
|
a}function Fa(a,b){a=a.updateQueue;if(null!==a){a=a.shared;var c=a.pending;null===c?b.next=b:(b.next=c.next,c.next=b);a.pending=b}}function Ug(a,b){var c=a.alternate;null!==c&&oe(c,a);a=a.updateQueue;c=a.baseQueue;null===c?(a.baseQueue=b.next=b,b.next=b):(b.next=c.next,c.next=b)}function Qb(a,b,c,d){var e=a.updateQueue;Ga=!1;var f=e.baseQueue,g=e.shared.pending;if(null!==g){if(null!==f){var h=f.next;f.next=g.next;g.next=h}f=g;e.shared.pending=null;h=a.alternate;null!==h&&(h=h.updateQueue,null!==h&&
|
|
(h.baseQueue=g))}if(null!==f){h=f.next;var m=e.baseState,n=0,k=null,ba=null,l=null;if(null!==h){var p=h;do{g=p.expirationTime;if(g<d){var t={expirationTime:p.expirationTime,suspenseConfig:p.suspenseConfig,tag:p.tag,payload:p.payload,callback:p.callback,next:null};null===l?(ba=l=t,k=m):l=l.next=t;g>n&&(n=g)}else{null!==l&&(l=l.next={expirationTime:1073741823,suspenseConfig:p.suspenseConfig,tag:p.tag,payload:p.payload,callback:p.callback,next:null});Vg(g,p.suspenseConfig);a:{var q=a,r=p;g=b;t=c;switch(r.tag){case 1:q=
|
|
r.payload;if("function"===typeof q){m=q.call(t,m,g);break a}m=q;break a;case 3:q.effectTag=q.effectTag&-4097|64;case Tg:q=r.payload;g="function"===typeof q?q.call(t,m,g):q;if(null===g||void 0===g)break a;m=M({},m,g);break a;case Jc:Ga=!0}}null!==p.callback&&(a.effectTag|=32,g=e.effects,null===g?e.effects=[p]:g.push(p))}p=p.next;if(null===p||p===h)if(g=e.shared.pending,null===g)break;else p=f.next=g.next,g.next=h,e.baseQueue=f=g,e.shared.pending=null}while(1)}null===l?k=m:l.next=ba;e.baseState=k;e.baseQueue=
|
|
l;Kc(n);a.expirationTime=n;a.memoizedState=m}}function Wg(a,b,c){a=b.effects;b.effects=null;if(null!==a)for(b=0;b<a.length;b++){var d=a[b],e=d.callback;if(null!==e){d.callback=null;d=e;e=c;if("function"!==typeof d)throw Error(k(191,d));d.call(e)}}}function Lc(a,b,c,d){b=a.memoizedState;c=c(d,b);c=null===c||void 0===c?b:M({},b,c);a.memoizedState=c;0===a.expirationTime&&(a.updateQueue.baseState=c)}function Xg(a,b,c,d,e,f,g){a=a.stateNode;return"function"===typeof a.shouldComponentUpdate?a.shouldComponentUpdate(d,
|
|
f,g):b.prototype&&b.prototype.isPureReactComponent?!Ob(c,d)||!Ob(e,f):!0}function Yg(a,b,c){var d=!1,e=Ca;var f=b.contextType;"object"===typeof f&&null!==f?f=W(f):(e=N(b)?Ra:B.current,d=b.contextTypes,f=(d=null!==d&&void 0!==d)?pb(a,e):Ca);b=new b(c,f);a.memoizedState=null!==b.state&&void 0!==b.state?b.state:null;b.updater=Mc;a.stateNode=b;b._reactInternalFiber=a;d&&(a=a.stateNode,a.__reactInternalMemoizedUnmaskedChildContext=e,a.__reactInternalMemoizedMaskedChildContext=f);return b}function Zg(a,
|
|
b,c,d){a=b.state;"function"===typeof b.componentWillReceiveProps&&b.componentWillReceiveProps(c,d);"function"===typeof b.UNSAFE_componentWillReceiveProps&&b.UNSAFE_componentWillReceiveProps(c,d);b.state!==a&&Mc.enqueueReplaceState(b,b.state,null)}function pe(a,b,c,d){var e=a.stateNode;e.props=c;e.state=a.memoizedState;e.refs=$g;ne(a);var f=b.contextType;"object"===typeof f&&null!==f?e.context=W(f):(f=N(b)?Ra:B.current,e.context=pb(a,f));Qb(a,c,e,d);e.state=a.memoizedState;f=b.getDerivedStateFromProps;
|
|
"function"===typeof f&&(Lc(a,b,f,c),e.state=a.memoizedState);"function"===typeof b.getDerivedStateFromProps||"function"===typeof e.getSnapshotBeforeUpdate||"function"!==typeof e.UNSAFE_componentWillMount&&"function"!==typeof e.componentWillMount||(b=e.state,"function"===typeof e.componentWillMount&&e.componentWillMount(),"function"===typeof e.UNSAFE_componentWillMount&&e.UNSAFE_componentWillMount(),b!==e.state&&Mc.enqueueReplaceState(e,e.state,null),Qb(a,c,e,d),e.state=a.memoizedState);"function"===
|
|
typeof e.componentDidMount&&(a.effectTag|=4)}function Rb(a,b,c){a=c.ref;if(null!==a&&"function"!==typeof a&&"object"!==typeof a){if(c._owner){c=c._owner;if(c){if(1!==c.tag)throw Error(k(309));var d=c.stateNode}if(!d)throw Error(k(147,a));var e=""+a;if(null!==b&&null!==b.ref&&"function"===typeof b.ref&&b.ref._stringRef===e)return b.ref;b=function(a){var b=d.refs;b===$g&&(b=d.refs={});null===a?delete b[e]:b[e]=a};b._stringRef=e;return b}if("string"!==typeof a)throw Error(k(284));if(!c._owner)throw Error(k(290,
|
|
a));}return a}function Nc(a,b){if("textarea"!==a.type)throw Error(k(31,"[object Object]"===Object.prototype.toString.call(b)?"object with keys {"+Object.keys(b).join(", ")+"}":b,""));}function ah(a){function b(b,c){if(a){var d=b.lastEffect;null!==d?(d.nextEffect=c,b.lastEffect=c):b.firstEffect=b.lastEffect=c;c.nextEffect=null;c.effectTag=8}}function c(c,d){if(!a)return null;for(;null!==d;)b(c,d),d=d.sibling;return null}function d(a,b){for(a=new Map;null!==b;)null!==b.key?a.set(b.key,b):a.set(b.index,
|
|
b),b=b.sibling;return a}function e(a,b){a=Sa(a,b);a.index=0;a.sibling=null;return a}function f(b,c,d){b.index=d;if(!a)return c;d=b.alternate;if(null!==d)return d=d.index,d<c?(b.effectTag=2,c):d;b.effectTag=2;return c}function g(b){a&&null===b.alternate&&(b.effectTag=2);return b}function h(a,b,c,d){if(null===b||6!==b.tag)return b=qe(c,a.mode,d),b.return=a,b;b=e(b,c);b.return=a;return b}function m(a,b,c,d){if(null!==b&&b.elementType===c.type)return d=e(b,c.props),d.ref=Rb(a,b,c),d.return=a,d;d=Oc(c.type,
|
|
c.key,c.props,null,a.mode,d);d.ref=Rb(a,b,c);d.return=a;return d}function n(a,b,c,d){if(null===b||4!==b.tag||b.stateNode.containerInfo!==c.containerInfo||b.stateNode.implementation!==c.implementation)return b=re(c,a.mode,d),b.return=a,b;b=e(b,c.children||[]);b.return=a;return b}function l(a,b,c,d,f){if(null===b||7!==b.tag)return b=Ha(c,a.mode,d,f),b.return=a,b;b=e(b,c);b.return=a;return b}function ba(a,b,c){if("string"===typeof b||"number"===typeof b)return b=qe(""+b,a.mode,c),b.return=a,b;if("object"===
|
|
typeof b&&null!==b){switch(b.$$typeof){case Pc:return c=Oc(b.type,b.key,b.props,null,a.mode,c),c.ref=Rb(a,null,b),c.return=a,c;case gb:return b=re(b,a.mode,c),b.return=a,b}if(Qc(b)||zb(b))return b=Ha(b,a.mode,c,null),b.return=a,b;Nc(a,b)}return null}function p(a,b,c,d){var e=null!==b?b.key:null;if("string"===typeof c||"number"===typeof c)return null!==e?null:h(a,b,""+c,d);if("object"===typeof c&&null!==c){switch(c.$$typeof){case Pc:return c.key===e?c.type===Ma?l(a,b,c.props.children,d,e):m(a,b,c,
|
|
d):null;case gb:return c.key===e?n(a,b,c,d):null}if(Qc(c)||zb(c))return null!==e?null:l(a,b,c,d,null);Nc(a,c)}return null}function t(a,b,c,d,e){if("string"===typeof d||"number"===typeof d)return a=a.get(c)||null,h(b,a,""+d,e);if("object"===typeof d&&null!==d){switch(d.$$typeof){case Pc:return a=a.get(null===d.key?c:d.key)||null,d.type===Ma?l(b,a,d.props.children,e,d.key):m(b,a,d,e);case gb:return a=a.get(null===d.key?c:d.key)||null,n(b,a,d,e)}if(Qc(d)||zb(d))return a=a.get(c)||null,l(b,a,d,e,null);
|
|
Nc(b,d)}return null}function q(e,g,h,m){for(var n=null,k=null,l=g,r=g=0,C=null;null!==l&&r<h.length;r++){l.index>r?(C=l,l=null):C=l.sibling;var O=p(e,l,h[r],m);if(null===O){null===l&&(l=C);break}a&&l&&null===O.alternate&&b(e,l);g=f(O,g,r);null===k?n=O:k.sibling=O;k=O;l=C}if(r===h.length)return c(e,l),n;if(null===l){for(;r<h.length;r++)l=ba(e,h[r],m),null!==l&&(g=f(l,g,r),null===k?n=l:k.sibling=l,k=l);return n}for(l=d(e,l);r<h.length;r++)C=t(l,e,r,h[r],m),null!==C&&(a&&null!==C.alternate&&l.delete(null===
|
|
C.key?r:C.key),g=f(C,g,r),null===k?n=C:k.sibling=C,k=C);a&&l.forEach(function(a){return b(e,a)});return n}function w(e,g,h,n){var m=zb(h);if("function"!==typeof m)throw Error(k(150));h=m.call(h);if(null==h)throw Error(k(151));for(var l=m=null,r=g,C=g=0,O=null,v=h.next();null!==r&&!v.done;C++,v=h.next()){r.index>C?(O=r,r=null):O=r.sibling;var q=p(e,r,v.value,n);if(null===q){null===r&&(r=O);break}a&&r&&null===q.alternate&&b(e,r);g=f(q,g,C);null===l?m=q:l.sibling=q;l=q;r=O}if(v.done)return c(e,r),m;
|
|
if(null===r){for(;!v.done;C++,v=h.next())v=ba(e,v.value,n),null!==v&&(g=f(v,g,C),null===l?m=v:l.sibling=v,l=v);return m}for(r=d(e,r);!v.done;C++,v=h.next())v=t(r,e,C,v.value,n),null!==v&&(a&&null!==v.alternate&&r.delete(null===v.key?C:v.key),g=f(v,g,C),null===l?m=v:l.sibling=v,l=v);a&&r.forEach(function(a){return b(e,a)});return m}return function(a,d,f,h){var m="object"===typeof f&&null!==f&&f.type===Ma&&null===f.key;m&&(f=f.props.children);var n="object"===typeof f&&null!==f;if(n)switch(f.$$typeof){case Pc:a:{n=
|
|
f.key;for(m=d;null!==m;){if(m.key===n){switch(m.tag){case 7:if(f.type===Ma){c(a,m.sibling);d=e(m,f.props.children);d.return=a;a=d;break a}break;default:if(m.elementType===f.type){c(a,m.sibling);d=e(m,f.props);d.ref=Rb(a,m,f);d.return=a;a=d;break a}}c(a,m);break}else b(a,m);m=m.sibling}f.type===Ma?(d=Ha(f.props.children,a.mode,h,f.key),d.return=a,a=d):(h=Oc(f.type,f.key,f.props,null,a.mode,h),h.ref=Rb(a,d,f),h.return=a,a=h)}return g(a);case gb:a:{for(m=f.key;null!==d;){if(d.key===m)if(4===d.tag&&d.stateNode.containerInfo===
|
|
f.containerInfo&&d.stateNode.implementation===f.implementation){c(a,d.sibling);d=e(d,f.children||[]);d.return=a;a=d;break a}else{c(a,d);break}else b(a,d);d=d.sibling}d=re(f,a.mode,h);d.return=a;a=d}return g(a)}if("string"===typeof f||"number"===typeof f)return f=""+f,null!==d&&6===d.tag?(c(a,d.sibling),d=e(d,f),d.return=a,a=d):(c(a,d),d=qe(f,a.mode,h),d.return=a,a=d),g(a);if(Qc(f))return q(a,d,f,h);if(zb(f))return w(a,d,f,h);n&&Nc(a,f);if("undefined"===typeof f&&!m)switch(a.tag){case 1:case 0:throw a=
|
|
a.type,Error(k(152,a.displayName||a.name||"Component"));}return c(a,d)}}function Ta(a){if(a===Sb)throw Error(k(174));return a}function se(a,b){y(Tb,b);y(Ub,a);y(ja,Sb);a=b.nodeType;switch(a){case 9:case 11:b=(b=b.documentElement)?b.namespaceURI:Hd(null,"");break;default:a=8===a?b.parentNode:b,b=a.namespaceURI||null,a=a.tagName,b=Hd(b,a)}q(ja);y(ja,b)}function tb(a){q(ja);q(Ub);q(Tb)}function bh(a){Ta(Tb.current);var b=Ta(ja.current);var c=Hd(b,a.type);b!==c&&(y(Ub,a),y(ja,c))}function te(a){Ub.current===
|
|
a&&(q(ja),q(Ub))}function Rc(a){for(var b=a;null!==b;){if(13===b.tag){var c=b.memoizedState;if(null!==c&&(c=c.dehydrated,null===c||c.data===$d||c.data===Zd))return b}else if(19===b.tag&&void 0!==b.memoizedProps.revealOrder){if(0!==(b.effectTag&64))return b}else if(null!==b.child){b.child.return=b;b=b.child;continue}if(b===a)break;for(;null===b.sibling;){if(null===b.return||b.return===a)return null;b=b.return}b.sibling.return=b.return;b=b.sibling}return null}function ue(a,b){return{responder:a,props:b}}
|
|
function S(){throw Error(k(321));}function ve(a,b){if(null===b)return!1;for(var c=0;c<b.length&&c<a.length;c++)if(!Qa(a[c],b[c]))return!1;return!0}function we(a,b,c,d,e,f){Ia=f;z=b;b.memoizedState=null;b.updateQueue=null;b.expirationTime=0;Sc.current=null===a||null===a.memoizedState?dj:ej;a=c(d,e);if(b.expirationTime===Ia){f=0;do{b.expirationTime=0;if(!(25>f))throw Error(k(301));f+=1;J=K=null;b.updateQueue=null;Sc.current=fj;a=c(d,e)}while(b.expirationTime===Ia)}Sc.current=Tc;b=null!==K&&null!==K.next;
|
|
Ia=0;J=K=z=null;Uc=!1;if(b)throw Error(k(300));return a}function ub(){var a={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};null===J?z.memoizedState=J=a:J=J.next=a;return J}function vb(){if(null===K){var a=z.alternate;a=null!==a?a.memoizedState:null}else a=K.next;var b=null===J?z.memoizedState:J.next;if(null!==b)J=b,K=a;else{if(null===a)throw Error(k(310));K=a;a={memoizedState:K.memoizedState,baseState:K.baseState,baseQueue:K.baseQueue,queue:K.queue,next:null};null===J?z.memoizedState=
|
|
J=a:J=J.next=a}return J}function Ua(a,b){return"function"===typeof b?b(a):b}function Vc(a,b,c){b=vb();c=b.queue;if(null===c)throw Error(k(311));c.lastRenderedReducer=a;var d=K,e=d.baseQueue,f=c.pending;if(null!==f){if(null!==e){var g=e.next;e.next=f.next;f.next=g}d.baseQueue=e=f;c.pending=null}if(null!==e){e=e.next;d=d.baseState;var h=g=f=null,m=e;do{var n=m.expirationTime;if(n<Ia){var l={expirationTime:m.expirationTime,suspenseConfig:m.suspenseConfig,action:m.action,eagerReducer:m.eagerReducer,eagerState:m.eagerState,
|
|
next:null};null===h?(g=h=l,f=d):h=h.next=l;n>z.expirationTime&&(z.expirationTime=n,Kc(n))}else null!==h&&(h=h.next={expirationTime:1073741823,suspenseConfig:m.suspenseConfig,action:m.action,eagerReducer:m.eagerReducer,eagerState:m.eagerState,next:null}),Vg(n,m.suspenseConfig),d=m.eagerReducer===a?m.eagerState:a(d,m.action);m=m.next}while(null!==m&&m!==e);null===h?f=d:h.next=g;Qa(d,b.memoizedState)||(ia=!0);b.memoizedState=d;b.baseState=f;b.baseQueue=h;c.lastRenderedState=d}return[b.memoizedState,
|
|
c.dispatch]}function Wc(a,b,c){b=vb();c=b.queue;if(null===c)throw Error(k(311));c.lastRenderedReducer=a;var d=c.dispatch,e=c.pending,f=b.memoizedState;if(null!==e){c.pending=null;var g=e=e.next;do f=a(f,g.action),g=g.next;while(g!==e);Qa(f,b.memoizedState)||(ia=!0);b.memoizedState=f;null===b.baseQueue&&(b.baseState=f);c.lastRenderedState=f}return[f,d]}function xe(a){var b=ub();"function"===typeof a&&(a=a());b.memoizedState=b.baseState=a;a=b.queue={pending:null,dispatch:null,lastRenderedReducer:Ua,
|
|
lastRenderedState:a};a=a.dispatch=ch.bind(null,z,a);return[b.memoizedState,a]}function ye(a,b,c,d){a={tag:a,create:b,destroy:c,deps:d,next:null};b=z.updateQueue;null===b?(b={lastEffect:null},z.updateQueue=b,b.lastEffect=a.next=a):(c=b.lastEffect,null===c?b.lastEffect=a.next=a:(d=c.next,c.next=a,a.next=d,b.lastEffect=a));return a}function dh(a){return vb().memoizedState}function ze(a,b,c,d){var e=ub();z.effectTag|=a;e.memoizedState=ye(1|b,c,void 0,void 0===d?null:d)}function Ae(a,b,c,d){var e=vb();
|
|
d=void 0===d?null:d;var f=void 0;if(null!==K){var g=K.memoizedState;f=g.destroy;if(null!==d&&ve(d,g.deps)){ye(b,c,f,d);return}}z.effectTag|=a;e.memoizedState=ye(1|b,c,f,d)}function eh(a,b){return ze(516,4,a,b)}function Xc(a,b){return Ae(516,4,a,b)}function fh(a,b){return Ae(4,2,a,b)}function gh(a,b){if("function"===typeof b)return a=a(),b(a),function(){b(null)};if(null!==b&&void 0!==b)return a=a(),b.current=a,function(){b.current=null}}function hh(a,b,c){c=null!==c&&void 0!==c?c.concat([a]):null;
|
|
return Ae(4,2,gh.bind(null,b,a),c)}function Be(a,b){}function ih(a,b){ub().memoizedState=[a,void 0===b?null:b];return a}function Yc(a,b){var c=vb();b=void 0===b?null:b;var d=c.memoizedState;if(null!==d&&null!==b&&ve(b,d[1]))return d[0];c.memoizedState=[a,b];return a}function jh(a,b){var c=vb();b=void 0===b?null:b;var d=c.memoizedState;if(null!==d&&null!==b&&ve(b,d[1]))return d[0];a=a();c.memoizedState=[a,b];return a}function Ce(a,b,c){var d=Cc();Da(98>d?98:d,function(){a(!0)});Da(97<d?97:d,function(){var d=
|
|
X.suspense;X.suspense=void 0===b?null:b;try{a(!1),c()}finally{X.suspense=d}})}function ch(a,b,c){var d=ka(),e=Vb.suspense;d=Va(d,a,e);e={expirationTime:d,suspenseConfig:e,action:c,eagerReducer:null,eagerState:null,next:null};var f=b.pending;null===f?e.next=e:(e.next=f.next,f.next=e);b.pending=e;f=a.alternate;if(a===z||null!==f&&f===z)Uc=!0,e.expirationTime=Ia,z.expirationTime=Ia;else{if(0===a.expirationTime&&(null===f||0===f.expirationTime)&&(f=b.lastRenderedReducer,null!==f))try{var g=b.lastRenderedState,
|
|
h=f(g,c);e.eagerReducer=f;e.eagerState=h;if(Qa(h,g))return}catch(m){}finally{}Ja(a,d)}}function kh(a,b){var c=la(5,null,null,0);c.elementType="DELETED";c.type="DELETED";c.stateNode=b;c.return=a;c.effectTag=8;null!==a.lastEffect?(a.lastEffect.nextEffect=c,a.lastEffect=c):a.firstEffect=a.lastEffect=c}function lh(a,b){switch(a.tag){case 5:var c=a.type;b=1!==b.nodeType||c.toLowerCase()!==b.nodeName.toLowerCase()?null:b;return null!==b?(a.stateNode=b,!0):!1;case 6:return b=""===a.pendingProps||3!==b.nodeType?
|
|
null:b,null!==b?(a.stateNode=b,!0):!1;case 13:return!1;default:return!1}}function De(a){if(Wa){var b=Ka;if(b){var c=b;if(!lh(a,b)){b=kb(c.nextSibling);if(!b||!lh(a,b)){a.effectTag=a.effectTag&-1025|2;Wa=!1;ra=a;return}kh(ra,c)}ra=a;Ka=kb(b.firstChild)}else a.effectTag=a.effectTag&-1025|2,Wa=!1,ra=a}}function mh(a){for(a=a.return;null!==a&&5!==a.tag&&3!==a.tag&&13!==a.tag;)a=a.return;ra=a}function Zc(a){if(a!==ra)return!1;if(!Wa)return mh(a),Wa=!0,!1;var b=a.type;if(5!==a.tag||"head"!==b&&"body"!==
|
|
b&&!Yd(b,a.memoizedProps))for(b=Ka;b;)kh(a,b),b=kb(b.nextSibling);mh(a);if(13===a.tag){a=a.memoizedState;a=null!==a?a.dehydrated:null;if(!a)throw Error(k(317));a:{a=a.nextSibling;for(b=0;a;){if(8===a.nodeType){var c=a.data;if(c===og){if(0===b){Ka=kb(a.nextSibling);break a}b--}else c!==ng&&c!==Zd&&c!==$d||b++}a=a.nextSibling}Ka=null}}else Ka=ra?kb(a.stateNode.nextSibling):null;return!0}function Ee(){Ka=ra=null;Wa=!1}function T(a,b,c,d){b.child=null===a?Fe(b,null,c,d):wb(b,a.child,c,d)}function nh(a,
|
|
b,c,d,e){c=c.render;var f=b.ref;rb(b,e);d=we(a,b,c,d,f,e);if(null!==a&&!ia)return b.updateQueue=a.updateQueue,b.effectTag&=-517,a.expirationTime<=e&&(a.expirationTime=0),sa(a,b,e);b.effectTag|=1;T(a,b,d,e);return b.child}function oh(a,b,c,d,e,f){if(null===a){var g=c.type;if("function"===typeof g&&!Ge(g)&&void 0===g.defaultProps&&null===c.compare&&void 0===c.defaultProps)return b.tag=15,b.type=g,ph(a,b,g,d,e,f);a=Oc(c.type,null,d,null,b.mode,f);a.ref=b.ref;a.return=b;return b.child=a}g=a.child;if(e<
|
|
f&&(e=g.memoizedProps,c=c.compare,c=null!==c?c:Ob,c(e,d)&&a.ref===b.ref))return sa(a,b,f);b.effectTag|=1;a=Sa(g,d);a.ref=b.ref;a.return=b;return b.child=a}function ph(a,b,c,d,e,f){return null!==a&&Ob(a.memoizedProps,d)&&a.ref===b.ref&&(ia=!1,e<f)?(b.expirationTime=a.expirationTime,sa(a,b,f)):He(a,b,c,d,f)}function qh(a,b){var c=b.ref;if(null===a&&null!==c||null!==a&&a.ref!==c)b.effectTag|=128}function He(a,b,c,d,e){var f=N(c)?Ra:B.current;f=pb(b,f);rb(b,e);c=we(a,b,c,d,f,e);if(null!==a&&!ia)return b.updateQueue=
|
|
a.updateQueue,b.effectTag&=-517,a.expirationTime<=e&&(a.expirationTime=0),sa(a,b,e);b.effectTag|=1;T(a,b,c,e);return b.child}function rh(a,b,c,d,e){if(N(c)){var f=!0;Bc(b)}else f=!1;rb(b,e);if(null===b.stateNode)null!==a&&(a.alternate=null,b.alternate=null,b.effectTag|=2),Yg(b,c,d),pe(b,c,d,e),d=!0;else if(null===a){var g=b.stateNode,h=b.memoizedProps;g.props=h;var m=g.context,n=c.contextType;"object"===typeof n&&null!==n?n=W(n):(n=N(c)?Ra:B.current,n=pb(b,n));var l=c.getDerivedStateFromProps,k="function"===
|
|
typeof l||"function"===typeof g.getSnapshotBeforeUpdate;k||"function"!==typeof g.UNSAFE_componentWillReceiveProps&&"function"!==typeof g.componentWillReceiveProps||(h!==d||m!==n)&&Zg(b,g,d,n);Ga=!1;var p=b.memoizedState;g.state=p;Qb(b,d,g,e);m=b.memoizedState;h!==d||p!==m||G.current||Ga?("function"===typeof l&&(Lc(b,c,l,d),m=b.memoizedState),(h=Ga||Xg(b,c,h,d,p,m,n))?(k||"function"!==typeof g.UNSAFE_componentWillMount&&"function"!==typeof g.componentWillMount||("function"===typeof g.componentWillMount&&
|
|
g.componentWillMount(),"function"===typeof g.UNSAFE_componentWillMount&&g.UNSAFE_componentWillMount()),"function"===typeof g.componentDidMount&&(b.effectTag|=4)):("function"===typeof g.componentDidMount&&(b.effectTag|=4),b.memoizedProps=d,b.memoizedState=m),g.props=d,g.state=m,g.context=n,d=h):("function"===typeof g.componentDidMount&&(b.effectTag|=4),d=!1)}else g=b.stateNode,oe(a,b),h=b.memoizedProps,g.props=b.type===b.elementType?h:aa(b.type,h),m=g.context,n=c.contextType,"object"===typeof n&&null!==
|
|
n?n=W(n):(n=N(c)?Ra:B.current,n=pb(b,n)),l=c.getDerivedStateFromProps,(k="function"===typeof l||"function"===typeof g.getSnapshotBeforeUpdate)||"function"!==typeof g.UNSAFE_componentWillReceiveProps&&"function"!==typeof g.componentWillReceiveProps||(h!==d||m!==n)&&Zg(b,g,d,n),Ga=!1,m=b.memoizedState,g.state=m,Qb(b,d,g,e),p=b.memoizedState,h!==d||m!==p||G.current||Ga?("function"===typeof l&&(Lc(b,c,l,d),p=b.memoizedState),(l=Ga||Xg(b,c,h,d,m,p,n))?(k||"function"!==typeof g.UNSAFE_componentWillUpdate&&
|
|
"function"!==typeof g.componentWillUpdate||("function"===typeof g.componentWillUpdate&&g.componentWillUpdate(d,p,n),"function"===typeof g.UNSAFE_componentWillUpdate&&g.UNSAFE_componentWillUpdate(d,p,n)),"function"===typeof g.componentDidUpdate&&(b.effectTag|=4),"function"===typeof g.getSnapshotBeforeUpdate&&(b.effectTag|=256)):("function"!==typeof g.componentDidUpdate||h===a.memoizedProps&&m===a.memoizedState||(b.effectTag|=4),"function"!==typeof g.getSnapshotBeforeUpdate||h===a.memoizedProps&&m===
|
|
a.memoizedState||(b.effectTag|=256),b.memoizedProps=d,b.memoizedState=p),g.props=d,g.state=p,g.context=n,d=l):("function"!==typeof g.componentDidUpdate||h===a.memoizedProps&&m===a.memoizedState||(b.effectTag|=4),"function"!==typeof g.getSnapshotBeforeUpdate||h===a.memoizedProps&&m===a.memoizedState||(b.effectTag|=256),d=!1);return Ie(a,b,c,d,f,e)}function Ie(a,b,c,d,e,f){qh(a,b);var g=0!==(b.effectTag&64);if(!d&&!g)return e&&Hg(b,c,!1),sa(a,b,f);d=b.stateNode;gj.current=b;var h=g&&"function"!==typeof c.getDerivedStateFromError?
|
|
null:d.render();b.effectTag|=1;null!==a&&g?(b.child=wb(b,a.child,null,f),b.child=wb(b,null,h,f)):T(a,b,h,f);b.memoizedState=d.state;e&&Hg(b,c,!0);return b.child}function sh(a){var b=a.stateNode;b.pendingContext?Fg(a,b.pendingContext,b.pendingContext!==b.context):b.context&&Fg(a,b.context,!1);se(a,b.containerInfo)}function th(a,b,c){var d=b.mode,e=b.pendingProps,f=D.current,g=!1,h;(h=0!==(b.effectTag&64))||(h=0!==(f&2)&&(null===a||null!==a.memoizedState));h?(g=!0,b.effectTag&=-65):null!==a&&null===
|
|
a.memoizedState||void 0===e.fallback||!0===e.unstable_avoidThisFallback||(f|=1);y(D,f&1);if(null===a){void 0!==e.fallback&&De(b);if(g){g=e.fallback;e=Ha(null,d,0,null);e.return=b;if(0===(b.mode&2))for(a=null!==b.memoizedState?b.child.child:b.child,e.child=a;null!==a;)a.return=e,a=a.sibling;c=Ha(g,d,c,null);c.return=b;e.sibling=c;b.memoizedState=Je;b.child=e;return c}d=e.children;b.memoizedState=null;return b.child=Fe(b,null,d,c)}if(null!==a.memoizedState){a=a.child;d=a.sibling;if(g){e=e.fallback;
|
|
c=Sa(a,a.pendingProps);c.return=b;if(0===(b.mode&2)&&(g=null!==b.memoizedState?b.child.child:b.child,g!==a.child))for(c.child=g;null!==g;)g.return=c,g=g.sibling;d=Sa(d,e);d.return=b;c.sibling=d;c.childExpirationTime=0;b.memoizedState=Je;b.child=c;return d}c=wb(b,a.child,e.children,c);b.memoizedState=null;return b.child=c}a=a.child;if(g){g=e.fallback;e=Ha(null,d,0,null);e.return=b;e.child=a;null!==a&&(a.return=e);if(0===(b.mode&2))for(a=null!==b.memoizedState?b.child.child:b.child,e.child=a;null!==
|
|
a;)a.return=e,a=a.sibling;c=Ha(g,d,c,null);c.return=b;e.sibling=c;c.effectTag|=2;e.childExpirationTime=0;b.memoizedState=Je;b.child=e;return c}b.memoizedState=null;return b.child=wb(b,a,e.children,c)}function uh(a,b){a.expirationTime<b&&(a.expirationTime=b);var c=a.alternate;null!==c&&c.expirationTime<b&&(c.expirationTime=b);Sg(a.return,b)}function Ke(a,b,c,d,e,f){var g=a.memoizedState;null===g?a.memoizedState={isBackwards:b,rendering:null,renderingStartTime:0,last:d,tail:c,tailExpiration:0,tailMode:e,
|
|
lastEffect:f}:(g.isBackwards=b,g.rendering=null,g.renderingStartTime=0,g.last=d,g.tail=c,g.tailExpiration=0,g.tailMode=e,g.lastEffect=f)}function vh(a,b,c){var d=b.pendingProps,e=d.revealOrder,f=d.tail;T(a,b,d.children,c);d=D.current;if(0!==(d&2))d=d&1|2,b.effectTag|=64;else{if(null!==a&&0!==(a.effectTag&64))a:for(a=b.child;null!==a;){if(13===a.tag)null!==a.memoizedState&&uh(a,c);else if(19===a.tag)uh(a,c);else if(null!==a.child){a.child.return=a;a=a.child;continue}if(a===b)break a;for(;null===a.sibling;){if(null===
|
|
a.return||a.return===b)break a;a=a.return}a.sibling.return=a.return;a=a.sibling}d&=1}y(D,d);if(0===(b.mode&2))b.memoizedState=null;else switch(e){case "forwards":c=b.child;for(e=null;null!==c;)a=c.alternate,null!==a&&null===Rc(a)&&(e=c),c=c.sibling;c=e;null===c?(e=b.child,b.child=null):(e=c.sibling,c.sibling=null);Ke(b,!1,e,c,f,b.lastEffect);break;case "backwards":c=null;e=b.child;for(b.child=null;null!==e;){a=e.alternate;if(null!==a&&null===Rc(a)){b.child=e;break}a=e.sibling;e.sibling=c;c=e;e=a}Ke(b,
|
|
!0,c,null,f,b.lastEffect);break;case "together":Ke(b,!1,null,null,void 0,b.lastEffect);break;default:b.memoizedState=null}return b.child}function sa(a,b,c){null!==a&&(b.dependencies=a.dependencies);var d=b.expirationTime;0!==d&&Kc(d);if(b.childExpirationTime<c)return null;if(null!==a&&b.child!==a.child)throw Error(k(153));if(null!==b.child){a=b.child;c=Sa(a,a.pendingProps);b.child=c;for(c.return=b;null!==a.sibling;)a=a.sibling,c=c.sibling=Sa(a,a.pendingProps),c.return=b;c.sibling=null}return b.child}
|
|
function $c(a,b){switch(a.tailMode){case "hidden":b=a.tail;for(var c=null;null!==b;)null!==b.alternate&&(c=b),b=b.sibling;null===c?a.tail=null:c.sibling=null;break;case "collapsed":c=a.tail;for(var d=null;null!==c;)null!==c.alternate&&(d=c),c=c.sibling;null===d?b||null===a.tail?a.tail=null:a.tail.sibling=null:d.sibling=null}}function hj(a,b,c){var d=b.pendingProps;switch(b.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return null;case 1:return N(b.type)&&(q(G),q(B)),
|
|
null;case 3:return tb(),q(G),q(B),c=b.stateNode,c.pendingContext&&(c.context=c.pendingContext,c.pendingContext=null),null!==a&&null!==a.child||!Zc(b)||(b.effectTag|=4),wh(b),null;case 5:te(b);c=Ta(Tb.current);var e=b.type;if(null!==a&&null!=b.stateNode)ij(a,b,e,d,c),a.ref!==b.ref&&(b.effectTag|=128);else{if(!d){if(null===b.stateNode)throw Error(k(166));return null}a=Ta(ja.current);if(Zc(b)){d=b.stateNode;e=b.type;var f=b.memoizedProps;d[Aa]=b;d[vc]=f;switch(e){case "iframe":case "object":case "embed":w("load",
|
|
d);break;case "video":case "audio":for(a=0;a<Db.length;a++)w(Db[a],d);break;case "source":w("error",d);break;case "img":case "image":case "link":w("error",d);w("load",d);break;case "form":w("reset",d);w("submit",d);break;case "details":w("toggle",d);break;case "input":Hf(d,f);w("invalid",d);oa(c,"onChange");break;case "select":d._wrapperState={wasMultiple:!!f.multiple};w("invalid",d);oa(c,"onChange");break;case "textarea":Kf(d,f),w("invalid",d),oa(c,"onChange")}Ud(e,f);a=null;for(var g in f)if(f.hasOwnProperty(g)){var h=
|
|
f[g];"children"===g?"string"===typeof h?d.textContent!==h&&(a=["children",h]):"number"===typeof h&&d.textContent!==""+h&&(a=["children",""+h]):db.hasOwnProperty(g)&&null!=h&&oa(c,g)}switch(e){case "input":mc(d);Jf(d,f,!0);break;case "textarea":mc(d);Mf(d);break;case "select":case "option":break;default:"function"===typeof f.onClick&&(d.onclick=uc)}c=a;b.updateQueue=c;null!==c&&(b.effectTag|=4)}else{g=9===c.nodeType?c:c.ownerDocument;"http://www.w3.org/1999/xhtml"===a&&(a=Nf(e));"http://www.w3.org/1999/xhtml"===
|
|
a?"script"===e?(a=g.createElement("div"),a.innerHTML="<script>\x3c/script>",a=a.removeChild(a.firstChild)):"string"===typeof d.is?a=g.createElement(e,{is:d.is}):(a=g.createElement(e),"select"===e&&(g=a,d.multiple?g.multiple=!0:d.size&&(g.size=d.size))):a=g.createElementNS(a,e);a[Aa]=b;a[vc]=d;jj(a,b,!1,!1);b.stateNode=a;g=Vd(e,d);switch(e){case "iframe":case "object":case "embed":w("load",a);h=d;break;case "video":case "audio":for(h=0;h<Db.length;h++)w(Db[h],a);h=d;break;case "source":w("error",a);
|
|
h=d;break;case "img":case "image":case "link":w("error",a);w("load",a);h=d;break;case "form":w("reset",a);w("submit",a);h=d;break;case "details":w("toggle",a);h=d;break;case "input":Hf(a,d);h=Cd(a,d);w("invalid",a);oa(c,"onChange");break;case "option":h=Fd(a,d);break;case "select":a._wrapperState={wasMultiple:!!d.multiple};h=M({},d,{value:void 0});w("invalid",a);oa(c,"onChange");break;case "textarea":Kf(a,d);h=Gd(a,d);w("invalid",a);oa(c,"onChange");break;default:h=d}Ud(e,h);var m=h;for(f in m)if(m.hasOwnProperty(f)){var n=
|
|
m[f];"style"===f?gg(a,n):"dangerouslySetInnerHTML"===f?(n=n?n.__html:void 0,null!=n&&xh(a,n)):"children"===f?"string"===typeof n?("textarea"!==e||""!==n)&&Wb(a,n):"number"===typeof n&&Wb(a,""+n):"suppressContentEditableWarning"!==f&&"suppressHydrationWarning"!==f&&"autoFocus"!==f&&(db.hasOwnProperty(f)?null!=n&&oa(c,f):null!=n&&xd(a,f,n,g))}switch(e){case "input":mc(a);Jf(a,d,!1);break;case "textarea":mc(a);Mf(a);break;case "option":null!=d.value&&a.setAttribute("value",""+va(d.value));break;case "select":a.multiple=
|
|
!!d.multiple;c=d.value;null!=c?hb(a,!!d.multiple,c,!1):null!=d.defaultValue&&hb(a,!!d.multiple,d.defaultValue,!0);break;default:"function"===typeof h.onClick&&(a.onclick=uc)}lg(e,d)&&(b.effectTag|=4)}null!==b.ref&&(b.effectTag|=128)}return null;case 6:if(a&&null!=b.stateNode)kj(a,b,a.memoizedProps,d);else{if("string"!==typeof d&&null===b.stateNode)throw Error(k(166));c=Ta(Tb.current);Ta(ja.current);Zc(b)?(c=b.stateNode,d=b.memoizedProps,c[Aa]=b,c.nodeValue!==d&&(b.effectTag|=4)):(c=(9===c.nodeType?
|
|
c:c.ownerDocument).createTextNode(d),c[Aa]=b,b.stateNode=c)}return null;case 13:q(D);d=b.memoizedState;if(0!==(b.effectTag&64))return b.expirationTime=c,b;c=null!==d;d=!1;null===a?void 0!==b.memoizedProps.fallback&&Zc(b):(e=a.memoizedState,d=null!==e,c||null===e||(e=a.child.sibling,null!==e&&(f=b.firstEffect,null!==f?(b.firstEffect=e,e.nextEffect=f):(b.firstEffect=b.lastEffect=e,e.nextEffect=null),e.effectTag=8)));if(c&&!d&&0!==(b.mode&2))if(null===a&&!0!==b.memoizedProps.unstable_avoidThisFallback||
|
|
0!==(D.current&1))F===Xa&&(F=ad);else{if(F===Xa||F===ad)F=bd;0!==Xb&&null!==U&&(Ya(U,P),yh(U,Xb))}if(c||d)b.effectTag|=4;return null;case 4:return tb(),wh(b),null;case 10:return me(b),null;case 17:return N(b.type)&&(q(G),q(B)),null;case 19:q(D);d=b.memoizedState;if(null===d)return null;e=0!==(b.effectTag&64);f=d.rendering;if(null===f)if(e)$c(d,!1);else{if(F!==Xa||null!==a&&0!==(a.effectTag&64))for(f=b.child;null!==f;){a=Rc(f);if(null!==a){b.effectTag|=64;$c(d,!1);e=a.updateQueue;null!==e&&(b.updateQueue=
|
|
e,b.effectTag|=4);null===d.lastEffect&&(b.firstEffect=null);b.lastEffect=d.lastEffect;for(d=b.child;null!==d;)e=d,f=c,e.effectTag&=2,e.nextEffect=null,e.firstEffect=null,e.lastEffect=null,a=e.alternate,null===a?(e.childExpirationTime=0,e.expirationTime=f,e.child=null,e.memoizedProps=null,e.memoizedState=null,e.updateQueue=null,e.dependencies=null):(e.childExpirationTime=a.childExpirationTime,e.expirationTime=a.expirationTime,e.child=a.child,e.memoizedProps=a.memoizedProps,e.memoizedState=a.memoizedState,
|
|
e.updateQueue=a.updateQueue,f=a.dependencies,e.dependencies=null===f?null:{expirationTime:f.expirationTime,firstContext:f.firstContext,responders:f.responders}),d=d.sibling;y(D,D.current&1|2);return b.child}f=f.sibling}}else{if(!e)if(a=Rc(f),null!==a){if(b.effectTag|=64,e=!0,c=a.updateQueue,null!==c&&(b.updateQueue=c,b.effectTag|=4),$c(d,!0),null===d.tail&&"hidden"===d.tailMode&&!f.alternate)return b=b.lastEffect=d.lastEffect,null!==b&&(b.nextEffect=null),null}else 2*Y()-d.renderingStartTime>d.tailExpiration&&
|
|
1<c&&(b.effectTag|=64,e=!0,$c(d,!1),b.expirationTime=b.childExpirationTime=c-1);d.isBackwards?(f.sibling=b.child,b.child=f):(c=d.last,null!==c?c.sibling=f:b.child=f,d.last=f)}return null!==d.tail?(0===d.tailExpiration&&(d.tailExpiration=Y()+500),c=d.tail,d.rendering=c,d.tail=c.sibling,d.lastEffect=b.lastEffect,d.renderingStartTime=Y(),c.sibling=null,b=D.current,y(D,e?b&1|2:b&1),c):null}throw Error(k(156,b.tag));}function lj(a,b){switch(a.tag){case 1:return N(a.type)&&(q(G),q(B)),b=a.effectTag,b&4096?
|
|
(a.effectTag=b&-4097|64,a):null;case 3:tb();q(G);q(B);b=a.effectTag;if(0!==(b&64))throw Error(k(285));a.effectTag=b&-4097|64;return a;case 5:return te(a),null;case 13:return q(D),b=a.effectTag,b&4096?(a.effectTag=b&-4097|64,a):null;case 19:return q(D),null;case 4:return tb(),null;case 10:return me(a),null;default:return null}}function Le(a,b){return{value:a,source:b,stack:Bd(b)}}function Me(a,b){var c=b.source,d=b.stack;null===d&&null!==c&&(d=Bd(c));null!==c&&na(c.type);b=b.value;null!==a&&1===a.tag&&
|
|
na(a.type);try{console.error(b)}catch(e){setTimeout(function(){throw e;})}}function mj(a,b){try{b.props=a.memoizedProps,b.state=a.memoizedState,b.componentWillUnmount()}catch(c){Za(a,c)}}function zh(a){var b=a.ref;if(null!==b)if("function"===typeof b)try{b(null)}catch(c){Za(a,c)}else b.current=null}function nj(a,b){switch(b.tag){case 0:case 11:case 15:case 22:return;case 1:if(b.effectTag&256&&null!==a){var c=a.memoizedProps,d=a.memoizedState;a=b.stateNode;b=a.getSnapshotBeforeUpdate(b.elementType===
|
|
b.type?c:aa(b.type,c),d);a.__reactInternalSnapshotBeforeUpdate=b}return;case 3:case 5:case 6:case 4:case 17:return}throw Error(k(163));}function Ah(a,b){b=b.updateQueue;b=null!==b?b.lastEffect:null;if(null!==b){var c=b=b.next;do{if((c.tag&a)===a){var d=c.destroy;c.destroy=void 0;void 0!==d&&d()}c=c.next}while(c!==b)}}function Bh(a,b){b=b.updateQueue;b=null!==b?b.lastEffect:null;if(null!==b){var c=b=b.next;do{if((c.tag&a)===a){var d=c.create;c.destroy=d()}c=c.next}while(c!==b)}}function oj(a,b,c,d){switch(c.tag){case 0:case 11:case 15:case 22:Bh(3,
|
|
c);return;case 1:a=c.stateNode;c.effectTag&4&&(null===b?a.componentDidMount():(d=c.elementType===c.type?b.memoizedProps:aa(c.type,b.memoizedProps),a.componentDidUpdate(d,b.memoizedState,a.__reactInternalSnapshotBeforeUpdate)));b=c.updateQueue;null!==b&&Wg(c,b,a);return;case 3:b=c.updateQueue;if(null!==b){a=null;if(null!==c.child)switch(c.child.tag){case 5:a=c.child.stateNode;break;case 1:a=c.child.stateNode}Wg(c,b,a)}return;case 5:a=c.stateNode;null===b&&c.effectTag&4&&lg(c.type,c.memoizedProps)&&
|
|
a.focus();return;case 6:return;case 4:return;case 12:return;case 13:null===c.memoizedState&&(c=c.alternate,null!==c&&(c=c.memoizedState,null!==c&&(c=c.dehydrated,null!==c&&bg(c))));return;case 19:case 17:case 20:case 21:return}throw Error(k(163));}function Ch(a,b,c){"function"===typeof Ne&&Ne(b);switch(b.tag){case 0:case 11:case 14:case 15:case 22:a=b.updateQueue;if(null!==a&&(a=a.lastEffect,null!==a)){var d=a.next;Da(97<c?97:c,function(){var a=d;do{var c=a.destroy;if(void 0!==c){var g=b;try{c()}catch(h){Za(g,
|
|
h)}}a=a.next}while(a!==d)})}break;case 1:zh(b);c=b.stateNode;"function"===typeof c.componentWillUnmount&&mj(b,c);break;case 5:zh(b);break;case 4:Dh(a,b,c)}}function Eh(a){var b=a.alternate;a.return=null;a.child=null;a.memoizedState=null;a.updateQueue=null;a.dependencies=null;a.alternate=null;a.firstEffect=null;a.lastEffect=null;a.pendingProps=null;a.memoizedProps=null;a.stateNode=null;null!==b&&Eh(b)}function Fh(a){return 5===a.tag||3===a.tag||4===a.tag}function Gh(a){a:{for(var b=a.return;null!==
|
|
b;){if(Fh(b)){var c=b;break a}b=b.return}throw Error(k(160));}b=c.stateNode;switch(c.tag){case 5:var d=!1;break;case 3:b=b.containerInfo;d=!0;break;case 4:b=b.containerInfo;d=!0;break;default:throw Error(k(161));}c.effectTag&16&&(Wb(b,""),c.effectTag&=-17);a:b:for(c=a;;){for(;null===c.sibling;){if(null===c.return||Fh(c.return)){c=null;break a}c=c.return}c.sibling.return=c.return;for(c=c.sibling;5!==c.tag&&6!==c.tag&&18!==c.tag;){if(c.effectTag&2)continue b;if(null===c.child||4===c.tag)continue b;
|
|
else c.child.return=c,c=c.child}if(!(c.effectTag&2)){c=c.stateNode;break a}}d?Oe(a,c,b):Pe(a,c,b)}function Oe(a,b,c){var d=a.tag,e=5===d||6===d;if(e)a=e?a.stateNode:a.stateNode.instance,b?8===c.nodeType?c.parentNode.insertBefore(a,b):c.insertBefore(a,b):(8===c.nodeType?(b=c.parentNode,b.insertBefore(a,c)):(b=c,b.appendChild(a)),c=c._reactRootContainer,null!==c&&void 0!==c||null!==b.onclick||(b.onclick=uc));else if(4!==d&&(a=a.child,null!==a))for(Oe(a,b,c),a=a.sibling;null!==a;)Oe(a,b,c),a=a.sibling}
|
|
function Pe(a,b,c){var d=a.tag,e=5===d||6===d;if(e)a=e?a.stateNode:a.stateNode.instance,b?c.insertBefore(a,b):c.appendChild(a);else if(4!==d&&(a=a.child,null!==a))for(Pe(a,b,c),a=a.sibling;null!==a;)Pe(a,b,c),a=a.sibling}function Dh(a,b,c){for(var d=b,e=!1,f,g;;){if(!e){e=d.return;a:for(;;){if(null===e)throw Error(k(160));f=e.stateNode;switch(e.tag){case 5:g=!1;break a;case 3:f=f.containerInfo;g=!0;break a;case 4:f=f.containerInfo;g=!0;break a}e=e.return}e=!0}if(5===d.tag||6===d.tag){a:for(var h=
|
|
a,m=d,n=c,l=m;;)if(Ch(h,l,n),null!==l.child&&4!==l.tag)l.child.return=l,l=l.child;else{if(l===m)break a;for(;null===l.sibling;){if(null===l.return||l.return===m)break a;l=l.return}l.sibling.return=l.return;l=l.sibling}g?(h=f,m=d.stateNode,8===h.nodeType?h.parentNode.removeChild(m):h.removeChild(m)):f.removeChild(d.stateNode)}else if(4===d.tag){if(null!==d.child){f=d.stateNode.containerInfo;g=!0;d.child.return=d;d=d.child;continue}}else if(Ch(a,d,c),null!==d.child){d.child.return=d;d=d.child;continue}if(d===
|
|
b)break;for(;null===d.sibling;){if(null===d.return||d.return===b)return;d=d.return;4===d.tag&&(e=!1)}d.sibling.return=d.return;d=d.sibling}}function Qe(a,b){switch(b.tag){case 0:case 11:case 14:case 15:case 22:Ah(3,b);return;case 1:return;case 5:var c=b.stateNode;if(null!=c){var d=b.memoizedProps,e=null!==a?a.memoizedProps:d;a=b.type;var f=b.updateQueue;b.updateQueue=null;if(null!==f){c[vc]=d;"input"===a&&"radio"===d.type&&null!=d.name&&If(c,d);Vd(a,e);b=Vd(a,d);for(e=0;e<f.length;e+=2){var g=f[e],
|
|
h=f[e+1];"style"===g?gg(c,h):"dangerouslySetInnerHTML"===g?xh(c,h):"children"===g?Wb(c,h):xd(c,g,h,b)}switch(a){case "input":Dd(c,d);break;case "textarea":Lf(c,d);break;case "select":b=c._wrapperState.wasMultiple,c._wrapperState.wasMultiple=!!d.multiple,a=d.value,null!=a?hb(c,!!d.multiple,a,!1):b!==!!d.multiple&&(null!=d.defaultValue?hb(c,!!d.multiple,d.defaultValue,!0):hb(c,!!d.multiple,d.multiple?[]:"",!1))}}}return;case 6:if(null===b.stateNode)throw Error(k(162));b.stateNode.nodeValue=b.memoizedProps;
|
|
return;case 3:b=b.stateNode;b.hydrate&&(b.hydrate=!1,bg(b.containerInfo));return;case 12:return;case 13:c=b;null===b.memoizedState?d=!1:(d=!0,c=b.child,Re=Y());if(null!==c)a:for(a=c;;){if(5===a.tag)f=a.stateNode,d?(f=f.style,"function"===typeof f.setProperty?f.setProperty("display","none","important"):f.display="none"):(f=a.stateNode,e=a.memoizedProps.style,e=void 0!==e&&null!==e&&e.hasOwnProperty("display")?e.display:null,f.style.display=fg("display",e));else if(6===a.tag)a.stateNode.nodeValue=d?
|
|
"":a.memoizedProps;else if(13===a.tag&&null!==a.memoizedState&&null===a.memoizedState.dehydrated){f=a.child.sibling;f.return=a;a=f;continue}else if(null!==a.child){a.child.return=a;a=a.child;continue}if(a===c)break;for(;null===a.sibling;){if(null===a.return||a.return===c)break a;a=a.return}a.sibling.return=a.return;a=a.sibling}Hh(b);return;case 19:Hh(b);return;case 17:return}throw Error(k(163));}function Hh(a){var b=a.updateQueue;if(null!==b){a.updateQueue=null;var c=a.stateNode;null===c&&(c=a.stateNode=
|
|
new pj);b.forEach(function(b){var d=qj.bind(null,a,b);c.has(b)||(c.add(b),b.then(d,d))})}}function Ih(a,b,c){c=Ea(c,null);c.tag=3;c.payload={element:null};var d=b.value;c.callback=function(){cd||(cd=!0,Se=d);Me(a,b)};return c}function Jh(a,b,c){c=Ea(c,null);c.tag=3;var d=a.type.getDerivedStateFromError;if("function"===typeof d){var e=b.value;c.payload=function(){Me(a,b);return d(e)}}var f=a.stateNode;null!==f&&"function"===typeof f.componentDidCatch&&(c.callback=function(){"function"!==typeof d&&
|
|
(null===La?La=new Set([this]):La.add(this),Me(a,b));var c=b.stack;this.componentDidCatch(b.value,{componentStack:null!==c?c:""})});return c}function ka(){return(p&(ca|ma))!==H?1073741821-(Y()/10|0):0!==dd?dd:dd=1073741821-(Y()/10|0)}function Va(a,b,c){b=b.mode;if(0===(b&2))return 1073741823;var d=Cc();if(0===(b&4))return 99===d?1073741823:1073741822;if((p&ca)!==H)return P;if(null!==c)a=Fc(a,c.timeoutMs|0||5E3,250);else switch(d){case 99:a=1073741823;break;case 98:a=Fc(a,150,100);break;case 97:case 96:a=
|
|
Fc(a,5E3,250);break;case 95:a=2;break;default:throw Error(k(326));}null!==U&&a===P&&--a;return a}function ed(a,b){a.expirationTime<b&&(a.expirationTime=b);var c=a.alternate;null!==c&&c.expirationTime<b&&(c.expirationTime=b);var d=a.return,e=null;if(null===d&&3===a.tag)e=a.stateNode;else for(;null!==d;){c=d.alternate;d.childExpirationTime<b&&(d.childExpirationTime=b);null!==c&&c.childExpirationTime<b&&(c.childExpirationTime=b);if(null===d.return&&3===d.tag){e=d.stateNode;break}d=d.return}null!==e&&
|
|
(U===e&&(Kc(b),F===bd&&Ya(e,P)),yh(e,b));return e}function fd(a){var b=a.lastExpiredTime;if(0!==b)return b;b=a.firstPendingTime;if(!Kh(a,b))return b;var c=a.lastPingedTime;a=a.nextKnownPendingLevel;a=c>a?c:a;return 2>=a&&b!==a?0:a}function V(a){if(0!==a.lastExpiredTime)a.callbackExpirationTime=1073741823,a.callbackPriority=99,a.callbackNode=Og(Te.bind(null,a));else{var b=fd(a),c=a.callbackNode;if(0===b)null!==c&&(a.callbackNode=null,a.callbackExpirationTime=0,a.callbackPriority=90);else{var d=ka();
|
|
1073741823===b?d=99:1===b||2===b?d=95:(d=10*(1073741821-b)-10*(1073741821-d),d=0>=d?99:250>=d?98:5250>=d?97:95);if(null!==c){var e=a.callbackPriority;if(a.callbackExpirationTime===b&&e>=d)return;c!==Qg&&Rg(c)}a.callbackExpirationTime=b;a.callbackPriority=d;b=1073741823===b?Og(Te.bind(null,a)):Ng(d,Lh.bind(null,a),{timeout:10*(1073741821-b)-Y()});a.callbackNode=b}}}function Lh(a,b){dd=0;if(b)return b=ka(),Ue(a,b),V(a),null;var c=fd(a);if(0!==c){b=a.callbackNode;if((p&(ca|ma))!==H)throw Error(k(327));
|
|
xb();a===U&&c===P||$a(a,c);if(null!==t){var d=p;p|=ca;var e=Mh();do try{rj();break}catch(h){Nh(a,h)}while(1);le();p=d;gd.current=e;if(F===hd)throw b=id,$a(a,c),Ya(a,c),V(a),b;if(null===t)switch(e=a.finishedWork=a.current.alternate,a.finishedExpirationTime=c,d=F,U=null,d){case Xa:case hd:throw Error(k(345));case Oh:Ue(a,2<c?2:c);break;case ad:Ya(a,c);d=a.lastSuspendedTime;c===d&&(a.nextKnownPendingLevel=Ve(e));if(1073741823===ta&&(e=Re+Ph-Y(),10<e)){if(jd){var f=a.lastPingedTime;if(0===f||f>=c){a.lastPingedTime=
|
|
c;$a(a,c);break}}f=fd(a);if(0!==f&&f!==c)break;if(0!==d&&d!==c){a.lastPingedTime=d;break}a.timeoutHandle=We(ab.bind(null,a),e);break}ab(a);break;case bd:Ya(a,c);d=a.lastSuspendedTime;c===d&&(a.nextKnownPendingLevel=Ve(e));if(jd&&(e=a.lastPingedTime,0===e||e>=c)){a.lastPingedTime=c;$a(a,c);break}e=fd(a);if(0!==e&&e!==c)break;if(0!==d&&d!==c){a.lastPingedTime=d;break}1073741823!==Yb?d=10*(1073741821-Yb)-Y():1073741823===ta?d=0:(d=10*(1073741821-ta)-5E3,e=Y(),c=10*(1073741821-c)-e,d=e-d,0>d&&(d=0),d=
|
|
(120>d?120:480>d?480:1080>d?1080:1920>d?1920:3E3>d?3E3:4320>d?4320:1960*sj(d/1960))-d,c<d&&(d=c));if(10<d){a.timeoutHandle=We(ab.bind(null,a),d);break}ab(a);break;case Xe:if(1073741823!==ta&&null!==kd){f=ta;var g=kd;d=g.busyMinDurationMs|0;0>=d?d=0:(e=g.busyDelayMs|0,f=Y()-(10*(1073741821-f)-(g.timeoutMs|0||5E3)),d=f<=e?0:e+d-f);if(10<d){Ya(a,c);a.timeoutHandle=We(ab.bind(null,a),d);break}}ab(a);break;default:throw Error(k(329));}V(a);if(a.callbackNode===b)return Lh.bind(null,a)}}return null}function Te(a){var b=
|
|
a.lastExpiredTime;b=0!==b?b:1073741823;if((p&(ca|ma))!==H)throw Error(k(327));xb();a===U&&b===P||$a(a,b);if(null!==t){var c=p;p|=ca;var d=Mh();do try{tj();break}catch(e){Nh(a,e)}while(1);le();p=c;gd.current=d;if(F===hd)throw c=id,$a(a,b),Ya(a,b),V(a),c;if(null!==t)throw Error(k(261));a.finishedWork=a.current.alternate;a.finishedExpirationTime=b;U=null;ab(a);V(a)}return null}function uj(){if(null!==bb){var a=bb;bb=null;a.forEach(function(a,c){Ue(c,a);V(c)});ha()}}function Qh(a,b){var c=p;p|=1;try{return a(b)}finally{p=
|
|
c,p===H&&ha()}}function Rh(a,b){var c=p;p&=-2;p|=Ye;try{return a(b)}finally{p=c,p===H&&ha()}}function $a(a,b){a.finishedWork=null;a.finishedExpirationTime=0;var c=a.timeoutHandle;-1!==c&&(a.timeoutHandle=-1,vj(c));if(null!==t)for(c=t.return;null!==c;){var d=c;switch(d.tag){case 1:d=d.type.childContextTypes;null!==d&&void 0!==d&&(q(G),q(B));break;case 3:tb();q(G);q(B);break;case 5:te(d);break;case 4:tb();break;case 13:q(D);break;case 19:q(D);break;case 10:me(d)}c=c.return}U=a;t=Sa(a.current,null);
|
|
P=b;F=Xa;id=null;Yb=ta=1073741823;kd=null;Xb=0;jd=!1}function Nh(a,b){do{try{le();Sc.current=Tc;if(Uc)for(var c=z.memoizedState;null!==c;){var d=c.queue;null!==d&&(d.pending=null);c=c.next}Ia=0;J=K=z=null;Uc=!1;if(null===t||null===t.return)return F=hd,id=b,t=null;a:{var e=a,f=t.return,g=t,h=b;b=P;g.effectTag|=2048;g.firstEffect=g.lastEffect=null;if(null!==h&&"object"===typeof h&&"function"===typeof h.then){var m=h;if(0===(g.mode&2)){var n=g.alternate;n?(g.updateQueue=n.updateQueue,g.memoizedState=
|
|
n.memoizedState,g.expirationTime=n.expirationTime):(g.updateQueue=null,g.memoizedState=null)}var l=0!==(D.current&1),k=f;do{var p;if(p=13===k.tag){var q=k.memoizedState;if(null!==q)p=null!==q.dehydrated?!0:!1;else{var w=k.memoizedProps;p=void 0===w.fallback?!1:!0!==w.unstable_avoidThisFallback?!0:l?!1:!0}}if(p){var y=k.updateQueue;if(null===y){var r=new Set;r.add(m);k.updateQueue=r}else y.add(m);if(0===(k.mode&2)){k.effectTag|=64;g.effectTag&=-2981;if(1===g.tag)if(null===g.alternate)g.tag=17;else{var O=
|
|
Ea(1073741823,null);O.tag=Jc;Fa(g,O)}g.expirationTime=1073741823;break a}h=void 0;g=b;var v=e.pingCache;null===v?(v=e.pingCache=new wj,h=new Set,v.set(m,h)):(h=v.get(m),void 0===h&&(h=new Set,v.set(m,h)));if(!h.has(g)){h.add(g);var x=xj.bind(null,e,m,g);m.then(x,x)}k.effectTag|=4096;k.expirationTime=b;break a}k=k.return}while(null!==k);h=Error((na(g.type)||"A React component")+" suspended while rendering, but no fallback UI was specified.\n\nAdd a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display."+
|
|
Bd(g))}F!==Xe&&(F=Oh);h=Le(h,g);k=f;do{switch(k.tag){case 3:m=h;k.effectTag|=4096;k.expirationTime=b;var A=Ih(k,m,b);Ug(k,A);break a;case 1:m=h;var u=k.type,B=k.stateNode;if(0===(k.effectTag&64)&&("function"===typeof u.getDerivedStateFromError||null!==B&&"function"===typeof B.componentDidCatch&&(null===La||!La.has(B)))){k.effectTag|=4096;k.expirationTime=b;var H=Jh(k,m,b);Ug(k,H);break a}}k=k.return}while(null!==k)}t=Sh(t)}catch(cj){b=cj;continue}break}while(1)}function Mh(a){a=gd.current;gd.current=
|
|
Tc;return null===a?Tc:a}function Vg(a,b){a<ta&&2<a&&(ta=a);null!==b&&a<Yb&&2<a&&(Yb=a,kd=b)}function Kc(a){a>Xb&&(Xb=a)}function tj(){for(;null!==t;)t=Th(t)}function rj(){for(;null!==t&&!yj();)t=Th(t)}function Th(a){var b=zj(a.alternate,a,P);a.memoizedProps=a.pendingProps;null===b&&(b=Sh(a));Uh.current=null;return b}function Sh(a){t=a;do{var b=t.alternate;a=t.return;if(0===(t.effectTag&2048)){b=hj(b,t,P);if(1===P||1!==t.childExpirationTime){for(var c=0,d=t.child;null!==d;){var e=d.expirationTime,
|
|
f=d.childExpirationTime;e>c&&(c=e);f>c&&(c=f);d=d.sibling}t.childExpirationTime=c}if(null!==b)return b;null!==a&&0===(a.effectTag&2048)&&(null===a.firstEffect&&(a.firstEffect=t.firstEffect),null!==t.lastEffect&&(null!==a.lastEffect&&(a.lastEffect.nextEffect=t.firstEffect),a.lastEffect=t.lastEffect),1<t.effectTag&&(null!==a.lastEffect?a.lastEffect.nextEffect=t:a.firstEffect=t,a.lastEffect=t))}else{b=lj(t);if(null!==b)return b.effectTag&=2047,b;null!==a&&(a.firstEffect=a.lastEffect=null,a.effectTag|=
|
|
2048)}b=t.sibling;if(null!==b)return b;t=a}while(null!==t);F===Xa&&(F=Xe);return null}function Ve(a){var b=a.expirationTime;a=a.childExpirationTime;return b>a?b:a}function ab(a){var b=Cc();Da(99,Aj.bind(null,a,b));return null}function Aj(a,b){do xb();while(null!==Zb);if((p&(ca|ma))!==H)throw Error(k(327));var c=a.finishedWork,d=a.finishedExpirationTime;if(null===c)return null;a.finishedWork=null;a.finishedExpirationTime=0;if(c===a.current)throw Error(k(177));a.callbackNode=null;a.callbackExpirationTime=
|
|
0;a.callbackPriority=90;a.nextKnownPendingLevel=0;var e=Ve(c);a.firstPendingTime=e;d<=a.lastSuspendedTime?a.firstSuspendedTime=a.lastSuspendedTime=a.nextKnownPendingLevel=0:d<=a.firstSuspendedTime&&(a.firstSuspendedTime=d-1);d<=a.lastPingedTime&&(a.lastPingedTime=0);d<=a.lastExpiredTime&&(a.lastExpiredTime=0);a===U&&(t=U=null,P=0);1<c.effectTag?null!==c.lastEffect?(c.lastEffect.nextEffect=c,e=c.firstEffect):e=c:e=c.firstEffect;if(null!==e){var f=p;p|=ma;Uh.current=null;Ze=tc;var g=kg();if(Xd(g)){if("selectionStart"in
|
|
g)var h={start:g.selectionStart,end:g.selectionEnd};else a:{h=(h=g.ownerDocument)&&h.defaultView||window;var m=h.getSelection&&h.getSelection();if(m&&0!==m.rangeCount){h=m.anchorNode;var n=m.anchorOffset,q=m.focusNode;m=m.focusOffset;try{h.nodeType,q.nodeType}catch(sb){h=null;break a}var ba=0,w=-1,y=-1,B=0,D=0,r=g,z=null;b:for(;;){for(var v;;){r!==h||0!==n&&3!==r.nodeType||(w=ba+n);r!==q||0!==m&&3!==r.nodeType||(y=ba+m);3===r.nodeType&&(ba+=r.nodeValue.length);if(null===(v=r.firstChild))break;z=r;
|
|
r=v}for(;;){if(r===g)break b;z===h&&++B===n&&(w=ba);z===q&&++D===m&&(y=ba);if(null!==(v=r.nextSibling))break;r=z;z=r.parentNode}r=v}h=-1===w||-1===y?null:{start:w,end:y}}else h=null}h=h||{start:0,end:0}}else h=null;$e={activeElementDetached:null,focusedElem:g,selectionRange:h};tc=!1;l=e;do try{Bj()}catch(sb){if(null===l)throw Error(k(330));Za(l,sb);l=l.nextEffect}while(null!==l);l=e;do try{for(g=a,h=b;null!==l;){var x=l.effectTag;x&16&&Wb(l.stateNode,"");if(x&128){var A=l.alternate;if(null!==A){var u=
|
|
A.ref;null!==u&&("function"===typeof u?u(null):u.current=null)}}switch(x&1038){case 2:Gh(l);l.effectTag&=-3;break;case 6:Gh(l);l.effectTag&=-3;Qe(l.alternate,l);break;case 1024:l.effectTag&=-1025;break;case 1028:l.effectTag&=-1025;Qe(l.alternate,l);break;case 4:Qe(l.alternate,l);break;case 8:n=l,Dh(g,n,h),Eh(n)}l=l.nextEffect}}catch(sb){if(null===l)throw Error(k(330));Za(l,sb);l=l.nextEffect}while(null!==l);u=$e;A=kg();x=u.focusedElem;h=u.selectionRange;if(A!==x&&x&&x.ownerDocument&&jg(x.ownerDocument.documentElement,
|
|
x)){null!==h&&Xd(x)&&(A=h.start,u=h.end,void 0===u&&(u=A),"selectionStart"in x?(x.selectionStart=A,x.selectionEnd=Math.min(u,x.value.length)):(u=(A=x.ownerDocument||document)&&A.defaultView||window,u.getSelection&&(u=u.getSelection(),n=x.textContent.length,g=Math.min(h.start,n),h=void 0===h.end?g:Math.min(h.end,n),!u.extend&&g>h&&(n=h,h=g,g=n),n=ig(x,g),q=ig(x,h),n&&q&&(1!==u.rangeCount||u.anchorNode!==n.node||u.anchorOffset!==n.offset||u.focusNode!==q.node||u.focusOffset!==q.offset)&&(A=A.createRange(),
|
|
A.setStart(n.node,n.offset),u.removeAllRanges(),g>h?(u.addRange(A),u.extend(q.node,q.offset)):(A.setEnd(q.node,q.offset),u.addRange(A))))));A=[];for(u=x;u=u.parentNode;)1===u.nodeType&&A.push({element:u,left:u.scrollLeft,top:u.scrollTop});"function"===typeof x.focus&&x.focus();for(x=0;x<A.length;x++)u=A[x],u.element.scrollLeft=u.left,u.element.scrollTop=u.top}tc=!!Ze;$e=Ze=null;a.current=c;l=e;do try{for(x=a;null!==l;){var F=l.effectTag;F&36&&oj(x,l.alternate,l);if(F&128){A=void 0;var E=l.ref;if(null!==
|
|
E){var G=l.stateNode;switch(l.tag){case 5:A=G;break;default:A=G}"function"===typeof E?E(A):E.current=A}}l=l.nextEffect}}catch(sb){if(null===l)throw Error(k(330));Za(l,sb);l=l.nextEffect}while(null!==l);l=null;Cj();p=f}else a.current=c;if(ld)ld=!1,Zb=a,$b=b;else for(l=e;null!==l;)b=l.nextEffect,l.nextEffect=null,l=b;b=a.firstPendingTime;0===b&&(La=null);1073741823===b?a===af?ac++:(ac=0,af=a):ac=0;"function"===typeof bf&&bf(c.stateNode,d);V(a);if(cd)throw cd=!1,a=Se,Se=null,a;if((p&Ye)!==H)return null;
|
|
ha();return null}function Bj(){for(;null!==l;){var a=l.effectTag;0!==(a&256)&&nj(l.alternate,l);0===(a&512)||ld||(ld=!0,Ng(97,function(){xb();return null}));l=l.nextEffect}}function xb(){if(90!==$b){var a=97<$b?97:$b;$b=90;return Da(a,Dj)}}function Dj(){if(null===Zb)return!1;var a=Zb;Zb=null;if((p&(ca|ma))!==H)throw Error(k(331));var b=p;p|=ma;for(a=a.current.firstEffect;null!==a;){try{var c=a;if(0!==(c.effectTag&512))switch(c.tag){case 0:case 11:case 15:case 22:Ah(5,c),Bh(5,c)}}catch(d){if(null===
|
|
a)throw Error(k(330));Za(a,d)}c=a.nextEffect;a.nextEffect=null;a=c}p=b;ha();return!0}function Vh(a,b,c){b=Le(c,b);b=Ih(a,b,1073741823);Fa(a,b);a=ed(a,1073741823);null!==a&&V(a)}function Za(a,b){if(3===a.tag)Vh(a,a,b);else for(var c=a.return;null!==c;){if(3===c.tag){Vh(c,a,b);break}else if(1===c.tag){var d=c.stateNode;if("function"===typeof c.type.getDerivedStateFromError||"function"===typeof d.componentDidCatch&&(null===La||!La.has(d))){a=Le(b,a);a=Jh(c,a,1073741823);Fa(c,a);c=ed(c,1073741823);null!==
|
|
c&&V(c);break}}c=c.return}}function xj(a,b,c){var d=a.pingCache;null!==d&&d.delete(b);U===a&&P===c?F===bd||F===ad&&1073741823===ta&&Y()-Re<Ph?$a(a,P):jd=!0:Kh(a,c)&&(b=a.lastPingedTime,0!==b&&b<c||(a.lastPingedTime=c,V(a)))}function qj(a,b){var c=a.stateNode;null!==c&&c.delete(b);b=0;0===b&&(b=ka(),b=Va(b,a,null));a=ed(a,b);null!==a&&V(a)}function Ej(a){if("undefined"===typeof __REACT_DEVTOOLS_GLOBAL_HOOK__)return!1;var b=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(b.isDisabled||!b.supportsFiber)return!0;try{var c=
|
|
b.inject(a);bf=function(a,e){try{b.onCommitFiberRoot(c,a,void 0,64===(a.current.effectTag&64))}catch(f){}};Ne=function(a){try{b.onCommitFiberUnmount(c,a)}catch(e){}}}catch(d){}return!0}function Fj(a,b,c,d){this.tag=a;this.key=c;this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null;this.index=0;this.ref=null;this.pendingProps=b;this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null;this.mode=d;this.effectTag=0;this.lastEffect=this.firstEffect=this.nextEffect=
|
|
null;this.childExpirationTime=this.expirationTime=0;this.alternate=null}function Ge(a){a=a.prototype;return!(!a||!a.isReactComponent)}function Gj(a){if("function"===typeof a)return Ge(a)?1:0;if(void 0!==a&&null!==a){a=a.$$typeof;if(a===zd)return 11;if(a===Ad)return 14}return 2}function Sa(a,b){var c=a.alternate;null===c?(c=la(a.tag,b,a.key,a.mode),c.elementType=a.elementType,c.type=a.type,c.stateNode=a.stateNode,c.alternate=a,a.alternate=c):(c.pendingProps=b,c.effectTag=0,c.nextEffect=null,c.firstEffect=
|
|
null,c.lastEffect=null);c.childExpirationTime=a.childExpirationTime;c.expirationTime=a.expirationTime;c.child=a.child;c.memoizedProps=a.memoizedProps;c.memoizedState=a.memoizedState;c.updateQueue=a.updateQueue;b=a.dependencies;c.dependencies=null===b?null:{expirationTime:b.expirationTime,firstContext:b.firstContext,responders:b.responders};c.sibling=a.sibling;c.index=a.index;c.ref=a.ref;return c}function Oc(a,b,c,d,e,f){var g=2;d=a;if("function"===typeof a)Ge(a)&&(g=1);else if("string"===typeof a)g=
|
|
5;else a:switch(a){case Ma:return Ha(c.children,e,f,b);case Hj:g=8;e|=7;break;case Af:g=8;e|=1;break;case kc:return a=la(12,c,b,e|8),a.elementType=kc,a.type=kc,a.expirationTime=f,a;case lc:return a=la(13,c,b,e),a.type=lc,a.elementType=lc,a.expirationTime=f,a;case yd:return a=la(19,c,b,e),a.elementType=yd,a.expirationTime=f,a;default:if("object"===typeof a&&null!==a)switch(a.$$typeof){case Cf:g=10;break a;case Bf:g=9;break a;case zd:g=11;break a;case Ad:g=14;break a;case Ef:g=16;d=null;break a;case Df:g=
|
|
22;break a}throw Error(k(130,null==a?a:typeof a,""));}b=la(g,c,b,e);b.elementType=a;b.type=d;b.expirationTime=f;return b}function Ha(a,b,c,d){a=la(7,a,d,b);a.expirationTime=c;return a}function qe(a,b,c){a=la(6,a,null,b);a.expirationTime=c;return a}function re(a,b,c){b=la(4,null!==a.children?a.children:[],a.key,b);b.expirationTime=c;b.stateNode={containerInfo:a.containerInfo,pendingChildren:null,implementation:a.implementation};return b}function Ij(a,b,c){this.tag=b;this.current=null;this.containerInfo=
|
|
a;this.pingCache=this.pendingChildren=null;this.finishedExpirationTime=0;this.finishedWork=null;this.timeoutHandle=-1;this.pendingContext=this.context=null;this.hydrate=c;this.callbackNode=null;this.callbackPriority=90;this.lastExpiredTime=this.lastPingedTime=this.nextKnownPendingLevel=this.lastSuspendedTime=this.firstSuspendedTime=this.firstPendingTime=0}function Kh(a,b){var c=a.firstSuspendedTime;a=a.lastSuspendedTime;return 0!==c&&c>=b&&a<=b}function Ya(a,b){var c=a.firstSuspendedTime,d=a.lastSuspendedTime;
|
|
c<b&&(a.firstSuspendedTime=b);if(d>b||0===c)a.lastSuspendedTime=b;b<=a.lastPingedTime&&(a.lastPingedTime=0);b<=a.lastExpiredTime&&(a.lastExpiredTime=0)}function yh(a,b){b>a.firstPendingTime&&(a.firstPendingTime=b);var c=a.firstSuspendedTime;0!==c&&(b>=c?a.firstSuspendedTime=a.lastSuspendedTime=a.nextKnownPendingLevel=0:b>=a.lastSuspendedTime&&(a.lastSuspendedTime=b+1),b>a.nextKnownPendingLevel&&(a.nextKnownPendingLevel=b))}function Ue(a,b){var c=a.lastExpiredTime;if(0===c||c>b)a.lastExpiredTime=b}
|
|
function md(a,b,c,d){var e=b.current,f=ka(),g=Vb.suspense;f=Va(f,e,g);a:if(c){c=c._reactInternalFiber;b:{if(Na(c)!==c||1!==c.tag)throw Error(k(170));var h=c;do{switch(h.tag){case 3:h=h.stateNode.context;break b;case 1:if(N(h.type)){h=h.stateNode.__reactInternalMemoizedMergedChildContext;break b}}h=h.return}while(null!==h);throw Error(k(171));}if(1===c.tag){var m=c.type;if(N(m)){c=Gg(c,m,h);break a}}c=h}else c=Ca;null===b.context?b.context=c:b.pendingContext=c;b=Ea(f,g);b.payload={element:a};d=void 0===
|
|
d?null:d;null!==d&&(b.callback=d);Fa(e,b);Ja(e,f);return f}function cf(a){a=a.current;if(!a.child)return null;switch(a.child.tag){case 5:return a.child.stateNode;default:return a.child.stateNode}}function Wh(a,b){a=a.memoizedState;null!==a&&null!==a.dehydrated&&a.retryTime<b&&(a.retryTime=b)}function df(a,b){Wh(a,b);(a=a.alternate)&&Wh(a,b)}function ef(a,b,c){c=null!=c&&!0===c.hydrate;var d=new Ij(a,b,c),e=la(3,null,null,2===b?7:1===b?3:0);d.current=e;e.stateNode=d;ne(e);a[Lb]=d.current;c&&0!==b&&
|
|
xi(a,9===a.nodeType?a:a.ownerDocument);this._internalRoot=d}function bc(a){return!(!a||1!==a.nodeType&&9!==a.nodeType&&11!==a.nodeType&&(8!==a.nodeType||" react-mount-point-unstable "!==a.nodeValue))}function Jj(a,b){b||(b=a?9===a.nodeType?a.documentElement:a.firstChild:null,b=!(!b||1!==b.nodeType||!b.hasAttribute("data-reactroot")));if(!b)for(var c;c=a.lastChild;)a.removeChild(c);return new ef(a,0,b?{hydrate:!0}:void 0)}function nd(a,b,c,d,e){var f=c._reactRootContainer;if(f){var g=f._internalRoot;
|
|
if("function"===typeof e){var h=e;e=function(){var a=cf(g);h.call(a)}}md(b,g,a,e)}else{f=c._reactRootContainer=Jj(c,d);g=f._internalRoot;if("function"===typeof e){var m=e;e=function(){var a=cf(g);m.call(a)}}Rh(function(){md(b,g,a,e)})}return cf(g)}function Kj(a,b,c){var d=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null;return{$$typeof:gb,key:null==d?null:""+d,children:a,containerInfo:b,implementation:c}}function Xh(a,b){var c=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null;
|
|
if(!bc(b))throw Error(k(200));return Kj(a,b,null,c)}if(!ea)throw Error(k(227));var ki=function(a,b,c,d,e,f,g,h,m){var n=Array.prototype.slice.call(arguments,3);try{b.apply(c,n)}catch(C){this.onError(C)}},yb=!1,gc=null,hc=!1,pd=null,li={onError:function(a){yb=!0;gc=a}},td=null,rf=null,mf=null,ic=null,cb={},jc=[],qd={},db={},rd={},wa=!("undefined"===typeof window||"undefined"===typeof window.document||"undefined"===typeof window.document.createElement),M=ea.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.assign,
|
|
sd=null,eb=null,fb=null,ee=function(a,b){return a(b)},eg=function(a,b,c,d,e){return a(b,c,d,e)},vd=function(){},vf=ee,Oa=!1,wd=!1,Z=ea.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler,Lj=Z.unstable_cancelCallback,ff=Z.unstable_now,$f=Z.unstable_scheduleCallback,Mj=Z.unstable_shouldYield,Yh=Z.unstable_requestPaint,Pd=Z.unstable_runWithPriority,Nj=Z.unstable_getCurrentPriorityLevel,Oj=Z.unstable_ImmediatePriority,Zh=Z.unstable_UserBlockingPriority,ag=Z.unstable_NormalPriority,Pj=Z.unstable_LowPriority,
|
|
Qj=Z.unstable_IdlePriority,oi=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,wf=Object.prototype.hasOwnProperty,yf={},xf={},E={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(a){E[a]=
|
|
new L(a,0,!1,a,null,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(a){var b=a[0];E[b]=new L(b,1,!1,a[1],null,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(a){E[a]=new L(a,2,!1,a.toLowerCase(),null,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(a){E[a]=new L(a,2,!1,a,null,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(a){E[a]=
|
|
new L(a,3,!1,a.toLowerCase(),null,!1)});["checked","multiple","muted","selected"].forEach(function(a){E[a]=new L(a,3,!0,a,null,!1)});["capture","download"].forEach(function(a){E[a]=new L(a,4,!1,a,null,!1)});["cols","rows","size","span"].forEach(function(a){E[a]=new L(a,6,!1,a,null,!1)});["rowSpan","start"].forEach(function(a){E[a]=new L(a,5,!1,a.toLowerCase(),null,!1)});var gf=/[\-:]([a-z])/g,hf=function(a){return a[1].toUpperCase()};"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(a){var b=
|
|
a.replace(gf,hf);E[b]=new L(b,1,!1,a,null,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(a){var b=a.replace(gf,hf);E[b]=new L(b,1,!1,a,"http://www.w3.org/1999/xlink",!1)});["xml:base","xml:lang","xml:space"].forEach(function(a){var b=a.replace(gf,hf);E[b]=new L(b,1,!1,a,"http://www.w3.org/XML/1998/namespace",!1)});["tabIndex","crossOrigin"].forEach(function(a){E[a]=new L(a,1,!1,a.toLowerCase(),null,!1)});E.xlinkHref=new L("xlinkHref",1,
|
|
!1,"xlink:href","http://www.w3.org/1999/xlink",!0);["src","href","action","formAction"].forEach(function(a){E[a]=new L(a,1,!1,a.toLowerCase(),null,!0)});var da=ea.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;da.hasOwnProperty("ReactCurrentDispatcher")||(da.ReactCurrentDispatcher={current:null});da.hasOwnProperty("ReactCurrentBatchConfig")||(da.ReactCurrentBatchConfig={suspense:null});var si=/^(.*)[\\\/]/,Q="function"===typeof Symbol&&Symbol.for,Pc=Q?Symbol.for("react.element"):60103,gb=Q?Symbol.for("react.portal"):
|
|
60106,Ma=Q?Symbol.for("react.fragment"):60107,Af=Q?Symbol.for("react.strict_mode"):60108,kc=Q?Symbol.for("react.profiler"):60114,Cf=Q?Symbol.for("react.provider"):60109,Bf=Q?Symbol.for("react.context"):60110,Hj=Q?Symbol.for("react.concurrent_mode"):60111,zd=Q?Symbol.for("react.forward_ref"):60112,lc=Q?Symbol.for("react.suspense"):60113,yd=Q?Symbol.for("react.suspense_list"):60120,Ad=Q?Symbol.for("react.memo"):60115,Ef=Q?Symbol.for("react.lazy"):60116,Df=Q?Symbol.for("react.block"):60121,zf="function"===
|
|
typeof Symbol&&Symbol.iterator,od,xh=function(a){return"undefined"!==typeof MSApp&&MSApp.execUnsafeLocalFunction?function(b,c,d,e){MSApp.execUnsafeLocalFunction(function(){return a(b,c,d,e)})}:a}(function(a,b){if("http://www.w3.org/2000/svg"!==a.namespaceURI||"innerHTML"in a)a.innerHTML=b;else{od=od||document.createElement("div");od.innerHTML="<svg>"+b.valueOf().toString()+"</svg>";for(b=od.firstChild;a.firstChild;)a.removeChild(a.firstChild);for(;b.firstChild;)a.appendChild(b.firstChild)}}),Wb=function(a,
|
|
b){if(b){var c=a.firstChild;if(c&&c===a.lastChild&&3===c.nodeType){c.nodeValue=b;return}}a.textContent=b},ib={animationend:nc("Animation","AnimationEnd"),animationiteration:nc("Animation","AnimationIteration"),animationstart:nc("Animation","AnimationStart"),transitionend:nc("Transition","TransitionEnd")},Id={},Of={};wa&&(Of=document.createElement("div").style,"AnimationEvent"in window||(delete ib.animationend.animation,delete ib.animationiteration.animation,delete ib.animationstart.animation),"TransitionEvent"in
|
|
window||delete ib.transitionend.transition);var $h=oc("animationend"),ai=oc("animationiteration"),bi=oc("animationstart"),ci=oc("transitionend"),Db="abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange seeked seeking stalled suspend timeupdate volumechange waiting".split(" "),Pf=new ("function"===typeof WeakMap?WeakMap:Map),Ab=null,wi=function(a){if(a){var b=a._dispatchListeners,c=a._dispatchInstances;
|
|
if(Array.isArray(b))for(var d=0;d<b.length&&!a.isPropagationStopped();d++)lf(a,b[d],c[d]);else b&&lf(a,b,c);a._dispatchListeners=null;a._dispatchInstances=null;a.isPersistent()||a.constructor.release(a)}},qc=[],Rd=!1,fa=[],xa=null,ya=null,za=null,Eb=new Map,Fb=new Map,Jb=[],Nd="mousedown mouseup touchcancel touchend touchstart auxclick dblclick pointercancel pointerdown pointerup dragend dragstart drop compositionend compositionstart keydown keypress keyup input textInput close cancel copy cut paste click change contextmenu reset submit".split(" "),
|
|
yi="focus blur dragenter dragleave mouseover mouseout pointerover pointerout gotpointercapture lostpointercapture".split(" "),dg={},cg=new Map,Td=new Map,Rj=["abort","abort",$h,"animationEnd",ai,"animationIteration",bi,"animationStart","canplay","canPlay","canplaythrough","canPlayThrough","durationchange","durationChange","emptied","emptied","encrypted","encrypted","ended","ended","error","error","gotpointercapture","gotPointerCapture","load","load","loadeddata","loadedData","loadedmetadata","loadedMetadata",
|
|
"loadstart","loadStart","lostpointercapture","lostPointerCapture","playing","playing","progress","progress","seeking","seeking","stalled","stalled","suspend","suspend","timeupdate","timeUpdate",ci,"transitionEnd","waiting","waiting"];Sd("blur blur cancel cancel click click close close contextmenu contextMenu copy copy cut cut auxclick auxClick dblclick doubleClick dragend dragEnd dragstart dragStart drop drop focus focus input input invalid invalid keydown keyDown keypress keyPress keyup keyUp mousedown mouseDown mouseup mouseUp paste paste pause pause play play pointercancel pointerCancel pointerdown pointerDown pointerup pointerUp ratechange rateChange reset reset seeked seeked submit submit touchcancel touchCancel touchend touchEnd touchstart touchStart volumechange volumeChange".split(" "),
|
|
0);Sd("drag drag dragenter dragEnter dragexit dragExit dragleave dragLeave dragover dragOver mousemove mouseMove mouseout mouseOut mouseover mouseOver pointermove pointerMove pointerout pointerOut pointerover pointerOver scroll scroll toggle toggle touchmove touchMove wheel wheel".split(" "),1);Sd(Rj,2);(function(a,b){for(var c=0;c<a.length;c++)Td.set(a[c],b)})("change selectionchange textInput compositionstart compositionend compositionupdate".split(" "),0);var Hi=Zh,Gi=Pd,tc=!0,Kb={animationIterationCount:!0,
|
|
borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,
|
|
strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},Sj=["Webkit","ms","Moz","O"];Object.keys(Kb).forEach(function(a){Sj.forEach(function(b){b=b+a.charAt(0).toUpperCase()+a.substring(1);Kb[b]=Kb[a]})});var Ii=M({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0}),ng="$",og="/$",$d="$?",Zd="$!",Ze=null,$e=null,We="function"===typeof setTimeout?setTimeout:void 0,vj="function"===
|
|
typeof clearTimeout?clearTimeout:void 0,jf=Math.random().toString(36).slice(2),Aa="__reactInternalInstance$"+jf,vc="__reactEventHandlers$"+jf,Lb="__reactContainere$"+jf,Ba=null,ce=null,wc=null;M(R.prototype,{preventDefault:function(){this.defaultPrevented=!0;var a=this.nativeEvent;a&&(a.preventDefault?a.preventDefault():"unknown"!==typeof a.returnValue&&(a.returnValue=!1),this.isDefaultPrevented=xc)},stopPropagation:function(){var a=this.nativeEvent;a&&(a.stopPropagation?a.stopPropagation():"unknown"!==
|
|
typeof a.cancelBubble&&(a.cancelBubble=!0),this.isPropagationStopped=xc)},persist:function(){this.isPersistent=xc},isPersistent:yc,destructor:function(){var a=this.constructor.Interface,b;for(b in a)this[b]=null;this.nativeEvent=this._targetInst=this.dispatchConfig=null;this.isPropagationStopped=this.isDefaultPrevented=yc;this._dispatchInstances=this._dispatchListeners=null}});R.Interface={type:null,target:null,currentTarget:function(){return null},eventPhase:null,bubbles:null,cancelable:null,timeStamp:function(a){return a.timeStamp||
|
|
Date.now()},defaultPrevented:null,isTrusted:null};R.extend=function(a){function b(){return c.apply(this,arguments)}var c=this,d=function(){};d.prototype=c.prototype;d=new d;M(d,b.prototype);b.prototype=d;b.prototype.constructor=b;b.Interface=M({},c.Interface,a);b.extend=c.extend;sg(b);return b};sg(R);var Tj=R.extend({data:null}),Uj=R.extend({data:null}),Ni=[9,13,27,32],de=wa&&"CompositionEvent"in window,cc=null;wa&&"documentMode"in document&&(cc=document.documentMode);var Vj=wa&&"TextEvent"in window&&
|
|
!cc,xg=wa&&(!de||cc&&8<cc&&11>=cc),wg=String.fromCharCode(32),ua={beforeInput:{phasedRegistrationNames:{bubbled:"onBeforeInput",captured:"onBeforeInputCapture"},dependencies:["compositionend","keypress","textInput","paste"]},compositionEnd:{phasedRegistrationNames:{bubbled:"onCompositionEnd",captured:"onCompositionEndCapture"},dependencies:"blur compositionend keydown keypress keyup mousedown".split(" ")},compositionStart:{phasedRegistrationNames:{bubbled:"onCompositionStart",captured:"onCompositionStartCapture"},
|
|
dependencies:"blur compositionstart keydown keypress keyup mousedown".split(" ")},compositionUpdate:{phasedRegistrationNames:{bubbled:"onCompositionUpdate",captured:"onCompositionUpdateCapture"},dependencies:"blur compositionupdate keydown keypress keyup mousedown".split(" ")}},vg=!1,mb=!1,Wj={eventTypes:ua,extractEvents:function(a,b,c,d,e){var f;if(de)b:{switch(a){case "compositionstart":var g=ua.compositionStart;break b;case "compositionend":g=ua.compositionEnd;break b;case "compositionupdate":g=
|
|
ua.compositionUpdate;break b}g=void 0}else mb?tg(a,c)&&(g=ua.compositionEnd):"keydown"===a&&229===c.keyCode&&(g=ua.compositionStart);g?(xg&&"ko"!==c.locale&&(mb||g!==ua.compositionStart?g===ua.compositionEnd&&mb&&(f=rg()):(Ba=d,ce="value"in Ba?Ba.value:Ba.textContent,mb=!0)),e=Tj.getPooled(g,b,c,d),f?e.data=f:(f=ug(c),null!==f&&(e.data=f)),lb(e),f=e):f=null;(a=Vj?Oi(a,c):Pi(a,c))?(b=Uj.getPooled(ua.beforeInput,b,c,d),b.data=a,lb(b)):b=null;return null===f?b:null===b?f:[f,b]}},Qi={color:!0,date:!0,
|
|
datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0},Ag={change:{phasedRegistrationNames:{bubbled:"onChange",captured:"onChangeCapture"},dependencies:"blur change click focus input keydown keyup selectionchange".split(" ")}},Mb=null,Nb=null,kf=!1;wa&&(kf=Tf("input")&&(!document.documentMode||9<document.documentMode));var Xj={eventTypes:Ag,_isInputEventSupported:kf,extractEvents:function(a,b,c,d,e){e=b?Pa(b):window;var f=
|
|
e.nodeName&&e.nodeName.toLowerCase();if("select"===f||"input"===f&&"file"===e.type)var g=Si;else if(yg(e))if(kf)g=Wi;else{g=Ui;var h=Ti}else(f=e.nodeName)&&"input"===f.toLowerCase()&&("checkbox"===e.type||"radio"===e.type)&&(g=Vi);if(g&&(g=g(a,b)))return zg(g,c,d);h&&h(a,e,b);"blur"===a&&(a=e._wrapperState)&&a.controlled&&"number"===e.type&&Ed(e,"number",e.value)}},dc=R.extend({view:null,detail:null}),Yi={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"},di=0,ei=0,fi=!1,gi=!1,ec=dc.extend({screenX:null,
|
|
screenY:null,clientX:null,clientY:null,pageX:null,pageY:null,ctrlKey:null,shiftKey:null,altKey:null,metaKey:null,getModifierState:fe,button:null,buttons:null,relatedTarget:function(a){return a.relatedTarget||(a.fromElement===a.srcElement?a.toElement:a.fromElement)},movementX:function(a){if("movementX"in a)return a.movementX;var b=di;di=a.screenX;return fi?"mousemove"===a.type?a.screenX-b:0:(fi=!0,0)},movementY:function(a){if("movementY"in a)return a.movementY;var b=ei;ei=a.screenY;return gi?"mousemove"===
|
|
a.type?a.screenY-b:0:(gi=!0,0)}}),hi=ec.extend({pointerId:null,width:null,height:null,pressure:null,tangentialPressure:null,tiltX:null,tiltY:null,twist:null,pointerType:null,isPrimary:null}),fc={mouseEnter:{registrationName:"onMouseEnter",dependencies:["mouseout","mouseover"]},mouseLeave:{registrationName:"onMouseLeave",dependencies:["mouseout","mouseover"]},pointerEnter:{registrationName:"onPointerEnter",dependencies:["pointerout","pointerover"]},pointerLeave:{registrationName:"onPointerLeave",dependencies:["pointerout",
|
|
"pointerover"]}},Yj={eventTypes:fc,extractEvents:function(a,b,c,d,e){var f="mouseover"===a||"pointerover"===a,g="mouseout"===a||"pointerout"===a;if(f&&0===(e&32)&&(c.relatedTarget||c.fromElement)||!g&&!f)return null;f=d.window===d?d:(f=d.ownerDocument)?f.defaultView||f.parentWindow:window;if(g){if(g=b,b=(b=c.relatedTarget||c.toElement)?Bb(b):null,null!==b){var h=Na(b);if(b!==h||5!==b.tag&&6!==b.tag)b=null}}else g=null;if(g===b)return null;if("mouseout"===a||"mouseover"===a){var m=ec;var n=fc.mouseLeave;
|
|
var l=fc.mouseEnter;var k="mouse"}else if("pointerout"===a||"pointerover"===a)m=hi,n=fc.pointerLeave,l=fc.pointerEnter,k="pointer";a=null==g?f:Pa(g);f=null==b?f:Pa(b);n=m.getPooled(n,g,c,d);n.type=k+"leave";n.target=a;n.relatedTarget=f;c=m.getPooled(l,b,c,d);c.type=k+"enter";c.target=f;c.relatedTarget=a;d=g;k=b;if(d&&k)a:{m=d;l=k;g=0;for(a=m;a;a=pa(a))g++;a=0;for(b=l;b;b=pa(b))a++;for(;0<g-a;)m=pa(m),g--;for(;0<a-g;)l=pa(l),a--;for(;g--;){if(m===l||m===l.alternate)break a;m=pa(m);l=pa(l)}m=null}else m=
|
|
null;l=m;for(m=[];d&&d!==l;){g=d.alternate;if(null!==g&&g===l)break;m.push(d);d=pa(d)}for(d=[];k&&k!==l;){g=k.alternate;if(null!==g&&g===l)break;d.push(k);k=pa(k)}for(k=0;k<m.length;k++)be(m[k],"bubbled",n);for(k=d.length;0<k--;)be(d[k],"captured",c);return 0===(e&64)?[n]:[n,c]}},Qa="function"===typeof Object.is?Object.is:Zi,$i=Object.prototype.hasOwnProperty,Zj=wa&&"documentMode"in document&&11>=document.documentMode,Eg={select:{phasedRegistrationNames:{bubbled:"onSelect",captured:"onSelectCapture"},
|
|
dependencies:"blur contextmenu dragend focus keydown keyup mousedown mouseup selectionchange".split(" ")}},nb=null,he=null,Pb=null,ge=!1,ak={eventTypes:Eg,extractEvents:function(a,b,c,d,e,f){e=f||(d.window===d?d.document:9===d.nodeType?d:d.ownerDocument);if(!(f=!e)){a:{e=Jd(e);f=rd.onSelect;for(var g=0;g<f.length;g++)if(!e.has(f[g])){e=!1;break a}e=!0}f=!e}if(f)return null;e=b?Pa(b):window;switch(a){case "focus":if(yg(e)||"true"===e.contentEditable)nb=e,he=b,Pb=null;break;case "blur":Pb=he=nb=null;
|
|
break;case "mousedown":ge=!0;break;case "contextmenu":case "mouseup":case "dragend":return ge=!1,Dg(c,d);case "selectionchange":if(Zj)break;case "keydown":case "keyup":return Dg(c,d)}return null}},bk=R.extend({animationName:null,elapsedTime:null,pseudoElement:null}),ck=R.extend({clipboardData:function(a){return"clipboardData"in a?a.clipboardData:window.clipboardData}}),dk=dc.extend({relatedTarget:null}),ek={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",
|
|
Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},fk={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",
|
|
224:"Meta"},gk=dc.extend({key:function(a){if(a.key){var b=ek[a.key]||a.key;if("Unidentified"!==b)return b}return"keypress"===a.type?(a=Ac(a),13===a?"Enter":String.fromCharCode(a)):"keydown"===a.type||"keyup"===a.type?fk[a.keyCode]||"Unidentified":""},location:null,ctrlKey:null,shiftKey:null,altKey:null,metaKey:null,repeat:null,locale:null,getModifierState:fe,charCode:function(a){return"keypress"===a.type?Ac(a):0},keyCode:function(a){return"keydown"===a.type||"keyup"===a.type?a.keyCode:0},which:function(a){return"keypress"===
|
|
a.type?Ac(a):"keydown"===a.type||"keyup"===a.type?a.keyCode:0}}),hk=ec.extend({dataTransfer:null}),ik=dc.extend({touches:null,targetTouches:null,changedTouches:null,altKey:null,metaKey:null,ctrlKey:null,shiftKey:null,getModifierState:fe}),jk=R.extend({propertyName:null,elapsedTime:null,pseudoElement:null}),kk=ec.extend({deltaX:function(a){return"deltaX"in a?a.deltaX:"wheelDeltaX"in a?-a.wheelDeltaX:0},deltaY:function(a){return"deltaY"in a?a.deltaY:"wheelDeltaY"in a?-a.wheelDeltaY:"wheelDelta"in a?
|
|
-a.wheelDelta:0},deltaZ:null,deltaMode:null}),lk={eventTypes:dg,extractEvents:function(a,b,c,d,e){e=cg.get(a);if(!e)return null;switch(a){case "keypress":if(0===Ac(c))return null;case "keydown":case "keyup":a=gk;break;case "blur":case "focus":a=dk;break;case "click":if(2===c.button)return null;case "auxclick":case "dblclick":case "mousedown":case "mousemove":case "mouseup":case "mouseout":case "mouseover":case "contextmenu":a=ec;break;case "drag":case "dragend":case "dragenter":case "dragexit":case "dragleave":case "dragover":case "dragstart":case "drop":a=
|
|
hk;break;case "touchcancel":case "touchend":case "touchmove":case "touchstart":a=ik;break;case $h:case ai:case bi:a=bk;break;case ci:a=jk;break;case "scroll":a=dc;break;case "wheel":a=kk;break;case "copy":case "cut":case "paste":a=ck;break;case "gotpointercapture":case "lostpointercapture":case "pointercancel":case "pointerdown":case "pointermove":case "pointerout":case "pointerover":case "pointerup":a=hi;break;default:a=R}b=a.getPooled(e,b,c,d);lb(b);return b}};(function(a){if(ic)throw Error(k(101));
|
|
ic=Array.prototype.slice.call(a);nf()})("ResponderEventPlugin SimpleEventPlugin EnterLeaveEventPlugin ChangeEventPlugin SelectEventPlugin BeforeInputEventPlugin".split(" "));(function(a,b,c){td=a;rf=b;mf=c})(ae,Hb,Pa);pf({SimpleEventPlugin:lk,EnterLeaveEventPlugin:Yj,ChangeEventPlugin:Xj,SelectEventPlugin:ak,BeforeInputEventPlugin:Wj});var ie=[],ob=-1,Ca={},B={current:Ca},G={current:!1},Ra=Ca,bj=Pd,je=$f,Rg=Lj,aj=Nj,Dc=Oj,Ig=Zh,Jg=ag,Kg=Pj,Lg=Qj,Qg={},yj=Mj,Cj=void 0!==Yh?Yh:function(){},qa=null,
|
|
Ec=null,ke=!1,ii=ff(),Y=1E4>ii?ff:function(){return ff()-ii},Ic={current:null},Hc=null,qb=null,Gc=null,Tg=0,Jc=2,Ga=!1,Vb=da.ReactCurrentBatchConfig,$g=(new ea.Component).refs,Mc={isMounted:function(a){return(a=a._reactInternalFiber)?Na(a)===a:!1},enqueueSetState:function(a,b,c){a=a._reactInternalFiber;var d=ka(),e=Vb.suspense;d=Va(d,a,e);e=Ea(d,e);e.payload=b;void 0!==c&&null!==c&&(e.callback=c);Fa(a,e);Ja(a,d)},enqueueReplaceState:function(a,b,c){a=a._reactInternalFiber;var d=ka(),e=Vb.suspense;
|
|
d=Va(d,a,e);e=Ea(d,e);e.tag=1;e.payload=b;void 0!==c&&null!==c&&(e.callback=c);Fa(a,e);Ja(a,d)},enqueueForceUpdate:function(a,b){a=a._reactInternalFiber;var c=ka(),d=Vb.suspense;c=Va(c,a,d);d=Ea(c,d);d.tag=Jc;void 0!==b&&null!==b&&(d.callback=b);Fa(a,d);Ja(a,c)}},Qc=Array.isArray,wb=ah(!0),Fe=ah(!1),Sb={},ja={current:Sb},Ub={current:Sb},Tb={current:Sb},D={current:0},Sc=da.ReactCurrentDispatcher,X=da.ReactCurrentBatchConfig,Ia=0,z=null,K=null,J=null,Uc=!1,Tc={readContext:W,useCallback:S,useContext:S,
|
|
useEffect:S,useImperativeHandle:S,useLayoutEffect:S,useMemo:S,useReducer:S,useRef:S,useState:S,useDebugValue:S,useResponder:S,useDeferredValue:S,useTransition:S},dj={readContext:W,useCallback:ih,useContext:W,useEffect:eh,useImperativeHandle:function(a,b,c){c=null!==c&&void 0!==c?c.concat([a]):null;return ze(4,2,gh.bind(null,b,a),c)},useLayoutEffect:function(a,b){return ze(4,2,a,b)},useMemo:function(a,b){var c=ub();b=void 0===b?null:b;a=a();c.memoizedState=[a,b];return a},useReducer:function(a,b,c){var d=
|
|
ub();b=void 0!==c?c(b):b;d.memoizedState=d.baseState=b;a=d.queue={pending:null,dispatch:null,lastRenderedReducer:a,lastRenderedState:b};a=a.dispatch=ch.bind(null,z,a);return[d.memoizedState,a]},useRef:function(a){var b=ub();a={current:a};return b.memoizedState=a},useState:xe,useDebugValue:Be,useResponder:ue,useDeferredValue:function(a,b){var c=xe(a),d=c[0],e=c[1];eh(function(){var c=X.suspense;X.suspense=void 0===b?null:b;try{e(a)}finally{X.suspense=c}},[a,b]);return d},useTransition:function(a){var b=
|
|
xe(!1),c=b[0];b=b[1];return[ih(Ce.bind(null,b,a),[b,a]),c]}},ej={readContext:W,useCallback:Yc,useContext:W,useEffect:Xc,useImperativeHandle:hh,useLayoutEffect:fh,useMemo:jh,useReducer:Vc,useRef:dh,useState:function(a){return Vc(Ua)},useDebugValue:Be,useResponder:ue,useDeferredValue:function(a,b){var c=Vc(Ua),d=c[0],e=c[1];Xc(function(){var c=X.suspense;X.suspense=void 0===b?null:b;try{e(a)}finally{X.suspense=c}},[a,b]);return d},useTransition:function(a){var b=Vc(Ua),c=b[0];b=b[1];return[Yc(Ce.bind(null,
|
|
b,a),[b,a]),c]}},fj={readContext:W,useCallback:Yc,useContext:W,useEffect:Xc,useImperativeHandle:hh,useLayoutEffect:fh,useMemo:jh,useReducer:Wc,useRef:dh,useState:function(a){return Wc(Ua)},useDebugValue:Be,useResponder:ue,useDeferredValue:function(a,b){var c=Wc(Ua),d=c[0],e=c[1];Xc(function(){var c=X.suspense;X.suspense=void 0===b?null:b;try{e(a)}finally{X.suspense=c}},[a,b]);return d},useTransition:function(a){var b=Wc(Ua),c=b[0];b=b[1];return[Yc(Ce.bind(null,b,a),[b,a]),c]}},ra=null,Ka=null,Wa=
|
|
!1,gj=da.ReactCurrentOwner,ia=!1,Je={dehydrated:null,retryTime:0};var jj=function(a,b,c,d){for(c=b.child;null!==c;){if(5===c.tag||6===c.tag)a.appendChild(c.stateNode);else if(4!==c.tag&&null!==c.child){c.child.return=c;c=c.child;continue}if(c===b)break;for(;null===c.sibling;){if(null===c.return||c.return===b)return;c=c.return}c.sibling.return=c.return;c=c.sibling}};var wh=function(a){};var ij=function(a,b,c,d,e){var f=a.memoizedProps;if(f!==d){var g=b.stateNode;Ta(ja.current);a=null;switch(c){case "input":f=
|
|
Cd(g,f);d=Cd(g,d);a=[];break;case "option":f=Fd(g,f);d=Fd(g,d);a=[];break;case "select":f=M({},f,{value:void 0});d=M({},d,{value:void 0});a=[];break;case "textarea":f=Gd(g,f);d=Gd(g,d);a=[];break;default:"function"!==typeof f.onClick&&"function"===typeof d.onClick&&(g.onclick=uc)}Ud(c,d);var h,m;c=null;for(h in f)if(!d.hasOwnProperty(h)&&f.hasOwnProperty(h)&&null!=f[h])if("style"===h)for(m in g=f[h],g)g.hasOwnProperty(m)&&(c||(c={}),c[m]="");else"dangerouslySetInnerHTML"!==h&&"children"!==h&&"suppressContentEditableWarning"!==
|
|
h&&"suppressHydrationWarning"!==h&&"autoFocus"!==h&&(db.hasOwnProperty(h)?a||(a=[]):(a=a||[]).push(h,null));for(h in d){var k=d[h];g=null!=f?f[h]:void 0;if(d.hasOwnProperty(h)&&k!==g&&(null!=k||null!=g))if("style"===h)if(g){for(m in g)!g.hasOwnProperty(m)||k&&k.hasOwnProperty(m)||(c||(c={}),c[m]="");for(m in k)k.hasOwnProperty(m)&&g[m]!==k[m]&&(c||(c={}),c[m]=k[m])}else c||(a||(a=[]),a.push(h,c)),c=k;else"dangerouslySetInnerHTML"===h?(k=k?k.__html:void 0,g=g?g.__html:void 0,null!=k&&g!==k&&(a=a||
|
|
[]).push(h,k)):"children"===h?g===k||"string"!==typeof k&&"number"!==typeof k||(a=a||[]).push(h,""+k):"suppressContentEditableWarning"!==h&&"suppressHydrationWarning"!==h&&(db.hasOwnProperty(h)?(null!=k&&oa(e,h),a||g===k||(a=[])):(a=a||[]).push(h,k))}c&&(a=a||[]).push("style",c);e=a;if(b.updateQueue=e)b.effectTag|=4}};var kj=function(a,b,c,d){c!==d&&(b.effectTag|=4)};var pj="function"===typeof WeakSet?WeakSet:Set,wj="function"===typeof WeakMap?WeakMap:Map,sj=Math.ceil,gd=da.ReactCurrentDispatcher,
|
|
Uh=da.ReactCurrentOwner,H=0,Ye=8,ca=16,ma=32,Xa=0,hd=1,Oh=2,ad=3,bd=4,Xe=5,p=H,U=null,t=null,P=0,F=Xa,id=null,ta=1073741823,Yb=1073741823,kd=null,Xb=0,jd=!1,Re=0,Ph=500,l=null,cd=!1,Se=null,La=null,ld=!1,Zb=null,$b=90,bb=null,ac=0,af=null,dd=0,Ja=function(a,b){if(50<ac)throw ac=0,af=null,Error(k(185));a=ed(a,b);if(null!==a){var c=Cc();1073741823===b?(p&Ye)!==H&&(p&(ca|ma))===H?Te(a):(V(a),p===H&&ha()):V(a);(p&4)===H||98!==c&&99!==c||(null===bb?bb=new Map([[a,b]]):(c=bb.get(a),(void 0===c||c>b)&&bb.set(a,
|
|
b)))}};var zj=function(a,b,c){var d=b.expirationTime;if(null!==a){var e=b.pendingProps;if(a.memoizedProps!==e||G.current)ia=!0;else{if(d<c){ia=!1;switch(b.tag){case 3:sh(b);Ee();break;case 5:bh(b);if(b.mode&4&&1!==c&&e.hidden)return b.expirationTime=b.childExpirationTime=1,null;break;case 1:N(b.type)&&Bc(b);break;case 4:se(b,b.stateNode.containerInfo);break;case 10:d=b.memoizedProps.value;e=b.type._context;y(Ic,e._currentValue);e._currentValue=d;break;case 13:if(null!==b.memoizedState){d=b.child.childExpirationTime;
|
|
if(0!==d&&d>=c)return th(a,b,c);y(D,D.current&1);b=sa(a,b,c);return null!==b?b.sibling:null}y(D,D.current&1);break;case 19:d=b.childExpirationTime>=c;if(0!==(a.effectTag&64)){if(d)return vh(a,b,c);b.effectTag|=64}e=b.memoizedState;null!==e&&(e.rendering=null,e.tail=null);y(D,D.current);if(!d)return null}return sa(a,b,c)}ia=!1}}else ia=!1;b.expirationTime=0;switch(b.tag){case 2:d=b.type;null!==a&&(a.alternate=null,b.alternate=null,b.effectTag|=2);a=b.pendingProps;e=pb(b,B.current);rb(b,c);e=we(null,
|
|
b,d,a,e,c);b.effectTag|=1;if("object"===typeof e&&null!==e&&"function"===typeof e.render&&void 0===e.$$typeof){b.tag=1;b.memoizedState=null;b.updateQueue=null;if(N(d)){var f=!0;Bc(b)}else f=!1;b.memoizedState=null!==e.state&&void 0!==e.state?e.state:null;ne(b);var g=d.getDerivedStateFromProps;"function"===typeof g&&Lc(b,d,g,a);e.updater=Mc;b.stateNode=e;e._reactInternalFiber=b;pe(b,d,a,c);b=Ie(null,b,d,!0,f,c)}else b.tag=0,T(null,b,e,c),b=b.child;return b;case 16:a:{e=b.elementType;null!==a&&(a.alternate=
|
|
null,b.alternate=null,b.effectTag|=2);a=b.pendingProps;ri(e);if(1!==e._status)throw e._result;e=e._result;b.type=e;f=b.tag=Gj(e);a=aa(e,a);switch(f){case 0:b=He(null,b,e,a,c);break a;case 1:b=rh(null,b,e,a,c);break a;case 11:b=nh(null,b,e,a,c);break a;case 14:b=oh(null,b,e,aa(e.type,a),d,c);break a}throw Error(k(306,e,""));}return b;case 0:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:aa(d,e),He(a,b,d,e,c);case 1:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:aa(d,e),rh(a,b,d,e,c);
|
|
case 3:sh(b);d=b.updateQueue;if(null===a||null===d)throw Error(k(282));d=b.pendingProps;e=b.memoizedState;e=null!==e?e.element:null;oe(a,b);Qb(b,d,null,c);d=b.memoizedState.element;if(d===e)Ee(),b=sa(a,b,c);else{if(e=b.stateNode.hydrate)Ka=kb(b.stateNode.containerInfo.firstChild),ra=b,e=Wa=!0;if(e)for(c=Fe(b,null,d,c),b.child=c;c;)c.effectTag=c.effectTag&-3|1024,c=c.sibling;else T(a,b,d,c),Ee();b=b.child}return b;case 5:return bh(b),null===a&&De(b),d=b.type,e=b.pendingProps,f=null!==a?a.memoizedProps:
|
|
null,g=e.children,Yd(d,e)?g=null:null!==f&&Yd(d,f)&&(b.effectTag|=16),qh(a,b),b.mode&4&&1!==c&&e.hidden?(b.expirationTime=b.childExpirationTime=1,b=null):(T(a,b,g,c),b=b.child),b;case 6:return null===a&&De(b),null;case 13:return th(a,b,c);case 4:return se(b,b.stateNode.containerInfo),d=b.pendingProps,null===a?b.child=wb(b,null,d,c):T(a,b,d,c),b.child;case 11:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:aa(d,e),nh(a,b,d,e,c);case 7:return T(a,b,b.pendingProps,c),b.child;case 8:return T(a,
|
|
b,b.pendingProps.children,c),b.child;case 12:return T(a,b,b.pendingProps.children,c),b.child;case 10:a:{d=b.type._context;e=b.pendingProps;g=b.memoizedProps;f=e.value;var h=b.type._context;y(Ic,h._currentValue);h._currentValue=f;if(null!==g)if(h=g.value,f=Qa(h,f)?0:("function"===typeof d._calculateChangedBits?d._calculateChangedBits(h,f):1073741823)|0,0===f){if(g.children===e.children&&!G.current){b=sa(a,b,c);break a}}else for(h=b.child,null!==h&&(h.return=b);null!==h;){var m=h.dependencies;if(null!==
|
|
m){g=h.child;for(var l=m.firstContext;null!==l;){if(l.context===d&&0!==(l.observedBits&f)){1===h.tag&&(l=Ea(c,null),l.tag=Jc,Fa(h,l));h.expirationTime<c&&(h.expirationTime=c);l=h.alternate;null!==l&&l.expirationTime<c&&(l.expirationTime=c);Sg(h.return,c);m.expirationTime<c&&(m.expirationTime=c);break}l=l.next}}else g=10===h.tag?h.type===b.type?null:h.child:h.child;if(null!==g)g.return=h;else for(g=h;null!==g;){if(g===b){g=null;break}h=g.sibling;if(null!==h){h.return=g.return;g=h;break}g=g.return}h=
|
|
g}T(a,b,e.children,c);b=b.child}return b;case 9:return e=b.type,f=b.pendingProps,d=f.children,rb(b,c),e=W(e,f.unstable_observedBits),d=d(e),b.effectTag|=1,T(a,b,d,c),b.child;case 14:return e=b.type,f=aa(e,b.pendingProps),f=aa(e.type,f),oh(a,b,e,f,d,c);case 15:return ph(a,b,b.type,b.pendingProps,d,c);case 17:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:aa(d,e),null!==a&&(a.alternate=null,b.alternate=null,b.effectTag|=2),b.tag=1,N(d)?(a=!0,Bc(b)):a=!1,rb(b,c),Yg(b,d,e),pe(b,d,e,c),Ie(null,
|
|
b,d,!0,a,c);case 19:return vh(a,b,c)}throw Error(k(156,b.tag));};var bf=null,Ne=null,la=function(a,b,c,d){return new Fj(a,b,c,d)};ef.prototype.render=function(a){md(a,this._internalRoot,null,null)};ef.prototype.unmount=function(){var a=this._internalRoot,b=a.containerInfo;md(null,a,null,function(){b[Lb]=null})};var Di=function(a){if(13===a.tag){var b=Fc(ka(),150,100);Ja(a,b);df(a,b)}};var Yf=function(a){13===a.tag&&(Ja(a,3),df(a,3))};var Bi=function(a){if(13===a.tag){var b=ka();b=Va(b,a,null);Ja(a,
|
|
b);df(a,b)}};sd=function(a,b,c){switch(b){case "input":Dd(a,c);b=c.name;if("radio"===c.type&&null!=b){for(c=a;c.parentNode;)c=c.parentNode;c=c.querySelectorAll("input[name="+JSON.stringify(""+b)+'][type="radio"]');for(b=0;b<c.length;b++){var d=c[b];if(d!==a&&d.form===a.form){var e=ae(d);if(!e)throw Error(k(90));Gf(d);Dd(d,e)}}}break;case "textarea":Lf(a,c);break;case "select":b=c.value,null!=b&&hb(a,!!c.multiple,b,!1)}};(function(a,b,c,d){ee=a;eg=b;vd=c;vf=d})(Qh,function(a,b,c,d,e){var f=p;p|=4;
|
|
try{return Da(98,a.bind(null,b,c,d,e))}finally{p=f,p===H&&ha()}},function(){(p&(1|ca|ma))===H&&(uj(),xb())},function(a,b){var c=p;p|=2;try{return a(b)}finally{p=c,p===H&&ha()}});var mk={Events:[Hb,Pa,ae,pf,qd,lb,function(a){Kd(a,Ki)},sf,tf,sc,pc,xb,{current:!1}]};(function(a){var b=a.findFiberByHostInstance;return Ej(M({},a,{overrideHookState:null,overrideProps:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:da.ReactCurrentDispatcher,findHostInstanceByFiber:function(a){a=Sf(a);
|
|
return null===a?null:a.stateNode},findFiberByHostInstance:function(a){return b?b(a):null},findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null}))})({findFiberByHostInstance:Bb,bundleType:0,version:"16.13.1",rendererPackageName:"react-dom"});I.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=mk;I.createPortal=Xh;I.findDOMNode=function(a){if(null==a)return null;if(1===a.nodeType)return a;var b=a._reactInternalFiber;if(void 0===
|
|
b){if("function"===typeof a.render)throw Error(k(188));throw Error(k(268,Object.keys(a)));}a=Sf(b);a=null===a?null:a.stateNode;return a};I.flushSync=function(a,b){if((p&(ca|ma))!==H)throw Error(k(187));var c=p;p|=1;try{return Da(99,a.bind(null,b))}finally{p=c,ha()}};I.hydrate=function(a,b,c){if(!bc(b))throw Error(k(200));return nd(null,a,b,!0,c)};I.render=function(a,b,c){if(!bc(b))throw Error(k(200));return nd(null,a,b,!1,c)};I.unmountComponentAtNode=function(a){if(!bc(a))throw Error(k(40));return a._reactRootContainer?
|
|
(Rh(function(){nd(null,null,a,!1,function(){a._reactRootContainer=null;a[Lb]=null})}),!0):!1};I.unstable_batchedUpdates=Qh;I.unstable_createPortal=function(a,b){return Xh(a,b,2<arguments.length&&void 0!==arguments[2]?arguments[2]:null)};I.unstable_renderSubtreeIntoContainer=function(a,b,c,d){if(!bc(c))throw Error(k(200));if(null==a||void 0===a._reactInternalFiber)throw Error(k(38));return nd(a,b,c,!1,d)};I.version="16.13.1"});
|
|
</script>
|
|
<script>const e = React.createElement;
|
|
|
|
function pathToString(path) {
|
|
if (path[0] === '/') {
|
|
return '/' + path.slice(1).join('/');
|
|
} else {
|
|
return path.join('/');
|
|
}
|
|
}
|
|
|
|
function findCommonPath(files) {
|
|
if (!files || !files.length) {
|
|
return [];
|
|
}
|
|
|
|
function isPrefix(arr, prefix) {
|
|
if (arr.length < prefix.length) {
|
|
return false;
|
|
}
|
|
for (let i = prefix.length - 1; i >= 0; --i) {
|
|
if (arr[i] !== prefix[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
let commonPath = files[0].path.slice(0, -1);
|
|
while (commonPath.length) {
|
|
if (files.every(file => isPrefix(file.path, commonPath))) {
|
|
break;
|
|
}
|
|
commonPath.pop();
|
|
}
|
|
return commonPath;
|
|
}
|
|
|
|
function findFolders(files) {
|
|
if (!files || !files.length) {
|
|
return [];
|
|
}
|
|
|
|
let folders = files.filter(file => file.path.length > 1).map(file => file.path[0]);
|
|
folders = [...new Set(folders)]; // unique
|
|
folders.sort();
|
|
|
|
folders = folders.map(folder => {
|
|
let filesInFolder = files
|
|
.filter(file => file.path[0] === folder)
|
|
.map(file => ({
|
|
...file,
|
|
path: file.path.slice(1),
|
|
parent: [...file.parent, file.path[0]],
|
|
}));
|
|
|
|
const children = findFolders(filesInFolder); // recursion
|
|
|
|
return {
|
|
is_folder: true,
|
|
path: [folder],
|
|
parent: files[0].parent,
|
|
children,
|
|
covered: children.reduce((sum, file) => sum + file.covered, 0),
|
|
coverable: children.reduce((sum, file) => sum + file.coverable, 0),
|
|
prevRun: {
|
|
covered: children.reduce((sum, file) => sum + file.prevRun.covered, 0),
|
|
coverable: children.reduce((sum, file) => sum + file.prevRun.coverable, 0),
|
|
}
|
|
};
|
|
});
|
|
|
|
return [
|
|
...folders,
|
|
...files.filter(file => file.path.length === 1),
|
|
];
|
|
}
|
|
|
|
class App extends React.Component {
|
|
constructor(...args) {
|
|
super(...args);
|
|
|
|
this.state = {
|
|
current: [],
|
|
};
|
|
}
|
|
|
|
componentDidMount() {
|
|
this.updateStateFromLocation();
|
|
window.addEventListener("hashchange", () => this.updateStateFromLocation(), false);
|
|
}
|
|
|
|
updateStateFromLocation() {
|
|
if (window.location.hash.length > 1) {
|
|
const current = window.location.hash.substr(1).split('/');
|
|
this.setState({current});
|
|
} else {
|
|
this.setState({current: []});
|
|
}
|
|
}
|
|
|
|
getCurrentPath() {
|
|
let file = this.props.root;
|
|
let path = [file];
|
|
for (let p of this.state.current) {
|
|
file = file.children.find(file => file.path[0] === p);
|
|
if (!file) {
|
|
return path;
|
|
}
|
|
path.push(file);
|
|
}
|
|
return path;
|
|
}
|
|
|
|
render() {
|
|
const path = this.getCurrentPath();
|
|
const file = path[path.length - 1];
|
|
|
|
let w = null;
|
|
if (file.is_folder) {
|
|
w = e(FilesList, {
|
|
folder: file,
|
|
onSelectFile: this.selectFile.bind(this),
|
|
onBack: path.length > 1 ? this.back.bind(this) : null,
|
|
});
|
|
} else {
|
|
w = e(DisplayFile, {
|
|
file,
|
|
onBack: this.back.bind(this),
|
|
});
|
|
}
|
|
|
|
return e('div', {className: 'app'}, w);
|
|
}
|
|
|
|
selectFile(file) {
|
|
this.setState(({current}) => {
|
|
return {current: [...current, file.path[0]]};
|
|
}, () => this.updateHash());
|
|
}
|
|
|
|
back(file) {
|
|
this.setState(({current}) => {
|
|
return {current: current.slice(0, current.length - 1)};
|
|
}, () => this.updateHash());
|
|
}
|
|
|
|
updateHash() {
|
|
if (!this.state.current || !this.state.current.length) {
|
|
window.location = '#';
|
|
} else {
|
|
window.location = '#' + this.state.current.join('/');
|
|
}
|
|
}
|
|
}
|
|
|
|
function FilesList({folder, onSelectFile, onBack}) {
|
|
let files = folder.children;
|
|
return e('div', {className: 'display-folder'},
|
|
e(FileHeader, {file: folder, onBack}),
|
|
e('table', {className: 'files-list'},
|
|
e('thead', {className: 'files-list__head'},
|
|
e('tr', null,
|
|
e('th', null, "Path"),
|
|
e('th', null, "Coverage")
|
|
)
|
|
),
|
|
e('tbody', {className: 'files-list__body'},
|
|
files.map(file => e(File, {file, onClick: onSelectFile}))
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
function File({file, onClick}) {
|
|
const coverage = file.coverable ? file.covered / file.coverable * 100 : -1;
|
|
const coverageDelta = file.prevRun &&
|
|
(file.covered / file.coverable * 100 - file.prevRun.covered / file.prevRun.coverable * 100);
|
|
|
|
return e('tr', {
|
|
className: 'files-list__file'
|
|
+ (coverage >= 0 && coverage < 50 ? ' files-list__file_low': '')
|
|
+ (coverage >= 50 && coverage < 80 ? ' files-list__file_medium': '')
|
|
+ (coverage >= 80 ? ' files-list__file_high': '')
|
|
+ (file.is_folder ? ' files-list__file_folder': ''),
|
|
onClick: () => onClick(file),
|
|
},
|
|
e('td', null, e('a', null, pathToString(file.path))),
|
|
e('td', null,
|
|
file.covered + ' / ' + file.coverable +
|
|
(coverage >= 0 ? ' (' + coverage.toFixed(2) + '%)' : ''),
|
|
e('span', {title: 'Change from the previous run'},
|
|
(coverageDelta ? ` (${coverageDelta > 0 ? '+' : ''}${coverageDelta.toFixed(2)}%)` : ''))
|
|
)
|
|
);
|
|
}
|
|
|
|
function DisplayFile({file, onBack}) {
|
|
return e('div', {className: 'display-file'},
|
|
e(FileHeader, {file, onBack}),
|
|
e(FileContent, {file})
|
|
);
|
|
}
|
|
|
|
function FileHeader({file, onBack}) {
|
|
const coverage = file.covered / file.coverable * 100;
|
|
const coverageDelta = file.prevRun && (coverage - file.prevRun.covered / file.prevRun.coverable * 100);
|
|
|
|
return e('div', {className: 'file-header'},
|
|
onBack ? e('a', {className: 'file-header__back', onClick: onBack}, 'Back') : null,
|
|
e('div', {className: 'file-header__name'}, pathToString([...file.parent, ...file.path])),
|
|
e('div', {className: 'file-header__stat'},
|
|
'Covered: ' + file.covered + ' of ' + file.coverable +
|
|
(file.coverable ? ' (' + coverage.toFixed(2) + '%)' : ''),
|
|
e('span', {title: 'Change from the previous run'},
|
|
(coverageDelta ? ` (${coverageDelta > 0 ? '+' : ''}${coverageDelta.toFixed(2)}%)` : ''))
|
|
)
|
|
);
|
|
}
|
|
|
|
function FileContent({file}) {
|
|
return e('pre', {className: 'file-content'},
|
|
file.content.split(/\r?\n/).map((line, index) => {
|
|
const trace = file.traces.find(trace => trace.line === index + 1);
|
|
const covered = trace && trace.stats.Line;
|
|
const uncovered = trace && !trace.stats.Line;
|
|
return e('code', {
|
|
className: 'code-line'
|
|
+ (covered ? ' code-line_covered' : '')
|
|
+ (uncovered ? ' code-line_uncovered' : ''),
|
|
title: trace ? JSON.stringify(trace.stats, null, 2) : null,
|
|
}, line);
|
|
})
|
|
);
|
|
}
|
|
|
|
(function(){
|
|
const commonPath = findCommonPath(data.files);
|
|
const prevFilesMap = new Map();
|
|
|
|
previousData && previousData.files.forEach((file) => {
|
|
const path = file.path.slice(commonPath.length).join('/');
|
|
prevFilesMap.set(path, file);
|
|
});
|
|
|
|
const files = data.files.map((file) => {
|
|
const path = file.path.slice(commonPath.length);
|
|
const { covered = 0, coverable = 0 } = prevFilesMap.get(path.join('/')) || {};
|
|
return {
|
|
...file,
|
|
path,
|
|
parent: commonPath,
|
|
prevRun: { covered, coverable },
|
|
};
|
|
});
|
|
|
|
const children = findFolders(files);
|
|
|
|
const root = {
|
|
is_folder: true,
|
|
children,
|
|
path: commonPath,
|
|
parent: [],
|
|
covered: children.reduce((sum, file) => sum + file.covered, 0),
|
|
coverable: children.reduce((sum, file) => sum + file.coverable, 0),
|
|
prevRun: {
|
|
covered: children.reduce((sum, file) => sum + file.prevRun.covered, 0),
|
|
coverable: children.reduce((sum, file) => sum + file.prevRun.coverable, 0),
|
|
}
|
|
};
|
|
|
|
ReactDOM.render(e(App, {root, prevFilesMap}), document.getElementById('root'));
|
|
}());
|
|
</script>
|
|
</body>
|
|
</html> |