Switch from Mutex to AtomicU8

This commit is contained in:
Rekai Musuka 2020-07-15 18:32:38 -05:00
parent 3bbd896e18
commit 67c2b9b100
5 changed files with 98 additions and 123 deletions

View File

@ -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::io::{self, Read};
use std::path::Path;
@ -357,7 +358,7 @@ impl Chip8 {
fn copy_delay_timer_val(&mut self, x: u8) {
// 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) {
@ -372,12 +373,12 @@ impl Chip8 {
fn set_delay_to_vx(&mut self, x: u8) {
// 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) {
// 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) {

View File

@ -1,2 +1,3 @@
pub mod emu;
pub mod periph;
pub mod timer;

View File

@ -1,4 +1,4 @@
use chip8::{emu::Chip8, periph::TimerManager};
use chip8::{emu::Chip8, timer::Timer};
use pixels::{wgpu::Surface, Pixels, SurfaceTexture};
use std::path::Path;
use std::time::{Duration, Instant};
@ -23,7 +23,7 @@ fn main() {
let rom_path = Path::new(&path);
chip8.load_rom(rom_path).expect("Unable to load ROM");
TimerManager::start();
Timer::start_thread();
let mut start = Instant::now();
let frametime = Duration::from_nanos(1e+9 as u64 / OPCODES_PER_SECOND);

View File

@ -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)]
pub struct Display {
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)]
pub struct Keypad {
keys: [bool; 16],

90
src/timer.rs Normal file
View File

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