[cln] Restructure code
This commit is contained in:
@@ -1,16 +1,15 @@
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread::{JoinHandle, sleep};
|
|
||||||
use rand::random;
|
use rand::random;
|
||||||
use crate::device::instruction::Instruction;
|
use crate::device::instruction::Instruction;
|
||||||
use crate::device::keyboard::Keyboard;
|
use crate::device::keyboard::Keyboard;
|
||||||
use crate::device::timer::TimerManager;
|
use crate::device::timer::DeviceTimerManager;
|
||||||
use crate::util::EmulatorResult;
|
use crate::util::EmulatorResult;
|
||||||
|
|
||||||
|
|
||||||
pub struct Device {
|
pub struct Device {
|
||||||
pub registers: RegisterFile,
|
pub registers: RegisterFile,
|
||||||
pub memory: Box<[u8; Self::DEVICE_MEMORY_SIZE]>,
|
pub memory: Box<[u8; Self::DEVICE_MEMORY_SIZE]>,
|
||||||
pub timer: TimerManager,
|
pub timer: DeviceTimerManager,
|
||||||
pub stack: Vec<u16>,
|
pub stack: Vec<u16>,
|
||||||
pub frame_buffer: Arc<Mutex<Box<[bool; 64 * 32]>>>,
|
pub frame_buffer: Arc<Mutex<Box<[bool; 64 * 32]>>>,
|
||||||
pub new_chip8_mode: bool,
|
pub new_chip8_mode: bool,
|
||||||
@@ -22,7 +21,7 @@ impl Device {
|
|||||||
pub const FRAME_BUFFER_WIDTH: usize = 64;
|
pub const FRAME_BUFFER_WIDTH: usize = 64;
|
||||||
pub const FRAME_BUFFER_HEIGHT: usize = 32;
|
pub const FRAME_BUFFER_HEIGHT: usize = 32;
|
||||||
pub const FRAME_BUFFER_SIZE: usize = Self::FRAME_BUFFER_WIDTH * Self::FRAME_BUFFER_HEIGHT;
|
pub const FRAME_BUFFER_SIZE: usize = Self::FRAME_BUFFER_WIDTH * Self::FRAME_BUFFER_HEIGHT;
|
||||||
pub fn new(timer: TimerManager, fb: Arc<Mutex<Box<[bool; Device::FRAME_BUFFER_SIZE]>>>, device_keyboard: Keyboard, new_chip8_mode: bool) -> Device {
|
pub fn new(timer: DeviceTimerManager, fb: Arc<Mutex<Box<[bool; Device::FRAME_BUFFER_SIZE]>>>, device_keyboard: Keyboard, new_chip8_mode: bool) -> Device {
|
||||||
let memory = vec![0u8; Self::DEVICE_MEMORY_SIZE].into_boxed_slice().try_into().unwrap();
|
let memory = vec![0u8; Self::DEVICE_MEMORY_SIZE].into_boxed_slice().try_into().unwrap();
|
||||||
log::trace!("Successfully initiated device memory");
|
log::trace!("Successfully initiated device memory");
|
||||||
Device {
|
Device {
|
||||||
@@ -222,7 +221,7 @@ impl Device {
|
|||||||
let reg_value = self.registers.v[x];
|
let reg_value = self.registers.v[x];
|
||||||
let index_original = self.registers.i;
|
let index_original = self.registers.i;
|
||||||
// newer instruction set requires wrapping on 12 bit overflow, and setting vf
|
// newer instruction set requires wrapping on 12 bit overflow, and setting vf
|
||||||
let addn_res = if (self.new_chip8_mode) {
|
let addn_res = if self.new_chip8_mode {
|
||||||
let overflowing = (reg_value as u16 + index_original) >= 0x1000;
|
let overflowing = (reg_value as u16 + index_original) >= 0x1000;
|
||||||
self.set_flag_register(overflowing);
|
self.set_flag_register(overflowing);
|
||||||
(reg_value as u16 + index_original) % 0x1000
|
(reg_value as u16 + index_original) % 0x1000
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
pub mod timer;
|
pub mod timer;
|
||||||
pub mod keyboard;
|
pub mod keyboard;
|
||||||
mod sound;
|
|
||||||
pub mod instruction;
|
pub mod instruction;
|
||||||
mod device;
|
mod device;
|
||||||
|
|
||||||
|
@@ -1 +0,0 @@
|
|||||||
// TODO
|
|
@@ -7,22 +7,23 @@ use std::time::Duration;
|
|||||||
use crate::util::EmulatorResult;
|
use crate::util::EmulatorResult;
|
||||||
|
|
||||||
/// Manages the timer and the sound timer
|
/// Manages the timer and the sound timer
|
||||||
pub struct TimerManager {
|
pub struct DeviceTimerManager {
|
||||||
timer_left: Arc<Mutex<u8>>,
|
timer_left: Arc<Mutex<u8>>,
|
||||||
sound_left: Arc<Mutex<u8>>,
|
sound_left: Arc<Mutex<u8>>,
|
||||||
join_handle: Option<(JoinHandle<()>, std::sync::mpsc::Sender<()>)>,
|
join_handle: Option<(JoinHandle<()>, std::sync::mpsc::Sender<()>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TimerManager {
|
impl DeviceTimerManager {
|
||||||
pub const TIMER_THREAD_NAME: &'static str = "Timer";
|
pub const TIMER_THREAD_NAME: &'static str = "Timer";
|
||||||
pub fn new() -> TimerManager {
|
pub fn new(sound_timer: Arc<Mutex<u8>>) -> DeviceTimerManager {
|
||||||
TimerManager {
|
DeviceTimerManager {
|
||||||
timer_left: Arc::new(Mutex::default()),
|
timer_left: Arc::new(Mutex::default()),
|
||||||
sound_left: Arc::new(Mutex::default()),
|
sound_left: sound_timer,
|
||||||
join_handle: None,
|
join_handle: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn start(&mut self) -> Arc<Mutex<u8>> {
|
|
||||||
|
pub fn start(&mut self) {
|
||||||
let timer_left_ref = self.timer_left.clone();
|
let timer_left_ref = self.timer_left.clone();
|
||||||
let sound_timer_ref = self.sound_left.clone();
|
let sound_timer_ref = self.sound_left.clone();
|
||||||
let (sender, receiver) = std::sync::mpsc::channel();
|
let (sender, receiver) = std::sync::mpsc::channel();
|
||||||
@@ -51,7 +52,6 @@ impl TimerManager {
|
|||||||
}
|
}
|
||||||
}).expect("Failed to start timer thread");
|
}).expect("Failed to start timer thread");
|
||||||
self.join_handle = Some((res, sender));
|
self.join_handle = Some((res, sender));
|
||||||
self.sound_left.clone()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a timer down tick from `val`
|
/// Set a timer down tick from `val`
|
||||||
@@ -72,8 +72,8 @@ impl TimerManager {
|
|||||||
Ok(res.clone())
|
Ok(res.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop(self) {
|
pub fn _stop(self) {
|
||||||
if let Some((u, _)) = self.join_handle {
|
if let Some((u, _dead_sender)) = self.join_handle {
|
||||||
u.join().expect("Failed to close thread");
|
u.join().expect("Failed to close thread");
|
||||||
} else {
|
} else {
|
||||||
log::warn!("Nothing present!");
|
log::warn!("Nothing present!");
|
||||||
|
23
src/main.rs
23
src/main.rs
@@ -15,43 +15,38 @@ use sdl2::render::BlendMode;
|
|||||||
|
|
||||||
use sdl2::render::WindowCanvas;
|
use sdl2::render::WindowCanvas;
|
||||||
use simple_logger::SimpleLogger;
|
use simple_logger::SimpleLogger;
|
||||||
use device::timer::TimerManager;
|
use device::timer::DeviceTimerManager;
|
||||||
use crate::args::Porcel8ProgramArgs;
|
use crate::args::Porcel8ProgramArgs;
|
||||||
use crate::device::Device;
|
use crate::device::Device;
|
||||||
use crate::device::keyboard::Keyboard;
|
use crate::device::keyboard::Keyboard;
|
||||||
use crate::util::EmulatorResult;
|
use crate::util::EmulatorResult;
|
||||||
use crate::kb_map::get_key_index;
|
use crate::kb_map::get_key_index;
|
||||||
use crate::sdl_audio_adapter::SdlAudioAdapter;
|
use crate::sdl_adapters::sdl_audio_adapter::SdlAudioAdapter;
|
||||||
use crate::sdl_graphics_adapter::SdlGraphicsAdapter;
|
use crate::sdl_adapters::sdl_graphics_adapter::SdlGraphicsAdapter;
|
||||||
use crate::sdl_keyboard_adapter::SdlKeyboardAdapter;
|
use crate::sdl_adapters::sdl_keyboard_adapter::SdlKeyboardAdapter;
|
||||||
|
|
||||||
mod args;
|
mod args;
|
||||||
mod device;
|
mod device;
|
||||||
mod kb_map;
|
mod kb_map;
|
||||||
mod sdl_graphics_adapter;
|
|
||||||
mod util;
|
mod util;
|
||||||
mod sdl_keyboard_adapter;
|
mod sdl_adapters;
|
||||||
mod sdl_audio_adapter;
|
|
||||||
|
|
||||||
fn main() -> EmulatorResult<()> {
|
fn main() -> EmulatorResult<()> {
|
||||||
SimpleLogger::new().with_level(LevelFilter::Info).env().init().unwrap();
|
SimpleLogger::new().with_level(LevelFilter::Info).env().init().unwrap();
|
||||||
let Porcel8ProgramArgs { filename, new_chip8_behaviour,draw_scale } = Porcel8ProgramArgs::parse();
|
let Porcel8ProgramArgs { filename, new_chip8_behaviour,draw_scale } = Porcel8ProgramArgs::parse();
|
||||||
log::info!("Started emulator");
|
log::info!("Started emulator");
|
||||||
|
|
||||||
let mut timer = TimerManager::new();
|
|
||||||
|
|
||||||
|
|
||||||
let (mut canvas, mut event_pump,audio_queue) = try_initiate_sdl(draw_scale)?;
|
let (mut canvas, mut event_pump,audio_queue) = try_initiate_sdl(draw_scale)?;
|
||||||
|
|
||||||
let audio_state = timer.start();
|
let (mut timer,mut sdl_aud_adapter) = SdlAudioAdapter::new_timers(440.0,0.85,audio_queue);
|
||||||
|
|
||||||
let mut sdl_aud_adapter = SdlAudioAdapter::new(audio_state,440.0,0.85,audio_queue);
|
|
||||||
|
|
||||||
|
|
||||||
let (frame_buffer_for_display, frame_buffer_for_device) = get_frame_buffer_references();
|
let (frame_buffer_for_display, frame_buffer_for_device) = get_frame_buffer_references();
|
||||||
let (sdl_kb_adapter, device_keyboard) = SdlKeyboardAdapter::new_keyboard();
|
let (sdl_kb_adapter, device_keyboard) = SdlKeyboardAdapter::new_keyboard();
|
||||||
|
|
||||||
let (device_termination_signal_sender, device_termination_signal_sender_receiver) = std::sync::mpsc::channel();
|
let (device_termination_signal_sender, device_termination_signal_sender_receiver) = std::sync::mpsc::channel();
|
||||||
|
|
||||||
|
timer.start();
|
||||||
let compute_handle = thread::Builder::new().name("Compute".to_string()).spawn(move || {
|
let compute_handle = thread::Builder::new().name("Compute".to_string()).spawn(move || {
|
||||||
do_device_loop(timer, frame_buffer_for_device, device_termination_signal_sender_receiver, device_keyboard, filename, new_chip8_behaviour);
|
do_device_loop(timer, frame_buffer_for_device, device_termination_signal_sender_receiver, device_keyboard, filename, new_chip8_behaviour);
|
||||||
})?;
|
})?;
|
||||||
@@ -100,7 +95,7 @@ fn main() -> EmulatorResult<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_device_loop(timer: TimerManager, frame_buffer: Arc<Mutex<Box<[bool; 2048]>>>, receiver: Receiver<()>, device_keyboard: Keyboard, rom_file_location_option: Option<String>, new_chip_behaviour: bool) {
|
fn do_device_loop(timer: DeviceTimerManager, frame_buffer: Arc<Mutex<Box<[bool; 2048]>>>, receiver: Receiver<()>, device_keyboard: Keyboard, rom_file_location_option: Option<String>, new_chip_behaviour: bool) {
|
||||||
let mut device = Device::new(timer, frame_buffer, device_keyboard, new_chip_behaviour);
|
let mut device = Device::new(timer, frame_buffer, device_keyboard, new_chip_behaviour);
|
||||||
device.set_default_font();
|
device.set_default_font();
|
||||||
|
|
||||||
|
3
src/sdl_adapters/mod.rs
Normal file
3
src/sdl_adapters/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub mod sdl_graphics_adapter;
|
||||||
|
pub mod sdl_audio_adapter;
|
||||||
|
pub mod sdl_keyboard_adapter;
|
@@ -1,28 +1,40 @@
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use sdl2::audio::AudioQueue;
|
use sdl2::audio::AudioQueue;
|
||||||
|
use crate::device::timer::DeviceTimerManager;
|
||||||
use crate::util::EmulatorResult;
|
use crate::util::EmulatorResult;
|
||||||
|
|
||||||
|
/// An Audio adapter using `AudioQueue`. Generates a square wave of specified frequency
|
||||||
pub struct SdlAudioAdapter {
|
pub struct SdlAudioAdapter {
|
||||||
sound_timer: Arc<Mutex<u8>>,
|
sound_timer: Arc<Mutex<u8>>,
|
||||||
phase_inc: f32,
|
phase_inc: f32,
|
||||||
phase: f32,
|
phase: f32,
|
||||||
volume: f32,
|
volume: f32,
|
||||||
audio_queue: AudioQueue<f32>,
|
audio_queue: AudioQueue<f32>,
|
||||||
buf: Vec<f32>,
|
internal_buffer: Vec<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An Audio adapter using `AudioQueue`.
|
|
||||||
impl SdlAudioAdapter {
|
impl SdlAudioAdapter {
|
||||||
|
/// Number of samples per second
|
||||||
pub const SAMPLING_FREQ:i32 = 15360;
|
pub const SAMPLING_FREQ:i32 = 15360;
|
||||||
pub const SAMPLES_PER_FRAME: usize = (Self::SAMPLING_FREQ as usize / 60) * 2;
|
pub const SAMPLES_PER_FRAME: usize = (Self::SAMPLING_FREQ as usize / 60) * 2;
|
||||||
pub fn new(sound_timer: Arc<Mutex<u8>>,
|
pub fn new_timers(freq: f32,
|
||||||
|
volume: f32,
|
||||||
|
audio_queue: AudioQueue<f32>) ->(DeviceTimerManager,SdlAudioAdapter){
|
||||||
|
let device_sound_timer = Arc::new(Mutex::default());
|
||||||
|
let device_timer_manager = DeviceTimerManager::new(device_sound_timer.clone());
|
||||||
|
let sdl_audio_adapter = SdlAudioAdapter::new(device_sound_timer,freq,volume,audio_queue);
|
||||||
|
(device_timer_manager, sdl_audio_adapter)
|
||||||
|
}
|
||||||
|
fn new(sound_timer: Arc<Mutex<u8>>,
|
||||||
freq: f32,
|
freq: f32,
|
||||||
volume: f32,
|
volume: f32,
|
||||||
audio_queue: AudioQueue<f32>) -> SdlAudioAdapter {
|
audio_queue: AudioQueue<f32>) -> SdlAudioAdapter {
|
||||||
audio_queue.resume();
|
audio_queue.resume();
|
||||||
|
// ensure frequency isn't too low
|
||||||
|
assert!(((2.0*freq) as i32) < Self::SAMPLING_FREQ);
|
||||||
SdlAudioAdapter {
|
SdlAudioAdapter {
|
||||||
sound_timer,
|
sound_timer,
|
||||||
buf: vec![0f32; Self::SAMPLES_PER_FRAME],
|
internal_buffer: vec![0f32; Self::SAMPLES_PER_FRAME],
|
||||||
phase: 0f32,
|
phase: 0f32,
|
||||||
phase_inc: freq/Self::SAMPLING_FREQ as f32,
|
phase_inc: freq/Self::SAMPLING_FREQ as f32,
|
||||||
volume,
|
volume,
|
||||||
@@ -37,13 +49,13 @@ impl SdlAudioAdapter {
|
|||||||
};
|
};
|
||||||
if sound_timer>0 && self.audio_queue.size() < Self::SAMPLING_FREQ as u32 {
|
if sound_timer>0 && self.audio_queue.size() < Self::SAMPLING_FREQ as u32 {
|
||||||
self.fill_audio();
|
self.fill_audio();
|
||||||
self.audio_queue.queue_audio(&self.buf)?;
|
self.audio_queue.queue_audio(&self.internal_buffer)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fill_audio(&mut self) {
|
fn fill_audio(&mut self) {
|
||||||
let out = &mut self.buf;
|
let out = &mut self.internal_buffer;
|
||||||
|
|
||||||
// Generate a square wave
|
// Generate a square wave
|
||||||
for x in out.iter_mut() {
|
for x in out.iter_mut() {
|
Reference in New Issue
Block a user