Switch from Mutex to AtomicU8
This commit is contained in:
parent
3bbd896e18
commit
67c2b9b100
|
@ -1,4 +1,5 @@
|
||||||
use super::periph::{Display, Keypad, ManagedTimer as Timer, TimerManager};
|
use super::periph::{Display, Keypad};
|
||||||
|
use super::timer::{Timer, Type as TimerType};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
@ -357,7 +358,7 @@ impl Chip8 {
|
||||||
|
|
||||||
fn copy_delay_timer_val(&mut self, x: u8) {
|
fn copy_delay_timer_val(&mut self, x: u8) {
|
||||||
// set Vx to be the value of the delay timer
|
// set Vx to be the value of the delay timer
|
||||||
self.v[x as usize] = TimerManager::get(Timer::Delay);
|
self.v[x as usize] = Timer::get(TimerType::Delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loop_until_key_vx(&mut self, x: u8) {
|
fn loop_until_key_vx(&mut self, x: u8) {
|
||||||
|
@ -372,12 +373,12 @@ impl Chip8 {
|
||||||
|
|
||||||
fn set_delay_to_vx(&mut self, x: u8) {
|
fn set_delay_to_vx(&mut self, x: u8) {
|
||||||
// set delay timer to be value of Vx
|
// set delay timer to be value of Vx
|
||||||
TimerManager::set(self.v[x as usize], Timer::Delay);
|
Timer::set(self.v[x as usize], TimerType::Delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_sound_to_vx(&mut self, x: u8) {
|
fn set_sound_to_vx(&mut self, x: u8) {
|
||||||
// set sound timer to be value of Vx
|
// set sound timer to be value of Vx
|
||||||
TimerManager::set(self.v[x as usize], Timer::Sound);
|
Timer::set(self.v[x as usize], TimerType::Sound);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_vx_to_i(&mut self, x: u8) {
|
fn add_vx_to_i(&mut self, x: u8) {
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
pub mod emu;
|
pub mod emu;
|
||||||
pub mod periph;
|
pub mod periph;
|
||||||
|
pub mod timer;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use chip8::{emu::Chip8, periph::TimerManager};
|
use chip8::{emu::Chip8, timer::Timer};
|
||||||
use pixels::{wgpu::Surface, Pixels, SurfaceTexture};
|
use pixels::{wgpu::Surface, Pixels, SurfaceTexture};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
@ -23,7 +23,7 @@ fn main() {
|
||||||
let rom_path = Path::new(&path);
|
let rom_path = Path::new(&path);
|
||||||
chip8.load_rom(rom_path).expect("Unable to load ROM");
|
chip8.load_rom(rom_path).expect("Unable to load ROM");
|
||||||
|
|
||||||
TimerManager::start();
|
Timer::start_thread();
|
||||||
|
|
||||||
let mut start = Instant::now();
|
let mut start = Instant::now();
|
||||||
let frametime = Duration::from_nanos(1e+9 as u64 / OPCODES_PER_SECOND);
|
let frametime = Duration::from_nanos(1e+9 as u64 / OPCODES_PER_SECOND);
|
||||||
|
|
117
src/periph.rs
117
src/periph.rs
|
@ -1,14 +1,3 @@
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use rodio::{source::SineWave, Sink};
|
|
||||||
use std::sync::Mutex;
|
|
||||||
use std::thread;
|
|
||||||
use std::time::{Duration, Instant};
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref SOUND_TIMER: Mutex<Timer> = Mutex::new(Timer::default().with_beep());
|
|
||||||
static ref DELAY_TIMER: Mutex<Timer> = Mutex::new(Timer::default());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct Display {
|
pub struct Display {
|
||||||
pub buf: [u8; Self::WIDTH as usize * Self::HEIGHT as usize],
|
pub buf: [u8; Self::WIDTH as usize * Self::HEIGHT as usize],
|
||||||
|
@ -65,112 +54,6 @@ impl Default for Display {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TimerManager;
|
|
||||||
|
|
||||||
pub enum ManagedTimer {
|
|
||||||
Sound,
|
|
||||||
Delay,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TimerManager {
|
|
||||||
pub fn start() {
|
|
||||||
thread::spawn(|| {
|
|
||||||
let duration = Duration::from_nanos(1e+9 as u64 / 60);
|
|
||||||
let mut start = Instant::now();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if Instant::now().duration_since(start) > duration {
|
|
||||||
SOUND_TIMER.lock().unwrap().tick();
|
|
||||||
DELAY_TIMER.lock().unwrap().tick();
|
|
||||||
start = Instant::now();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(timer: ManagedTimer) -> u8 {
|
|
||||||
match timer {
|
|
||||||
ManagedTimer::Delay => DELAY_TIMER.lock().unwrap().get(),
|
|
||||||
ManagedTimer::Sound => SOUND_TIMER.lock().unwrap().get(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set(secs: u8, timer: ManagedTimer) {
|
|
||||||
match timer {
|
|
||||||
ManagedTimer::Delay => DELAY_TIMER.lock().unwrap().set(secs),
|
|
||||||
ManagedTimer::Sound => SOUND_TIMER.lock().unwrap().set(secs),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub struct Timer {
|
|
||||||
remaining: u8,
|
|
||||||
enabled: bool,
|
|
||||||
beep_enabled: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Timer {
|
|
||||||
fn default() -> Self {
|
|
||||||
Timer {
|
|
||||||
remaining: 0,
|
|
||||||
enabled: false,
|
|
||||||
beep_enabled: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Timer {
|
|
||||||
pub fn with_beep(mut self) -> Self {
|
|
||||||
self.beep_enabled = true;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set(&mut self, secs: u8) {
|
|
||||||
self.remaining = secs;
|
|
||||||
self.enabled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&self) -> u8 {
|
|
||||||
self.remaining
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tick(&mut self) {
|
|
||||||
if self.enabled {
|
|
||||||
if self.remaining == 0 {
|
|
||||||
self.enabled = false;
|
|
||||||
|
|
||||||
if self.beep_enabled {
|
|
||||||
Self::beep();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.remaining -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn beep() {
|
|
||||||
let maybe_device = rodio::default_output_device();
|
|
||||||
let beep = SineWave::new(440);
|
|
||||||
|
|
||||||
// TODO: Fix Pop when sound ends?
|
|
||||||
if let Some(device) = maybe_device {
|
|
||||||
std::thread::spawn(move || {
|
|
||||||
let sink = Sink::new(&device);
|
|
||||||
let duration = Duration::from_millis(100);
|
|
||||||
let start = Instant::now();
|
|
||||||
sink.append(beep);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if Instant::now().duration_since(start) > duration {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct Keypad {
|
pub struct Keypad {
|
||||||
keys: [bool; 16],
|
keys: [bool; 16],
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
use rodio::{source::SineWave, Sink};
|
||||||
|
use std::sync::atomic::{AtomicU8, Ordering};
|
||||||
|
use std::thread;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
static SOUND_TIMER: AtomicU8 = AtomicU8::new(0);
|
||||||
|
static DELAY_TIMER: AtomicU8 = AtomicU8::new(0);
|
||||||
|
|
||||||
|
pub enum Type {
|
||||||
|
Delay,
|
||||||
|
Sound,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Timer;
|
||||||
|
|
||||||
|
impl Timer {
|
||||||
|
pub fn start_thread() {
|
||||||
|
thread::spawn(|| {
|
||||||
|
let duration = Duration::from_nanos(1e+9 as u64 / 60);
|
||||||
|
let mut start = Instant::now();
|
||||||
|
let mut has_beeped = false;
|
||||||
|
loop {
|
||||||
|
if Instant::now().duration_since(start) > duration {
|
||||||
|
Timer::tick(&mut has_beeped);
|
||||||
|
start = Instant::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tick(has_beeped: &mut bool) {
|
||||||
|
// Sound Timer
|
||||||
|
let remaining = SOUND_TIMER.load(Ordering::Relaxed);
|
||||||
|
match (remaining, *has_beeped) {
|
||||||
|
(0, false) => {
|
||||||
|
Self::beep();
|
||||||
|
*has_beeped = true;
|
||||||
|
}
|
||||||
|
(0, true) => {}
|
||||||
|
_ => {
|
||||||
|
if *has_beeped {
|
||||||
|
*has_beeped = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SOUND_TIMER.store(remaining - 1, Ordering::Release)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delay Timer
|
||||||
|
let remaining = DELAY_TIMER.load(Ordering::Relaxed);
|
||||||
|
if remaining != 0 {
|
||||||
|
DELAY_TIMER.store(remaining - 1, Ordering::Release);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(timer: Type) -> u8 {
|
||||||
|
match timer {
|
||||||
|
Type::Delay => DELAY_TIMER.load(Ordering::Acquire),
|
||||||
|
Type::Sound => SOUND_TIMER.load(Ordering::Acquire),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(secs: u8, timer: Type) {
|
||||||
|
match timer {
|
||||||
|
Type::Delay => DELAY_TIMER.store(secs, Ordering::Relaxed),
|
||||||
|
Type::Sound => SOUND_TIMER.store(secs, Ordering::Relaxed),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn beep() {
|
||||||
|
let maybe_device = rodio::default_output_device();
|
||||||
|
let beep = SineWave::new(440);
|
||||||
|
|
||||||
|
// TODO: Fix Pop when sound ends?
|
||||||
|
if let Some(device) = maybe_device {
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let sink = Sink::new(&device);
|
||||||
|
let duration = Duration::from_millis(100);
|
||||||
|
let start = Instant::now();
|
||||||
|
sink.append(beep);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if Instant::now().duration_since(start) > duration {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue