[dev] lots of progress

Create main timer loop using an auxilliary thread.
This commit is contained in:
2024-03-02 13:00:57 +05:30
parent d1b0f03779
commit 2a4868c0c0
9 changed files with 192 additions and 26 deletions

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
/target
.idea
/roms

View File

@@ -1,3 +1,19 @@
# CHIP-8 Emulator
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/)

View File

@@ -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{
}

6
src/device/cpu.rs Normal file
View File

@@ -0,0 +1,6 @@
enum Instruction{
ClearScreen,
JumpTo(u16),
}

81
src/device/device.rs Normal file
View File

@@ -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<u16>
}
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,
}
}
}

6
src/device/mod.rs Normal file
View File

@@ -0,0 +1,6 @@
pub mod timer;
mod device;
mod sound;
mod cpu;
pub use device::*;

1
src/device/sound.rs Normal file
View File

@@ -0,0 +1 @@
// TODO

64
src/device/timer.rs Normal file
View File

@@ -0,0 +1,64 @@
use std::sync::{Arc, Mutex};
use std::thread::{JoinHandle, sleep};
use std::time::Duration;
pub struct Timer{
timer_left: Arc<Mutex<u16>>,
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!");
}
}
}

View File

@@ -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;
}