From 3471eb4e8cf950ce41eb9911b25eb1f27c79b6e1 Mon Sep 17 00:00:00 2001 From: transistor Date: Wed, 3 May 2023 22:42:24 -0700 Subject: [PATCH] Removed WindowUpdater and BlitableSurface --- docs/log.txt | 14 ++++ emulator/core/src/host/gfx.rs | 71 +++++++++++-------- emulator/core/src/host/mod.rs | 4 +- emulator/core/src/host/traits.rs | 34 +++------ emulator/frontends/minifb/src/lib.rs | 54 +++++++------- emulator/frontends/pixels/src/frontend.rs | 24 +++---- emulator/peripherals/yamaha/src/sn76489.rs | 4 +- emulator/peripherals/yamaha/src/ym2612.rs | 44 +++++++++--- emulator/systems/computie/src/system.rs | 8 +-- .../genesis/src/peripherals/controllers.rs | 21 ++++-- .../systems/genesis/src/peripherals/ym7101.rs | 14 ++-- emulator/systems/genesis/src/system.rs | 6 +- .../macintosh/src/peripherals/mainboard.rs | 2 +- .../macintosh/src/peripherals/video.rs | 16 ++--- emulator/systems/macintosh/src/system.rs | 6 +- .../systems/trs80/src/peripherals/model1.rs | 18 ++--- emulator/systems/trs80/src/system.rs | 2 +- todo.txt | 8 ++- 18 files changed, 200 insertions(+), 150 deletions(-) diff --git a/docs/log.txt b/docs/log.txt index 11a333b..c3d48c9 100644 --- a/docs/log.txt +++ b/docs/log.txt @@ -387,3 +387,17 @@ General Work - now it actually sounds pretty close for the high pitch tones, but the base tones are completely missing +2023-05-03 +- it still doesn't sound quite right but it's much better. The drum sounds are provided by the DAC + which explains why they aren't working properly. The DAC is not synchronized to the FM output + because the fm output is generated in 1 millisecond batches, so I'll have to change that +- one of the issues that came up was that in C code that has the attack calculation, the same as + detailed on page 28 of the Nemesis forum posts, the result is different. It turns out C is using + arithmetic shift right instead of logical shift right, despite the types of the inputs being + unsigned explicitly, however in rust, it will use the appropriate operation based on the sign of + the strongly typed numbers, so unsigned shift right will insert 0s in the upper bits, which makes + the number result be bigger than the previous version, so the attack phase ends on the first pass. + Forcing the numbers to be signed for the shift in Rust makes it sign-extend the number (insert 1s + because the upper bit is 1), so the number is negative. Even an unsigned addition will result in + the correct number at the end. It's just that shift that caused the issue + diff --git a/emulator/core/src/host/gfx.rs b/emulator/core/src/host/gfx.rs index a3e92b0..2817e85 100644 --- a/emulator/core/src/host/gfx.rs +++ b/emulator/core/src/host/gfx.rs @@ -1,8 +1,8 @@ use std::sync::{Arc, Mutex}; -use crate::host::traits::{BlitableSurface, ClockedQueue, WindowUpdater}; -use crate::ClockTime; use crate::Error; +use crate::ClockTime; +use crate::host::traits::ClockedQueue; pub const MASK_COLOUR: u32 = 0xFFFFFFFF; @@ -62,16 +62,15 @@ impl Frame { pub fn new_shared(width: u32, height: u32, encoding: PixelEncoding) -> Arc> { Arc::new(Mutex::new(Frame::new(width, height, encoding))) } -} -impl BlitableSurface for Frame { - fn set_size(&mut self, width: u32, height: u32) { + pub fn set_size(&mut self, width: u32, height: u32) { self.width = width; self.height = height; self.bitmap.resize((width * height) as usize, 0); } - fn set_pixel(&mut self, pos_x: u32, pos_y: u32, pixel: Pixel) { + #[inline] + pub fn set_pixel(&mut self, pos_x: u32, pos_y: u32, pixel: Pixel) { match pixel { Pixel::Mask => {} value if pos_x < self.width && pos_y < self.height => { @@ -82,7 +81,7 @@ impl BlitableSurface for Frame { } #[inline] - fn set_encoded_pixel(&mut self, pos_x: u32, pos_y: u32, pixel: u32) { + pub fn set_encoded_pixel(&mut self, pos_x: u32, pos_y: u32, pixel: u32) { match pixel { MASK_COLOUR => { }, value if pos_x < self.width && pos_y < self.height => { @@ -92,7 +91,7 @@ impl BlitableSurface for Frame { } } - fn blit>(&mut self, pos_x: u32, pos_y: u32, mut bitmap: B, width: u32, height: u32) { + pub fn blit>(&mut self, pos_x: u32, pos_y: u32, mut bitmap: B, width: u32, height: u32) { for y in pos_y..(pos_y + height) { for x in pos_x..(pos_x + width) { match bitmap.next().unwrap() { @@ -106,20 +105,35 @@ impl BlitableSurface for Frame { } } - fn clear(&mut self, value: Pixel) { + pub fn clear(&mut self, value: Pixel) { let value = value.encode(self.encoding); self.bitmap.iter_mut().for_each(|pixel| *pixel = value); } } -#[derive(Clone)] -pub struct FrameQueue { +pub fn frame_queue(width: u32, height: u32) -> (FrameSender, FrameReceiver) { + let sender = FrameSender { + max_size: (width, height), + encoding: Arc::new(Mutex::new(PixelEncoding::RGBA)), + queue: Default::default(), + }; + + let receiver = FrameReceiver { + max_size: (width, height), + encoding: sender.encoding.clone(), + queue: sender.queue.clone(), + }; + + (sender, receiver) +} + +pub struct FrameSender { max_size: (u32, u32), encoding: Arc>, queue: ClockedQueue, } -impl FrameQueue { +impl FrameSender { pub fn new(width: u32, height: u32) -> Self { Self { max_size: (width, height), @@ -128,31 +142,32 @@ impl FrameQueue { } } - pub fn encoding(&mut self) -> PixelEncoding { + pub fn encoding(&self) -> PixelEncoding { *self.encoding.lock().unwrap() } pub fn add(&self, clock: ClockTime, frame: Frame) { self.queue.push(clock, frame); } +} + +pub struct FrameReceiver { + max_size: (u32, u32), + encoding: Arc>, + queue: ClockedQueue, +} + +impl FrameReceiver { + pub fn max_size(&self) -> (u32, u32) { + self.max_size + } + + pub fn request_encoding(&self, encoding: PixelEncoding) { + *self.encoding.lock().unwrap() = encoding; + } pub fn latest(&self) -> Option<(ClockTime, Frame)> { self.queue.pop_latest() } } -impl WindowUpdater for FrameQueue { - fn max_size(&self) -> (u32, u32) { - self.max_size - } - - fn request_encoding(&mut self, encoding: PixelEncoding) { - *self.encoding.lock().unwrap() = encoding; - } - - fn take_frame(&mut self) -> Result { - self.latest() - .map(|(_, f)| f) - .ok_or_else(|| Error::new("No frame available")) - } -} diff --git a/emulator/core/src/host/mod.rs b/emulator/core/src/host/mod.rs index 832b45d..0e051ea 100644 --- a/emulator/core/src/host/mod.rs +++ b/emulator/core/src/host/mod.rs @@ -5,9 +5,9 @@ mod gfx; mod controllers; mod mouse; -pub use self::gfx::{Pixel, PixelEncoding, Frame, FrameQueue}; +pub use self::gfx::{Pixel, PixelEncoding, Frame, FrameSender, FrameReceiver, frame_queue}; pub use self::keys::{Key, KeyEvent}; pub use self::mouse::{MouseButton, MouseEventType, MouseEvent, MouseState}; pub use self::controllers::{ControllerDevice, ControllerEvent}; -pub use self::traits::{Host, Tty, WindowUpdater, ControllerUpdater, KeyboardUpdater, MouseUpdater, Audio, BlitableSurface, HostData, ClockedQueue, DummyAudio}; +pub use self::traits::{Host, Tty, ControllerUpdater, KeyboardUpdater, MouseUpdater, Audio, HostData, ClockedQueue, DummyAudio}; diff --git a/emulator/core/src/host/traits.rs b/emulator/core/src/host/traits.rs index cb694b0..85d8ca6 100644 --- a/emulator/core/src/host/traits.rs +++ b/emulator/core/src/host/traits.rs @@ -3,20 +3,24 @@ use std::collections::VecDeque; use std::sync::{Arc, Mutex, MutexGuard}; use crate::{ClockTime, Error}; -use crate::host::gfx::{PixelEncoding, Pixel, Frame}; +use crate::host::gfx::{PixelEncoding, Pixel, Frame, FrameReceiver}; use crate::host::keys::KeyEvent; use crate::host::controllers::{ControllerDevice, ControllerEvent}; use crate::host::mouse::MouseEvent; pub trait Host { - fn create_pty(&self) -> Result, Error> { + fn add_pty(&self) -> Result, Error> { Err(Error::new("This frontend doesn't support PTYs")) } - fn add_window(&mut self, _updater: Box) -> Result<(), Error> { + fn add_video_source(&mut self, _receiver: FrameReceiver) -> Result<(), Error> { Err(Error::new("This frontend doesn't support windows")) } + fn add_audio_source(&mut self) -> Result, Error> { + Err(Error::new("This frontend doesn't support the sound")) + } + fn register_controller(&mut self, _device: ControllerDevice, _input: Box) -> Result<(), Error> { Err(Error::new("This frontend doesn't support game controllers")) } @@ -28,10 +32,6 @@ pub trait Host { fn register_mouse(&mut self, _input: Box) -> Result<(), Error> { Err(Error::new("This frontend doesn't support the mouse")) } - - fn create_audio_source(&mut self) -> Result, Error> { - Err(Error::new("This frontend doesn't support the sound")) - } } @@ -41,22 +41,16 @@ pub trait Tty { fn write(&mut self, output: u8) -> bool; } -pub trait WindowUpdater: Send { - fn max_size(&self) -> (u32, u32); - fn request_encoding(&mut self, encoding: PixelEncoding); - fn take_frame(&mut self) -> Result; -} - pub trait ControllerUpdater: Send { - fn update_controller(&mut self, event: ControllerEvent); + fn update_controller(&self, event: ControllerEvent); } pub trait KeyboardUpdater: Send { - fn update_keyboard(&mut self, event: KeyEvent); + fn update_keyboard(&self, event: KeyEvent); } pub trait MouseUpdater: Send { - fn update_mouse(&mut self, event: MouseEvent); + fn update_mouse(&self, event: MouseEvent); } pub trait Audio { @@ -66,14 +60,6 @@ pub trait Audio { fn flush(&mut self); } -pub trait BlitableSurface { - fn set_size(&mut self, width: u32, height: u32); - fn set_pixel(&mut self, pos_x: u32, pos_y: u32, pixel: Pixel); - fn set_encoded_pixel(&mut self, pos_x: u32, pos_y: u32, pixel: u32); - fn blit>(&mut self, pos_x: u32, pos_y: u32, bitmap: B, width: u32, height: u32); - fn clear(&mut self, value: Pixel); -} - #[derive(Clone, Debug)] pub struct HostData(Arc>); diff --git a/emulator/frontends/minifb/src/lib.rs b/emulator/frontends/minifb/src/lib.rs index 487f9b8..ffaeb3d 100644 --- a/emulator/frontends/minifb/src/lib.rs +++ b/emulator/frontends/minifb/src/lib.rs @@ -8,7 +8,7 @@ use minifb::{self, Key, MouseMode, MouseButton}; use clap::{App, Arg, ArgMatches}; use moa_core::{System, Error, ClockDuration}; -use moa_core::host::{Host, ControllerUpdater, KeyboardUpdater, KeyEvent, MouseUpdater, MouseState, WindowUpdater, Audio, ControllerDevice, PixelEncoding, Frame}; +use moa_core::host::{Host, ControllerUpdater, KeyboardUpdater, KeyEvent, MouseUpdater, MouseState, Audio, ControllerDevice, PixelEncoding, Frame, FrameReceiver}; use moa_common::{AudioMixer, AudioSource}; use moa_common::CpalAudioOutput; @@ -95,18 +95,18 @@ fn wait_until_initialized(frontend: Arc>) { pub struct MiniFrontendBuilder { - pub window: Option>, - pub controller: Option>, - pub keyboard: Option>, - pub mouse: Option>, - pub mixer: Option>>, - pub finalized: bool, + video: Option, + controller: Option>, + keyboard: Option>, + mouse: Option>, + mixer: Option>>, + finalized: bool, } impl Default for MiniFrontendBuilder { fn default() -> Self { Self { - window: None, + video: None, controller: None, keyboard: None, mouse: None, @@ -122,24 +122,29 @@ impl MiniFrontendBuilder { } pub fn build(&mut self) -> MiniFrontend { - let window = std::mem::take(&mut self.window); + let video = std::mem::take(&mut self.video); let controller = std::mem::take(&mut self.controller); let keyboard = std::mem::take(&mut self.keyboard); let mouse = std::mem::take(&mut self.mouse); let mixer = std::mem::take(&mut self.mixer); - MiniFrontend::new(window, controller, keyboard, mouse, mixer.unwrap()) + MiniFrontend::new(video, controller, keyboard, mouse, mixer.unwrap()) } } impl Host for MiniFrontendBuilder { - fn add_window(&mut self, updater: Box) -> Result<(), Error> { - if self.window.is_some() { - return Err(Error::new("A window updater has already been registered with the frontend")); + fn add_video_source(&mut self, receiver: FrameReceiver) -> Result<(), Error> { + if self.video.is_some() { + return Err(Error::new("Only one video source can be registered with this frontend")); } - self.window = Some(updater); + self.video = Some(receiver); Ok(()) } + fn add_audio_source(&mut self) -> Result, Error> { + let source = AudioSource::new(self.mixer.as_ref().unwrap().clone()); + Ok(Box::new(source)) + } + fn register_controller(&mut self, device: ControllerDevice, input: Box) -> Result<(), Error> { if device != ControllerDevice::A { return Ok(()) @@ -167,18 +172,13 @@ impl Host for MiniFrontendBuilder { self.mouse = Some(input); Ok(()) } - - fn create_audio_source(&mut self) -> Result, Error> { - let source = AudioSource::new(self.mixer.as_ref().unwrap().clone()); - Ok(Box::new(source)) - } } pub struct MiniFrontend { pub modifiers: u16, pub mouse_state: MouseState, - pub window: Option>, + pub video: Option, pub controller: Option>, pub keyboard: Option>, pub mouse: Option>, @@ -188,7 +188,7 @@ pub struct MiniFrontend { impl MiniFrontend { pub fn new( - window: Option>, + video: Option, controller: Option>, keyboard: Option>, mouse: Option>, @@ -197,7 +197,7 @@ impl MiniFrontend { Self { modifiers: 0, mouse_state: Default::default(), - window, + video, controller, keyboard, mouse, @@ -239,9 +239,9 @@ impl MiniFrontend { }; let mut size = (WIDTH, HEIGHT); - if let Some(updater) = self.window.as_mut() { - size = updater.max_size(); - updater.request_encoding(PixelEncoding::ARGB); + if let Some(queue) = self.video.as_mut() { + size = queue.max_size(); + queue.request_encoding(PixelEncoding::ARGB); } let mut window = minifb::Window::new( @@ -306,8 +306,8 @@ impl MiniFrontend { } } - if let Some(updater) = self.window.as_mut() { - if let Ok(frame) = updater.take_frame() { + if let Some(queue) = self.video.as_mut() { + if let Some((clock, frame)) = queue.latest() { last_frame = frame } window.update_with_buffer(&last_frame.bitmap, last_frame.width as usize, last_frame.height as usize).unwrap(); diff --git a/emulator/frontends/pixels/src/frontend.rs b/emulator/frontends/pixels/src/frontend.rs index 247a653..42bba1a 100644 --- a/emulator/frontends/pixels/src/frontend.rs +++ b/emulator/frontends/pixels/src/frontend.rs @@ -7,7 +7,7 @@ use winit::event::{Event, VirtualKeyCode, WindowEvent, ElementState}; use winit::event_loop::{ControlFlow, EventLoop}; use moa_core::{System, Error}; -use moa_core::host::{Host, PixelEncoding, Frame, WindowUpdater, ControllerDevice, ControllerEvent, ControllerUpdater, Audio, DummyAudio}; +use moa_core::host::{Host, PixelEncoding, Frame, ControllerDevice, ControllerEvent, ControllerUpdater, Audio, DummyAudio, FrameReceiver}; use moa_common::{AudioMixer, AudioSource, CpalAudioOutput}; use crate::settings; @@ -20,7 +20,7 @@ pub const HEIGHT: u32 = 224; pub type LoadSystemFn = fn (&mut PixelsFrontend, Vec) -> Result; pub struct PixelsFrontend { - updater: Option>, + video: Option, controller: Option>, //mixer: Arc>, //audio_output: CpalAudioOutput, @@ -33,8 +33,8 @@ impl PixelsFrontend { //let audio_output = CpalAudioOutput::create_audio_output(mixer.lock().unwrap().get_sink()); PixelsFrontend { + video: None, controller: None, - updater: None, //mixer, //audio_output, } @@ -42,8 +42,8 @@ impl PixelsFrontend { } impl Host for PixelsFrontend { - fn add_window(&mut self, updater: Box) -> Result<(), Error> { - self.updater = Some(updater); + fn add_video_source(&mut self, receiver: FrameReceiver) -> Result<(), Error> { + self.video = Some(receiver); Ok(()) } @@ -56,20 +56,20 @@ impl Host for PixelsFrontend { Ok(()) } - fn create_audio_source(&mut self) -> Result, Error> { + fn add_audio_source(&mut self) -> Result, Error> { //let source = AudioSource::new(self.mixer.clone()); //Ok(Box::new(source)) Ok(Box::new(DummyAudio())) } } -pub async fn run_loop(mut host: PixelsFrontend) { +pub async fn run_loop(host: PixelsFrontend) { let event_loop = EventLoop::new(); let window = create_window(&event_loop); - if let Some(updater) = host.updater.as_mut() { - updater.request_encoding(PixelEncoding::ABGR); + if let Some(recevier) = host.video.as_ref() { + recevier.request_encoding(PixelEncoding::ABGR); } let mut pixels = { @@ -93,8 +93,8 @@ pub async fn run_loop(mut host: PixelsFrontend) { //log::warn!("updated after {:4}ms", update_timer.elapsed().as_millis()); //update_timer = Instant::now(); - if let Some(updater) = host.updater.as_mut() { - if let Ok(frame) = updater.take_frame() { + if let Some(updater) = host.video.as_ref() { + if let Some((clock, frame)) = updater.latest() { last_frame = frame; } @@ -131,7 +131,7 @@ pub async fn run_loop(mut host: PixelsFrontend) { } }; - if let Some(updater) = host.controller.as_mut() { + if let Some(updater) = host.controller.as_ref() { if let Some(key) = key { updater.update_controller(key); } diff --git a/emulator/peripherals/yamaha/src/sn76489.rs b/emulator/peripherals/yamaha/src/sn76489.rs index f70ea6d..eba4643 100644 --- a/emulator/peripherals/yamaha/src/sn76489.rs +++ b/emulator/peripherals/yamaha/src/sn76489.rs @@ -94,8 +94,8 @@ pub struct Sn76489 { } impl Sn76489 { - pub fn create(host: &mut H, clock_frequency: Frequency) -> Result { - let source = host.create_audio_source()?; + pub fn new(host: &mut H, clock_frequency: Frequency) -> Result { + let source = host.add_audio_source()?; let sample_rate = source.samples_per_second(); Ok(Self { diff --git a/emulator/peripherals/yamaha/src/ym2612.rs b/emulator/peripherals/yamaha/src/ym2612.rs index d4c2134..f0de109 100644 --- a/emulator/peripherals/yamaha/src/ym2612.rs +++ b/emulator/peripherals/yamaha/src/ym2612.rs @@ -5,14 +5,14 @@ //! source code that emulates the chip. It is still very much a work in progress //! //! Resources: -//! - Registers: https://www.smspower.org/maxim/Documents/YM2612 -//! - Internal Implementation: https://gendev.spritesmind.net/forum/viewtopic.php?t=386 [Nemesis] +//! - Registers: +//! - Internal Implementation: (Nemesis) //! * Envelope Generator and Corrections: -//! http://gendev.spritesmind.net/forum/viewtopic.php?p=5716#5716 -//! http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc&start=417 +//! +//! //! * Phase Generator and Output: -//! http://gendev.spritesmind.net/forum/viewtopic.php?f=24&t=386&start=150 -//! http://gendev.spritesmind.net/forum/viewtopic.php?p=6224#6224 +//! +//! use std::f32; use std::num::NonZeroU8; @@ -262,6 +262,9 @@ impl EnvelopeGenerator { } else { self.envelope_state = EnvelopeState::Release; } +//if self.debug_name == "ch 2, op 1" { +//println!("change: {} {:?} {}", state, self.envelope_state, self.envelope); +//} } fn update_envelope(&mut self, envelope_clock: EnvelopeClock, rate_adjust: usize) { @@ -272,13 +275,24 @@ impl EnvelopeGenerator { let rate = self.get_scaled_rate(self.envelope_state, rate_adjust); let counter_shift = COUNTER_SHIFT_VALUES[rate]; +//if self.debug_name == "ch 2, op 0" { +//println!("{:4x} {:4x} {:4x}", envelope_clock, counter_shift, envelope_clock % (1 << counter_shift)); +//} if envelope_clock % (1 << counter_shift) == 0 { let update_cycle = (envelope_clock >> counter_shift) & 0x07; let increment = RATE_TABLE[rate * 8 + update_cycle as usize]; match self.envelope_state { EnvelopeState::Attack => { - let new_envelope = self.envelope + ((!self.envelope * increment) >> 4) & 0xFFC; + // NOTE: the adjustment added to the envelope is negative, but the envelope is an unsigned number, so + // it's converted to signed to ensure an arithmetic (sign-extending) shift right is used. The addition + // will work the same regardless due to the magic of two's complement numbers. It would have also worked + // to bitwise-and with 0xFFC instead, which will wrap the number to a 12-bit signed number, which when + // clamped to MAX_ENVELOPE will produce the same results + let new_envelope = self.envelope + (((!self.envelope * increment) as i16) >> 4) as u16; +if self.debug_name == "ch 2, op 0" { +println!("{:4x} {:4x} {:4x} {:4x} {:4x}", self.envelope, update_cycle, rate * 8 + update_cycle as usize, (((!self.envelope * increment) as i16) >> 4) as u16 & 0xFFFC, new_envelope); +} if new_envelope > self.envelope { self.envelope_state = EnvelopeState::Decay; self.envelope = 0; @@ -296,6 +310,9 @@ impl EnvelopeGenerator { } }, } +//if self.debug_name == "ch 2, op 0" { +//println!("{:4x} {:4x} {:4x} {:4x} {:4x}", rate, counter_shift, self.envelope_state as usize, increment, self.envelope); +//} } } @@ -506,6 +523,10 @@ impl Operator { let mod_phase = phase + modulator; +//if self.debug_name == "ch 2, op 0" { +//println!("{:4x} = {:4x} + {:4x} + {:4x}, e: {:x}, {:4x} {:4x}", mod_phase, phase, self.phase.increment, modulator, self.envelope.envelope_state as usize, envelope, self.envelope.envelope); +//} + // The sine table contains the first half of the wave as an attenuation value // Use the phase with the sign truncated to get the attenuation, plus the // attenuation from the envelope, to get the total attenuation at this point @@ -601,7 +622,9 @@ impl Channel { //let output = sign_extend_u16(output, 14); //let output = output * 2 / 3; - +//if self.debug_name == "ch 2" { +//println!("{:6x}", output); +//} let sample = output as f32 / (1 << 13) as f32; let left = if self.enabled.0 { sample } else { 0.0 }; @@ -726,8 +749,8 @@ pub struct Ym2612 { } impl Ym2612 { - pub fn create(host: &mut H, clock_frequency: Frequency) -> Result { - let source = host.create_audio_source()?; + pub fn new(host: &mut H, clock_frequency: Frequency) -> Result { + let source = host.add_audio_source()?; let fm_clock = clock_frequency / (6 * 24); let fm_clock_period = fm_clock.period_duration(); @@ -817,6 +840,7 @@ impl Ym2612 { pub fn set_register(&mut self, clock: ClockTime, bank: u8, reg: u8, data: u8) { // Keep a copy for debugging purposes, and if the original values are needed self.registers[bank as usize * 256 + reg as usize] = data; + //println!("set {:x} to {:x}", bank as usize * 256 + reg as usize, data); //warn!("{}: set reg {}{:x} to {:x}", DEV_NAME, bank, reg, data); match reg { diff --git a/emulator/systems/computie/src/system.rs b/emulator/systems/computie/src/system.rs index 33d17c0..36ccf54 100644 --- a/emulator/systems/computie/src/system.rs +++ b/emulator/systems/computie/src/system.rs @@ -22,8 +22,8 @@ pub fn build_computie(host: &H) -> Result { system.add_addressable_device(0x00600000, wrap_transmutable(ata))?; let mut serial = MC68681::default(); - launch_terminal_emulator(serial.port_a.connect(host.create_pty()?)?); - launch_slip_connection(serial.port_b.connect(host.create_pty()?)?); + launch_terminal_emulator(serial.port_a.connect(host.add_pty()?)?); + launch_slip_connection(serial.port_b.connect(host.add_pty()?)?); system.add_addressable_device(0x00700000, wrap_transmutable(serial))?; @@ -60,8 +60,8 @@ pub fn build_computie_k30(host: &H) -> Result { system.add_addressable_device(0x00600000, wrap_transmutable(ata))?; let mut serial = MC68681::default(); - launch_terminal_emulator(serial.port_a.connect(host.create_pty()?)?); - //launch_slip_connection(serial.port_b.connect(host.create_pty()?)?); + launch_terminal_emulator(serial.port_a.connect(host.add_pty()?)?); + //launch_slip_connection(serial.port_b.connect(host.add_pty()?)?); system.add_addressable_device(0x00700000, wrap_transmutable(serial))?; diff --git a/emulator/systems/genesis/src/peripherals/controllers.rs b/emulator/systems/genesis/src/peripherals/controllers.rs index f5d966b..bc68151 100644 --- a/emulator/systems/genesis/src/peripherals/controllers.rs +++ b/emulator/systems/genesis/src/peripherals/controllers.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use std::sync::atomic::{AtomicU16, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU16, Ordering}; use moa_core::{warn, info}; use moa_core::{System, Error, ClockTime, ClockDuration, Address, Addressable, Steppable, Transmutable}; @@ -88,10 +88,10 @@ impl GenesisControllerPort { } } -pub struct GenesisControllersUpdater(Arc, HostData); +pub struct GenesisControllersUpdater(Arc, Arc); impl ControllerUpdater for GenesisControllersUpdater { - fn update_controller(&mut self, event: ControllerEvent) { + fn update_controller(&self, event: ControllerEvent) { let (mask, state) = match event { ControllerEvent::ButtonA(state) => (0x0040, state), ControllerEvent::ButtonB(state) => (0x0010, state), @@ -108,7 +108,7 @@ impl ControllerUpdater for GenesisControllersUpdater { let buttons = (self.0.load(Ordering::Acquire) & !mask) | (if !state { mask } else { 0 }); self.0.store(buttons, Ordering::Release); if buttons != 0 { - self.1.set(true); + self.1.store(true, Ordering::Release); } } } @@ -119,6 +119,7 @@ pub struct GenesisControllers { port_1: GenesisControllerPort, port_2: GenesisControllerPort, expansion: GenesisControllerPort, + has_changed: Arc, interrupt: HostData, reset_timer: ClockDuration, } @@ -129,6 +130,7 @@ impl Default for GenesisControllers { port_1: GenesisControllerPort::default(), port_2: GenesisControllerPort::default(), expansion: GenesisControllerPort::default(), + has_changed: Arc::new(AtomicBool::new(false)), interrupt: HostData::new(false), reset_timer: ClockDuration::ZERO, } @@ -136,12 +138,12 @@ impl Default for GenesisControllers { } impl GenesisControllers { - pub fn create(host: &mut H) -> Result { + pub fn new(host: &mut H) -> Result { let controller = GenesisControllers::default(); - let controller1 = Box::new(GenesisControllersUpdater(controller.port_1.buttons.clone(), controller.interrupt.clone())); + let controller1 = Box::new(GenesisControllersUpdater(controller.port_1.buttons.clone(), controller.has_changed.clone())); host.register_controller(ControllerDevice::A, controller1)?; - let controller2 = Box::new(GenesisControllersUpdater(controller.port_2.buttons.clone(), controller.interrupt.clone())); + let controller2 = Box::new(GenesisControllersUpdater(controller.port_2.buttons.clone(), controller.has_changed.clone())); host.register_controller(ControllerDevice::B, controller2)?; Ok(controller) @@ -206,6 +208,11 @@ impl Steppable for GenesisControllers { fn step(&mut self, _system: &System) -> Result { let duration = ClockDuration::from_micros(100); // Update every 100us + if self.has_changed.load(Ordering::Acquire) { + self.has_changed.store(false, Ordering::Release); + self.interrupt.set(true); + } + self.reset_timer += duration; if self.reset_timer >= ClockDuration::from_micros(1_500) { self.port_1.reset_count(); diff --git a/emulator/systems/genesis/src/peripherals/ym7101.rs b/emulator/systems/genesis/src/peripherals/ym7101.rs index 75cbb12..382d30d 100644 --- a/emulator/systems/genesis/src/peripherals/ym7101.rs +++ b/emulator/systems/genesis/src/peripherals/ym7101.rs @@ -1,7 +1,7 @@ use moa_core::{debug, warn, error}; use moa_core::{System, Error, EdgeSignal, ClockTime, ClockDuration, Frequency, Address, Addressable, Steppable, Inspectable, Transmutable, TransmutableBox, read_beu16, dump_slice}; -use moa_core::host::{Host, Pixel, PixelEncoding, Frame, FrameQueue, BlitableSurface, HostData}; +use moa_core::host::{self, Host, Pixel, PixelEncoding, Frame, FrameSender, HostData}; const REG_MODE_SET_1: usize = 0x00; @@ -659,9 +659,9 @@ impl Steppable for Ym7101 { } if (self.state.mode_1 & MODE1_BF_DISABLE_DISPLAY) == 0 { - let mut frame = Frame::new(self.state.screen_size.0 as u32 * 8, self.state.screen_size.1 as u32 * 8, self.queue.encoding()); + let mut frame = Frame::new(self.state.screen_size.0 as u32 * 8, self.state.screen_size.1 as u32 * 8, self.sender.encoding()); self.state.draw_frame(&mut frame); - self.queue.add(system.clock, frame); + self.sender.add(system.clock, frame); } self.frame_complete.signal(); @@ -681,7 +681,7 @@ impl Steppable for Ym7101 { pub struct Ym7101 { - queue: FrameQueue, + sender: FrameSender, state: Ym7101State, sn_sound: TransmutableBox, @@ -691,11 +691,11 @@ pub struct Ym7101 { impl Ym7101 { pub fn new(host: &mut H, external_interrupt: HostData, sn_sound: TransmutableBox) -> Ym7101 { - let queue = FrameQueue::new(320, 224); - host.add_window(Box::new(queue.clone())).unwrap(); + let (sender, receiver) = host::frame_queue(320, 224); + host.add_video_source(receiver).unwrap(); Ym7101 { - queue, + sender, state: Ym7101State::default(), sn_sound, external_interrupt, diff --git a/emulator/systems/genesis/src/system.rs b/emulator/systems/genesis/src/system.rs index c15574d..cbf6e10 100644 --- a/emulator/systems/genesis/src/system.rs +++ b/emulator/systems/genesis/src/system.rs @@ -70,8 +70,8 @@ pub fn build_genesis(host: &mut H, mut options: SegaGenesisOptions) -> // Build the Coprocessor's Bus let bank_register = Signal::new(0); let coproc_ram = wrap_transmutable(MemoryBlock::new(vec![0; 0x00002000])); - let coproc_ym_sound = wrap_transmutable(Ym2612::create(host, Frequency::from_hz(7_670_454))?); - let coproc_sn_sound = wrap_transmutable(Sn76489::create(host, Frequency::from_hz(3_579_545))?); + let coproc_ym_sound = wrap_transmutable(Ym2612::new(host, Frequency::from_hz(7_670_454))?); + let coproc_sn_sound = wrap_transmutable(Sn76489::new(host, Frequency::from_hz(3_579_545))?); let coproc_register = wrap_transmutable(CoprocessorBankRegister::new(bank_register.clone())); let coproc_area = wrap_transmutable(CoprocessorBankArea::new(bank_register, system.bus.clone())); @@ -98,7 +98,7 @@ pub fn build_genesis(host: &mut H, mut options: SegaGenesisOptions) -> system.add_device("coproc", wrap_transmutable(coproc))?; - let controllers = GenesisControllers::create(host)?; + let controllers = GenesisControllers::new(host)?; let interrupt = controllers.get_interrupt_signal(); system.add_addressable_device(0x00a10000, wrap_transmutable(controllers)).unwrap(); diff --git a/emulator/systems/macintosh/src/peripherals/mainboard.rs b/emulator/systems/macintosh/src/peripherals/mainboard.rs index af3929b..d1407ae 100644 --- a/emulator/systems/macintosh/src/peripherals/mainboard.rs +++ b/emulator/systems/macintosh/src/peripherals/mainboard.rs @@ -22,7 +22,7 @@ pub struct Mainboard { } impl Mainboard { - pub fn create(ram: TransmutableBox, rom: TransmutableBox) -> Result { + pub fn new(ram: TransmutableBox, rom: TransmutableBox) -> Result { let scc1 = Z8530::default(); let scc2 = Z8530::default(); let iwm = IWM::default(); diff --git a/emulator/systems/macintosh/src/peripherals/video.rs b/emulator/systems/macintosh/src/peripherals/video.rs index 9f3326f..7cd93ea 100644 --- a/emulator/systems/macintosh/src/peripherals/video.rs +++ b/emulator/systems/macintosh/src/peripherals/video.rs @@ -1,23 +1,23 @@ use moa_core::{System, Error, ClockDuration, Address, Addressable, Steppable, Transmutable}; -use moa_core::host::{Host, BlitableSurface, Frame, FrameQueue, Pixel}; +use moa_core::host::{self, Host, Frame, FrameSender, Pixel}; const SCRN_BASE: u32 = 0x07A700; const SCRN_SIZE: (u32, u32) = (512, 342); pub struct MacVideo { - frame_queue: FrameQueue, + frame_sender: FrameSender, } impl MacVideo { - pub fn create(host: &mut H) -> Result { - let frame_queue = FrameQueue::new(SCRN_SIZE.0, SCRN_SIZE.1); + pub fn new(host: &mut H) -> Result { + let (frame_sender, frame_receiver) = host::frame_queue(SCRN_SIZE.0, SCRN_SIZE.1); - host.add_window(Box::new(frame_queue.clone()))?; + host.add_video_source(frame_receiver)?; Ok(Self { - frame_queue, + frame_sender, }) } } @@ -58,7 +58,7 @@ impl Iterator for BitIter { impl Steppable for MacVideo { fn step(&mut self, system: &System) -> Result { let mut memory = system.get_bus(); - let mut frame = Frame::new(SCRN_SIZE.0, SCRN_SIZE.1, self.frame_queue.encoding()); + let mut frame = Frame::new(SCRN_SIZE.0, SCRN_SIZE.1, self.frame_sender.encoding()); for y in 0..SCRN_SIZE.1 { for x in 0..(SCRN_SIZE.0 / 16) { let word = memory.read_beu16(system.clock, (SCRN_BASE + (x * 2) + (y * (SCRN_SIZE.0 / 8))) as Address)?; @@ -66,7 +66,7 @@ impl Steppable for MacVideo { } } - self.frame_queue.add(system.clock, frame); + self.frame_sender.add(system.clock, frame); Ok(ClockDuration::from_micros(16_600)) } } diff --git a/emulator/systems/macintosh/src/system.rs b/emulator/systems/macintosh/src/system.rs index 4bdb42d..bfb77be 100644 --- a/emulator/systems/macintosh/src/system.rs +++ b/emulator/systems/macintosh/src/system.rs @@ -32,7 +32,7 @@ pub fn build_macintosh_512k(host: &mut H) -> Result { let misc = MemoryBlock::new(vec![0; 0x100000]); system.add_addressable_device(0x00f00000, wrap_transmutable(misc))?; - let video = MacVideo::create(host)?; + let video = MacVideo::new(host)?; system.add_device("video", wrap_transmutable(video)).unwrap(); let scc1 = Z8530::new(); @@ -62,10 +62,10 @@ pub fn build_macintosh_512k(host: &mut H) -> Result { let mut rom = MemoryBlock::load("binaries/macintosh/Macintosh 512k.rom")?; rom.read_only(); - let video = MacVideo::create(host)?; + let video = MacVideo::new(host)?; system.add_device("video", wrap_transmutable(video)).unwrap(); - let mainboard = Mainboard::create(wrap_transmutable(ram), wrap_transmutable(rom))?; + let mainboard = Mainboard::new(wrap_transmutable(ram), wrap_transmutable(rom))?; system.add_addressable_device(0x00000000, wrap_transmutable(mainboard))?; diff --git a/emulator/systems/trs80/src/peripherals/model1.rs b/emulator/systems/trs80/src/peripherals/model1.rs index ebf8ce9..2ce5069 100644 --- a/emulator/systems/trs80/src/peripherals/model1.rs +++ b/emulator/systems/trs80/src/peripherals/model1.rs @@ -2,7 +2,7 @@ use std::sync::{Arc, Mutex}; use moa_core::{System, Error, ClockTime, ClockDuration, Address, Addressable, Steppable, Transmutable, debug, warn}; -use moa_core::host::{Host, Frame, FrameQueue, BlitableSurface, KeyboardUpdater, KeyEvent}; +use moa_core::host::{self, Host, Frame, FrameSender, KeyboardUpdater, KeyEvent}; use super::keymap; use super::charset::CharacterGenerator; @@ -12,21 +12,21 @@ const DEV_NAME: &str = "model1"; const SCREEN_SIZE: (u32, u32) = (384, 128); pub struct Model1Peripherals { - frame_queue: FrameQueue, + frame_sender: FrameSender, keyboard_mem: Arc>, video_mem: [u8; 1024], } impl Model1Peripherals { - pub fn create(host: &mut H) -> Result { - let frame_queue = FrameQueue::new(SCREEN_SIZE.0, SCREEN_SIZE.1); + pub fn new(host: &mut H) -> Result { + let (frame_sender, frame_receiver) = host::frame_queue(SCREEN_SIZE.0, SCREEN_SIZE.1); let keyboard_mem = Arc::new(Mutex::new([0; 8])); - host.add_window(Box::new(frame_queue.clone()))?; + host.add_video_source(frame_receiver)?; host.register_keyboard(Box::new(Model1KeyboardUpdater(keyboard_mem.clone())))?; Ok(Self { - frame_queue, + frame_sender, keyboard_mem, video_mem: [0x20; 1024], }) @@ -36,7 +36,7 @@ impl Model1Peripherals { pub struct Model1KeyboardUpdater(Arc>); impl KeyboardUpdater for Model1KeyboardUpdater { - fn update_keyboard(&mut self, event: KeyEvent) { + fn update_keyboard(&self, event: KeyEvent) { println!(">>> {:?}", event.key); keymap::record_key_press(&mut self.0.lock().unwrap(), event.key, event.state); } @@ -44,7 +44,7 @@ impl KeyboardUpdater for Model1KeyboardUpdater { impl Steppable for Model1Peripherals { fn step(&mut self, system: &System) -> Result { - let mut frame = Frame::new(SCREEN_SIZE.0, SCREEN_SIZE.1, self.frame_queue.encoding()); + let mut frame = Frame::new(SCREEN_SIZE.0, SCREEN_SIZE.1, self.frame_sender.encoding()); for y in 0..16 { for x in 0..64 { let ch = self.video_mem[x + (y * 64)]; @@ -52,7 +52,7 @@ impl Steppable for Model1Peripherals { frame.blit((x * 6) as u32, (y * 8) as u32, iter, 6, 8); } } - self.frame_queue.add(system.clock, frame); + self.frame_sender.add(system.clock, frame); Ok(ClockDuration::from_micros(16_630)) } diff --git a/emulator/systems/trs80/src/system.rs b/emulator/systems/trs80/src/system.rs index dcfec82..56b3113 100644 --- a/emulator/systems/trs80/src/system.rs +++ b/emulator/systems/trs80/src/system.rs @@ -37,7 +37,7 @@ pub fn build_trs80(host: &mut H, options: Trs80Options) -> Result