From 2a4868c0c04a006e0eabae6cbe6367e57f976d60 Mon Sep 17 00:00:00 2001 From: Atreya Bain Date: Sat, 2 Mar 2024 13:00:57 +0530 Subject: [PATCH] [dev] lots of progress Create main timer loop using an auxilliary thread. --- .gitignore | 3 +- README.md | 18 +++++++++- src/device.rs | 22 ------------ src/device/cpu.rs | 6 ++++ src/device/device.rs | 81 ++++++++++++++++++++++++++++++++++++++++++++ src/device/mod.rs | 6 ++++ src/device/sound.rs | 1 + src/device/timer.rs | 64 ++++++++++++++++++++++++++++++++++ src/main.rs | 17 ++++++++-- 9 files changed, 192 insertions(+), 26 deletions(-) delete mode 100644 src/device.rs create mode 100644 src/device/cpu.rs create mode 100644 src/device/device.rs create mode 100644 src/device/mod.rs create mode 100644 src/device/sound.rs create mode 100644 src/device/timer.rs diff --git a/.gitignore b/.gitignore index 2a0038a..c787b09 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target -.idea \ No newline at end of file +.idea +/roms \ No newline at end of file diff --git a/README.md b/README.md index d1ad344..5569723 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,19 @@ # CHIP-8 Emulator -Chip 8 emulator made with Rust. \ No newline at end of file +Chip 8 emulator made with Rust. + + +### Status + +- [ ] Memory +- [ ] Loading fonts +- [ ] Registers +- [ ] Stack +- [ ] Instruction Processing +- [ ] Display +- [ ] Keyboard + +### More information on Chip-8 + +- [Guide to making a CHIP-8 emulator - Tobias V. Langhoff](https://tobiasvl.github.io/blog/write-a-chip-8-emulator/#specifications) +- [Awesome CHIP-8](https://chip-8.github.io/links/) \ No newline at end of file diff --git a/src/device.rs b/src/device.rs deleted file mode 100644 index 575a325..0000000 --- a/src/device.rs +++ /dev/null @@ -1,22 +0,0 @@ - - -pub struct Device{ - pub registers:RegisterFile, - pub memory: Box<[u8;Self::DEVICE_MEMORY_SIZE]> -} - -impl Device{ - pub const DEVICE_MEMORY_SIZE:usize = 1024; - pub fn new()->Device{ - let memory = vec![0u8;Self::DEVICE_MEMORY_SIZE].into_boxed_slice().try_into().unwrap(); - log::trace!("Successfully initiated device memory"); - Device{ - registers: RegisterFile{}, - memory - } - } -} - -pub struct RegisterFile{ - -} \ No newline at end of file diff --git a/src/device/cpu.rs b/src/device/cpu.rs new file mode 100644 index 0000000..2011745 --- /dev/null +++ b/src/device/cpu.rs @@ -0,0 +1,6 @@ + +enum Instruction{ + ClearScreen, + JumpTo(u16), + +} diff --git a/src/device/device.rs b/src/device/device.rs new file mode 100644 index 0000000..668172f --- /dev/null +++ b/src/device/device.rs @@ -0,0 +1,81 @@ +use std::ops::SubAssign; +use std::sync::atomic::{AtomicU16, Ordering}; +use std::sync::{Arc, Mutex, RwLock}; +use std::thread::{JoinHandle, sleep}; +use std::time::Duration; +use crate::device::timer::Timer; + + +pub struct Device { + pub registers: RegisterFile, + pub memory: Box<[u8; Self::DEVICE_MEMORY_SIZE]>, + pub timer: Timer, + pub stack: Vec +} + +impl Device { + pub const DEVICE_MEMORY_SIZE: usize = 2 << 12; + pub fn new(timer: Timer) -> Device { + let memory = vec![0u8; Self::DEVICE_MEMORY_SIZE].into_boxed_slice().try_into().unwrap(); + log::trace!("Successfully initiated device memory"); + Device { + registers: RegisterFile::new(), + memory, + stack:Vec::with_capacity(16), + timer, + } + } +} +impl Device{ + const DEFAULT_FONT:[u8;5*16] = [ + 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0 + 0x20, 0x60, 0x20, 0x20, 0x70, // 1 + 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2 + 0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3 + 0x90, 0x90, 0xF0, 0x10, 0x10, // 4 + 0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5 + 0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6 + 0xF0, 0x10, 0x20, 0x40, 0x40, // 7 + 0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8 + 0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9 + 0xF0, 0x90, 0xF0, 0x90, 0x90, // A + 0xE0, 0x90, 0xE0, 0x90, 0xE0, // B + 0xF0, 0x80, 0x80, 0x80, 0xF0, // C + 0xE0, 0x90, 0x90, 0x90, 0xE0, // D + 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E + 0xF0, 0x80, 0xF0, 0x80, 0x80 // F + ]; + const FONT_DEFAULT_MEM_LOCATION_START:usize = 0x50; + const FONT_DEFAULT_MEM_LOCATION_END:usize = 0x9F; + pub fn cycle(&mut self){ + + } + + pub fn set_default_font(&mut self){ + self.memory[Self::FONT_DEFAULT_MEM_LOCATION_START..=Self::FONT_DEFAULT_MEM_LOCATION_END].copy_from_slice(&Self::DEFAULT_FONT); + } + +} +impl Drop for Device{ + fn drop(&mut self) { + self.timer.send_stop_signal() + } +} + +pub struct RegisterFile { + pub v: [u8; 0x10], + // program counter - only u12 technically. + pub pc: u16, + /// stack pointer + pub i: u16, +} + +impl RegisterFile { + pub fn new() -> RegisterFile { + RegisterFile { + v: [0; 0x10], + pc: 0x200, + i: 0, + } + } +} diff --git a/src/device/mod.rs b/src/device/mod.rs new file mode 100644 index 0000000..a603634 --- /dev/null +++ b/src/device/mod.rs @@ -0,0 +1,6 @@ +pub mod timer; +mod device; +mod sound; +mod cpu; + +pub use device::*; diff --git a/src/device/sound.rs b/src/device/sound.rs new file mode 100644 index 0000000..0ffdd02 --- /dev/null +++ b/src/device/sound.rs @@ -0,0 +1 @@ +// TODO \ No newline at end of file diff --git a/src/device/timer.rs b/src/device/timer.rs new file mode 100644 index 0000000..83c77e7 --- /dev/null +++ b/src/device/timer.rs @@ -0,0 +1,64 @@ +use std::sync::{Arc, Mutex}; +use std::thread::{JoinHandle, sleep}; +use std::time::Duration; + +pub struct Timer{ + timer_left: Arc>, + join_handle: Option<(JoinHandle<()>,std::sync::mpsc::Sender<()>)> +} + +impl Timer{ + pub fn new()->Timer{ + Timer{timer_left:Arc::new(Mutex::default()),join_handle:None} + } + pub fn start(&mut self){ + let timer_left_ref = self.timer_left.clone(); + let (sender,receiver) = std::sync::mpsc::channel(); + let res = std::thread::spawn(move ||{ + loop{ + let val = receiver.try_recv(); + if let Ok(()) = val{ + break; + }else if let Err(std::sync::mpsc::TryRecvError::Disconnected) = val{ + panic!("Disconnected"); + } + { + let mut timer_lock = timer_left_ref.lock().expect("Failed to lock"); + if *timer_lock >0 { + *timer_lock -= 1; + } + } + sleep(Duration::from_secs_f32(1f32/60f32)); + } + + }); + self.join_handle = Some((res,sender)); + } + /// Set a timer down tick from `val` + pub fn set_timer(& self,val:u16){ + let mut timer_val = self.timer_left.lock().expect("Failed to get mutex"); + *timer_val = val; + } + + pub fn poll_value(&self)->u16{ + let res = self.timer_left.lock().expect("Failed to lock?"); + res.clone() + } + + pub fn stop(self){ + if let Some((u,x)) = self.join_handle{ + x.send(()).expect("Failed to send signal to close thread"); + u.join().expect("Failed to close thread"); + }else{ + log::warn!("Nothing present!"); + } + } + pub fn send_stop_signal(&mut self){ + if let Some((_,x)) = &self.join_handle{ + x.send(()).expect("Failed to send signal to close thread"); + }else{ + log::warn!("Nothing present!"); + } + } + +} diff --git a/src/main.rs b/src/main.rs index 11b6cd3..c1bc00e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ use log::LevelFilter; use simple_logger::SimpleLogger; -use crate::device::{Device}; +use device::timer::Timer; +use crate::device::Device; mod args; mod device; @@ -8,5 +9,17 @@ mod device; fn main() { SimpleLogger::new().with_level(LevelFilter::Info).env().init().unwrap(); log::info!("Started emulator"); - let device = Device::new(); + + let mut timer = Timer::new(); + timer.start(); + + let mut device = Device::new(timer); + device.set_default_font(); + let mut i = 0; + + + } + + +