fixes reset from exection completion
adds 'default.oc8' adds control window size to state for load/save of settings maybe? moves TestCompressionTool code into InstructionUtil remove gemmautil and moves into gemma
This commit is contained in:
Generated
+2
-10
@@ -1789,6 +1789,8 @@ dependencies = [
|
||||
"flate2",
|
||||
"hex",
|
||||
"log",
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"pretty_env_logger",
|
||||
"rand 0.9.0-alpha.2",
|
||||
"serde",
|
||||
@@ -1845,16 +1847,6 @@ dependencies = [
|
||||
"gemma",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gemmautil"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"gemma",
|
||||
"pest",
|
||||
"pest_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
|
||||
@@ -5,7 +5,6 @@ members = [
|
||||
"gemmaimgui",
|
||||
"gemmatelnet",
|
||||
"gemmasdl2",
|
||||
"gemmautil",
|
||||
]
|
||||
resolver = "2"
|
||||
|
||||
|
||||
@@ -16,3 +16,5 @@ serde_json.workspace = true
|
||||
flate2 = "1.0"
|
||||
clap = { version = "4.5.20", features = ["derive"] }
|
||||
hex = "0.4.3"
|
||||
pest = { version = "2.7.14" }
|
||||
pest_derive = { version = "2.7.14"}
|
||||
@@ -2,6 +2,7 @@ use gemma::chip8::util::InstructionUtil;
|
||||
use gemma::chip8::{instructions::Chip8CpuInstructions, quirk_modes::QuirkMode};
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
use clap::{Arg, Command};
|
||||
// Ch8Asm
|
||||
// Converts well formed CH8ASM.
|
||||
// no variables.
|
||||
@@ -16,9 +17,26 @@ use pest_derive::Parser;
|
||||
#[grammar = "chip8_asm.pest"]
|
||||
pub struct Chip8AsmParser;
|
||||
|
||||
|
||||
fn main() {
|
||||
println!("Taxation is Theft");
|
||||
|
||||
let matches = Command::new("Chip8Assembler")
|
||||
.version("0.0.1")
|
||||
.author("Trevor Merritt <trevor.merritt@geekback.dev>")
|
||||
.about("Tool to assemble simple ASM into Chip8 Machine code")
|
||||
.arg(
|
||||
Arg::new("input-file")
|
||||
.help("Name of file to assemble")
|
||||
.required(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::new("output-file")
|
||||
.help("Name of file to create")
|
||||
.required(false)
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let unparsed = fs::read_to_string("resources/test/gemma_disassembler_manual_document.asc")
|
||||
.expect("Unable to read input");
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
use clap::{Parser, Subcommand};
|
||||
use flate2::{write::{GzEncoder, GzDecoder}, Compression};
|
||||
use std::io::prelude::*;
|
||||
use std::io::{self, Write};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about = "Compress or decompress a string", long_about = None)]
|
||||
struct Cli {
|
||||
/// Subcommand: either 'compress' or 'decompress'
|
||||
#[command(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
/// Compress the input string
|
||||
Compress {
|
||||
/// The string to compress
|
||||
input: String,
|
||||
},
|
||||
/// Decompress the input string (must be compressed format)
|
||||
Decompress {
|
||||
/// The compressed string to decompress, in hex format
|
||||
input: String,
|
||||
},
|
||||
}
|
||||
|
||||
fn compress_string(input: &str) -> Vec<u8> {
|
||||
let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
|
||||
encoder.write_all(input.as_bytes()).expect("Compression failed");
|
||||
encoder.finish().expect("Failed to finish compression")
|
||||
}
|
||||
|
||||
fn decompress_string(input: &[u8]) -> String {
|
||||
let mut decoder = GzDecoder::new(Vec::new());
|
||||
decoder.write_all(input).expect("Decompression failed");
|
||||
let decompressed_data = decoder.finish().expect("Failed to finish decompression");
|
||||
String::from_utf8(decompressed_data).expect("Invalid UTF-8")
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cli = Cli::parse();
|
||||
|
||||
match cli.command {
|
||||
Commands::Compress { input } => {
|
||||
let compressed = compress_string(&input);
|
||||
// Convert to hex format for easier readability in the terminal
|
||||
println!("Compressed (hex): {:?} / from {}b to {}b", hex::encode(compressed.clone()), input.len(), compressed.len());
|
||||
}
|
||||
Commands::Decompress { input } => {
|
||||
// Decode hex string back to bytes
|
||||
let compressed_bytes = hex::decode(input).expect("Invalid hex input");
|
||||
let decompressed = decompress_string(&compressed_bytes);
|
||||
println!("Decompressed: {}", decompressed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
use clap::{ArgGroup, Parser};
|
||||
use gemma::chip8::util::InstructionUtil;
|
||||
/// TCT
|
||||
/// Test Compression Tool
|
||||
///
|
||||
/// A Tool to take a plaintext JSON object of the memory state
|
||||
/// for the CHIP-8 emulator and compress the input into compressed
|
||||
/// text. Test sizes go from ~22k to ~1k which makes a difference over
|
||||
/// hundreds of tests
|
||||
/// Written by Trevor Merritt and optimized by ChatGPT
|
||||
|
||||
/// Simple file compression and decompression tool
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about)]
|
||||
#[clap(group(
|
||||
ArgGroup::new("mode")
|
||||
.required(true)
|
||||
.args(["compress", "decompress"]),
|
||||
))]
|
||||
struct Cli {
|
||||
/// The filename to process
|
||||
filename: String,
|
||||
|
||||
/// Compress the file
|
||||
#[arg(short = 'c', long = "compress", group = "mode")]
|
||||
compress: bool,
|
||||
|
||||
/// Decompress the file
|
||||
#[arg(short = 'd', long = "decompress", group = "mode")]
|
||||
decompress: bool,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let cli = Cli::parse();
|
||||
|
||||
if cli.compress {
|
||||
InstructionUtil::compress_file(cli.filename).expect("Derp. Can't do that.");
|
||||
} else if cli.decompress {
|
||||
InstructionUtil::decompress_file(cli.filename).expect("Derp. Can't do that.");
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,8 @@
|
||||
use super::{
|
||||
cpu_states::Chip8CpuStates, instructions::Chip8CpuInstructions,
|
||||
system_memory::Chip8SystemMemory, video::Chip8Video,
|
||||
};
|
||||
use crate::chip8::cpu_states::Chip8CpuStates::WaitingForInstruction;
|
||||
use crate::chip8::delay_timer::DelayTimer;
|
||||
use crate::chip8::keypad::Keypad;
|
||||
use crate::chip8::quirk_modes::QuirkMode;
|
||||
@@ -7,12 +12,7 @@ use crate::chip8::stack::Chip8Stack;
|
||||
use log::debug;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{
|
||||
cpu_states::Chip8CpuStates, instructions::Chip8CpuInstructions,
|
||||
system_memory::Chip8SystemMemory, video::Chip8Video,
|
||||
};
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Chip8Computer {
|
||||
pub num_cycles: i32,
|
||||
pub memory: Chip8SystemMemory,
|
||||
@@ -52,6 +52,7 @@ impl Chip8Computer {
|
||||
self.stack.reset();
|
||||
self.memory.reset(quirk_mode);
|
||||
self.quirk_mode = quirk_mode;
|
||||
self.state = WaitingForInstruction;
|
||||
}
|
||||
|
||||
pub fn dump_keypad_to_string(&self) -> String {
|
||||
@@ -117,8 +118,19 @@ impl Chip8Computer {
|
||||
Chip8CpuStates::WaitingForKey => {
|
||||
debug!("waiting for a key press...");
|
||||
}
|
||||
Chip8CpuStates::ExecutionComplete => {
|
||||
debug!("Execution has completed.");
|
||||
self.num_cycles += 1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn serialize(&self) -> String {
|
||||
serde_json::to_string(&self).expect("Serialization failed")
|
||||
}
|
||||
pub fn deserialize(from: String) -> Chip8Computer {
|
||||
serde_json::from_str(&from).expect("Failed to deserialize")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ impl Chip8ComputerManager {
|
||||
self.computer.load_bytes_to_memory(0x200, &bytes_to_load);
|
||||
}
|
||||
|
||||
pub fn dump_to_string(&self, dump_type: ManagerDumpables) -> String {
|
||||
pub fn dump_to_string(&self, dump_type: ManagerDumpables) -> String{
|
||||
match dump_type {
|
||||
ManagerDumpables::Video => self.computer.video_memory.format_as_string(),
|
||||
ManagerDumpables::Registers => self.computer.registers.format_as_string(),
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Copy, Default, Serialize, Deserialize, Debug)]
|
||||
#[derive(Clone, Copy, Default, Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub enum Chip8CpuStates {
|
||||
#[default]
|
||||
WaitingForInstruction,
|
||||
WaitingForKey,
|
||||
ExecutingInstruction,
|
||||
Error,
|
||||
ExecutionComplete,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
||||
#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct DelayTimer {
|
||||
counter: u8,
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use std::ascii::AsciiExt;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::ops::BitAnd;
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::chip8::cpu_states::Chip8CpuStates;
|
||||
/*
|
||||
nnn or addr - A 12-bit value, the lowest 12 bits of the instruction
|
||||
n or nibble - A 4-bit value, the lowest 4 bits of the instruction
|
||||
@@ -326,9 +326,9 @@ impl Chip8CpuInstructions {
|
||||
Chip8CpuInstructions::HIGH => INST_HIGH,
|
||||
Chip8CpuInstructions::ORY(_, _) => INST_ORY,
|
||||
JPX(_, _) => INST_JPX,
|
||||
DW(_) => INST_DW,
|
||||
XXXXERRORINSTRUCTION => "XX ERROR XX",
|
||||
SCU(_) => INST_SCU,
|
||||
DW(_) => INST_DW,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -681,7 +681,7 @@ impl Chip8CpuInstructions {
|
||||
}
|
||||
}
|
||||
pub fn execute(&self, input: &mut Chip8Computer) -> Chip8Computer {
|
||||
// print!("INSTRUCTION {}", self);
|
||||
println!("INSTRUCTION {}", self);
|
||||
let start_time = Instant::now();
|
||||
let start_pc = input.registers.peek_pc();
|
||||
input.registers.poke_pc(start_pc + 2);
|
||||
@@ -700,6 +700,12 @@ impl Chip8CpuInstructions {
|
||||
}
|
||||
// 0x1nnn Jump to Address
|
||||
Chip8CpuInstructions::JPA(new_address) => {
|
||||
// if the jump is to the same address as we are at, we are in an infinite
|
||||
// loop and the program is effectively done. stop the CPU.
|
||||
if *new_address == start_pc {
|
||||
input.state = Chip8CpuStates::ExecutionComplete;
|
||||
println!("Execution complete.");
|
||||
}
|
||||
input.registers.poke_pc(*new_address);
|
||||
}
|
||||
// 0x2nnn Call Subroutine
|
||||
|
||||
@@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::constants::CHIP8_KEYBOARD;
|
||||
|
||||
#[derive(Clone, Copy, Default, Serialize, Deserialize, Debug)]
|
||||
#[derive(Clone, Copy, Default, Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Keypad {
|
||||
keys: [bool; 0x10],
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Display;
|
||||
|
||||
#[derive(Default, Clone, Serialize, Deserialize, Copy, Debug)]
|
||||
#[derive(Default, Clone, Serialize, Deserialize, Copy, Debug, PartialEq)]
|
||||
pub enum QuirkMode {
|
||||
Chip8,
|
||||
XOChip,
|
||||
|
||||
@@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Registers. numbered 1-16 publicly.
|
||||
/// Privately using zero base array so -1 to shift from pub to priv.
|
||||
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
||||
#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Chip8Registers {
|
||||
pub registers: [u8; 16],
|
||||
pub i_register: u16,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use log::trace;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
||||
#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct SoundTimer {
|
||||
counter: i32,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, Debug)]
|
||||
#[derive(Clone, Default, Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Chip8Stack {
|
||||
items: Vec<u16>,
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use serde::Serialize;
|
||||
use super::quirk_modes;
|
||||
use super::quirk_modes::QuirkMode;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Chip8SystemMemory {
|
||||
memory: Vec<u8>,
|
||||
}
|
||||
|
||||
+127
-2
@@ -1,3 +1,11 @@
|
||||
use flate2::read::ZlibDecoder;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use flate2::write::ZlibEncoder;
|
||||
use flate2::Compression;
|
||||
|
||||
pub struct InstructionUtil {}
|
||||
|
||||
impl InstructionUtil {
|
||||
@@ -29,7 +37,6 @@ impl InstructionUtil {
|
||||
}
|
||||
|
||||
pub fn join_bytes(high: u8, low: u8) -> u16 {
|
||||
|
||||
(high as u16) << 8 | low as u16
|
||||
}
|
||||
|
||||
@@ -40,7 +47,7 @@ impl InstructionUtil {
|
||||
|
||||
// n or nibble - A 4-bit value, the lowest 4 bits of the instruction
|
||||
pub fn read_nibble_from_instruction(instruction_to_read_from: u16) -> u8 {
|
||||
( instruction_to_read_from & 0x000F )as u8
|
||||
(instruction_to_read_from & 0x000F) as u8
|
||||
}
|
||||
|
||||
// x - A 4-bit value, the lower 4 bits of the high byte of the instruction
|
||||
@@ -61,4 +68,122 @@ impl InstructionUtil {
|
||||
pub fn read_upper_byte_lower_nibble(to_read_from: u16) -> u8 {
|
||||
((to_read_from & 0x0f00) >> 8) as u8
|
||||
}
|
||||
|
||||
pub fn compress_file<P: AsRef<Path>>(to_compress: P) -> io::Result<()> {
|
||||
let to_compress_path = to_compress.as_ref();
|
||||
let target_filename = format!("{}.tct", to_compress_path.display());
|
||||
println!(
|
||||
"Compressing file: {} to {}",
|
||||
to_compress_path.display(),
|
||||
target_filename
|
||||
);
|
||||
|
||||
// Open the source file
|
||||
let mut source_file = File::open(&to_compress_path)?;
|
||||
|
||||
// Read the entire file into a buffer
|
||||
let mut read_buffer = Vec::new();
|
||||
source_file.read_to_end(&mut read_buffer)?;
|
||||
|
||||
// Initialize the encoder and compress the read data
|
||||
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
|
||||
encoder.write_all(&read_buffer)?;
|
||||
let encoded_data = encoder.finish()?;
|
||||
|
||||
println!(
|
||||
"Compressed {} bytes into {} bytes.",
|
||||
read_buffer.len(),
|
||||
encoded_data.len()
|
||||
);
|
||||
|
||||
// Write the encoded data to the target file
|
||||
let mut target_file = File::create(target_filename)?;
|
||||
target_file.write_all(&encoded_data)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn decompress_file_to_string<P: AsRef<Path>>(to_decompress: P) -> io::Result<String> {
|
||||
let to_decompress_path = to_decompress.as_ref();
|
||||
|
||||
// Ensure the file has the expected `.tct` extension
|
||||
if to_decompress_path.extension() != Some("tct".as_ref()) {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"File must have a .tct extension",
|
||||
));
|
||||
}
|
||||
|
||||
println!(
|
||||
"Decompressing file: {} to string",
|
||||
to_decompress_path.display()
|
||||
);
|
||||
|
||||
// Open the compressed file and set up the decoder
|
||||
let compressed_file = File::open(&to_decompress_path)?;
|
||||
let mut decoder = ZlibDecoder::new(compressed_file);
|
||||
|
||||
// Read decompressed data
|
||||
let mut decompressed_data = Vec::new();
|
||||
decoder.read_to_end(&mut decompressed_data)?;
|
||||
|
||||
// Convert decompressed byte data to a UTF-8 String
|
||||
match String::from_utf8(decompressed_data) {
|
||||
Ok(decompressed_string) => {
|
||||
// Optionally, write decompressed data to a new file
|
||||
println!(
|
||||
"Decompressed {} bytes into {} bytes.",
|
||||
to_decompress_path.metadata()?.len(),
|
||||
decompressed_string.len()
|
||||
);
|
||||
|
||||
Ok(decompressed_string)
|
||||
}
|
||||
Err(e) => {
|
||||
// Handle invalid UTF-8 data (if the decompressed data isn't valid UTF-8)
|
||||
Err(io::Error::new(io::ErrorKind::InvalidData, e))
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn decompress_file<P: AsRef<Path>>(to_decompress: P) -> io::Result<()> {
|
||||
let to_decompress_path = to_decompress.as_ref();
|
||||
|
||||
// Ensure the file has the expected `.tct` extension
|
||||
if to_decompress_path.extension() != Some("tct".as_ref()) {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"File must have a .tct extension",
|
||||
));
|
||||
}
|
||||
|
||||
// Derive the output filename by removing the `.tct` extension
|
||||
let mut output_filename = PathBuf::from(to_decompress_path);
|
||||
output_filename.set_extension("untct"); // Remove .tct extension to restore original file name
|
||||
|
||||
println!(
|
||||
"Decompressing file: {} to {}",
|
||||
to_decompress_path.display(),
|
||||
output_filename.display()
|
||||
);
|
||||
|
||||
// Open the compressed file and set up the decoder
|
||||
let compressed_file = File::open(&to_decompress_path)?;
|
||||
let mut decoder = ZlibDecoder::new(compressed_file);
|
||||
|
||||
// Read decompressed data
|
||||
let mut decompressed_data = Vec::new();
|
||||
decoder.read_to_end(&mut decompressed_data)?;
|
||||
|
||||
// Write decompressed data to the output file
|
||||
let mut output_file = File::create(&output_filename)?;
|
||||
output_file.write_all(&decompressed_data)?;
|
||||
|
||||
println!(
|
||||
"Decompressed {} bytes into {} bytes.",
|
||||
to_decompress_path.metadata()?.len(),
|
||||
decompressed_data.len()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@ use crate::constants::{
|
||||
use log::debug;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
||||
#[derive(Clone, Copy, Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub enum Chip8VideoModes {
|
||||
LowRes,
|
||||
HighRes,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Chip8Video {
|
||||
memory: Vec<bool>,
|
||||
pub has_frame_changed: bool,
|
||||
@@ -36,7 +36,8 @@ impl Chip8Video {
|
||||
}
|
||||
|
||||
pub fn set_lowres(&mut self) {
|
||||
self.current_res = LowRes
|
||||
self.current_res = LowRes;
|
||||
self.cls();
|
||||
}
|
||||
|
||||
pub fn get_screen_resolution(&mut self) -> Chip8VideoModes {
|
||||
@@ -152,7 +153,6 @@ impl Chip8Video {
|
||||
}
|
||||
|
||||
pub fn scroll_right(&mut self) {
|
||||
println!("SCROLLRIGHTPRE:::[{}]", self.format_as_string());
|
||||
let (width, height) = self.get_resolution();
|
||||
|
||||
for current_row in 0..height {
|
||||
@@ -168,11 +168,9 @@ impl Chip8Video {
|
||||
// Clear the first 4 pixels in the current row
|
||||
self.memory[row_offset..row_offset + 4].fill(false);
|
||||
}
|
||||
println!("SCROLLRIGHTPOST:::[{}]", self.format_as_string());
|
||||
}
|
||||
|
||||
pub fn scroll_left(&mut self) {
|
||||
println!("SCROLLLEFTPRE:::[{}]", self.format_as_string());
|
||||
let (width, height) = self.get_resolution();
|
||||
|
||||
for current_row in 0..height {
|
||||
@@ -181,7 +179,6 @@ impl Chip8Video {
|
||||
let target: usize = (row_offset + current_column) as usize;
|
||||
let source: usize = target + 4;
|
||||
self.memory[target] = self.memory[source];
|
||||
println!("Moving from {source} to {target}");
|
||||
}
|
||||
|
||||
let clear_start: usize = (row_offset + width - 4) as usize;
|
||||
@@ -189,7 +186,6 @@ impl Chip8Video {
|
||||
|
||||
self.memory[clear_start..clear_end].fill(false);
|
||||
}
|
||||
println!("SCROLLLEFTPOST:::[{}]", self.format_as_string());
|
||||
}
|
||||
|
||||
pub fn scroll_up(&mut self, how_far: &u8) {
|
||||
@@ -240,7 +236,7 @@ impl Default for Chip8Video {
|
||||
Chip8Video {
|
||||
memory: mem,
|
||||
has_frame_changed: false,
|
||||
current_res: Chip8VideoModes::LowRes,
|
||||
current_res: LowRes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-20
@@ -1,26 +1,24 @@
|
||||
use std::fs::File;
|
||||
use flate2::write::{GzDecoder, GzEncoder};
|
||||
use flate2::Compression;
|
||||
use gemma::chip8::computer::Chip8Computer;
|
||||
use gemma::chip8::util::InstructionUtil;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
|
||||
fn load_result(to_load: &str) -> String {
|
||||
let full_path = format!("resources/test/state/{}", to_load);
|
||||
let full_path = format!("../resources/test/state/{}", to_load);
|
||||
println!("Loading state => (([{}]))", full_path);
|
||||
std::fs::read_to_string(full_path).unwrap()
|
||||
}
|
||||
|
||||
fn load_compressed_result(file_path: &str) -> io::Result<String> {
|
||||
// Load the compressed file contents
|
||||
let compressed_data = fs::read(file_path)?;
|
||||
|
||||
// Create a GzDecoder to uncompress the data
|
||||
let mut decoder = GzDecoder::new(&compressed_data[..]);
|
||||
let mut decompressed_data = String::new();
|
||||
|
||||
// Read the decompressed data directly into a String
|
||||
decoder.read_to_string(&mut decompressed_data)?;
|
||||
|
||||
Ok(decompressed_data)
|
||||
let full_path = format!("../resources/test/state/{}", file_path);
|
||||
println!(
|
||||
"ATTEMPTING TO LOAD {} AS A COMPRESSED TEST RESULT.",
|
||||
full_path
|
||||
);
|
||||
InstructionUtil::decompress_file_to_string(full_path)
|
||||
}
|
||||
|
||||
fn load_rom(to_load: &str) -> Vec<u8> {
|
||||
@@ -33,21 +31,21 @@ fn test_serialization_round_trip() {
|
||||
let expected_json = load_result("smoke_001_round_trip_serialize_deserialize.json");
|
||||
|
||||
// Serialize the Chip8Computer instance
|
||||
let serialized = serde_json::to_string(&original_computer).expect("Serialization failed");
|
||||
let serialized = Chip8Computer::serialize(&original_computer);
|
||||
let deserialized = Chip8Computer::deserialize(expected_json.clone());
|
||||
|
||||
// Compare the serialized output to the expected JSON
|
||||
println!("Serialized Output: [{}]", serialized);
|
||||
|
||||
assert_eq!(
|
||||
serialized.trim(),
|
||||
expected_json.trim(),
|
||||
expected_json.clone().trim(),
|
||||
"Serialized output does not match expected JSON"
|
||||
);
|
||||
|
||||
// Deserialize back to Chip8Computer and assert equality
|
||||
let deserialized_computer: Chip8Computer =
|
||||
serde_json::from_str(&serialized).expect("Deserialization failed");
|
||||
assert_eq!(
|
||||
deserialized_computer, original_computer,
|
||||
deserialized, original_computer,
|
||||
"Deserialized instance does not match the original"
|
||||
);
|
||||
}
|
||||
@@ -55,9 +53,9 @@ fn test_serialization_round_trip() {
|
||||
#[test]
|
||||
fn computer_001_system_zero_state() {
|
||||
let x = Chip8Computer::new();
|
||||
let expected_string = load_compressed_result("smoke_002_round_trip_serialize_deserialize.tflt");
|
||||
let serialized = serde_json::to_string(&x).unwrap();
|
||||
let expected_string = load_compressed_result("computer_001_system_zero_state.tct")
|
||||
.expect("Unable to read result");
|
||||
let serialized = x.serialize();
|
||||
assert_eq!(serialized, expected_string);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,11 +35,13 @@ fn decoder_test_invalid_instructions() {
|
||||
];
|
||||
|
||||
for i in invalid_to_encode {
|
||||
assert_eq!(Chip8CpuInstructions::decode(i, &Chip8).encode(), 0xffff);
|
||||
println!("TESTING 0x{i:04x}");
|
||||
println!("DECOODED TO {:?}", Chip8CpuInstructions::decode(i, &Chip8));
|
||||
assert!(matches!(
|
||||
Chip8CpuInstructions::decode(i, &Chip8),
|
||||
Chip8CpuInstructions::XXXXERRORINSTRUCTION
|
||||
));
|
||||
Chip8CpuInstructions::DW(i)
|
||||
) ||
|
||||
matches!(Chip8CpuInstructions::decode(i, &Chip8), Chip8CpuInstructions::XXXXERRORINSTRUCTION));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,6 @@ fn main() {
|
||||
system.wait_for_instruction();
|
||||
} else {
|
||||
// do we need to release it?
|
||||
|
||||
if system.is_key_pressed(key_reg) {
|
||||
system.release_key(key_reg);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ use log::debug;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::{Path, PathBuf};
|
||||
use imgui::sys::ImGuiIO;
|
||||
use gemma::chip8::instructions::Chip8CpuInstructions;
|
||||
|
||||
const ROM_ROOT: &str = "resources/roms";
|
||||
|
||||
@@ -43,70 +45,186 @@ impl GemmaImguiSupport {
|
||||
pub fn video_display(system_to_control: &Chip8Computer, gui_state: &ImGuiUiState, ui: &Ui) {
|
||||
// draw area size
|
||||
let (width, height) = system_to_control.video_memory.get_resolution();
|
||||
let draw_area_size = ui.io().display_size;
|
||||
// println!("DRAW_AREA_SIZE = {}x{}", draw_area_size[0], draw_area_size[1]);
|
||||
let cell_width = ((draw_area_size[0] as i32 / width) * 6) / 10;
|
||||
let cell_height = ((draw_area_size[1] as i32 / height) * 6) / 10;
|
||||
ui.window("Video")
|
||||
.size([gui_state.video_window_size[0] as f32, gui_state.video_window_size[1] as f32], Condition::Once)
|
||||
.build(|| {
|
||||
let draw_area_size = ui.window_size();
|
||||
let draw_offset = ui.window_pos();
|
||||
// now lets move the draw_offset by 0,20 to get it off the window title bar
|
||||
let draw_offset = [draw_offset[0], draw_offset[1] + 20.0];
|
||||
// and reduce the draw area size by the same values. {}
|
||||
let draw_area_size = [draw_area_size[0], draw_area_size[1] - 20.0];
|
||||
// println!("DRAW_AREA_SIZE = {}x{}", draw_area_size[0], draw_area_size[1]);
|
||||
let cell_width = ((draw_area_size[0] as i32 / width));
|
||||
let cell_height = ((draw_area_size[1] as i32 / height));
|
||||
|
||||
let origin = ui.cursor_pos();
|
||||
let fg = ui.get_foreground_draw_list();
|
||||
if system_to_control.video_memory.is_highres() {
|
||||
// ui.text("High Def Video here");
|
||||
for current_row in 0..=height {
|
||||
let y_offset = origin[1] as i32 + (current_row * cell_height);
|
||||
for current_column in 0..=width {
|
||||
let x_offset = origin[0] as i32 + (current_column * cell_width);
|
||||
let current_origin = [x_offset as f32, y_offset as f32];
|
||||
let current_limit = [
|
||||
(x_offset + cell_width) as f32,
|
||||
(y_offset + cell_height) as f32,
|
||||
];
|
||||
let memory_offset = (current_row * width + current_column) as u16;
|
||||
let to_render = system_to_control.video_memory.peek(memory_offset);
|
||||
let color: ImColor32 = if to_render {
|
||||
gui_state.on_colour
|
||||
} else {
|
||||
gui_state.off_colour
|
||||
};
|
||||
fg.add_rect_filled_multicolor(
|
||||
current_origin,
|
||||
current_limit,
|
||||
color,
|
||||
color,
|
||||
color,
|
||||
color,
|
||||
);
|
||||
let origin = draw_offset;
|
||||
let fg = ui.get_foreground_draw_list();
|
||||
for current_row in 0..height {
|
||||
let y_offset = origin[1] as i32 + (current_row * cell_height);
|
||||
for current_column in 0..width {
|
||||
let x_offset = origin[0] as i32 + (current_column * cell_width);
|
||||
let current_origin = [x_offset as f32, y_offset as f32];
|
||||
let current_limit = [
|
||||
(x_offset + cell_width) as f32,
|
||||
(y_offset + cell_height) as f32,
|
||||
];
|
||||
let memory_offset = (current_row * width + current_column) as u16;
|
||||
let to_render = system_to_control.video_memory.peek(memory_offset);
|
||||
let color: ImColor32 = if to_render {
|
||||
gui_state.on_colour
|
||||
} else {
|
||||
gui_state.off_colour
|
||||
};
|
||||
fg.add_rect_filled_multicolor(
|
||||
current_origin,
|
||||
current_limit,
|
||||
color,
|
||||
color,
|
||||
color,
|
||||
color,
|
||||
);
|
||||
}
|
||||
}
|
||||
}).expect("cant draw the video i guess");
|
||||
}
|
||||
|
||||
pub fn quirks_picker(system: &mut Chip8ComputerManager,
|
||||
ui: &Ui) {
|
||||
let selectors = [Chip8, SChipModern, XOChip];
|
||||
for current_selector in selectors {
|
||||
let mut working_selector =
|
||||
ui.selectable_config(current_selector.clone().to_string());
|
||||
match system.quirks_mode() {
|
||||
Chip8 => {
|
||||
working_selector = working_selector.selected(true);
|
||||
}
|
||||
SChipModern => {
|
||||
working_selector = working_selector.selected(true);
|
||||
}
|
||||
XOChip => {
|
||||
working_selector = working_selector.selected(true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for current_row in 0..height {
|
||||
let y_offset = origin[1] as i32 + (current_row * cell_height);
|
||||
for current_column in 0..width {
|
||||
let x_offset = origin[0] as i32 + (current_column * cell_width);
|
||||
let current_origin = [x_offset as f32, y_offset as f32];
|
||||
let current_limit = [
|
||||
(x_offset + cell_width) as f32,
|
||||
(y_offset + cell_height) as f32,
|
||||
];
|
||||
let memory_offset = (current_row * width + current_column) as u16;
|
||||
let to_render = system_to_control.video_memory.peek(memory_offset);
|
||||
let color: ImColor32 = if to_render {
|
||||
gui_state.on_colour
|
||||
} else {
|
||||
gui_state.off_colour
|
||||
};
|
||||
fg.add_rect_filled_multicolor(
|
||||
current_origin,
|
||||
current_limit,
|
||||
color,
|
||||
color,
|
||||
color,
|
||||
color,
|
||||
if working_selector.build() {
|
||||
system.reset(current_selector);
|
||||
println!("CLICK ON {}", ¤t_selector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn control_pickers(
|
||||
system: &mut Chip8ComputerManager,
|
||||
gui_state: &mut ImGuiUiState,
|
||||
ui: &Ui,
|
||||
) {
|
||||
if CollapsingHeader::new("Controls").build(ui) {
|
||||
// if the system has no program loaded hide the buttons.
|
||||
let bytes: [u8; 2] = [
|
||||
system.state().memory.peek(0x200),
|
||||
system.state().memory.peek(0x201),
|
||||
];
|
||||
let show_buttons = true; // bytes[0] != 0 || bytes[1] == 0xe0;
|
||||
|
||||
if show_buttons {
|
||||
if ui.button("Step") {
|
||||
system.step();
|
||||
};
|
||||
ui.same_line();
|
||||
if ui.button("Run") {
|
||||
system.start();
|
||||
}
|
||||
}
|
||||
ui.same_line();
|
||||
if ui.button("Stop") {
|
||||
system.stop();
|
||||
}
|
||||
ui.same_line();
|
||||
if ui.button("Reset") {
|
||||
system.reset(system.quirks_mode());
|
||||
}
|
||||
if ui.button("Dump Video Memory") {
|
||||
println!("{}", system.dump_to_string(Video));
|
||||
}
|
||||
ui.same_line();
|
||||
if ui.button("Dump Keypad State") {
|
||||
println!("{}", system.dump_to_string(Keyboard));
|
||||
}
|
||||
ui.same_line();
|
||||
if ui.button("Dump Registers") {
|
||||
println!("{}", system.dump_to_string(Registers));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn system_summary(
|
||||
system: &Chip8ComputerManager,
|
||||
ui: &Ui,
|
||||
) {
|
||||
/* System Step Counter */
|
||||
ui.text(format!("Step {:04x}", system.num_cycles()).as_str());
|
||||
ui.text(format!("Mode {}", system.quirks_mode()));
|
||||
}
|
||||
|
||||
fn rom_lister(
|
||||
system: &mut Chip8ComputerManager,
|
||||
gui_state: &mut ImGuiUiState,
|
||||
ui: &Ui,
|
||||
) {
|
||||
/* ROM Lister */
|
||||
if CollapsingHeader::new("Roms").build(ui) {
|
||||
let new_filename = GuiFileList::display_path(
|
||||
gui_state.roms_root_path.clone(),
|
||||
&gui_state.filename_to_load,
|
||||
ui,
|
||||
);
|
||||
if !new_filename.is_empty() {
|
||||
if new_filename != gui_state.filename_to_load {
|
||||
debug!("NEW FILENAME SELECTED -> {new_filename}");
|
||||
gui_state.filename_to_load = new_filename;
|
||||
}
|
||||
if ui.button("Load Program") {
|
||||
let mut buffer: Vec<u8> = Vec::new();
|
||||
let full_name = format!(
|
||||
"{}/{}",
|
||||
gui_state
|
||||
.roms_root_path
|
||||
.clone()
|
||||
.as_os_str()
|
||||
.to_string_lossy(),
|
||||
gui_state.filename_to_load.to_string()
|
||||
);
|
||||
debug!("PREPARING TO LOAD {}", full_name);
|
||||
|
||||
let input_file = File::open(Path::new(&full_name));
|
||||
input_file
|
||||
.unwrap()
|
||||
.read_to_end(&mut buffer)
|
||||
.expect("Unable to read rom.");
|
||||
system.load_new_program_to_system_memory(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn display_options(
|
||||
gui_state: &mut ImGuiUiState,
|
||||
ui: &Ui,
|
||||
) {
|
||||
if CollapsingHeader::new("Options").build(ui) {
|
||||
ui.checkbox("Show Memory", &mut gui_state.show_memory);
|
||||
ui.same_line();
|
||||
ui.checkbox("Show Video", &mut gui_state.show_video);
|
||||
ui.same_line();
|
||||
ui.checkbox("Show Registers", &mut gui_state.show_registers);
|
||||
ui.same_line();
|
||||
ui.checkbox("Show Keypad", &mut gui_state.show_keypad);
|
||||
ui.input_int("Target IPS", &mut gui_state.target_ips)
|
||||
.build();
|
||||
};
|
||||
}
|
||||
|
||||
pub fn system_controls(
|
||||
system_to_control: &mut Chip8ComputerManager,
|
||||
gui_state: &mut ImGuiUiState,
|
||||
@@ -116,114 +234,15 @@ impl GemmaImguiSupport {
|
||||
ui.window("!!!! CONTROLS !!!!")
|
||||
.position([100.0, 640.0], Condition::FirstUseEver)
|
||||
.build(|| {
|
||||
/* System Step Counter */
|
||||
ui.text(format!("Step {:04x}", system_to_control.num_cycles()).as_str());
|
||||
ui.text(format!("Mode {}", system_to_control.quirks_mode()));
|
||||
/* ROM Lister */
|
||||
if CollapsingHeader::new("Roms").build(ui) {
|
||||
let new_filename = GuiFileList::display_path(
|
||||
gui_state.roms_root_path.clone(),
|
||||
&gui_state.filename_to_load,
|
||||
ui,
|
||||
);
|
||||
if !new_filename.is_empty() {
|
||||
if new_filename != gui_state.filename_to_load {
|
||||
debug!("NEW FILENAME SELECTED -> {new_filename}");
|
||||
gui_state.filename_to_load = new_filename;
|
||||
}
|
||||
if ui.button("Load Program") {
|
||||
let mut buffer: Vec<u8> = Vec::new();
|
||||
let full_name = format!(
|
||||
"{}/{}",
|
||||
gui_state
|
||||
.roms_root_path
|
||||
.clone()
|
||||
.as_os_str()
|
||||
.to_string_lossy(),
|
||||
gui_state.filename_to_load.to_string()
|
||||
);
|
||||
debug!("PREPARING TO LOAD {}", full_name);
|
||||
GemmaImguiSupport::system_summary(system_to_control, ui);
|
||||
|
||||
let input_file = File::open(Path::new(&full_name));
|
||||
input_file
|
||||
.unwrap()
|
||||
.read_to_end(&mut buffer)
|
||||
.expect("Unable to read rom.");
|
||||
system_to_control.load_new_program_to_system_memory(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
GemmaImguiSupport::rom_lister(system_to_control, gui_state, ui);
|
||||
|
||||
if CollapsingHeader::new("Controls").build(ui) {
|
||||
// if the system has no program loaded hide the buttons.
|
||||
let bytes: [u8; 2] = [
|
||||
system_to_control.state().memory.peek(0x200),
|
||||
system_to_control.state().memory.peek(0x201),
|
||||
];
|
||||
let show_buttons = bytes[0] != 0 || bytes[1] == 0xe0;
|
||||
GemmaImguiSupport::control_pickers(system_to_control, gui_state, ui);
|
||||
|
||||
if show_buttons {
|
||||
if ui.button("Step") {
|
||||
system_to_control.step();
|
||||
};
|
||||
ui.same_line();
|
||||
if ui.button("Run") {
|
||||
system_to_control.start();
|
||||
}
|
||||
}
|
||||
ui.same_line();
|
||||
if ui.button("Stop") {
|
||||
system_to_control.stop();
|
||||
}
|
||||
ui.same_line();
|
||||
if ui.button("Reset") {
|
||||
system_to_control.reset(system_to_control.quirks_mode());
|
||||
}
|
||||
if ui.button("Dump Video Memory") {
|
||||
println!("{}", system_to_control.dump_to_string(Video));
|
||||
}
|
||||
ui.same_line();
|
||||
if ui.button("Dump Keypad State") {
|
||||
debug!("{}", system_to_control.dump_to_string(Keyboard));
|
||||
}
|
||||
ui.same_line();
|
||||
if ui.button("Dump Registers") {
|
||||
debug!("{}", system_to_control.dump_to_string(Registers));
|
||||
}
|
||||
}
|
||||
GemmaImguiSupport::display_options(gui_state, ui);
|
||||
|
||||
if CollapsingHeader::new("Options").build(ui) {
|
||||
ui.checkbox("Show Memory", &mut gui_state.show_memory);
|
||||
ui.same_line();
|
||||
ui.checkbox("Show Video", &mut gui_state.show_video);
|
||||
ui.same_line();
|
||||
ui.checkbox("Show Registers", &mut gui_state.show_registers);
|
||||
ui.same_line();
|
||||
ui.checkbox("Show Keypad", &mut gui_state.show_keypad);
|
||||
ui.input_int("Target IPS", &mut gui_state.target_ips)
|
||||
.build();
|
||||
};
|
||||
|
||||
let selectors = [Chip8, SChipModern, XOChip];
|
||||
for current_selector in selectors {
|
||||
let mut working_selector =
|
||||
ui.selectable_config(current_selector.clone().to_string());
|
||||
match system_to_control.quirks_mode() {
|
||||
Chip8 => {
|
||||
working_selector = working_selector.selected(true);
|
||||
}
|
||||
SChipModern => {
|
||||
working_selector = working_selector.selected(true);
|
||||
}
|
||||
XOChip => {
|
||||
working_selector = working_selector.selected(true);
|
||||
}
|
||||
}
|
||||
if working_selector.build() {
|
||||
system_to_control.reset(current_selector);
|
||||
println!("CLICK ON {}", ¤t_selector);
|
||||
}
|
||||
}
|
||||
GemmaImguiSupport::quirks_picker(system_to_control, ui);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -232,7 +251,7 @@ impl GemmaImguiSupport {
|
||||
.position([100.0, 640.0], Condition::FirstUseEver)
|
||||
.build(|| {
|
||||
ui.text("Registers");
|
||||
for i in 1..0x10 {
|
||||
for i in 0..0x10 {
|
||||
ui.text(format!("V{:X}: {}", i, system.registers.peek(i)));
|
||||
if i != 7 {
|
||||
ui.same_line();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::ffi::OsString;
|
||||
use std::fs::read_dir;
|
||||
use std::path::PathBuf;
|
||||
use imgui::Ui;
|
||||
use imgui::{ChildWindow, Ui};
|
||||
use log::debug;
|
||||
|
||||
pub struct GuiFileList {}
|
||||
@@ -20,16 +20,22 @@ impl GuiFileList {
|
||||
|
||||
known_files.sort();
|
||||
|
||||
for (index, entry) in known_files.iter().enumerate() {
|
||||
let mut working_select = ui.selectable_config(entry.clone().into_string().unwrap().to_string());
|
||||
if *entry.to_str().unwrap() == *selected_filename.as_str() {
|
||||
working_select = working_select.selected(true);
|
||||
}
|
||||
if working_select.build() {
|
||||
debug!("SELECTED {index} / {entry:?}");
|
||||
working_filename = entry.clone().into_string().unwrap();
|
||||
};
|
||||
}
|
||||
ui.child_window("Item List")
|
||||
.size([0.0, 200.0])
|
||||
.border(false)
|
||||
.build(|| {
|
||||
for (index, entry) in known_files.iter().enumerate() {
|
||||
let mut working_select = ui.selectable_config(entry.clone().into_string().unwrap().to_string());
|
||||
if *entry.to_str().unwrap() == *selected_filename.as_str() {
|
||||
working_select = working_select.selected(true);
|
||||
}
|
||||
if working_select.build() {
|
||||
debug!("SELECTED {index} / {entry:?}");
|
||||
working_filename = entry.clone().into_string().unwrap();
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
working_filename
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ pub fn create_context() -> imgui::Context {
|
||||
}),
|
||||
},
|
||||
]);
|
||||
imgui.set_ini_filename(None);
|
||||
// imgui.set_ini_filename(None);
|
||||
|
||||
imgui
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@ pub struct ImGuiUiState {
|
||||
pub frame_time: u32,
|
||||
pub last_frame_instant: Instant,
|
||||
pub target_ips: i32,
|
||||
pub roms_root_path: PathBuf
|
||||
pub roms_root_path: PathBuf,
|
||||
pub video_window_size: [i32; 2],
|
||||
pub control_window_size: [i32; 2]
|
||||
}
|
||||
|
||||
impl Clone for ImGuiUiState {
|
||||
@@ -33,7 +35,9 @@ impl Clone for ImGuiUiState {
|
||||
frame_time: self.frame_time,
|
||||
last_frame_instant: self.last_frame_instant,
|
||||
target_ips: self.target_ips,
|
||||
roms_root_path: self.roms_root_path.to_owned()
|
||||
roms_root_path: self.roms_root_path.to_owned(),
|
||||
video_window_size: self.video_window_size,
|
||||
control_window_size: self.control_window_size
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,8 +55,10 @@ impl Default for ImGuiUiState {
|
||||
is_running: false,
|
||||
frame_time: 16,
|
||||
last_frame_instant: Instant::now(),
|
||||
target_ips: 200000,
|
||||
roms_root_path: PathBuf::from(ROMPATH_DEFAULT)
|
||||
target_ips: 20,
|
||||
roms_root_path: PathBuf::from(ROMPATH_DEFAULT),
|
||||
control_window_size: [200, 600],
|
||||
video_window_size: [800, 600]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
[package]
|
||||
name = "gemmautil"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
gemma = { path = "../gemma" }
|
||||
clap.workspace = true
|
||||
pest = "2.7.14"
|
||||
pest_derive = "2.7.14"
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
1f8b08000000000000ffed9bcb8adb301440f7fd162dfc0c136d0b854257dd743104636c4d2212dba924b704e37fafecb13b4e42da4099a10c87631d45575792e56897b8abdb2a2b4ec5415919884a558d39c96eaa1fa324106192fc2e433b8ec47a35d85f61188db170f55c450f63bd0c4dd562021fbac89f9a67a12979eaf66bad92e15af69de5bc4c7e159ad78eaeeb79c9b98c63a3e47cd38bbcab5d2e624309e0d509c7271dff212316e1da1fcc5be387ef331d4a3a9670bdfee7ccf98c44893f0f69348eba9139cd3597f8e6dac1f9da7178e78cc3bddcbb9ff40d3397596f3fe7bdcffdde3c0000000000000000000000000078376c7a61d4565ba78c95ddcbc7c7bf8d133a9bb365208e854cc3a817b669eb3273baf2d1aef08db1bb17a53ae4a7cbb8ff59b2173f74a99aecf20f1b4ff9c12a8131c618638c31c618638c31c618638c31c618638c31c618638c31c618e3ffd81bb1cb6df664f24a65c52eafb7aa94cfdd456b8caa5d6694955f9a9f5f95ed8575b953f25bae9daeb79f1af3b9b6ceb485d34d2df6ea74cc4bd9f9dabefa6b059bf15e8abdecb453955fcf07beb7daecb3aa2995fcb8d3c787fec32fcefd4d09ab520000
|
||||
Reference in New Issue
Block a user