Compare commits

..

5 Commits

4 changed files with 849 additions and 42 deletions

2
.gitignore vendored
View File

@@ -1,3 +1,3 @@
/target
/IBMLogo.ch8
/roms
/.idea

352
Cargo.lock generated
View File

@@ -8,7 +8,9 @@ version = "0.1.0"
dependencies = [
"clap",
"clap_derive",
"cpal",
"pixels",
"rand",
"tao",
"tracing",
"tracing-subscriber",
@@ -23,7 +25,7 @@ dependencies = [
"cfg-if",
"once_cell",
"version_check",
"zerocopy",
"zerocopy 0.7.35",
]
[[package]]
@@ -41,6 +43,28 @@ version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "alsa"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43"
dependencies = [
"alsa-sys",
"bitflags 2.8.0",
"cfg-if",
"libc",
]
[[package]]
name = "alsa-sys"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527"
dependencies = [
"libc",
"pkg-config",
]
[[package]]
name = "android_system_properties"
version = "0.1.5"
@@ -144,6 +168,24 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bindgen"
version = "0.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f"
dependencies = [
"bitflags 2.8.0",
"cexpr",
"clang-sys",
"itertools",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn 2.0.98",
]
[[package]]
name = "bit-set"
version = "0.5.3"
@@ -189,6 +231,12 @@ version = "1.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "1.10.0"
@@ -226,6 +274,8 @@ version = "1.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda"
dependencies = [
"jobserver",
"libc",
"shlex",
]
@@ -235,6 +285,15 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-expr"
version = "0.15.8"
@@ -257,6 +316,17 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "clang-sys"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [
"glob",
"libc",
"libloading 0.8.6",
]
[[package]]
name = "clap"
version = "4.5.28"
@@ -445,6 +515,49 @@ dependencies = [
"libc",
]
[[package]]
name = "coreaudio-rs"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace"
dependencies = [
"bitflags 1.3.2",
"core-foundation-sys",
"coreaudio-sys",
]
[[package]]
name = "coreaudio-sys"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ce857aa0b77d77287acc1ac3e37a05a8c95a2af3647d23b15f263bdaeb7562b"
dependencies = [
"bindgen",
]
[[package]]
name = "cpal"
version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779"
dependencies = [
"alsa",
"core-foundation-sys",
"coreaudio-rs",
"dasp_sample",
"jni",
"js-sys",
"libc",
"mach2",
"ndk 0.8.0",
"ndk-context",
"oboe",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"windows 0.54.0",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.14"
@@ -471,6 +584,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "dasp_sample"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f"
[[package]]
name = "dispatch"
version = "0.2.0"
@@ -517,6 +636,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53"
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "equivalent"
version = "1.0.1"
@@ -717,6 +842,18 @@ dependencies = [
"x11",
]
[[package]]
name = "getrandom"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
dependencies = [
"cfg-if",
"libc",
"wasi",
"windows-targets 0.52.6",
]
[[package]]
name = "gio"
version = "0.18.4"
@@ -807,6 +944,12 @@ dependencies = [
"system-deps",
]
[[package]]
name = "glob"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "glow"
version = "0.13.1"
@@ -1147,6 +1290,15 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]]
name = "jni"
version = "0.21.1"
@@ -1169,6 +1321,15 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "jobserver"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
dependencies = [
"libc",
]
[[package]]
name = "js-sys"
version = "0.3.77"
@@ -1250,6 +1411,15 @@ version = "0.4.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
[[package]]
name = "mach2"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
dependencies = [
"libc",
]
[[package]]
name = "malloc_buf"
version = "0.0.6"
@@ -1298,6 +1468,12 @@ dependencies = [
"paste",
]
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "naga"
version = "0.19.2"
@@ -1318,6 +1494,20 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "ndk"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7"
dependencies = [
"bitflags 2.8.0",
"jni-sys",
"log",
"ndk-sys 0.5.0+25.2.9519653",
"num_enum",
"thiserror",
]
[[package]]
name = "ndk"
version = "0.9.0"
@@ -1357,6 +1547,16 @@ dependencies = [
"jni-sys",
]
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
@@ -1367,6 +1567,17 @@ dependencies = [
"winapi",
]
[[package]]
name = "num-derive"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.98",
]
[[package]]
name = "num-traits"
version = "0.2.19"
@@ -1416,6 +1627,29 @@ dependencies = [
"cc",
]
[[package]]
name = "oboe"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb"
dependencies = [
"jni",
"ndk 0.8.0",
"ndk-context",
"num-derive",
"num-traits",
"oboe-sys",
]
[[package]]
name = "oboe-sys"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d"
dependencies = [
"cc",
]
[[package]]
name = "once_cell"
version = "1.20.3"
@@ -1526,6 +1760,15 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2"
[[package]]
name = "ppv-lite86"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
"zerocopy 0.7.35",
]
[[package]]
name = "presser"
version = "0.3.1"
@@ -1600,6 +1843,37 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
dependencies = [
"rand_chacha",
"rand_core",
"zerocopy 0.8.18",
]
[[package]]
name = "rand_chacha"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff"
dependencies = [
"getrandom",
"zerocopy 0.8.18",
]
[[package]]
name = "range-alloc"
version = "0.1.4"
@@ -1884,7 +2158,7 @@ dependencies = [
"lazy_static",
"libc",
"log",
"ndk",
"ndk 0.9.0",
"ndk-context",
"ndk-sys 0.6.0+11769913",
"objc",
@@ -2163,6 +2437,15 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.13.3+wasi-0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
dependencies = [
"wit-bindgen-rt",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.100"
@@ -2408,6 +2691,16 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows"
version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49"
dependencies = [
"windows-core 0.54.0",
"windows-targets 0.52.6",
]
[[package]]
name = "windows"
version = "0.58.0"
@@ -2427,6 +2720,16 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65"
dependencies = [
"windows-result 0.1.2",
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.58.0"
@@ -2435,7 +2738,7 @@ checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
dependencies = [
"windows-implement",
"windows-interface",
"windows-result",
"windows-result 0.2.0",
"windows-strings",
"windows-targets 0.52.6",
]
@@ -2462,6 +2765,15 @@ dependencies = [
"syn 2.0.98",
]
[[package]]
name = "windows-result"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-result"
version = "0.2.0"
@@ -2477,7 +2789,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
dependencies = [
"windows-result",
"windows-result 0.2.0",
"windows-targets 0.52.6",
]
@@ -2702,6 +3014,15 @@ dependencies = [
"memchr",
]
[[package]]
name = "wit-bindgen-rt"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
dependencies = [
"bitflags 2.8.0",
]
[[package]]
name = "write16"
version = "1.0.0"
@@ -2771,7 +3092,17 @@ version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"zerocopy-derive",
"byteorder",
"zerocopy-derive 0.7.35",
]
[[package]]
name = "zerocopy"
version = "0.8.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79386d31a42a4996e3336b0919ddb90f81112af416270cff95b5f5af22b839c2"
dependencies = [
"zerocopy-derive 0.8.18",
]
[[package]]
@@ -2785,6 +3116,17 @@ dependencies = [
"syn 2.0.98",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76331675d372f91bf8d17e13afbd5fe639200b73d01f0fc748bb059f9cca2db7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.98",
]
[[package]]
name = "zerofrom"
version = "0.1.5"

View File

@@ -10,3 +10,5 @@ pixels = "0.15.0"
tao = "0.31.1"
tracing = "0.1.41"
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }
rand = "0.9.0"
cpal = "0.15.3"

View File

@@ -6,7 +6,7 @@ use std::num::NonZeroU32;
use std::rc::Rc;
use pixels::{Error, Pixels, SurfaceTexture};
use tao::{
event::{Event, KeyEvent, WindowEvent},
event::{Event, KeyEvent, WindowEvent, ElementState},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
keyboard::KeyCode,
@@ -14,8 +14,19 @@ use tao::{
use tao::dpi::LogicalSize;
use tracing::{info, error};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use rand::prelude::*;
use tao::keyboard::Key;
use std::time::{Duration, Instant};
use cpal::{SampleFormat, SampleRate, Stream, SupportedStreamConfig};
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use rand::seq::index::sample;
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
const MODERNSHIFT: bool = false;
const OLDJUMP: bool = true;
const MODERNLOADSAVE: bool = false;
#[derive(Parser, Debug)]
struct Args {
@@ -23,6 +34,81 @@ struct Args {
file: PathBuf,
}
struct AudioPlayer {
stream: Stream,
}
struct Oscilator {
sample_index: f32,
volume: f32,
}
impl AudioPlayer {
fn make(rx: Receiver<f32>) -> Self {
let host = cpal::default_host();
let device = host
.default_output_device()
.expect("no output device available");
let config = device.supported_output_configs().expect("error while querying config").find(|config| config.sample_format() == SampleFormat::F32);
if config.is_none() {panic!("no supported config found");}
let config = config.unwrap();
if config.min_sample_rate() > SampleRate(48000) || config.max_sample_rate() < SampleRate(48000) {
//("{:?},{:?}", config.min_sample_rate(), config.max_sample_rate());
panic!("sample rate out of range");
}
let format = SupportedStreamConfig::new(
config.channels(),
SampleRate(48000),
config.buffer_size().clone(),
SampleFormat::F32
);
//let time_at_start = Instant::now();
let mut oscilator = Oscilator{sample_index: 0.0, volume: 0.0};
let stream = device.build_output_stream(
&format.config(),
move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
//let time_since_start = Instant::now().duration_since(time_at_start).as_secs_f32();
if let Ok(vol) = rx.try_recv() {
oscilator.volume = vol as f32;
}
process_frame(data, config.channels().into(), &mut oscilator);
},
(|err| error!("Error while creating output stream, {}", err)),
None,
);
Self {
stream: stream.expect("no stream available"),
}
}
fn run(&mut self) {
self.stream.play().unwrap();
}
}
fn process_frame(output: &mut [f32], channels: usize, oscilator: &mut Oscilator) {
for frame in output.chunks_mut(channels) {
let value = oscilator.tick() * oscilator.volume;
for sample in frame.iter_mut() {
*sample = value;
}
}
}
impl Oscilator {
fn tick(&mut self) -> f32 {
self.sample_index = (self.sample_index + 1.0) % 48000.0;
let two_pi = 2.0 * std::f32::consts::PI;
(self.sample_index * 440.0 * two_pi/48000.0).sin()
}
}
#[derive(Copy, Clone)]
struct Chip8 {
display: [u64; 32],
@@ -32,8 +118,13 @@ struct Chip8 {
delay_timer: u8,
ram: [u8; 4096],
pc: u16,
stack: [u8; 64],
stack: [u16; 64],
stack_pointer: u8,
keys: [bool; 16],
get_key_pause: bool,
keys_released: [bool; 16],
keys_pressed: [bool; 16],
display_wait: bool,
}
impl Chip8 {
@@ -48,6 +139,11 @@ impl Chip8 {
pc: 0x200,
stack: [0; 64],
stack_pointer: 0,
keys: [false; 16],
get_key_pause: false,
keys_released: [false; 16],
keys_pressed: [false; 16],
display_wait: false,
}
}
@@ -61,7 +157,16 @@ impl Chip8 {
self
}
fn draw(self, frame: &mut [u8], dimensions: (u32, u32)) -> Self {
fn draw(&mut self, frame: &mut [u8], dimensions: (u32, u32), tx: &SyncSender<f32>) -> Self {
if self.sound_timer != 0 {
self.sound_timer -= 1;
tx.send(0.5).unwrap();
} else {
tx.send(0.0).unwrap();
}
if self.delay_timer != 0 {
self.delay_timer -= 1;
}
for(i, pixel) in frame.chunks_exact_mut(4).enumerate() {
let x = i % dimensions.0 as usize;
let y = i / dimensions.0 as usize;
@@ -77,8 +182,9 @@ impl Chip8 {
pixel.copy_from_slice(&rgba);
}
info!("done");
self
self.display_wait = false;
//info!("done");
*self
}
fn update(&mut self, instructions: u32) -> Self {
@@ -102,13 +208,27 @@ impl Chip8 {
0x00 => {
self.clear_screen();
},
_ => {}
0x0e => {
if self.stack_pointer != 0 {
self.pc = self.stack[self.stack_pointer as usize];
self.stack_pointer -= 1;
} else {
error!("at root subroutine")
}
},
_ => {
error!("Does not support machine code");
}
}
},
_ => {}
_ => {
error!("Does not support machine code");
}
}
},
_ => {}
_ => {
error!("Does not support machine code");
}
}
},
0x01 => {
@@ -116,16 +236,34 @@ impl Chip8 {
self.pc = position;
},
0x02 => {
if self.stack_pointer != 63 {
self.stack_pointer += 1;
self.stack[self.stack_pointer as usize] = self.pc;
self.pc = ((opcodes[1] as u16) << 8) | ((opcodes[2] as u16) << 4) | opcodes[3] as u16;
} else {
error!("reached the limit of the stack")
}
},
0x03 => {
//info!("{},{},{}",(self.registers[opcodes[1] as usize]),(((opcodes[2]) << 4) + opcodes[3]),(self.registers[opcodes[1] as usize]) == (((opcodes[2]) << 4) + opcodes[3]));
if (self.registers[opcodes[1] as usize]) == (((opcodes[2]) << 4) + opcodes[3]) {
self.pc += 2;
}
},
0x04 => {
if (self.registers[opcodes[1] as usize]) != (((opcodes[2]) << 4) + opcodes[3]) {
self.pc += 2;
}
},
0x05 => {
match opcodes[3] {
0x00 => {
if self.registers[opcodes[1] as usize] == self.registers[opcodes[2] as usize] {
self.pc += 2;
}
},
_ => {error!("unknown opcode")}
}
},
0x06 => {
self.registers[opcodes[1] as usize] = opcodes[2] << 4 | opcodes[3];
@@ -135,36 +273,280 @@ impl Chip8 {
self.registers[opcodes[1] as usize] = (((self.registers[opcodes[1] as usize] as u16) + value) & 255) as u8;
},
0x08 => {
match opcodes[3] {
0x00 => {
self.registers[opcodes[1] as usize] = self.registers[opcodes[2] as usize];
},
0x01 => {
self.registers[opcodes[1] as usize] = self.registers[opcodes[1] as usize] | self.registers[opcodes[2] as usize];
self.registers[0x0f] = 0;
},
0x02 => {
self.registers[opcodes[1] as usize] = self.registers[opcodes[1] as usize] & self.registers[opcodes[2] as usize];
self.registers[0x0f] = 0;
},
0x03 => {
self.registers[opcodes[1] as usize] = self.registers[opcodes[1] as usize] ^ self.registers[opcodes[2] as usize];
self.registers[0x0f] = 0;
},
0x04 => {
let added_base = (self.registers[opcodes[1] as usize] as u16) + (self.registers[opcodes[2] as usize] as u16);
self.registers[opcodes[1] as usize] = (added_base & 255) as u8;
if added_base > 255 {
self.registers[0x0f] = 1;
} else {
self.registers[0x0f] = 0;
}
},
0x05 => {
let r1 = self.registers[opcodes[1] as usize];
let r2 = self.registers[opcodes[2] as usize];
//info!("{},{}", r1 , r2);
let no_underflow = (r1 >= r2);
if no_underflow {
//info!("{}",r1 - r2);
self.registers[opcodes[1] as usize] = r1 - r2;
} else {
self.registers[opcodes[1] as usize] = 255 - ((r2 - r1) - 1);
}
self.registers[0x0f] = no_underflow as u8;
},
0x06 => {
if MODERNSHIFT {
let t = ((self.registers[opcodes[1] as usize] & 1) != 0) as u8;
self.registers[opcodes[1] as usize] = self.registers[opcodes[1] as usize] >> 1;
self.registers[0x0f] = t;
} else {
self.registers[opcodes[1] as usize] = self.registers[opcodes[2] as usize];
let t = ((self.registers[opcodes[1] as usize] & 1) != 0) as u8;
self.registers[opcodes[1] as usize] = self.registers[opcodes[1] as usize] >> 1;
self.registers[0x0f] = t;
}
},
0x07 => {
let r1 = self.registers[opcodes[1] as usize];
let r2 = self.registers[opcodes[2] as usize];
let no_underflow = (r2 >= r1);
//self.registers[0x0f] = no_underflow as u8;
if no_underflow {
self.registers[opcodes[1] as usize] = r2 - r1;
} else {
self.registers[opcodes[1] as usize] = 255 - ((r1 - r2) - 1);
}
self.registers[0x0f] = no_underflow as u8;
},
0x0e => {
if MODERNSHIFT {
let t = ((self.registers[opcodes[1] as usize] & 128) != 0) as u8;
self.registers[opcodes[1] as usize] = self.registers[opcodes[1] as usize] << 1;
self.registers[0x0f] = t;
} else {
self.registers[opcodes[1] as usize] = self.registers[opcodes[2] as usize];
let t = ((self.registers[opcodes[1] as usize] & 128) != 0) as u8;
self.registers[opcodes[1] as usize] = self.registers[opcodes[1] as usize] << 1;
self.registers[0x0f] = t;
}
},
_ => {error!("unknown opcode")}
}
},
0x09 => {
match opcodes[3] {
0x00 => {
if self.registers[opcodes[1] as usize] != self.registers[opcodes[2] as usize] {
self.pc += 2;
}
},
_ => {error!("unknown opcode")}
}
},
0x0a => {
self.index_register = (opcodes[1] as u16) << 8 | (opcodes[2] as u16) << 4 | (opcodes[3] as u16);
},
0x0b => {
if OLDJUMP {
self.pc = ((opcodes[1] as u16) << 8) + ((opcodes[2] as u16) << 4) + (opcodes[3] as u16) + (self.registers[0] as u16);
} else {
self.pc = ((opcodes[1] as u16) << 8) + ((opcodes[2] as u16) << 4) + (opcodes[3] as u16) + (self.registers[opcodes[1] as usize] as u16)
}
},
0x0c => {
let mut rng = rand::rng();
let random = rng.random::<u8>();
self.registers[opcodes[1] as usize] = random & (opcodes[2] << 4 | opcodes[3]);
},
0x0d => {
let x = self.registers[opcodes[1] as usize] % 64;
let y = self.registers[opcodes[2] as usize] % 32;
self.registers[0x0f] = 0;
for n in 0..opcodes[3] {
let spritedata = self.ram[self.index_register as usize + n as usize];
for i in 0..7 {
let bit = get_bit_u8(spritedata, i);
self.display[(y + n) as usize] = self.display[(y + n) as usize] ^ ((bit as u64) << (x + i));
if !self.display_wait {
let x = self.registers[opcodes[1] as usize] % 64;
let y = self.registers[opcodes[2] as usize] % 32;
self.registers[0x0f] = 0;
for n in 0..opcodes[3] {
let spritedata = self.ram[self.index_register as usize + n as usize];
let mut checkdata: u8 = 0;
for i in 0..8 {
let bit = get_bit_u8(spritedata, i);
checkdata += (bit as u8) << (7 - i);
if (x+i <= 63) && (y+n <= 31) {
if (get_bit(self.display[(y+n) as usize], (x+i)) && bit) {
self.registers[0x0f] = 1;
}
self.display[(y + n) as usize] = self.display[(y + n) as usize] ^ ((bit as u64) << (x + i));
}
}
//info!("{},{}", spritedata, checkdata);
}
self.display_wait = true;
} else {
self.pc -= 2;
}
},
0x0e => {
match opcodes[2] {
0x09 => {
match opcodes[3] {
0x0e => {
//info!("23: {}", self.registers[opcodes[1] as usize]);
if self.registers[opcodes[1] as usize] < 16{
if self.keys[(self.registers[opcodes[1] as usize] & 15) as usize] {
self.pc += 2;
}
} else {
error!("invalid keycode");
}
}
_ => {}
}
},
0x0a => {
match opcodes[3] {
0x01 => {
//info!("a1 {}", self.registers[opcodes[1] as usize]);
if self.registers[opcodes[1] as usize] < 16{
if !self.keys[(self.registers[opcodes[1] as usize] & 15) as usize] {
self.pc += 2;
}
} else {
error!("invalid keycode");
}
},
_ => {error!("invalid opcode");}
}
},
_ => {error!("unknown opcode")}
}
},
0x0f => {
match opcodes[2] {
0x00 => {
match opcodes[3] {
0x07 => {
self.registers[opcodes[1] as usize] = self.delay_timer;
},
0x0a => {
let mut keypress = false;
if !self.get_key_pause {
self.get_key_pause = true;
for i in 0..16 {
self.keys_released[i] = !self.keys[i];
self.keys_pressed[i] = false;
}
} else {
for i in 0..16 {
if !keypress {
if self.keys_pressed[i] && !self.keys[i] {
self.registers[opcodes[1] as usize] = i as u8;
self.get_key_pause = false;
keypress = true;
} else if self.keys_released[i] && self.keys[i] {
self.keys_pressed[i] = true;
} else if !self.keys_released[i] && !self.keys[i] {
self.keys_released[i] = true;
}
}
}
}
if !keypress {
self.pc -= 2;
}
},
_ => {
error!("unknown opcode");
}
}
}
0x01 => {
match opcodes[3] {
0x05 => {
self.delay_timer = self.registers[opcodes[1] as usize];
},
0x08 => {
self.sound_timer = self.registers[opcodes[1] as usize];
}
0x0e => {
if self.index_register + self.registers[opcodes[1] as usize] as u16 >= 0x1000 {
self.registers[0x0f] = 1;
}
self.index_register = (self.index_register + self.registers[opcodes[1] as usize] as u16) & 0x0FFF;
},
_ => {error!("unknown opcode");}
}
},
0x02 => {
match opcodes[3] {
0x09 => {
self.index_register = 0x050 + (((self.registers[opcodes[1] as usize] & 0x0F) as u16) * 5);
},
_ => {error!("unknown opcode");}
}
},
0x03 => {
match opcodes[3] {
0x03 => {
self.ram[self.index_register as usize] = self.registers[opcodes[1] as usize] / 100;
self.ram[self.index_register as usize + 1] = (self.registers[opcodes[1] as usize] / 10) % 10;
self.ram[self.index_register as usize + 2] = self.registers[opcodes[1] as usize] % 10;
},
_ => {error!("unknown opcode");}
}
}
0x05 => {
match opcodes[3] {
0x05 => {
if MODERNLOADSAVE {
for i in 0..=opcodes[1] {
self.ram[(self.index_register + i as u16) as usize] = self.registers[i as usize];
}
} else {
for i in 0..=opcodes[1] {
//self.index_register += i as u16;
self.ram[self.index_register as usize] = self.registers[i as usize];
self.index_register += 1;
}
}
},
_ => {error!("unknown opcode");}
}
},
0x06 => {
match opcodes[3] {
0x05 => {
if MODERNLOADSAVE {
for i in 0..=opcodes[1] {
self.registers[i as usize] = self.ram[(self.index_register + i as u16) as usize];
}
} else {
for i in 0..=opcodes[1] {
//self.index_register += 1;
self.registers[i as usize] = self.ram[self.index_register as usize];
self.index_register += 1;
}
}
},
_ => {error!("unknown opcode");}
}
},
_ => {error!("unknown opcode")}
}
},
_ => {
@@ -176,9 +558,9 @@ impl Chip8 {
*self
}
fn clear_screen(mut self) -> Self {
fn clear_screen(&mut self) -> Self {
self.display = [0;32];
self
*self
}
}
@@ -193,6 +575,7 @@ fn main() {
let args = Args::parse();
let mut chip8 = Chip8::new().insert_font().load_file(args.file);
let (tx, rx) = sync_channel(1);
println!("ram: {:?}", chip8.ram);
@@ -201,7 +584,7 @@ fn main() {
let window = { let window = WindowBuilder::new()
.with_title("Chip8 Emulator")
.with_inner_size(LogicalSize::new(320, 240))
.with_min_inner_size(LogicalSize::new(320, 240))
.with_min_inner_size(LogicalSize::new(600, 300))
.build(&event_loop)
.unwrap();
Arc::new(window)
@@ -213,9 +596,13 @@ fn main() {
Pixels::new(window_size.width, window_size.height, surface_texture).unwrap()
};
let test: u64 = 1;
info!("{}", get_bit(test, 0));
let mut audio = AudioPlayer::make(rx);
audio.run();
let test: u64 = 1;
//info!("{}", get_bit(test, 0));
let mut start = Instant::now();
event_loop.run(move |event, _, control_flow| {
match event {
Event::WindowEvent {event, ..} => match event {
@@ -226,20 +613,87 @@ fn main() {
*control_flow = ControlFlow::Exit;
}
},
WindowEvent::KeyboardInput {
event:
KeyEvent {
logical_key,
state,
..
},
..
} => {
match logical_key {
Key::Character("1") => {
set_keystate(&mut chip8.keys, 1, state);
},
Key::Character("2") => {
set_keystate(&mut chip8.keys, 2, state);
},
Key::Character("3") => {
set_keystate(&mut chip8.keys, 3, state);
},
Key::Character("4") => {
set_keystate(&mut chip8.keys, 0x0c, state);
},
Key::Character("q") => {
set_keystate(&mut chip8.keys, 4, state);
},
Key::Character("w") => {
set_keystate(&mut chip8.keys, 5, state);
},
Key::Character("e") => {
set_keystate(&mut chip8.keys, 6, state);
},
Key::Character("r") => {
set_keystate(&mut chip8.keys, 0x0d, state);
},
Key::Character("a") => {
set_keystate(&mut chip8.keys, 7, state);
},
Key::Character("s") => {
set_keystate(&mut chip8.keys, 8, state);
},
Key::Character("d") => {
set_keystate(&mut chip8.keys, 9, state);
},
Key::Character("f") => {
set_keystate(&mut chip8.keys, 0x0e, state);
},
Key::Character("z") => {
set_keystate(&mut chip8.keys, 0x0a, state);
},
Key::Character("x") => {
set_keystate(&mut chip8.keys, 0, state);
},
Key::Character("c") => {
set_keystate(&mut chip8.keys, 0x0b, state);
},
Key::Character("v") => {
set_keystate(&mut chip8.keys, 0x0f, state);
},
_ => {}
}
}
_ => {}
},
Event::MainEventsCleared => {
info!(chip8.pc);
//info!(chip8.pc);
chip8.update(40);
info!(chip8.pc);
//info!(chip8.pc);
//for i in chip8.display {
// println!("{:#64b}", i);
//}
window.request_redraw();
}
Event::RedrawRequested(_) => {
chip8.draw(pixels.frame_mut(), (window.inner_size().width, window.inner_size().height));
chip8.draw(pixels.frame_mut(), (window.inner_size().width, window.inner_size().height), &tx);
if let Err(err) = pixels.render() {
error!("pixels.render");
*control_flow = ControlFlow::Exit;
}
//let duration = start.elapsed();
//info!("{:?}", duration);
//start = Instant::now();
}
_ => {}
}
@@ -297,10 +751,19 @@ fn get_bit(num: u64, bit: u8) -> bool {
fn get_bit_u8(num: u8, bit: u8) -> bool {
if bit <= 8 {
let mask: u8 = 128 >> bit;
let mask: u8 = 1 << (7 - bit);
let bitvalue = (num & mask) != 0;
//info!("{},{},{},{}", num, bit, mask, bitvalue);
bitvalue
} else {
false
}
}
fn set_keystate(keys: &mut [bool; 16], key: u8, state: ElementState) {
if state == ElementState::Pressed {
keys[key as usize] = true;
} else if state == ElementState::Released {
keys[key as usize] = false;
}
}