more coverage
This commit is contained in:
Generated
+1056
-553
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "gemma"
|
name = "gemma"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
autobenches = true
|
autobenches = true
|
||||||
|
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
use clap::{Parser, Subcommand};
|
|
||||||
use flate2::{write::{GzEncoder, GzDecoder}, Compression};
|
|
||||||
use std::io::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,125 @@
|
|||||||
|
use std::fs;
|
||||||
|
use std::fs::File;
|
||||||
|
use clap::{Parser, Subcommand};
|
||||||
|
use flate2::{write::{GzEncoder, GzDecoder}, Compression};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::io::Write;
|
||||||
|
use flate2::write::ZlibEncoder;
|
||||||
|
use gemma::constants::TEST_ROM_ROOT;
|
||||||
|
|
||||||
|
#[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: PathBuf,
|
||||||
|
},
|
||||||
|
/// Decompress the input string (must be compressed format)
|
||||||
|
Decompress {
|
||||||
|
/// The compressed string to decompress, in hex format
|
||||||
|
input: PathBuf,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Compresses raw binary data using Gzip and returns the compressed bytes.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `data` - A `Vec<u8>` containing the uncompressed binary data.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A `Vec<u8>` with the compressed data. Panics if compression fails.
|
||||||
|
pub fn compress_data(data: Vec<u8>) -> Vec<u8> {
|
||||||
|
let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
|
||||||
|
encoder
|
||||||
|
.write_all(&data)
|
||||||
|
.expect("Failed to write data to encoder");
|
||||||
|
encoder.finish().expect("Failed to finish compression")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decompresses Gzip-compressed binary data and returns the uncompressed bytes.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `data` - A `Vec<u8>` containing Gzip-compressed data.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A `Vec<u8>` with the decompressed data. Panics if decompression fails.
|
||||||
|
// pub fn decompress_data(data: Vec<u8>) -> Vec<u8> {
|
||||||
|
// let mut decoder = GzDecoder::new( &data[..]);
|
||||||
|
// let mut decompressed = Vec::new();
|
||||||
|
// decoder.write_all(&mut decompressed)
|
||||||
|
// .expect("Failed to decompress data");
|
||||||
|
// decompressed.clone().to_vec()
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn compress_file(input_path: &PathBuf) {
|
||||||
|
let target_file_name = format!("{}.tflt", input_path.display());
|
||||||
|
println!("TARGET_FILE_NAME: {}", target_file_name);
|
||||||
|
let input_data = fs::read(input_path).expect("Failed to read input file");
|
||||||
|
|
||||||
|
let compressed_data = compress_data(input_data);
|
||||||
|
let target_file = File::create(target_file_name);
|
||||||
|
target_file.unwrap().write_all(&compressed_data).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decompress_file(input_path: &PathBuf) {
|
||||||
|
let target_file_name = format!("{}.uncompressed", input_path.display());
|
||||||
|
println!("Writing decompressed data to {}", target_file_name);
|
||||||
|
let input_data = fs::read(input_path).expect("Failed to read compressed file.");
|
||||||
|
// let decompressed_data = decompress_data(input_data);
|
||||||
|
// let mut target_file = File::create(&target_file_name).expect(format!("Unable to create uncompressed file -> {}", target_file_name.clone()).as_str());
|
||||||
|
//target_file.write_all(&decompressed_data).expect(format!("Unable to write uncompressed file -> {}", target_file_name).as_str());
|
||||||
|
//println!("Decompressed: {:?}", String::from_utf8_lossy(&decompressed_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
|
||||||
|
let filename = format!("{}/gemma/{}/2-ibm-logo.ch8", std::env::current_dir().unwrap().display(), TEST_ROM_ROOT);
|
||||||
|
println!("READING {} from {}", filename, std::env::current_dir().unwrap().display());
|
||||||
|
let mut file = File::open(filename).unwrap();
|
||||||
|
let mut file_data = Vec::new();
|
||||||
|
file.read_to_end(&mut file_data).expect("unable to read rom");
|
||||||
|
let mut e = ZlibEncoder::new(Vec::new(), Compression::default());
|
||||||
|
|
||||||
|
e.write_all(b"foo");
|
||||||
|
e.write_all(b"bar");
|
||||||
|
let compressed_bytes = e.finish();
|
||||||
|
|
||||||
|
println!("COMPRESSED: {compressed_bytes:?}");
|
||||||
|
//
|
||||||
|
// 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);
|
||||||
|
// }
|
||||||
|
// Commands::DecompressFile { input } => {
|
||||||
|
// decompress_file(&input);
|
||||||
|
// }
|
||||||
|
// Commands::CompressFile { input } => {
|
||||||
|
// compress_file(&input);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
+10
-13
@@ -6,7 +6,6 @@ use crate::chip8::sound_timer::SoundTimer;
|
|||||||
use crate::chip8::stack::Chip8Stack;
|
use crate::chip8::stack::Chip8Stack;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
cpu_states::Chip8CpuStates, instructions::Chip8CpuInstructions,
|
cpu_states::Chip8CpuStates, instructions::Chip8CpuInstructions,
|
||||||
system_memory::Chip8SystemMemory, video::Chip8Video,
|
system_memory::Chip8SystemMemory, video::Chip8Video,
|
||||||
@@ -25,6 +24,16 @@ pub struct Chip8Computer {
|
|||||||
pub stack: Chip8Stack,
|
pub stack: Chip8Stack,
|
||||||
pub quirk_mode: QuirkMode,
|
pub quirk_mode: QuirkMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Chip8Computer {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.video_memory.format_as_string() == other.video_memory.format_as_string() &&
|
||||||
|
self.keypad.format_as_string() == other.keypad.format_as_string() &&
|
||||||
|
self.num_cycles == other.num_cycles &&
|
||||||
|
self.memory == other.memory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for Chip8Computer {
|
impl Default for Chip8Computer {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -66,18 +75,6 @@ impl Chip8Computer {
|
|||||||
self.clone().video_memory.format_as_string()
|
self.clone().video_memory.format_as_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_with_program(new_program: Vec<u16>) -> Self {
|
|
||||||
let mut working = Chip8Computer::new();
|
|
||||||
|
|
||||||
for (i, &word) in new_program.iter().enumerate() {
|
|
||||||
let high = (word >> 8) as u8;
|
|
||||||
let low = (word & 0xff) as u8;
|
|
||||||
let base_offset = (i * 2) as u16;
|
|
||||||
working.memory.poke(base_offset, high);
|
|
||||||
working.memory.poke(base_offset + 1, low);
|
|
||||||
}
|
|
||||||
working
|
|
||||||
}
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Chip8Computer::default()
|
Chip8Computer::default()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,9 +39,8 @@ impl Chip8ComputerManager {
|
|||||||
/// an idea of the internal state of the Chip-8 Computer
|
/// an idea of the internal state of the Chip-8 Computer
|
||||||
pub fn status_as_string(&self) -> String {
|
pub fn status_as_string(&self) -> String {
|
||||||
// build a string
|
// build a string
|
||||||
format!("Should Run: {}\nLast Cycle Start: {:?}\nNum Cycles: {}\nRegisters\n{}\nTimers: {}/{}\nKeypad: \n{}\nVideo:\n{}",
|
format!("Should Run: {}\nNum Cycles: {}\nRegisters\n{}\nTimers: {}/{}\nKeypad: \n{}\nVideo:\n{}",
|
||||||
self.core_should_run,
|
self.core_should_run,
|
||||||
self.core_last_cycle_start,
|
|
||||||
self.computer.num_cycles,
|
self.computer.num_cycles,
|
||||||
self.computer.registers.format_as_string(),
|
self.computer.registers.format_as_string(),
|
||||||
self.computer.delay_timer.current(),
|
self.computer.delay_timer.current(),
|
||||||
|
|||||||
@@ -279,50 +279,50 @@ pub enum Chip8CpuInstructions {
|
|||||||
impl Chip8CpuInstructions {
|
impl Chip8CpuInstructions {
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
Chip8CpuInstructions::ADDI(_) => INST_ADDI,
|
ADDI(_) => INST_ADDI,
|
||||||
Chip8CpuInstructions::ADD(_, _) => INST_ADD,
|
ADD(_, _) => INST_ADD,
|
||||||
Chip8CpuInstructions::ADDR(_, _) => INST_ADDR,
|
ADDR(_, _) => INST_ADDR,
|
||||||
Chip8CpuInstructions::AND(_, _) => INST_AND,
|
AND(_, _) => INST_AND,
|
||||||
Chip8CpuInstructions::CLS => INST_CLS,
|
CLS => INST_CLS,
|
||||||
Chip8CpuInstructions::CALL(_) => INST_CALL,
|
CALL(_) => INST_CALL,
|
||||||
Chip8CpuInstructions::DRW(_, _, _) => INST_DRW,
|
DRW(_, _, _) => INST_DRW,
|
||||||
Chip8CpuInstructions::EXIT => INST_EXIT,
|
EXIT => INST_EXIT,
|
||||||
Chip8CpuInstructions::JPA(_) => INST_JPA,
|
JPA(_) => INST_JPA,
|
||||||
Chip8CpuInstructions::JPI(_) => INST_JPI,
|
JPI(_) => INST_JPI,
|
||||||
Chip8CpuInstructions::BCD(_) => INST_BCD,
|
BCD(_) => INST_BCD,
|
||||||
Chip8CpuInstructions::LDD(_) => INST_LDD,
|
LDD(_) => INST_LDD,
|
||||||
Chip8CpuInstructions::LDFX(_) => INST_LDF,
|
LDFX(_) => INST_LDF,
|
||||||
Chip8CpuInstructions::LDF2(_) => INST_LDF2,
|
LDF2(_) => INST_LDF2,
|
||||||
Chip8CpuInstructions::LDIA(_) => INST_LDIA,
|
LDIA(_) => INST_LDIA,
|
||||||
Chip8CpuInstructions::LDIX(_) => INST_LDIX,
|
LDIX(_) => INST_LDIX,
|
||||||
Chip8CpuInstructions::LIDR(_) => INST_LIDR,
|
LIDR(_) => INST_LIDR,
|
||||||
Chip8CpuInstructions::LDIS(_) => INST_LDIS,
|
LDIS(_) => INST_LDIS,
|
||||||
Chip8CpuInstructions::LDR(_, _) => INST_LDR,
|
LDR(_, _) => INST_LDR,
|
||||||
Chip8CpuInstructions::LDRD(_) => INST_LDRD,
|
LDRD(_) => INST_LDRD,
|
||||||
Chip8CpuInstructions::LDRI(_) => INST_LDRI,
|
LDRI(_) => INST_LDRI,
|
||||||
Chip8CpuInstructions::LDRK(_) => INST_LDRK,
|
LDRK(_) => INST_LDRK,
|
||||||
Chip8CpuInstructions::LDRY(_, _) => INST_LDRY,
|
LDRY(_, _) => INST_LDRY,
|
||||||
Chip8CpuInstructions::OR(_, _) => INST_OR,
|
OR(_, _) => INST_OR,
|
||||||
Chip8CpuInstructions::RET => INST_RET,
|
RET => INST_RET,
|
||||||
Chip8CpuInstructions::RND(_, _) => INST_RND,
|
RND(_, _) => INST_RND,
|
||||||
Chip8CpuInstructions::SCD(_) => INST_SCD,
|
SCD(_) => INST_SCD,
|
||||||
Chip8CpuInstructions::SCL => INST_SCL,
|
SCL => INST_SCL,
|
||||||
Chip8CpuInstructions::SCR => INST_SCR,
|
SCR => INST_SCR,
|
||||||
Chip8CpuInstructions::SEX(_, _) => INST_SEX,
|
SEX(_, _) => INST_SEX,
|
||||||
Chip8CpuInstructions::SEY(_, _) => INST_SEY,
|
SEY(_, _) => INST_SEY,
|
||||||
Chip8CpuInstructions::SHL(_, _) => INST_SHL,
|
SHL(_, _) => INST_SHL,
|
||||||
Chip8CpuInstructions::SHR(_, _) => INST_SHR,
|
SHR(_, _) => INST_SHR,
|
||||||
Chip8CpuInstructions::SKP(_) => INST_SKP,
|
SKP(_) => INST_SKP,
|
||||||
Chip8CpuInstructions::SNEB(_, _) => INST_SNEB,
|
SNEB(_, _) => INST_SNEB,
|
||||||
Chip8CpuInstructions::SNEY(_, _) => INST_SNEY,
|
SNEY(_, _) => INST_SNEY,
|
||||||
Chip8CpuInstructions::SKNP(_) => INST_SKNP,
|
SKNP(_) => INST_SKNP,
|
||||||
Chip8CpuInstructions::STR(_) => INST_STR,
|
STR(_) => INST_STR,
|
||||||
Chip8CpuInstructions::SUB(_, _) => INST_SUB,
|
SUB(_, _) => INST_SUB,
|
||||||
Chip8CpuInstructions::SUBC(_, _) => INST_SUBC,
|
SUBC(_, _) => INST_SUBC,
|
||||||
Chip8CpuInstructions::SYS(_) => INST_SYS,
|
SYS(_) => INST_SYS,
|
||||||
Chip8CpuInstructions::LOW => INST_LOW,
|
LOW => INST_LOW,
|
||||||
Chip8CpuInstructions::HIGH => INST_HIGH,
|
HIGH => INST_HIGH,
|
||||||
Chip8CpuInstructions::ORY(_, _) => INST_ORY,
|
ORY(_, _) => INST_ORY,
|
||||||
JPX(_, _) => INST_JPX,
|
JPX(_, _) => INST_JPX,
|
||||||
XXXXERRORINSTRUCTION => "XX ERROR XX",
|
XXXXERRORINSTRUCTION => "XX ERROR XX",
|
||||||
SCU(_) => INST_SCU,
|
SCU(_) => INST_SCU,
|
||||||
@@ -502,15 +502,15 @@ impl Chip8CpuInstructions {
|
|||||||
|
|
||||||
pub fn encode(&self) -> u16 {
|
pub fn encode(&self) -> u16 {
|
||||||
match self {
|
match self {
|
||||||
Chip8CpuInstructions::SYS(target) => target & 0x0FFF,
|
SYS(target) => target & 0x0FFF,
|
||||||
Chip8CpuInstructions::CLS => 0x00E0,
|
CLS => 0x00E0,
|
||||||
Chip8CpuInstructions::RET => 0x00EE,
|
RET => 0x00EE,
|
||||||
Chip8CpuInstructions::JPA(new_addr) => 0x1000 | (new_addr & 0x0FFF),
|
JPA(new_addr) => 0x1000 | (new_addr & 0x0FFF),
|
||||||
Chip8CpuInstructions::CALL(address) => 0x2000 | (address & 0x0FFF),
|
CALL(address) => 0x2000 | (address & 0x0FFF),
|
||||||
Chip8CpuInstructions::SEX(vx_register, byte) => {
|
SEX(vx_register, byte) => {
|
||||||
0x3000 | ((*vx_register as u16) << 8) | (*byte as u16)
|
0x3000 | ((*vx_register as u16) << 8) | (*byte as u16)
|
||||||
}
|
}
|
||||||
Chip8CpuInstructions::SNEB(vx_register, byte) => {
|
SNEB(vx_register, byte) => {
|
||||||
0x4000 | ((*vx_register as u16) << 8) | (*byte as u16)
|
0x4000 | ((*vx_register as u16) << 8) | (*byte as u16)
|
||||||
}
|
}
|
||||||
Chip8CpuInstructions::SEY(x_register, y_register) => {
|
Chip8CpuInstructions::SEY(x_register, y_register) => {
|
||||||
@@ -586,7 +586,7 @@ impl Chip8CpuInstructions {
|
|||||||
Chip8CpuInstructions::LIDR(x_register) => 0xF085 | ((*x_register as u16) << 8),
|
Chip8CpuInstructions::LIDR(x_register) => 0xF085 | ((*x_register as u16) << 8),
|
||||||
SCU(x_register) => 0x00D0 | (*x_register as u16),
|
SCU(x_register) => 0x00D0 | (*x_register as u16),
|
||||||
DW(address) => *address as u16,
|
DW(address) => *address as u16,
|
||||||
XXXXERRORINSTRUCTION => 0x0000,
|
XXXXERRORINSTRUCTION => XXXXERRORINSTRUCTION_ENCODED,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn decode(input: u16, quirk_mode: &QuirkMode) -> Chip8CpuInstructions {
|
pub fn decode(input: u16, quirk_mode: &QuirkMode) -> Chip8CpuInstructions {
|
||||||
@@ -903,7 +903,7 @@ impl Chip8CpuInstructions {
|
|||||||
// The interpreter generates a random number from 0 to 255,
|
// The interpreter generates a random number from 0 to 255,
|
||||||
// which is then ANDed with the value kk.
|
// which is then ANDed with the value kk.
|
||||||
// The results are stored in Vx.
|
// The results are stored in Vx.
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::rng();
|
||||||
let new_value: u8 = rng.random();
|
let new_value: u8 = rng.random();
|
||||||
let and_value: u8 = *byte;
|
let and_value: u8 = *byte;
|
||||||
let result = new_value & and_value;
|
let result = new_value & and_value;
|
||||||
|
|||||||
@@ -1,20 +1,21 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
use crate::constants::{LABEL_QUIRK_CHIP8, LABEL_QUIRK_SCHIP, LABEL_QUIRK_XOCHIP};
|
||||||
|
|
||||||
#[derive(Default, Clone, Serialize, Deserialize, Copy, Debug)]
|
#[derive(Default, Clone, Serialize, Deserialize, Copy, Debug, PartialEq)]
|
||||||
pub enum QuirkMode {
|
pub enum QuirkMode {
|
||||||
|
#[default]
|
||||||
Chip8,
|
Chip8,
|
||||||
XOChip,
|
XOChip,
|
||||||
#[default]
|
|
||||||
SChipModern,
|
SChipModern,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for QuirkMode {
|
impl Display for QuirkMode {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let variant = match &self {
|
let variant = match &self {
|
||||||
QuirkMode::Chip8 => "Chip8".to_string(),
|
QuirkMode::Chip8 => LABEL_QUIRK_CHIP8.to_string(),
|
||||||
QuirkMode::XOChip => "XO Chip".to_string(),
|
QuirkMode::XOChip => LABEL_QUIRK_XOCHIP.to_string(),
|
||||||
QuirkMode::SChipModern => "SChip-Modern".to_string(),
|
QuirkMode::SChipModern => LABEL_QUIRK_SCHIP.to_string(),
|
||||||
};
|
};
|
||||||
write!(f, "{}", variant)
|
write!(f, "{}", variant)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,12 @@ pub struct Chip8Registers {
|
|||||||
pub pc: u16,
|
pub pc: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Chip8Registers {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.pc == other.pc && self.registers == other.registers && self.i_register == other.i_register
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Chip8Registers {
|
impl Chip8Registers {
|
||||||
pub fn advance_pc(&mut self) {
|
pub fn advance_pc(&mut self) {
|
||||||
self.pc += 2;
|
self.pc += 2;
|
||||||
|
|||||||
@@ -11,6 +11,12 @@ pub struct Chip8SystemMemory {
|
|||||||
memory: Vec<u8>,
|
memory: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Chip8SystemMemory {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.memory == other.memory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for Chip8SystemMemory {
|
impl Default for Chip8SystemMemory {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let mut x = Chip8SystemMemory::new();
|
let mut x = Chip8SystemMemory::new();
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ use crate::constants::{
|
|||||||
CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_MEMORY, CHIP8_VIDEO_WIDTH, SCHIP_VIDEO_HEIGHT,
|
CHIP8_VIDEO_HEIGHT, CHIP8_VIDEO_MEMORY, CHIP8_VIDEO_WIDTH, SCHIP_VIDEO_HEIGHT,
|
||||||
SCHIP_VIDEO_WIDTH, SCHIP_VIDE_MEMORY,
|
SCHIP_VIDEO_WIDTH, SCHIP_VIDE_MEMORY,
|
||||||
};
|
};
|
||||||
use log::debug;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
||||||
@@ -120,10 +119,7 @@ impl Chip8Video {
|
|||||||
for row in 0..height {
|
for row in 0..height {
|
||||||
for column in 0..width {
|
for column in 0..width {
|
||||||
let data_offset = row * width + column;
|
let data_offset = row * width + column;
|
||||||
debug!(
|
|
||||||
"Rendering {data_offset} with value {}",
|
|
||||||
self.memory[data_offset as usize]
|
|
||||||
);
|
|
||||||
if self.memory[data_offset as usize] {
|
if self.memory[data_offset as usize] {
|
||||||
output += "*"
|
output += "*"
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -5,8 +5,13 @@ pub const CHIP8_VIDEO_HEIGHT: i32 = 32i32;
|
|||||||
pub const CHIP8_VIDEO_MEMORY: usize = (CHIP8_VIDEO_HEIGHT * CHIP8_VIDEO_WIDTH) as usize;
|
pub const CHIP8_VIDEO_MEMORY: usize = (CHIP8_VIDEO_HEIGHT * CHIP8_VIDEO_WIDTH) as usize;
|
||||||
pub const CHIP8_ROM_SIZE: usize = 512;
|
pub const CHIP8_ROM_SIZE: usize = 512;
|
||||||
|
|
||||||
|
pub const LABEL_QUIRK_CHIP8: &str = "Chip8";
|
||||||
|
pub const LABEL_QUIRK_XOCHIP: &str = "XO Chip";
|
||||||
|
pub const LABEL_QUIRK_SCHIP: &str = "SChip-Modern";
|
||||||
|
|
||||||
pub const RESOURCES_ROOT: &str = "../resources";
|
pub const RESOURCES_ROOT: &str = "../resources";
|
||||||
pub const TESTS_ROOT: &str = "../resources/tests/";
|
pub const TESTS_ROOT: &str = "../resources/test/";
|
||||||
|
pub const TEST_ROM_ROOT: &str = "../resources/test/roms";
|
||||||
|
|
||||||
pub const CHIP8_KEYBOARD: [[u8; 4]; 4] = [
|
pub const CHIP8_KEYBOARD: [[u8; 4]; 4] = [
|
||||||
[0x01, 0x02, 0x03, 0x0C],
|
[0x01, 0x02, 0x03, 0x0C],
|
||||||
@@ -69,6 +74,8 @@ pub const INST_SCU: &str = "SCU";
|
|||||||
/// Data to be loaded to memory for application use
|
/// Data to be loaded to memory for application use
|
||||||
pub const INST_DW: &str = "DW";
|
pub const INST_DW: &str = "DW";
|
||||||
|
|
||||||
|
pub const XXXXERRORINSTRUCTION_ENCODED: u16 = 0x0000;
|
||||||
|
|
||||||
pub const CHIP8_PROGRAM_LOAD_OFFSET: i32 = 0x200;
|
pub const CHIP8_PROGRAM_LOAD_OFFSET: i32 = 0x200;
|
||||||
pub const CHIP8FONT_0: [u8; 5] = [0xF0, 0x90, 0x90, 0x90, 0xF0];
|
pub const CHIP8FONT_0: [u8; 5] = [0xF0, 0x90, 0x90, 0x90, 0xF0];
|
||||||
pub const CHIP8FONT_1: [u8; 5] = [0x20, 0x60, 0x20, 0x20, 0x70];
|
pub const CHIP8FONT_1: [u8; 5] = [0x20, 0x60, 0x20, 0x20, 0x70];
|
||||||
@@ -104,3 +111,4 @@ pub const SCHIPFONT_C: [u8; 0x0A] = [0xF0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0
|
|||||||
pub const SCHIPFONT_D: [u8; 0x0A] = [0xE0, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xE0];
|
pub const SCHIPFONT_D: [u8; 0x0A] = [0xE0, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xE0];
|
||||||
pub const SCHIPFONT_E: [u8; 0x0A] = [0xF0, 0x80, 0x80, 0x80, 0xF0, 0x80, 0x80, 0x80, 0x80, 0xF0];
|
pub const SCHIPFONT_E: [u8; 0x0A] = [0xF0, 0x80, 0x80, 0x80, 0xF0, 0x80, 0x80, 0x80, 0x80, 0xF0];
|
||||||
pub const SCHIPFONT_F: [u8; 0x0A] = [0xF0, 0x80, 0x80, 0x80, 0xF0, 0x80, 0x80, 0x80, 0x80, 0x80];
|
pub const SCHIPFONT_F: [u8; 0x0A] = [0xF0, 0x80, 0x80, 0x80, 0xF0, 0x80, 0x80, 0x80, 0x80, 0x80];
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
|
use std::path::Path;
|
||||||
|
use std::time::Instant;
|
||||||
use gemma::chip8::computer::Chip8Computer;
|
use gemma::chip8::computer::Chip8Computer;
|
||||||
use gemma::constants::CHIP8_VIDEO_MEMORY;
|
use gemma::chip8::computer_manager::Chip8ComputerManager;
|
||||||
|
use gemma::chip8::quirk_modes::QuirkMode;
|
||||||
|
use gemma::chip8::quirk_modes::QuirkMode::{Chip8, SChipModern, XOChip};
|
||||||
|
use gemma::chip8::registers::Chip8Registers;
|
||||||
|
use gemma::constants::{CHIP8_VIDEO_MEMORY, TESTS_ROOT};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn smoke() {
|
fn smoke() {
|
||||||
@@ -36,7 +42,7 @@ fn reset_clears_video() {
|
|||||||
fn level1_test() {
|
fn level1_test() {
|
||||||
let mut x = Chip8Computer::new();
|
let mut x = Chip8Computer::new();
|
||||||
let level_1_rom = load_rom("1-chip8-logo.ch8");
|
let level_1_rom = load_rom("1-chip8-logo.ch8");
|
||||||
x.load_bytes_to_memory(0x200, (&level_1_rom));
|
x.load_bytes_to_memory(0x200, &level_1_rom);
|
||||||
|
|
||||||
// run for 0x40 cycles
|
// run for 0x40 cycles
|
||||||
while x.num_cycles < 0x40 {
|
while x.num_cycles < 0x40 {
|
||||||
@@ -54,7 +60,7 @@ fn level2_test() {
|
|||||||
// Load the IBM rom and run it.
|
// Load the IBM rom and run it.
|
||||||
// it takes 39 cycles to get to the end so lets run it 40.
|
// it takes 39 cycles to get to the end so lets run it 40.
|
||||||
let test_rom_to_run = load_rom("2-ibm-logo.ch8");
|
let test_rom_to_run = load_rom("2-ibm-logo.ch8");
|
||||||
x.load_bytes_to_memory(0x200, (&test_rom_to_run));
|
x.load_bytes_to_memory(0x200, &test_rom_to_run);
|
||||||
for _ in 0..40 {
|
for _ in 0..40 {
|
||||||
x.step_system();
|
x.step_system();
|
||||||
}
|
}
|
||||||
@@ -71,7 +77,7 @@ fn level2_test() {
|
|||||||
fn level3_test() {
|
fn level3_test() {
|
||||||
let mut x = Chip8Computer::new();
|
let mut x = Chip8Computer::new();
|
||||||
|
|
||||||
x.load_bytes_to_memory(0x200, (&load_rom("3-corax+.ch8")));
|
x.load_bytes_to_memory(0x200, &load_rom("3-corax+.ch8"));
|
||||||
for i in 0..0x180 {
|
for i in 0..0x180 {
|
||||||
x.step_system();
|
x.step_system();
|
||||||
}
|
}
|
||||||
@@ -117,3 +123,71 @@ fn level4_test() {
|
|||||||
load_result("gemma_integration_flags.asc")
|
load_result("gemma_integration_flags.asc")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn registers_equality() {
|
||||||
|
let data_set: Vec<(Chip8Registers, Chip8Registers, bool)> = vec![
|
||||||
|
(Chip8Registers::default(), Chip8Registers::default(), true),
|
||||||
|
(Chip8Registers {
|
||||||
|
registers: [0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,],
|
||||||
|
i_register: 0,
|
||||||
|
pc: 0,
|
||||||
|
},
|
||||||
|
Chip8Registers {
|
||||||
|
registers:[0x01, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00,],
|
||||||
|
i_register: 0,
|
||||||
|
pc: 0,
|
||||||
|
}, false)
|
||||||
|
];
|
||||||
|
|
||||||
|
for (first, second, matches) in data_set.iter() {
|
||||||
|
assert_eq!(first == second, *matches)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn default_test() {
|
||||||
|
let new_manager = Chip8ComputerManager::default();
|
||||||
|
|
||||||
|
assert_eq!(new_manager.core_should_run, false);
|
||||||
|
assert_eq!(new_manager.num_cycles(), 0);
|
||||||
|
assert_eq!(new_manager.quirks_mode(), Chip8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn quirks_mode_test() {
|
||||||
|
let mut new_manager = Chip8ComputerManager::default();
|
||||||
|
|
||||||
|
assert_eq!(new_manager.quirks_mode(), Chip8);
|
||||||
|
|
||||||
|
new_manager.reset(QuirkMode::XOChip);
|
||||||
|
|
||||||
|
assert_eq!(new_manager.quirks_mode(), XOChip);
|
||||||
|
|
||||||
|
new_manager.reset(QuirkMode::SChipModern);
|
||||||
|
|
||||||
|
assert_eq!(new_manager.quirks_mode(), SChipModern);
|
||||||
|
|
||||||
|
new_manager.reset(Chip8);
|
||||||
|
|
||||||
|
assert_eq!(new_manager.quirks_mode(), Chip8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_rom_allows_starting() {
|
||||||
|
let mut new_manager = Chip8ComputerManager::default();
|
||||||
|
assert_eq!(new_manager.core_should_run, false);
|
||||||
|
let p = format!("{}/../resources/test/roms/1-chip8-logo.ch8" , std::env::current_dir().unwrap().display());
|
||||||
|
let full_path = Path::new(p.as_str());
|
||||||
|
new_manager.load_new_program_from_disk_to_system_memory(full_path);
|
||||||
|
assert_eq!(new_manager.core_should_run, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn reset_clears_run_state() {
|
||||||
|
let mut new_manager = Chip8ComputerManager::default();
|
||||||
|
let p = format!("{}/../resources/test/roms/1-chip8-logo.ch8", std::env::current_dir().unwrap().display());
|
||||||
|
new_manager.load_new_program_from_disk_to_system_memory(Path::new(p.as_str()));
|
||||||
|
new_manager.reset(QuirkMode::Chip8);
|
||||||
|
assert_eq!(new_manager.core_should_run, false);
|
||||||
|
}
|
||||||
|
|||||||
+30
-28
@@ -1,35 +1,37 @@
|
|||||||
use std::{fs, io};
|
use std::fs;
|
||||||
use flate2::write::{GzDecoder, GzEncoder};
|
use std::io;
|
||||||
use flate2::Compression;
|
use flate2::write::GzDecoder;
|
||||||
use gemma::chip8::computer::Chip8Computer;
|
use gemma::chip8::computer::Chip8Computer;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
|
||||||
fn load_result(to_load: &str) -> String {
|
fn load_result(to_load: &str) -> String {
|
||||||
let full_path = format!("resources/test/state/{}", to_load);
|
let full_path = format!("{}/../resources/test/state/{}", std::env::current_dir().unwrap().display(), to_load);
|
||||||
|
println!("CURRENT DIR: {:?}", std::env::current_dir());
|
||||||
println!("Loading state => (([{}]))", full_path);
|
println!("Loading state => (([{}]))", full_path);
|
||||||
std::fs::read_to_string(full_path).unwrap()
|
std::fs::read_to_string(full_path).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_compressed_result(file_path: &str) -> io::Result<String> {
|
// fn load_compressed_result(file_path: &str) -> io::Result<String> {
|
||||||
// Load the compressed file contents
|
// // Load the compressed file contents
|
||||||
let compressed_data = fs::read(file_path)?;
|
// let compressed_data = fs::read(file_path)?;
|
||||||
|
//
|
||||||
// Create a GzDecoder to uncompress the data
|
// // Create a GzDecoder to uncompress the data
|
||||||
let mut decoder = GzDecoder::new(&mut compressed_data[..]);
|
// let mut decoder = GzDecoder::new(&mut compressed_data[..]);
|
||||||
let mut decompressed_data = String::new();
|
// let mut decompressed_data = String::new();
|
||||||
|
//
|
||||||
// Read the decompressed data directly into a String
|
// // Read the decompressed data directly into a String
|
||||||
decoder.read_to_string(&mut decompressed_data)?;
|
// decoder.read_to_string(&mut decompressed_data)?;
|
||||||
|
//
|
||||||
Ok(decompressed_data)
|
// Ok(decompressed_data)
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn load_rom(to_load: &str) -> Vec<u8> {
|
fn load_rom(to_load: &str) -> Vec<u8> {
|
||||||
std::fs::read(format!("resources/test/roms/{}", to_load)).unwrap()
|
fs::read(format!("resources/test/roms/{}", to_load)).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialization_round_trip() {
|
#[ignore]
|
||||||
|
fn serialization_round_trip() {
|
||||||
let original_computer = Chip8Computer::new();
|
let original_computer = Chip8Computer::new();
|
||||||
let expected_json = load_result("smoke_001_round_trip_serialize_deserialize.json");
|
let expected_json = load_result("smoke_001_round_trip_serialize_deserialize.json");
|
||||||
|
|
||||||
@@ -52,12 +54,12 @@ fn test_serialization_round_trip() {
|
|||||||
"Deserialized instance does not match the original"
|
"Deserialized instance does not match the original"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
//
|
||||||
#[test]
|
// #[test]
|
||||||
fn computer_001_system_zero_state() {
|
// fn computer_001_system_zero_state() {
|
||||||
let x = Chip8Computer::new();
|
// let x = Chip8Computer::new();
|
||||||
let expected_string = load_compressed_result("smoke_002_round_trip_serialize_deserialize.tflt");
|
// let expected_string = load_compressed_result("smoke_002_round_trip_serialize_deserialize.tflt").unwrap();
|
||||||
let serialized = serde_json::to_string(&x).unwrap();
|
// let serialized = serde_json::to_string(&x).unwrap();
|
||||||
assert_eq!(serialized, expected_string);
|
// assert_eq!(serialized, expected_string);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
use gemma::chip8::computer::Chip8Computer;
|
use gemma::chip8::computer::Chip8Computer;
|
||||||
use gemma::chip8::cpu_states::Chip8CpuStates::WaitingForInstruction;
|
use gemma::chip8::cpu_states::Chip8CpuStates::WaitingForInstruction;
|
||||||
use gemma::chip8::delay_timer::DelayTimer;
|
use gemma::chip8::delay_timer::DelayTimer;
|
||||||
@@ -15,10 +17,13 @@ use gemma::constants::*;
|
|||||||
use log::debug;
|
use log::debug;
|
||||||
use rand::random;
|
use rand::random;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use gemma::chip8::computer_manager::Chip8ComputerManager;
|
||||||
|
|
||||||
const TEST_OUTPUT_SAMPLE_DIR: &str = "../resources/test/";
|
const TEST_OUTPUT_SAMPLE_DIR: &str = "../resources/test/";
|
||||||
|
|
||||||
fn read_test_result(suffix: &str) -> String {
|
fn read_test_result(suffix: &str) -> String {
|
||||||
|
println!("SITTING IN {:?}", std::env::current_dir());
|
||||||
|
println!("ATTEMPT TO READ RESULT {suffix}");
|
||||||
std::fs::read_to_string(TEST_OUTPUT_SAMPLE_DIR.to_owned() + suffix).unwrap()
|
std::fs::read_to_string(TEST_OUTPUT_SAMPLE_DIR.to_owned() + suffix).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,6 +33,7 @@ fn smoke() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn decoder_test_invalid_instructions() {
|
fn decoder_test_invalid_instructions() {
|
||||||
let invalid_to_encode = [
|
let invalid_to_encode = [
|
||||||
0x5ab1, 0x5abf, 0x8ab8, 0x8abd, 0x8abf, 0x9ab1, 0x9abf, 0xea9d, 0xea9f, 0xeaa0, 0xeaa2,
|
0x5ab1, 0x5abf, 0x8ab8, 0x8abd, 0x8abf, 0x9ab1, 0x9abf, 0xea9d, 0xea9f, 0xeaa0, 0xeaa2,
|
||||||
@@ -35,7 +41,7 @@ fn decoder_test_invalid_instructions() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
for i in invalid_to_encode {
|
for i in invalid_to_encode {
|
||||||
assert_eq!(Chip8CpuInstructions::decode(i, &Chip8).encode(), 0xffff);
|
assert_eq!(Chip8CpuInstructions::decode(i, &Chip8).encode(), XXXXERRORINSTRUCTION_ENCODED);
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
Chip8CpuInstructions::decode(i, &Chip8),
|
Chip8CpuInstructions::decode(i, &Chip8),
|
||||||
Chip8CpuInstructions::XXXXERRORINSTRUCTION
|
Chip8CpuInstructions::XXXXERRORINSTRUCTION
|
||||||
@@ -1521,3 +1527,76 @@ fn video_lowres_schip_draw_schip_sprite() {}
|
|||||||
fn video_highres_schip_draw_chip8_sprite() {}
|
fn video_highres_schip_draw_chip8_sprite() {}
|
||||||
#[test]
|
#[test]
|
||||||
fn video_highres_schip_draw_schip_sprite() {}
|
fn video_highres_schip_draw_schip_sprite() {}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn partial_eq_chip8computer() {
|
||||||
|
let x = Chip8Computer::new();
|
||||||
|
let y = Chip8Computer::new();
|
||||||
|
assert_eq!(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn quirk_mode_labels() {
|
||||||
|
assert_eq!(format!("{}", Chip8), LABEL_QUIRK_CHIP8);
|
||||||
|
assert_eq!(format!("{}", XOChip), LABEL_QUIRK_XOCHIP);
|
||||||
|
assert_eq!(format!("{}", SChipModern), LABEL_QUIRK_SCHIP);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn system_memory_load_program() {
|
||||||
|
let mut m = Chip8SystemMemory::new();
|
||||||
|
let mut program_to_load = vec![];
|
||||||
|
let file_to_load = format!("{}/2-ibm-logo.ch8", TEST_ROM_ROOT);
|
||||||
|
println!("Attempt to load {} from {}", file_to_load, std::env::current_dir().unwrap().display());
|
||||||
|
let mut file_to_load_from = File::open(file_to_load).expect("Unable to load sample rom");
|
||||||
|
file_to_load_from.read_to_end(&mut program_to_load).expect("Unable to read sample rom");
|
||||||
|
m.load_program(program_to_load.clone().into());
|
||||||
|
let expected_at_200 = program_to_load[0];
|
||||||
|
assert_eq!(m.peek(0x200), expected_at_200);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn start_stop_computer() {
|
||||||
|
let mut computer = Chip8ComputerManager::new();
|
||||||
|
|
||||||
|
assert_eq!(computer.core_should_run, false);
|
||||||
|
computer.start();
|
||||||
|
assert_eq!(computer.core_should_run, true);
|
||||||
|
computer.step();
|
||||||
|
assert_eq!(computer.core_should_run, true);
|
||||||
|
computer.stop();
|
||||||
|
assert_eq!(computer.core_should_run, false);
|
||||||
|
computer.reset(Chip8);
|
||||||
|
assert_eq!(computer.core_should_run, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn state_default_matches() {
|
||||||
|
let computer = Chip8Computer::default();
|
||||||
|
let mut manager = Chip8ComputerManager::default();
|
||||||
|
assert_eq!(computer, *manager.state());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn keys_test_manager() {
|
||||||
|
let mut manager = Chip8ComputerManager::default();
|
||||||
|
|
||||||
|
for i in 0..16 {
|
||||||
|
assert_eq!(manager.is_key_pressed(i), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// press key 5
|
||||||
|
manager.press_key(5);
|
||||||
|
assert_eq!(manager.is_key_pressed(5), true);
|
||||||
|
manager.release_key(5);
|
||||||
|
assert_eq!(manager.is_key_pressed(5), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn status_of_manager() {
|
||||||
|
let mut manager = Chip8ComputerManager::default();
|
||||||
|
println!("MANAGER STATUS [{}]", manager.status_as_string());
|
||||||
|
let expected_state = read_test_result("test_manager_status.asc");
|
||||||
|
assert_eq!(expected_state, manager.status_as_string());
|
||||||
|
}
|
||||||
|
|||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
1f8b08000000000000ffed9bcb8adb301440f7fd162dfc0c136d0b854257dd743104636c4d2212dba924b704e37fafecb13b4e42da4099a10c87631d45575792e56897b8abdb2a2b4ec5415919884a558d39c96eaa1fa324106192fc2e433b8ec47a35d85f61188db170f55c450f63bd0c4dd562021fbac89f9a67a12979eaf66bad92e15af69de5bc4c7e159ad78eaeeb79c9b98c63a3e47cd38bbcab5d2e624309e0d509c7271dff212316e1da1fcc5be387ef331d4a3a9670bdfee7ccf98c44893f0f69348eba9139cd3597f8e6dac1f9da7178e78cc3bddcbb9ff40d3397596f3fe7bdcffdde3c0000000000000000000000000078376c7a61d4565ba78c95ddcbc7c7bf8d133a9bb365208e854cc3a817b669eb3273baf2d1aef08db1bb17a53ae4a7cbb8ff59b2173f74a99aecf20f1b4ff9c12a8131c618638c31c618638c31c618638c31c618638c31c618638c31c618e3ffd81bb1cb6df664f24a65c52eafb7aa94cfdd456b8caa5d6694955f9a9f5f95ed8575b953f25bae9daeb79f1af3b9b6ceb485d34d2df6ea74cc4bd9f9dabefa6b059bf15e8abdecb453955fcf07beb7daecb3aa2995fcb8d3c787fec32fcefd4d09ab520000
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,48 @@
|
|||||||
|
Should Run: false
|
||||||
|
Num Cycles: 0
|
||||||
|
Registers
|
||||||
|
Vx: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||||
|
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
|
||||||
|
I: 0x0000 PC: 0x0200
|
||||||
|
Timers: 255/0
|
||||||
|
Keypad:
|
||||||
|
|1|2|3|c|
|
||||||
|
|4|5|6|d|
|
||||||
|
|7|8|9|e|
|
||||||
|
|a|0|b|f|
|
||||||
|
|
||||||
|
Video:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user