[dev] lots of progress
Create main timer loop using an auxilliary thread.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
/target
|
/target
|
||||||
.idea
|
.idea
|
||||||
|
/roms
|
16
README.md
16
README.md
@@ -1,3 +1,19 @@
|
|||||||
# CHIP-8 Emulator
|
# CHIP-8 Emulator
|
||||||
|
|
||||||
Chip 8 emulator made with Rust.
|
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/)
|
@@ -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
6
src/device/cpu.rs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
enum Instruction{
|
||||||
|
ClearScreen,
|
||||||
|
JumpTo(u16),
|
||||||
|
|
||||||
|
}
|
81
src/device/device.rs
Normal file
81
src/device/device.rs
Normal 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
6
src/device/mod.rs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
pub mod timer;
|
||||||
|
mod device;
|
||||||
|
mod sound;
|
||||||
|
mod cpu;
|
||||||
|
|
||||||
|
pub use device::*;
|
1
src/device/sound.rs
Normal file
1
src/device/sound.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
// TODO
|
64
src/device/timer.rs
Normal file
64
src/device/timer.rs
Normal 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!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
17
src/main.rs
17
src/main.rs
@@ -1,6 +1,7 @@
|
|||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use simple_logger::SimpleLogger;
|
use simple_logger::SimpleLogger;
|
||||||
use crate::device::{Device};
|
use device::timer::Timer;
|
||||||
|
use crate::device::Device;
|
||||||
|
|
||||||
mod args;
|
mod args;
|
||||||
mod device;
|
mod device;
|
||||||
@@ -8,5 +9,17 @@ mod device;
|
|||||||
fn main() {
|
fn main() {
|
||||||
SimpleLogger::new().with_level(LevelFilter::Info).env().init().unwrap();
|
SimpleLogger::new().with_level(LevelFilter::Info).env().init().unwrap();
|
||||||
log::info!("Started emulator");
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user