Removed WindowUpdater and BlitableSurface

This commit is contained in:
transistor 2023-05-03 22:42:24 -07:00
parent 8a8bcb2277
commit 3471eb4e8c
18 changed files with 200 additions and 150 deletions

View File

@ -387,3 +387,17 @@ General Work
- now it actually sounds pretty close for the high pitch tones, but the base tones are completely - now it actually sounds pretty close for the high pitch tones, but the base tones are completely
missing 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

View File

@ -1,8 +1,8 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use crate::host::traits::{BlitableSurface, ClockedQueue, WindowUpdater};
use crate::ClockTime;
use crate::Error; use crate::Error;
use crate::ClockTime;
use crate::host::traits::ClockedQueue;
pub const MASK_COLOUR: u32 = 0xFFFFFFFF; pub const MASK_COLOUR: u32 = 0xFFFFFFFF;
@ -62,16 +62,15 @@ impl Frame {
pub fn new_shared(width: u32, height: u32, encoding: PixelEncoding) -> Arc<Mutex<Frame>> { pub fn new_shared(width: u32, height: u32, encoding: PixelEncoding) -> Arc<Mutex<Frame>> {
Arc::new(Mutex::new(Frame::new(width, height, encoding))) Arc::new(Mutex::new(Frame::new(width, height, encoding)))
} }
}
impl BlitableSurface for Frame { pub fn set_size(&mut self, width: u32, height: u32) {
fn set_size(&mut self, width: u32, height: u32) {
self.width = width; self.width = width;
self.height = height; self.height = height;
self.bitmap.resize((width * height) as usize, 0); 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 { match pixel {
Pixel::Mask => {} Pixel::Mask => {}
value if pos_x < self.width && pos_y < self.height => { value if pos_x < self.width && pos_y < self.height => {
@ -82,7 +81,7 @@ impl BlitableSurface for Frame {
} }
#[inline] #[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 { match pixel {
MASK_COLOUR => { }, MASK_COLOUR => { },
value if pos_x < self.width && pos_y < self.height => { value if pos_x < self.width && pos_y < self.height => {
@ -92,7 +91,7 @@ impl BlitableSurface for Frame {
} }
} }
fn blit<B: Iterator<Item = Pixel>>(&mut self, pos_x: u32, pos_y: u32, mut bitmap: B, width: u32, height: u32) { pub fn blit<B: Iterator<Item = Pixel>>(&mut self, pos_x: u32, pos_y: u32, mut bitmap: B, width: u32, height: u32) {
for y in pos_y..(pos_y + height) { for y in pos_y..(pos_y + height) {
for x in pos_x..(pos_x + width) { for x in pos_x..(pos_x + width) {
match bitmap.next().unwrap() { 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); let value = value.encode(self.encoding);
self.bitmap.iter_mut().for_each(|pixel| *pixel = value); self.bitmap.iter_mut().for_each(|pixel| *pixel = value);
} }
} }
#[derive(Clone)] pub fn frame_queue(width: u32, height: u32) -> (FrameSender, FrameReceiver) {
pub struct FrameQueue { 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), max_size: (u32, u32),
encoding: Arc<Mutex<PixelEncoding>>, encoding: Arc<Mutex<PixelEncoding>>,
queue: ClockedQueue<Frame>, queue: ClockedQueue<Frame>,
} }
impl FrameQueue { impl FrameSender {
pub fn new(width: u32, height: u32) -> Self { pub fn new(width: u32, height: u32) -> Self {
Self { Self {
max_size: (width, height), 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() *self.encoding.lock().unwrap()
} }
pub fn add(&self, clock: ClockTime, frame: Frame) { pub fn add(&self, clock: ClockTime, frame: Frame) {
self.queue.push(clock, frame); self.queue.push(clock, frame);
} }
}
pub struct FrameReceiver {
max_size: (u32, u32),
encoding: Arc<Mutex<PixelEncoding>>,
queue: ClockedQueue<Frame>,
}
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)> { pub fn latest(&self) -> Option<(ClockTime, Frame)> {
self.queue.pop_latest() 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<Frame, Error> {
self.latest()
.map(|(_, f)| f)
.ok_or_else(|| Error::new("No frame available"))
}
}

View File

@ -5,9 +5,9 @@ mod gfx;
mod controllers; mod controllers;
mod mouse; 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::keys::{Key, KeyEvent};
pub use self::mouse::{MouseButton, MouseEventType, MouseEvent, MouseState}; pub use self::mouse::{MouseButton, MouseEventType, MouseEvent, MouseState};
pub use self::controllers::{ControllerDevice, ControllerEvent}; 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};

View File

@ -3,20 +3,24 @@ use std::collections::VecDeque;
use std::sync::{Arc, Mutex, MutexGuard}; use std::sync::{Arc, Mutex, MutexGuard};
use crate::{ClockTime, Error}; 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::keys::KeyEvent;
use crate::host::controllers::{ControllerDevice, ControllerEvent}; use crate::host::controllers::{ControllerDevice, ControllerEvent};
use crate::host::mouse::MouseEvent; use crate::host::mouse::MouseEvent;
pub trait Host { pub trait Host {
fn create_pty(&self) -> Result<Box<dyn Tty>, Error> { fn add_pty(&self) -> Result<Box<dyn Tty>, Error> {
Err(Error::new("This frontend doesn't support PTYs")) Err(Error::new("This frontend doesn't support PTYs"))
} }
fn add_window(&mut self, _updater: Box<dyn WindowUpdater>) -> Result<(), Error> { fn add_video_source(&mut self, _receiver: FrameReceiver) -> Result<(), Error> {
Err(Error::new("This frontend doesn't support windows")) Err(Error::new("This frontend doesn't support windows"))
} }
fn add_audio_source(&mut self) -> Result<Box<dyn Audio>, Error> {
Err(Error::new("This frontend doesn't support the sound"))
}
fn register_controller(&mut self, _device: ControllerDevice, _input: Box<dyn ControllerUpdater>) -> Result<(), Error> { fn register_controller(&mut self, _device: ControllerDevice, _input: Box<dyn ControllerUpdater>) -> Result<(), Error> {
Err(Error::new("This frontend doesn't support game controllers")) Err(Error::new("This frontend doesn't support game controllers"))
} }
@ -28,10 +32,6 @@ pub trait Host {
fn register_mouse(&mut self, _input: Box<dyn MouseUpdater>) -> Result<(), Error> { fn register_mouse(&mut self, _input: Box<dyn MouseUpdater>) -> Result<(), Error> {
Err(Error::new("This frontend doesn't support the mouse")) Err(Error::new("This frontend doesn't support the mouse"))
} }
fn create_audio_source(&mut self) -> Result<Box<dyn Audio>, 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; 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<Frame, Error>;
}
pub trait ControllerUpdater: Send { pub trait ControllerUpdater: Send {
fn update_controller(&mut self, event: ControllerEvent); fn update_controller(&self, event: ControllerEvent);
} }
pub trait KeyboardUpdater: Send { pub trait KeyboardUpdater: Send {
fn update_keyboard(&mut self, event: KeyEvent); fn update_keyboard(&self, event: KeyEvent);
} }
pub trait MouseUpdater: Send { pub trait MouseUpdater: Send {
fn update_mouse(&mut self, event: MouseEvent); fn update_mouse(&self, event: MouseEvent);
} }
pub trait Audio { pub trait Audio {
@ -66,14 +60,6 @@ pub trait Audio {
fn flush(&mut self); 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<B: Iterator<Item=Pixel>>(&mut self, pos_x: u32, pos_y: u32, bitmap: B, width: u32, height: u32);
fn clear(&mut self, value: Pixel);
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct HostData<T>(Arc<Mutex<T>>); pub struct HostData<T>(Arc<Mutex<T>>);

View File

@ -8,7 +8,7 @@ use minifb::{self, Key, MouseMode, MouseButton};
use clap::{App, Arg, ArgMatches}; use clap::{App, Arg, ArgMatches};
use moa_core::{System, Error, ClockDuration}; 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::{AudioMixer, AudioSource};
use moa_common::CpalAudioOutput; use moa_common::CpalAudioOutput;
@ -95,18 +95,18 @@ fn wait_until_initialized(frontend: Arc<Mutex<MiniFrontendBuilder>>) {
pub struct MiniFrontendBuilder { pub struct MiniFrontendBuilder {
pub window: Option<Box<dyn WindowUpdater>>, video: Option<FrameReceiver>,
pub controller: Option<Box<dyn ControllerUpdater>>, controller: Option<Box<dyn ControllerUpdater>>,
pub keyboard: Option<Box<dyn KeyboardUpdater>>, keyboard: Option<Box<dyn KeyboardUpdater>>,
pub mouse: Option<Box<dyn MouseUpdater>>, mouse: Option<Box<dyn MouseUpdater>>,
pub mixer: Option<Arc<Mutex<AudioMixer>>>, mixer: Option<Arc<Mutex<AudioMixer>>>,
pub finalized: bool, finalized: bool,
} }
impl Default for MiniFrontendBuilder { impl Default for MiniFrontendBuilder {
fn default() -> Self { fn default() -> Self {
Self { Self {
window: None, video: None,
controller: None, controller: None,
keyboard: None, keyboard: None,
mouse: None, mouse: None,
@ -122,24 +122,29 @@ impl MiniFrontendBuilder {
} }
pub fn build(&mut self) -> MiniFrontend { 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 controller = std::mem::take(&mut self.controller);
let keyboard = std::mem::take(&mut self.keyboard); let keyboard = std::mem::take(&mut self.keyboard);
let mouse = std::mem::take(&mut self.mouse); let mouse = std::mem::take(&mut self.mouse);
let mixer = std::mem::take(&mut self.mixer); 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 { impl Host for MiniFrontendBuilder {
fn add_window(&mut self, updater: Box<dyn WindowUpdater>) -> Result<(), Error> { fn add_video_source(&mut self, receiver: FrameReceiver) -> Result<(), Error> {
if self.window.is_some() { if self.video.is_some() {
return Err(Error::new("A window updater has already been registered with the frontend")); return Err(Error::new("Only one video source can be registered with this frontend"));
} }
self.window = Some(updater); self.video = Some(receiver);
Ok(()) Ok(())
} }
fn add_audio_source(&mut self) -> Result<Box<dyn Audio>, Error> {
let source = AudioSource::new(self.mixer.as_ref().unwrap().clone());
Ok(Box::new(source))
}
fn register_controller(&mut self, device: ControllerDevice, input: Box<dyn ControllerUpdater>) -> Result<(), Error> { fn register_controller(&mut self, device: ControllerDevice, input: Box<dyn ControllerUpdater>) -> Result<(), Error> {
if device != ControllerDevice::A { if device != ControllerDevice::A {
return Ok(()) return Ok(())
@ -167,18 +172,13 @@ impl Host for MiniFrontendBuilder {
self.mouse = Some(input); self.mouse = Some(input);
Ok(()) Ok(())
} }
fn create_audio_source(&mut self) -> Result<Box<dyn Audio>, Error> {
let source = AudioSource::new(self.mixer.as_ref().unwrap().clone());
Ok(Box::new(source))
}
} }
pub struct MiniFrontend { pub struct MiniFrontend {
pub modifiers: u16, pub modifiers: u16,
pub mouse_state: MouseState, pub mouse_state: MouseState,
pub window: Option<Box<dyn WindowUpdater>>, pub video: Option<FrameReceiver>,
pub controller: Option<Box<dyn ControllerUpdater>>, pub controller: Option<Box<dyn ControllerUpdater>>,
pub keyboard: Option<Box<dyn KeyboardUpdater>>, pub keyboard: Option<Box<dyn KeyboardUpdater>>,
pub mouse: Option<Box<dyn MouseUpdater>>, pub mouse: Option<Box<dyn MouseUpdater>>,
@ -188,7 +188,7 @@ pub struct MiniFrontend {
impl MiniFrontend { impl MiniFrontend {
pub fn new( pub fn new(
window: Option<Box<dyn WindowUpdater>>, video: Option<FrameReceiver>,
controller: Option<Box<dyn ControllerUpdater>>, controller: Option<Box<dyn ControllerUpdater>>,
keyboard: Option<Box<dyn KeyboardUpdater>>, keyboard: Option<Box<dyn KeyboardUpdater>>,
mouse: Option<Box<dyn MouseUpdater>>, mouse: Option<Box<dyn MouseUpdater>>,
@ -197,7 +197,7 @@ impl MiniFrontend {
Self { Self {
modifiers: 0, modifiers: 0,
mouse_state: Default::default(), mouse_state: Default::default(),
window, video,
controller, controller,
keyboard, keyboard,
mouse, mouse,
@ -239,9 +239,9 @@ impl MiniFrontend {
}; };
let mut size = (WIDTH, HEIGHT); let mut size = (WIDTH, HEIGHT);
if let Some(updater) = self.window.as_mut() { if let Some(queue) = self.video.as_mut() {
size = updater.max_size(); size = queue.max_size();
updater.request_encoding(PixelEncoding::ARGB); queue.request_encoding(PixelEncoding::ARGB);
} }
let mut window = minifb::Window::new( let mut window = minifb::Window::new(
@ -306,8 +306,8 @@ impl MiniFrontend {
} }
} }
if let Some(updater) = self.window.as_mut() { if let Some(queue) = self.video.as_mut() {
if let Ok(frame) = updater.take_frame() { if let Some((clock, frame)) = queue.latest() {
last_frame = frame last_frame = frame
} }
window.update_with_buffer(&last_frame.bitmap, last_frame.width as usize, last_frame.height as usize).unwrap(); window.update_with_buffer(&last_frame.bitmap, last_frame.width as usize, last_frame.height as usize).unwrap();

View File

@ -7,7 +7,7 @@ use winit::event::{Event, VirtualKeyCode, WindowEvent, ElementState};
use winit::event_loop::{ControlFlow, EventLoop}; use winit::event_loop::{ControlFlow, EventLoop};
use moa_core::{System, Error}; 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 moa_common::{AudioMixer, AudioSource, CpalAudioOutput};
use crate::settings; use crate::settings;
@ -20,7 +20,7 @@ pub const HEIGHT: u32 = 224;
pub type LoadSystemFn = fn (&mut PixelsFrontend, Vec<u8>) -> Result<System, Error>; pub type LoadSystemFn = fn (&mut PixelsFrontend, Vec<u8>) -> Result<System, Error>;
pub struct PixelsFrontend { pub struct PixelsFrontend {
updater: Option<Box<dyn WindowUpdater>>, video: Option<FrameReceiver>,
controller: Option<Box<dyn ControllerUpdater>>, controller: Option<Box<dyn ControllerUpdater>>,
//mixer: Arc<Mutex<AudioMixer>>, //mixer: Arc<Mutex<AudioMixer>>,
//audio_output: CpalAudioOutput, //audio_output: CpalAudioOutput,
@ -33,8 +33,8 @@ impl PixelsFrontend {
//let audio_output = CpalAudioOutput::create_audio_output(mixer.lock().unwrap().get_sink()); //let audio_output = CpalAudioOutput::create_audio_output(mixer.lock().unwrap().get_sink());
PixelsFrontend { PixelsFrontend {
video: None,
controller: None, controller: None,
updater: None,
//mixer, //mixer,
//audio_output, //audio_output,
} }
@ -42,8 +42,8 @@ impl PixelsFrontend {
} }
impl Host for PixelsFrontend { impl Host for PixelsFrontend {
fn add_window(&mut self, updater: Box<dyn WindowUpdater>) -> Result<(), Error> { fn add_video_source(&mut self, receiver: FrameReceiver) -> Result<(), Error> {
self.updater = Some(updater); self.video = Some(receiver);
Ok(()) Ok(())
} }
@ -56,20 +56,20 @@ impl Host for PixelsFrontend {
Ok(()) Ok(())
} }
fn create_audio_source(&mut self) -> Result<Box<dyn Audio>, Error> { fn add_audio_source(&mut self) -> Result<Box<dyn Audio>, Error> {
//let source = AudioSource::new(self.mixer.clone()); //let source = AudioSource::new(self.mixer.clone());
//Ok(Box::new(source)) //Ok(Box::new(source))
Ok(Box::new(DummyAudio())) 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 event_loop = EventLoop::new();
let window = create_window(&event_loop); let window = create_window(&event_loop);
if let Some(updater) = host.updater.as_mut() { if let Some(recevier) = host.video.as_ref() {
updater.request_encoding(PixelEncoding::ABGR); recevier.request_encoding(PixelEncoding::ABGR);
} }
let mut pixels = { 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()); //log::warn!("updated after {:4}ms", update_timer.elapsed().as_millis());
//update_timer = Instant::now(); //update_timer = Instant::now();
if let Some(updater) = host.updater.as_mut() { if let Some(updater) = host.video.as_ref() {
if let Ok(frame) = updater.take_frame() { if let Some((clock, frame)) = updater.latest() {
last_frame = frame; 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 { if let Some(key) = key {
updater.update_controller(key); updater.update_controller(key);
} }

View File

@ -94,8 +94,8 @@ pub struct Sn76489 {
} }
impl Sn76489 { impl Sn76489 {
pub fn create<H: Host>(host: &mut H, clock_frequency: Frequency) -> Result<Self, Error> { pub fn new<H: Host>(host: &mut H, clock_frequency: Frequency) -> Result<Self, Error> {
let source = host.create_audio_source()?; let source = host.add_audio_source()?;
let sample_rate = source.samples_per_second(); let sample_rate = source.samples_per_second();
Ok(Self { Ok(Self {

View File

@ -5,14 +5,14 @@
//! source code that emulates the chip. It is still very much a work in progress //! source code that emulates the chip. It is still very much a work in progress
//! //!
//! Resources: //! Resources:
//! - Registers: https://www.smspower.org/maxim/Documents/YM2612 //! - Registers: <https://www.smspower.org/maxim/Documents/YM2612>
//! - Internal Implementation: https://gendev.spritesmind.net/forum/viewtopic.php?t=386 [Nemesis] //! - Internal Implementation: <https://gendev.spritesmind.net/forum/viewtopic.php?t=386> (Nemesis)
//! * Envelope Generator and Corrections: //! * Envelope Generator and Corrections:
//! http://gendev.spritesmind.net/forum/viewtopic.php?p=5716#5716 //! <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 //! <http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc&start=417>
//! * Phase Generator and Output: //! * Phase Generator and Output:
//! http://gendev.spritesmind.net/forum/viewtopic.php?f=24&t=386&start=150 //! <http://gendev.spritesmind.net/forum/viewtopic.php?f=24&t=386&start=150>
//! http://gendev.spritesmind.net/forum/viewtopic.php?p=6224#6224 //! <http://gendev.spritesmind.net/forum/viewtopic.php?p=6224#6224>
use std::f32; use std::f32;
use std::num::NonZeroU8; use std::num::NonZeroU8;
@ -262,6 +262,9 @@ impl EnvelopeGenerator {
} else { } else {
self.envelope_state = EnvelopeState::Release; 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) { 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 rate = self.get_scaled_rate(self.envelope_state, rate_adjust);
let counter_shift = COUNTER_SHIFT_VALUES[rate]; 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 { if envelope_clock % (1 << counter_shift) == 0 {
let update_cycle = (envelope_clock >> counter_shift) & 0x07; let update_cycle = (envelope_clock >> counter_shift) & 0x07;
let increment = RATE_TABLE[rate * 8 + update_cycle as usize]; let increment = RATE_TABLE[rate * 8 + update_cycle as usize];
match self.envelope_state { match self.envelope_state {
EnvelopeState::Attack => { 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 { if new_envelope > self.envelope {
self.envelope_state = EnvelopeState::Decay; self.envelope_state = EnvelopeState::Decay;
self.envelope = 0; 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; 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 // 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 // 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 // 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 = sign_extend_u16(output, 14);
//let output = output * 2 / 3; //let output = output * 2 / 3;
//if self.debug_name == "ch 2" {
//println!("{:6x}", output);
//}
let sample = output as f32 / (1 << 13) as f32; let sample = output as f32 / (1 << 13) as f32;
let left = if self.enabled.0 { sample } else { 0.0 }; let left = if self.enabled.0 { sample } else { 0.0 };
@ -726,8 +749,8 @@ pub struct Ym2612 {
} }
impl Ym2612 { impl Ym2612 {
pub fn create<H: Host>(host: &mut H, clock_frequency: Frequency) -> Result<Self, Error> { pub fn new<H: Host>(host: &mut H, clock_frequency: Frequency) -> Result<Self, Error> {
let source = host.create_audio_source()?; let source = host.add_audio_source()?;
let fm_clock = clock_frequency / (6 * 24); let fm_clock = clock_frequency / (6 * 24);
let fm_clock_period = fm_clock.period_duration(); 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) { 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 // Keep a copy for debugging purposes, and if the original values are needed
self.registers[bank as usize * 256 + reg as usize] = data; 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); //warn!("{}: set reg {}{:x} to {:x}", DEV_NAME, bank, reg, data);
match reg { match reg {

View File

@ -22,8 +22,8 @@ pub fn build_computie<H: Host>(host: &H) -> Result<System, Error> {
system.add_addressable_device(0x00600000, wrap_transmutable(ata))?; system.add_addressable_device(0x00600000, wrap_transmutable(ata))?;
let mut serial = MC68681::default(); let mut serial = MC68681::default();
launch_terminal_emulator(serial.port_a.connect(host.create_pty()?)?); launch_terminal_emulator(serial.port_a.connect(host.add_pty()?)?);
launch_slip_connection(serial.port_b.connect(host.create_pty()?)?); launch_slip_connection(serial.port_b.connect(host.add_pty()?)?);
system.add_addressable_device(0x00700000, wrap_transmutable(serial))?; system.add_addressable_device(0x00700000, wrap_transmutable(serial))?;
@ -60,8 +60,8 @@ pub fn build_computie_k30<H: Host>(host: &H) -> Result<System, Error> {
system.add_addressable_device(0x00600000, wrap_transmutable(ata))?; system.add_addressable_device(0x00600000, wrap_transmutable(ata))?;
let mut serial = MC68681::default(); let mut serial = MC68681::default();
launch_terminal_emulator(serial.port_a.connect(host.create_pty()?)?); launch_terminal_emulator(serial.port_a.connect(host.add_pty()?)?);
//launch_slip_connection(serial.port_b.connect(host.create_pty()?)?); //launch_slip_connection(serial.port_b.connect(host.add_pty()?)?);
system.add_addressable_device(0x00700000, wrap_transmutable(serial))?; system.add_addressable_device(0x00700000, wrap_transmutable(serial))?;

View File

@ -1,6 +1,6 @@
use std::sync::Arc; 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::{warn, info};
use moa_core::{System, Error, ClockTime, ClockDuration, Address, Addressable, Steppable, Transmutable}; use moa_core::{System, Error, ClockTime, ClockDuration, Address, Addressable, Steppable, Transmutable};
@ -88,10 +88,10 @@ impl GenesisControllerPort {
} }
} }
pub struct GenesisControllersUpdater(Arc<AtomicU16>, HostData<bool>); pub struct GenesisControllersUpdater(Arc<AtomicU16>, Arc<AtomicBool>);
impl ControllerUpdater for GenesisControllersUpdater { impl ControllerUpdater for GenesisControllersUpdater {
fn update_controller(&mut self, event: ControllerEvent) { fn update_controller(&self, event: ControllerEvent) {
let (mask, state) = match event { let (mask, state) = match event {
ControllerEvent::ButtonA(state) => (0x0040, state), ControllerEvent::ButtonA(state) => (0x0040, state),
ControllerEvent::ButtonB(state) => (0x0010, 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 }); let buttons = (self.0.load(Ordering::Acquire) & !mask) | (if !state { mask } else { 0 });
self.0.store(buttons, Ordering::Release); self.0.store(buttons, Ordering::Release);
if buttons != 0 { if buttons != 0 {
self.1.set(true); self.1.store(true, Ordering::Release);
} }
} }
} }
@ -119,6 +119,7 @@ pub struct GenesisControllers {
port_1: GenesisControllerPort, port_1: GenesisControllerPort,
port_2: GenesisControllerPort, port_2: GenesisControllerPort,
expansion: GenesisControllerPort, expansion: GenesisControllerPort,
has_changed: Arc<AtomicBool>,
interrupt: HostData<bool>, interrupt: HostData<bool>,
reset_timer: ClockDuration, reset_timer: ClockDuration,
} }
@ -129,6 +130,7 @@ impl Default for GenesisControllers {
port_1: GenesisControllerPort::default(), port_1: GenesisControllerPort::default(),
port_2: GenesisControllerPort::default(), port_2: GenesisControllerPort::default(),
expansion: GenesisControllerPort::default(), expansion: GenesisControllerPort::default(),
has_changed: Arc::new(AtomicBool::new(false)),
interrupt: HostData::new(false), interrupt: HostData::new(false),
reset_timer: ClockDuration::ZERO, reset_timer: ClockDuration::ZERO,
} }
@ -136,12 +138,12 @@ impl Default for GenesisControllers {
} }
impl GenesisControllers { impl GenesisControllers {
pub fn create<H: Host>(host: &mut H) -> Result<Self, Error> { pub fn new<H: Host>(host: &mut H) -> Result<Self, Error> {
let controller = GenesisControllers::default(); 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)?; 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)?; host.register_controller(ControllerDevice::B, controller2)?;
Ok(controller) Ok(controller)
@ -206,6 +208,11 @@ impl Steppable for GenesisControllers {
fn step(&mut self, _system: &System) -> Result<ClockDuration, Error> { fn step(&mut self, _system: &System) -> Result<ClockDuration, Error> {
let duration = ClockDuration::from_micros(100); // Update every 100us 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; self.reset_timer += duration;
if self.reset_timer >= ClockDuration::from_micros(1_500) { if self.reset_timer >= ClockDuration::from_micros(1_500) {
self.port_1.reset_count(); self.port_1.reset_count();

View File

@ -1,7 +1,7 @@
use moa_core::{debug, warn, error}; 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::{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; 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 { 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.state.draw_frame(&mut frame);
self.queue.add(system.clock, frame); self.sender.add(system.clock, frame);
} }
self.frame_complete.signal(); self.frame_complete.signal();
@ -681,7 +681,7 @@ impl Steppable for Ym7101 {
pub struct Ym7101 { pub struct Ym7101 {
queue: FrameQueue, sender: FrameSender,
state: Ym7101State, state: Ym7101State,
sn_sound: TransmutableBox, sn_sound: TransmutableBox,
@ -691,11 +691,11 @@ pub struct Ym7101 {
impl Ym7101 { impl Ym7101 {
pub fn new<H: Host>(host: &mut H, external_interrupt: HostData<bool>, sn_sound: TransmutableBox) -> Ym7101 { pub fn new<H: Host>(host: &mut H, external_interrupt: HostData<bool>, sn_sound: TransmutableBox) -> Ym7101 {
let queue = FrameQueue::new(320, 224); let (sender, receiver) = host::frame_queue(320, 224);
host.add_window(Box::new(queue.clone())).unwrap(); host.add_video_source(receiver).unwrap();
Ym7101 { Ym7101 {
queue, sender,
state: Ym7101State::default(), state: Ym7101State::default(),
sn_sound, sn_sound,
external_interrupt, external_interrupt,

View File

@ -70,8 +70,8 @@ pub fn build_genesis<H: Host>(host: &mut H, mut options: SegaGenesisOptions) ->
// Build the Coprocessor's Bus // Build the Coprocessor's Bus
let bank_register = Signal::new(0); let bank_register = Signal::new(0);
let coproc_ram = wrap_transmutable(MemoryBlock::new(vec![0; 0x00002000])); 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_ym_sound = wrap_transmutable(Ym2612::new(host, Frequency::from_hz(7_670_454))?);
let coproc_sn_sound = wrap_transmutable(Sn76489::create(host, Frequency::from_hz(3_579_545))?); 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_register = wrap_transmutable(CoprocessorBankRegister::new(bank_register.clone()));
let coproc_area = wrap_transmutable(CoprocessorBankArea::new(bank_register, system.bus.clone())); let coproc_area = wrap_transmutable(CoprocessorBankArea::new(bank_register, system.bus.clone()));
@ -98,7 +98,7 @@ pub fn build_genesis<H: Host>(host: &mut H, mut options: SegaGenesisOptions) ->
system.add_device("coproc", wrap_transmutable(coproc))?; system.add_device("coproc", wrap_transmutable(coproc))?;
let controllers = GenesisControllers::create(host)?; let controllers = GenesisControllers::new(host)?;
let interrupt = controllers.get_interrupt_signal(); let interrupt = controllers.get_interrupt_signal();
system.add_addressable_device(0x00a10000, wrap_transmutable(controllers)).unwrap(); system.add_addressable_device(0x00a10000, wrap_transmutable(controllers)).unwrap();

View File

@ -22,7 +22,7 @@ pub struct Mainboard {
} }
impl Mainboard { impl Mainboard {
pub fn create(ram: TransmutableBox, rom: TransmutableBox) -> Result<Self, Error> { pub fn new(ram: TransmutableBox, rom: TransmutableBox) -> Result<Self, Error> {
let scc1 = Z8530::default(); let scc1 = Z8530::default();
let scc2 = Z8530::default(); let scc2 = Z8530::default();
let iwm = IWM::default(); let iwm = IWM::default();

View File

@ -1,23 +1,23 @@
use moa_core::{System, Error, ClockDuration, Address, Addressable, Steppable, Transmutable}; 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_BASE: u32 = 0x07A700;
const SCRN_SIZE: (u32, u32) = (512, 342); const SCRN_SIZE: (u32, u32) = (512, 342);
pub struct MacVideo { pub struct MacVideo {
frame_queue: FrameQueue, frame_sender: FrameSender,
} }
impl MacVideo { impl MacVideo {
pub fn create<H: Host>(host: &mut H) -> Result<Self, Error> { pub fn new<H: Host>(host: &mut H) -> Result<Self, Error> {
let frame_queue = FrameQueue::new(SCRN_SIZE.0, SCRN_SIZE.1); 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 { Ok(Self {
frame_queue, frame_sender,
}) })
} }
} }
@ -58,7 +58,7 @@ impl Iterator for BitIter {
impl Steppable for MacVideo { impl Steppable for MacVideo {
fn step(&mut self, system: &System) -> Result<ClockDuration, Error> { fn step(&mut self, system: &System) -> Result<ClockDuration, Error> {
let mut memory = system.get_bus(); 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 y in 0..SCRN_SIZE.1 {
for x in 0..(SCRN_SIZE.0 / 16) { 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)?; 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)) Ok(ClockDuration::from_micros(16_600))
} }
} }

View File

@ -32,7 +32,7 @@ pub fn build_macintosh_512k<H: Host>(host: &mut H) -> Result<System, Error> {
let misc = MemoryBlock::new(vec![0; 0x100000]); let misc = MemoryBlock::new(vec![0; 0x100000]);
system.add_addressable_device(0x00f00000, wrap_transmutable(misc))?; 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(); system.add_device("video", wrap_transmutable(video)).unwrap();
let scc1 = Z8530::new(); let scc1 = Z8530::new();
@ -62,10 +62,10 @@ pub fn build_macintosh_512k<H: Host>(host: &mut H) -> Result<System, Error> {
let mut rom = MemoryBlock::load("binaries/macintosh/Macintosh 512k.rom")?; let mut rom = MemoryBlock::load("binaries/macintosh/Macintosh 512k.rom")?;
rom.read_only(); rom.read_only();
let video = MacVideo::create(host)?; let video = MacVideo::new(host)?;
system.add_device("video", wrap_transmutable(video)).unwrap(); 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))?; system.add_addressable_device(0x00000000, wrap_transmutable(mainboard))?;

View File

@ -2,7 +2,7 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use moa_core::{System, Error, ClockTime, ClockDuration, Address, Addressable, Steppable, Transmutable, debug, warn}; 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::keymap;
use super::charset::CharacterGenerator; use super::charset::CharacterGenerator;
@ -12,21 +12,21 @@ const DEV_NAME: &str = "model1";
const SCREEN_SIZE: (u32, u32) = (384, 128); const SCREEN_SIZE: (u32, u32) = (384, 128);
pub struct Model1Peripherals { pub struct Model1Peripherals {
frame_queue: FrameQueue, frame_sender: FrameSender,
keyboard_mem: Arc<Mutex<[u8; 8]>>, keyboard_mem: Arc<Mutex<[u8; 8]>>,
video_mem: [u8; 1024], video_mem: [u8; 1024],
} }
impl Model1Peripherals { impl Model1Peripherals {
pub fn create<H: Host>(host: &mut H) -> Result<Self, Error> { pub fn new<H: Host>(host: &mut H) -> Result<Self, Error> {
let frame_queue = FrameQueue::new(SCREEN_SIZE.0, SCREEN_SIZE.1); let (frame_sender, frame_receiver) = host::frame_queue(SCREEN_SIZE.0, SCREEN_SIZE.1);
let keyboard_mem = Arc::new(Mutex::new([0; 8])); 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())))?; host.register_keyboard(Box::new(Model1KeyboardUpdater(keyboard_mem.clone())))?;
Ok(Self { Ok(Self {
frame_queue, frame_sender,
keyboard_mem, keyboard_mem,
video_mem: [0x20; 1024], video_mem: [0x20; 1024],
}) })
@ -36,7 +36,7 @@ impl Model1Peripherals {
pub struct Model1KeyboardUpdater(Arc<Mutex<[u8; 8]>>); pub struct Model1KeyboardUpdater(Arc<Mutex<[u8; 8]>>);
impl KeyboardUpdater for Model1KeyboardUpdater { impl KeyboardUpdater for Model1KeyboardUpdater {
fn update_keyboard(&mut self, event: KeyEvent) { fn update_keyboard(&self, event: KeyEvent) {
println!(">>> {:?}", event.key); println!(">>> {:?}", event.key);
keymap::record_key_press(&mut self.0.lock().unwrap(), event.key, event.state); 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 { impl Steppable for Model1Peripherals {
fn step(&mut self, system: &System) -> Result<ClockDuration, Error> { fn step(&mut self, system: &System) -> Result<ClockDuration, Error> {
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 y in 0..16 {
for x in 0..64 { for x in 0..64 {
let ch = self.video_mem[x + (y * 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); 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)) Ok(ClockDuration::from_micros(16_630))
} }

View File

@ -37,7 +37,7 @@ pub fn build_trs80<H: Host>(host: &mut H, options: Trs80Options) -> Result<Syste
let ram = MemoryBlock::new(vec![0; options.memory as usize]); let ram = MemoryBlock::new(vec![0; options.memory as usize]);
system.add_addressable_device(0x4000, wrap_transmutable(ram))?; system.add_addressable_device(0x4000, wrap_transmutable(ram))?;
let model1 = Model1Peripherals::create(host)?; let model1 = Model1Peripherals::new(host)?;
system.add_addressable_device(0x37E0, wrap_transmutable(model1)).unwrap(); system.add_addressable_device(0x37E0, wrap_transmutable(model1)).unwrap();
let cpu = Z80::new(Z80Type::Z80, options.frequency, BusPort::new(0, 16, 8, system.bus.clone())); let cpu = Z80::new(Z80Type::Z80, options.frequency, BusPort::new(0, 16, 8, system.bus.clone()));

View File

@ -1,7 +1,11 @@
* add runtime checks for arithmetic to look for errors * make the ym generate audio in sync so the DAC timings can be more accurate
* change the host things to use queues instead
* add rust runtime checks for math to look for overflow errors
* I think the overflowing add and subs return the original number and not the overflowed result. I might have already checked that
in the m68k impl but I should check again
* the first 512 entries are 0 for some reason, in the log table, but otherwise seems ok
* you need to scale the output sample to be +/- 1.0 instead of 0-1.0 * you need to scale the output sample to be +/- 1.0 instead of 0-1.0
* AudioFrame (and possibly the mixer and source) should be moved to the core, it should probably have the sample rate * AudioFrame (and possibly the mixer and source) should be moved to the core, it should probably have the sample rate