v0.1.1 Partial Super Chip Support #11
28
Cargo.toml
28
Cargo.toml
@ -1,18 +1,40 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "chirp"
|
name = "chirp"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
ignore = ["justfile", ".gitmodules", "chip8-test-suite", "chip8Archive"]
|
||||||
|
default-run = "chirp"
|
||||||
authors = ["John Breaux"]
|
authors = ["John Breaux"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["unstable", "drawille"]
|
default = ["unstable", "drawille", "minifb"]
|
||||||
unstable = []
|
unstable = []
|
||||||
drawille = ["dep:drawille"]
|
drawille = ["dep:drawille"]
|
||||||
iced = ["dep:iced"]
|
iced = ["dep:iced"]
|
||||||
|
minifb = ["dep:minifb"]
|
||||||
rhexdump = ["dep:rhexdump"]
|
rhexdump = ["dep:rhexdump"]
|
||||||
serde = ["dep:serde"]
|
serde = ["dep:serde"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "chirp"
|
||||||
|
path = "src/bin/chirp-minifb/main.rs"
|
||||||
|
required-features = ["minifb"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "chirp-disasm"
|
||||||
|
required-features = ["default"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "chirp-iced"
|
||||||
|
required-features = ["iced"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "chirp-shot-viewer"
|
||||||
|
required-features = ["default", "drawille"]
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
@ -31,10 +53,10 @@ drawille = {version = "0.3.0", optional = true}
|
|||||||
iced = {version = "0.8.0", optional = true}
|
iced = {version = "0.8.0", optional = true}
|
||||||
rhexdump = {version = "^0.1.1", optional = true }
|
rhexdump = {version = "^0.1.1", optional = true }
|
||||||
serde = { version = "^1.0", features = ["derive"], optional = true }
|
serde = { version = "^1.0", features = ["derive"], optional = true }
|
||||||
|
minifb = { version = "^0.24.0", optional = true }
|
||||||
|
|
||||||
gumdrop = "^0.8.1"
|
gumdrop = "^0.8.1"
|
||||||
imperative-rs = "0.3.1"
|
imperative-rs = "0.3.1"
|
||||||
minifb = { version = "^0.24.0" }
|
|
||||||
owo-colors = "^3"
|
owo-colors = "^3"
|
||||||
rand = "^0.8.5"
|
rand = "^0.8.5"
|
||||||
thiserror = "^1.0.39"
|
thiserror = "^1.0.39"
|
||||||
|
8
justfile
8
justfile
@ -8,19 +8,19 @@ test:
|
|||||||
cargo nextest run
|
cargo nextest run
|
||||||
|
|
||||||
run rom:
|
run rom:
|
||||||
cargo run --bin chirp-minifb -- '{{rom}}'
|
cargo run -- '{{rom}}'
|
||||||
|
|
||||||
debug rom:
|
debug rom:
|
||||||
cargo run --bin chirp-minifb -- -d '{{rom}}'
|
cargo run -- -d '{{rom}}'
|
||||||
# Run at 2100000 instructions per frame, and output per-frame runtime statistics
|
# Run at 2100000 instructions per frame, and output per-frame runtime statistics
|
||||||
bench:
|
bench:
|
||||||
cargo run --bin chirp-minifb --release -- chip8Archive/roms/1dcell.ch8 -Ps10 -S2100000 -m xochip
|
cargo run --release -- chip8Archive/roms/1dcell.ch8 -Ps10 -S2100000 -m xochip
|
||||||
|
|
||||||
flame rom:
|
flame rom:
|
||||||
CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph -F 15300 --open --bin chirp-minifb -- '{{rom}}' -s10
|
CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph -F 15300 --open --bin chirp-minifb -- '{{rom}}' -s10
|
||||||
|
|
||||||
flamebench:
|
flamebench:
|
||||||
CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph -F 15300 --open --bin chirp-minifb -- chip8Archive/roms/1dcell.ch8 -xPs10 -S2100000
|
CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph -F 15300 --open --bin chirp-minifb -- chip8Archive/roms/1dcell.ch8 -Ps10 -S2100000 -m xochip
|
||||||
|
|
||||||
cover:
|
cover:
|
||||||
cargo llvm-cov --open --doctests
|
cargo llvm-cov --open --doctests
|
||||||
|
@ -66,6 +66,7 @@ Optional arguments:
|
|||||||
|
|
||||||
## TODO:
|
## TODO:
|
||||||
|
|
||||||
|
- [ ] Move the screen, stack, charset, and program memory into the CPU
|
||||||
- [ ] Implement sound
|
- [ ] Implement sound
|
||||||
- [ ] Finish unit tests for "quirks"
|
- [ ] Finish unit tests for "quirks"
|
||||||
- [ ] Make pausing/unpausing the emulator less messy
|
- [ ] Make pausing/unpausing the emulator less messy
|
||||||
|
@ -1,24 +1,8 @@
|
|||||||
use chirp::{cpu::Disassembler, error::Result, *};
|
use chirp::{error::Result, *};
|
||||||
use gumdrop::*;
|
use gumdrop::*;
|
||||||
use owo_colors::OwoColorize;
|
use owo_colors::OwoColorize;
|
||||||
use std::{fs::read, path::PathBuf};
|
use std::{fs::read, path::PathBuf};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Options, Hash)]
|
|
||||||
struct Arguments {
|
|
||||||
#[options(help = "Show help text")]
|
|
||||||
help: bool,
|
|
||||||
#[options(help = "Load a ROM to run on Chirp", free, required)]
|
|
||||||
pub file: PathBuf,
|
|
||||||
#[options(help = "Load address (usually 200)", parse(try_from_str = "parse_hex"))]
|
|
||||||
pub loadaddr: u16,
|
|
||||||
#[options(help = "Start disassembling at offset...")]
|
|
||||||
pub offset: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_hex(value: &str) -> std::result::Result<u16, std::num::ParseIntError> {
|
|
||||||
u16::from_str_radix(value, 16)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let options = Arguments::parse_args_default_or_exit();
|
let options = Arguments::parse_args_default_or_exit();
|
||||||
let contents = &read(&options.file)?;
|
let contents = &read(&options.file)?;
|
||||||
@ -40,3 +24,19 @@ fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Options, Hash)]
|
||||||
|
struct Arguments {
|
||||||
|
#[options(help = "Show help text")]
|
||||||
|
help: bool,
|
||||||
|
#[options(help = "Load a ROM to run on Chirp", free, required)]
|
||||||
|
pub file: PathBuf,
|
||||||
|
#[options(help = "Load address (usually 200)", parse(try_from_str = "parse_hex"))]
|
||||||
|
pub loadaddr: u16,
|
||||||
|
#[options(help = "Start disassembling at offset...")]
|
||||||
|
pub offset: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_hex(value: &str) -> std::result::Result<u16, std::num::ParseIntError> {
|
||||||
|
u16::from_str_radix(value, 16)
|
||||||
|
}
|
||||||
|
12
src/cpu.rs
12
src/cpu.rs
@ -6,12 +6,6 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
/// Disassembles Chip-8 instructions
|
|
||||||
pub trait Disassembler {
|
|
||||||
/// Disassemble a single instruction
|
|
||||||
fn once(&self, insn: u16) -> String;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod disassembler;
|
pub mod disassembler;
|
||||||
pub mod flags;
|
pub mod flags;
|
||||||
pub mod instruction;
|
pub mod instruction;
|
||||||
@ -19,7 +13,7 @@ pub mod mode;
|
|||||||
pub mod quirks;
|
pub mod quirks;
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
disassembler::{Dis, Insn},
|
disassembler::{Dis, Disassembler, Insn},
|
||||||
flags::Flags,
|
flags::Flags,
|
||||||
mode::Mode,
|
mode::Mode,
|
||||||
quirks::Quirks,
|
quirks::Quirks,
|
||||||
@ -57,7 +51,7 @@ impl Default for Timers {
|
|||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct CPU {
|
pub struct CPU {
|
||||||
/// Flags that control how the CPU behaves, but which aren't inherent to the
|
/// Flags that control how the CPU behaves, but which aren't inherent to the
|
||||||
/// implementation. Includes [Quirks], target IPF, etc.
|
/// chip-8. Includes [Quirks], target IPF, etc.
|
||||||
pub flags: Flags,
|
pub flags: Flags,
|
||||||
// memory map info
|
// memory map info
|
||||||
screen: Adr,
|
screen: Adr,
|
||||||
@ -478,7 +472,7 @@ impl CPU {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn tick(&mut self, bus: &mut Bus) -> Result<&mut Self> {
|
pub fn tick(&mut self, bus: &mut Bus) -> Result<&mut Self> {
|
||||||
// Do nothing if paused
|
// Do nothing if paused
|
||||||
if self.flags.pause || self.flags.draw_wait || self.flags.keypause {
|
if self.flags.is_paused() {
|
||||||
// always tick in test mode
|
// always tick in test mode
|
||||||
if self.flags.monotonic.is_some() {
|
if self.flags.monotonic.is_some() {
|
||||||
self.cycle += 1;
|
self.cycle += 1;
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
//! A disassembler for Chip-8 opcodes
|
//! A disassembler for Chip-8 opcodes
|
||||||
#![allow(clippy::bad_bit_mask)]
|
#![allow(clippy::bad_bit_mask)]
|
||||||
use super::Disassembler;
|
|
||||||
use imperative_rs::InstructionSet;
|
use imperative_rs::InstructionSet;
|
||||||
use owo_colors::{OwoColorize, Style};
|
use owo_colors::{OwoColorize, Style};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
/// Disassembles Chip-8 instructions
|
||||||
|
pub trait Disassembler {
|
||||||
|
/// Disassemble a single instruction
|
||||||
|
fn once(&self, insn: u16) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types, non_snake_case, missing_docs)]
|
#[allow(non_camel_case_types, non_snake_case, missing_docs)]
|
||||||
#[derive(Clone, Copy, Debug, InstructionSet, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, InstructionSet, PartialEq, Eq)]
|
||||||
/// Implements a Disassembler using imperative_rs
|
/// Implements a Disassembler using imperative_rs
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
//! Represents flags that aid in implementation but aren't a part of the Chip-8 spec
|
//! Represents [Flags] that aid in implementation but aren't a part of the Chip-8 spec
|
||||||
|
|
||||||
use super::{Mode, Quirks};
|
use super::{Mode, Quirks};
|
||||||
|
|
||||||
/// Represents flags that aid in operation, but aren't inherent to the CPU
|
/// Represents flags that aid in implementation but aren't a part of the Chip-8 spec
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct Flags {
|
pub struct Flags {
|
||||||
/// Set when debug (live disassembly) mode enabled
|
/// Set when debug (live disassembly) mode enabled
|
||||||
@ -55,4 +55,9 @@ impl Flags {
|
|||||||
pub fn pause(&mut self) {
|
pub fn pause(&mut self) {
|
||||||
self.pause = !self.pause
|
self.pause = !self.pause
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets whether the CPU is paused for any reason
|
||||||
|
pub fn is_paused(&self) -> bool {
|
||||||
|
self.pause || self.draw_wait || self.keypause
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// (c) 2023 John A. Breaux
|
// (c) 2023 John A. Breaux
|
||||||
// This code is licensed under MIT license (see LICENSE.txt for details)
|
// This code is licensed under MIT license (see LICENSE.txt for details)
|
||||||
|
|
||||||
//! Contains implementations for each instruction defined in [super::disassembler]
|
//! Contains implementations for each [Insn] as private member functions of [CPU]
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
//! Selects the memory behavior of the [super::CPU]
|
//! Selects the memory behavior of the [super::CPU]
|
||||||
|
//!
|
||||||
|
//! Since [super::Quirks] implements [From<Mode>],
|
||||||
|
//! this can be used to select the appropriate quirk-set
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//! Controls the authenticity behavior of the CPU on a granular level.
|
//! Controls the [Quirks] behavior of the CPU on a granular level.
|
||||||
use super::Mode;
|
use super::Mode;
|
||||||
/// Controls the authenticity behavior of the CPU on a granular level.
|
/// Controls the authenticity behavior of the CPU on a granular level.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
@ -64,6 +64,7 @@ pub enum Error {
|
|||||||
/// Error originated in [std::array::TryFromSliceError]
|
/// Error originated in [std::array::TryFromSliceError]
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
TryFromSliceError(#[from] std::array::TryFromSliceError),
|
TryFromSliceError(#[from] std::array::TryFromSliceError),
|
||||||
|
#[cfg(feature = "minifb")]
|
||||||
/// Error originated in [minifb]
|
/// Error originated in [minifb]
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
MinifbError(#[from] minifb::Error),
|
MinifbError(#[from] minifb::Error),
|
||||||
|
10
src/lib.rs
10
src/lib.rs
@ -14,8 +14,14 @@ pub mod error;
|
|||||||
|
|
||||||
// Common imports for Chirp
|
// Common imports for Chirp
|
||||||
pub use bus::{Bus, Read, Region::*, Write};
|
pub use bus::{Bus, Read, Region::*, Write};
|
||||||
pub use cpu::{disassembler::Dis, flags::Flags, mode::Mode, quirks::Quirks, CPU};
|
pub use cpu::{
|
||||||
pub use error::Result;
|
disassembler::{Dis, Disassembler},
|
||||||
|
flags::Flags,
|
||||||
|
mode::Mode,
|
||||||
|
quirks::Quirks,
|
||||||
|
CPU,
|
||||||
|
};
|
||||||
|
pub use error::{Error, Result};
|
||||||
|
|
||||||
/// Holds the state of a Chip-8
|
/// Holds the state of a Chip-8
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, PartialEq)]
|
||||||
|
Loading…
Reference in New Issue
Block a user