Split some parts of moa-core into libraries/

This commit is contained in:
transistor 2024-03-01 21:17:09 -08:00
parent 5653cf47a1
commit 55efc4f406
57 changed files with 276 additions and 133 deletions

41
Cargo.lock generated
View File

@ -577,12 +577,6 @@ version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "iz80"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76e13cd358184c4b647f19a858246b82e3327ed29c2893d232f01ed016ac5d3c"
[[package]] [[package]]
name = "jni" name = "jni"
version = "0.19.0" version = "0.19.0"
@ -744,6 +738,7 @@ dependencies = [
"femtos", "femtos",
"log", "log",
"moa-core", "moa-core",
"moa-host",
"nix 0.25.1", "nix 0.25.1",
] ]
@ -770,15 +765,23 @@ version = "0.1.0"
dependencies = [ dependencies = [
"femtos", "femtos",
"log", "log",
"moa-host",
"thiserror",
] ]
[[package]] [[package]]
name = "moa-iz80" name = "moa-debugger"
version = "0.1.0"
dependencies = [
"moa-core",
]
[[package]]
name = "moa-host"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"femtos", "femtos",
"iz80", "thiserror",
"moa-core",
] ]
[[package]] [[package]]
@ -789,6 +792,7 @@ dependencies = [
"log", "log",
"moa-core", "moa-core",
"moa-parsing", "moa-parsing",
"thiserror",
] ]
[[package]] [[package]]
@ -801,6 +805,8 @@ dependencies = [
"minifb", "minifb",
"moa-common", "moa-common",
"moa-core", "moa-core",
"moa-debugger",
"moa-host",
"moa-peripherals-yamaha", "moa-peripherals-yamaha",
"moa-systems-computie", "moa-systems-computie",
"moa-systems-genesis", "moa-systems-genesis",
@ -832,6 +838,7 @@ dependencies = [
"femtos", "femtos",
"log", "log",
"moa-core", "moa-core",
"moa-signals",
] ]
[[package]] [[package]]
@ -841,6 +848,7 @@ dependencies = [
"femtos", "femtos",
"log", "log",
"moa-core", "moa-core",
"moa-host",
] ]
[[package]] [[package]]
@ -852,6 +860,7 @@ dependencies = [
"log", "log",
"moa-audio", "moa-audio",
"moa-core", "moa-core",
"moa-host",
] ]
[[package]] [[package]]
@ -863,6 +872,13 @@ dependencies = [
"moa-core", "moa-core",
] ]
[[package]]
name = "moa-signals"
version = "0.1.0"
dependencies = [
"femtos",
]
[[package]] [[package]]
name = "moa-systems-computie" name = "moa-systems-computie"
version = "0.1.0" version = "0.1.0"
@ -870,6 +886,7 @@ dependencies = [
"femtos", "femtos",
"log", "log",
"moa-core", "moa-core",
"moa-host",
"moa-m68k", "moa-m68k",
"moa-peripherals-generic", "moa-peripherals-generic",
"moa-peripherals-motorola", "moa-peripherals-motorola",
@ -882,8 +899,10 @@ dependencies = [
"femtos", "femtos",
"log", "log",
"moa-core", "moa-core",
"moa-host",
"moa-m68k", "moa-m68k",
"moa-peripherals-yamaha", "moa-peripherals-yamaha",
"moa-signals",
"moa-z80", "moa-z80",
] ]
@ -894,9 +913,11 @@ dependencies = [
"femtos", "femtos",
"log", "log",
"moa-core", "moa-core",
"moa-host",
"moa-m68k", "moa-m68k",
"moa-peripherals-mos", "moa-peripherals-mos",
"moa-peripherals-zilog", "moa-peripherals-zilog",
"moa-signals",
] ]
[[package]] [[package]]
@ -906,6 +927,7 @@ dependencies = [
"femtos", "femtos",
"log", "log",
"moa-core", "moa-core",
"moa-host",
"moa-z80", "moa-z80",
] ]
@ -916,6 +938,7 @@ dependencies = [
"femtos", "femtos",
"log", "log",
"moa-core", "moa-core",
"moa-signals",
] ]
[[package]] [[package]]

View File

@ -6,4 +6,5 @@ edition = "2021"
[dependencies] [dependencies]
log = "0.4" log = "0.4"
femtos = "0.1" femtos = "0.1"
thiserror = "1.0"
moa-host = { path = "../libraries/host" }

View File

@ -1,16 +1,21 @@
use std::fmt;
use std::error::{Error as StdError};
use moa_host::HostError;
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum EmulatorErrorKind { pub enum EmulatorErrorKind {
Misc, Misc,
MemoryAlignment, MemoryAlignment,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug, thiserror::Error)]
pub enum Error { pub enum Error {
Assertion(String), Assertion(String),
Breakpoint(String), Breakpoint(String),
Emulator(EmulatorErrorKind, String), Emulator(EmulatorErrorKind, String),
Processor(u32), Processor(u32),
Other(String),
} }
impl Error { impl Error {
@ -50,9 +55,28 @@ impl Error {
match self { match self {
Error::Assertion(msg) | Error::Assertion(msg) |
Error::Breakpoint(msg) | Error::Breakpoint(msg) |
Error::Other(msg) |
Error::Emulator(_, msg) => msg.as_str(), Error::Emulator(_, msg) => msg.as_str(),
Error::Processor(_) => "native exception", Error::Processor(_) => "native exception",
} }
} }
} }
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::Assertion(msg) |
Error::Breakpoint(msg) |
Error::Other(msg) |
Error::Emulator(_, msg) => write!(f, "{}", msg),
Error::Processor(_) => write!(f, "native exception"),
}
}
}
impl<E> From<HostError<E>> for Error {
fn from(err: HostError<E>) -> Self {
Self::Other(format!("other"))
}
}

View File

@ -1,17 +0,0 @@
mod audio;
mod controllers;
mod gfx;
mod input;
mod keys;
mod mouse;
mod traits;
pub use self::audio::{Sample, AudioFrame};
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, ControllerInput, ControllerEvent};
pub use self::input::{EventSender, EventReceiver, event_queue};
pub use self::traits::{Host, Tty, Audio, ClockedQueue, DummyAudio};

View File

@ -2,21 +2,15 @@
#[macro_use] #[macro_use]
mod error; mod error;
mod debugger;
mod devices; mod devices;
mod interrupts; mod interrupts;
mod memory; mod memory;
mod signals;
mod system; mod system;
pub mod host;
pub use crate::debugger::{DebugControl, Debugger};
pub use crate::devices::{Address, Addressable, Steppable, Interruptable, Debuggable, Inspectable, Transmutable, TransmutableBox, Device}; pub use crate::devices::{Address, Addressable, Steppable, Interruptable, Debuggable, Inspectable, Transmutable, TransmutableBox, Device};
pub use crate::devices::{read_beu16, read_beu32, read_leu16, read_leu32, write_beu16, write_beu32, write_leu16, write_leu32, wrap_transmutable}; pub use crate::devices::{read_beu16, read_beu32, read_leu16, read_leu32, write_beu16, write_beu32, write_leu16, write_leu32, wrap_transmutable};
pub use crate::error::Error; pub use crate::error::Error;
pub use crate::interrupts::InterruptController; pub use crate::interrupts::InterruptController;
pub use crate::memory::{MemoryBlock, AddressTranslator, AddressRepeater, Bus, BusPort, dump_slice}; pub use crate::memory::{MemoryBlock, AddressTranslator, AddressRepeater, Bus, BusPort, dump_slice};
pub use crate::signals::{Observable, Signal, EdgeSignal, ObservableSignal, ObservableEdgeSignal};
pub use crate::system::System; pub use crate::system::System;

View File

@ -4,7 +4,7 @@ use std::cell::{RefCell, RefMut};
use std::collections::HashMap; use std::collections::HashMap;
use femtos::{Instant, Duration}; use femtos::{Instant, Duration};
use crate::{Bus, EdgeSignal, Error, InterruptController, Address, Device}; use crate::{Bus, Error, InterruptController, Address, Device};
pub struct System { pub struct System {
@ -17,8 +17,6 @@ pub struct System {
pub bus: Rc<RefCell<Bus>>, pub bus: Rc<RefCell<Bus>>,
pub buses: HashMap<String, Rc<RefCell<Bus>>>, pub buses: HashMap<String, Rc<RefCell<Bus>>>,
pub interrupt_controller: RefCell<InterruptController>, pub interrupt_controller: RefCell<InterruptController>,
pub break_signal: Option<EdgeSignal>,
} }
impl Default for System { impl Default for System {
@ -33,8 +31,6 @@ impl Default for System {
bus: Rc::new(RefCell::new(Bus::default())), bus: Rc::new(RefCell::new(Bus::default())),
buses: HashMap::new(), buses: HashMap::new(),
interrupt_controller: RefCell::new(InterruptController::default()), interrupt_controller: RefCell::new(InterruptController::default()),
break_signal: None,
} }
} }
} }

View File

@ -5,6 +5,7 @@ edition = "2021"
[dependencies] [dependencies]
log = "0.4" log = "0.4"
thiserror = "1.0"
femtos = "0.1" femtos = "0.1"
moa-core = { path = "../../core" } moa-core = { path = "../../core" }
moa-parsing = { path = "../../libraries/parsing" } moa-parsing = { path = "../../libraries/parsing" }

View File

@ -9,5 +9,5 @@ pub mod memory;
pub mod timing; pub mod timing;
pub mod tests; pub mod tests;
pub use self::state::{M68k, M68kType}; pub use self::state::{M68k, M68kType, M68kError};

View File

@ -7,3 +7,4 @@ edition = "2021"
log = "0.4" log = "0.4"
femtos = "0.1" femtos = "0.1"
moa-core = { path = "../../core" } moa-core = { path = "../../core" }
moa-signals = { path = "../../libraries/signals" }

View File

@ -3,7 +3,8 @@ use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;
use femtos::{Instant, Frequency}; use femtos::{Instant, Frequency};
use moa_core::{Address, Bus, BusPort, Signal}; use moa_core::{Address, Bus, BusPort};
use moa_signals::Signal;
use crate::decode::Z80Decoder; use crate::decode::Z80Decoder;
use crate::debugger::Z80Debugger; use crate::debugger::Z80Debugger;

View File

@ -11,6 +11,7 @@ audio = ["cpal"]
log = "0.4" log = "0.4"
femtos = "0.1" femtos = "0.1"
moa-core = { path = "../../core" } moa-core = { path = "../../core" }
moa-host = { path = "../../libraries/host" }
nix = { version = "0.25", optional = true } nix = { version = "0.25", optional = true }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] [target.'cfg(not(target_arch = "wasm32"))'.dependencies]

View File

@ -2,7 +2,7 @@
use std::sync::{Arc, Mutex, MutexGuard}; use std::sync::{Arc, Mutex, MutexGuard};
use femtos::{Instant, Duration}; use femtos::{Instant, Duration};
use moa_core::host::{Audio, Sample, AudioFrame, ClockedQueue}; use moa_host::{Audio, Sample, AudioFrame, ClockedQueue};
pub const SAMPLE_RATE: usize = 48000; pub const SAMPLE_RATE: usize = 48000;

View File

@ -9,22 +9,24 @@ use moa_core::host::{Host, Tty, ControllerEvent, Audio, DummyAudio, FrameReceive
pub struct ConsoleFrontend; pub struct ConsoleFrontend;
impl Host for ConsoleFrontend { impl Host for ConsoleFrontend {
fn add_pty(&self) -> Result<Box<dyn Tty>, Error> { type Error = Error;
fn add_pty(&self) -> Result<Box<dyn Tty>, HostError<Self::Error>> {
use moa_common::tty::SimplePty; use moa_common::tty::SimplePty;
Ok(Box::new(SimplePty::open()?)) Ok(Box::new(SimplePty::open()?))
} }
fn add_video_source(&mut self, _receiver: FrameReceiver) -> Result<(), Error> { fn add_video_source(&mut self, _receiver: FrameReceiver) -> Result<(), HostError<Self::Error>> {
println!("console: add_window() is not supported from the console; ignoring request..."); println!("console: add_window() is not supported from the console; ignoring request...");
Ok(()) Ok(())
} }
fn register_controllers(&mut self, _sender: EventSender<ControllerEvent>) -> Result<(), Error> { fn register_controllers(&mut self, _sender: EventSender<ControllerEvent>) -> Result<(), HostError<Self::Error>> {
println!("console: register_controller() is not supported from the console; ignoring request..."); println!("console: register_controller() is not supported from the console; ignoring request...");
Ok(()) Ok(())
} }
fn add_audio_source(&mut self) -> Result<Box<dyn Audio>, Error> { fn add_audio_source(&mut self) -> Result<Box<dyn Audio>, HostError<Self::Error>> {
println!("console: create_audio_source() is not supported from the console; returning dummy device..."); println!("console: create_audio_source() is not supported from the console; returning dummy device...");
Ok(Box::new(DummyAudio())) Ok(Box::new(DummyAudio()))
} }

View File

@ -12,8 +12,10 @@ simple_logger = "^2"
femtos = "0.1" femtos = "0.1"
moa-core = { path = "../../core" } moa-core = { path = "../../core" }
moa-host = { path = "../../libraries/host" }
moa-common = { path = "../common", features = ["audio"] } moa-common = { path = "../common", features = ["audio"] }
moa-debugger = { path = "../../libraries/debugger" }
moa-systems-genesis = { path = "../../systems/genesis" } moa-systems-genesis = { path = "../../systems/genesis" }
moa-systems-computie = { path = "../../systems/computie" } moa-systems-computie = { path = "../../systems/computie" }
moa-systems-trs80 = { path = "../../systems/trs80" } moa-systems-trs80 = { path = "../../systems/trs80" }

View File

@ -3,7 +3,7 @@ use femtos::{Instant, Duration, Frequency};
use moa_peripherals_yamaha::{Ym2612, Sn76489}; use moa_peripherals_yamaha::{Ym2612, Sn76489};
use moa_core::host::{self, Host, Frame, FrameSender, PixelEncoding, Key, KeyEvent, EventReceiver}; use moa_host::{self, Host, Frame, FrameSender, PixelEncoding, Key, KeyEvent, EventReceiver};
use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable, Device}; use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable, Device};
const SCREEN_WIDTH: u32 = 384; const SCREEN_WIDTH: u32 = 384;
@ -85,8 +85,8 @@ fn main() {
moa_minifb::run(matches, |host| { moa_minifb::run(matches, |host| {
let mut system = System::default(); let mut system = System::default();
let (frame_sender, frame_receiver) = host::frame_queue(SCREEN_WIDTH, SCREEN_HEIGHT); let (frame_sender, frame_receiver) = moa_host::frame_queue(SCREEN_WIDTH, SCREEN_HEIGHT);
let (key_sender, key_receiver) = host::event_queue(); let (key_sender, key_receiver) = moa_host::event_queue();
let control = Device::new(SynthControl::new(key_receiver, frame_sender)); let control = Device::new(SynthControl::new(key_receiver, frame_sender));
system.add_device("control", control)?; system.add_device("control", control)?;

View File

@ -1,6 +1,6 @@
use minifb::Key as MiniKey; use minifb::Key as MiniKey;
use moa_core::host::ControllerInput; use moa_host::ControllerInput;
pub fn map_controller_a(key: MiniKey, state: bool) -> Option<ControllerInput> { pub fn map_controller_a(key: MiniKey, state: bool) -> Option<ControllerInput> {
match key { match key {

View File

@ -1,6 +1,6 @@
use minifb::Key as MiniKey; use minifb::Key as MiniKey;
use moa_core::host::Key; use moa_host::Key;
pub fn map_key(key: MiniKey) -> Key { pub fn map_key(key: MiniKey) -> Key {
match key { match key {

View File

@ -8,8 +8,9 @@ use minifb::{self, Key, MouseMode, MouseButton};
use clap::{Command, Arg, ArgAction, ArgMatches}; use clap::{Command, Arg, ArgAction, ArgMatches};
use femtos::{Duration as FemtosDuration}; use femtos::{Duration as FemtosDuration};
use moa_core::{System, Error, Device, Debugger, DebugControl}; use moa_core::{System, Error, Device};
use moa_core::host::{Host, Audio, KeyEvent, MouseEvent, MouseState, ControllerDevice, ControllerEvent, EventSender, PixelEncoding, Frame, FrameReceiver}; use moa_debugger::{Debugger, DebugControl};
use moa_host::{Host, HostError, Audio, KeyEvent, MouseEvent, MouseState, ControllerDevice, ControllerEvent, EventSender, PixelEncoding, Frame, FrameReceiver};
use moa_common::{AudioMixer, AudioSource}; use moa_common::{AudioMixer, AudioSource};
use moa_common::CpalAudioOutput; use moa_common::CpalAudioOutput;
@ -138,38 +139,40 @@ impl MiniFrontendBuilder {
} }
impl Host for MiniFrontendBuilder { impl Host for MiniFrontendBuilder {
fn add_video_source(&mut self, receiver: FrameReceiver) -> Result<(), Error> { type Error = Error;
fn add_video_source(&mut self, receiver: FrameReceiver) -> Result<(), HostError<Self::Error>> {
if self.video.is_some() { if self.video.is_some() {
return Err(Error::new("Only one video source can be registered with this frontend")); return Err(HostError::Specific(Error::new("Only one video source can be registered with this frontend")));
} }
self.video = Some(receiver); self.video = Some(receiver);
Ok(()) Ok(())
} }
fn add_audio_source(&mut self) -> Result<Box<dyn Audio>, Error> { fn add_audio_source(&mut self) -> Result<Box<dyn Audio>, HostError<Self::Error>> {
let source = AudioSource::new(self.mixer.as_ref().unwrap().clone()); let source = AudioSource::new(self.mixer.as_ref().unwrap().clone());
Ok(Box::new(source)) Ok(Box::new(source))
} }
fn register_controllers(&mut self, sender: EventSender<ControllerEvent>) -> Result<(), Error> { fn register_controllers(&mut self, sender: EventSender<ControllerEvent>) -> Result<(), HostError<Self::Error>> {
if self.controllers.is_some() { if self.controllers.is_some() {
return Err(Error::new("A controller updater has already been registered with the frontend")); return Err(HostError::Specific(Error::new("A controller updater has already been registered with the frontend")));
} }
self.controllers = Some(sender); self.controllers = Some(sender);
Ok(()) Ok(())
} }
fn register_keyboard(&mut self, sender: EventSender<KeyEvent>) -> Result<(), Error> { fn register_keyboard(&mut self, sender: EventSender<KeyEvent>) -> Result<(), HostError<Self::Error>> {
if self.keyboard.is_some() { if self.keyboard.is_some() {
return Err(Error::new("A keyboard updater has already been registered with the frontend")); return Err(HostError::Specific(Error::new("A keyboard updater has already been registered with the frontend")));
} }
self.keyboard = Some(sender); self.keyboard = Some(sender);
Ok(()) Ok(())
} }
fn register_mouse(&mut self, sender: EventSender<MouseEvent>) -> Result<(), Error> { fn register_mouse(&mut self, sender: EventSender<MouseEvent>) -> Result<(), HostError<Self::Error>> {
if self.mouse.is_some() { if self.mouse.is_some() {
return Err(Error::new("A mouse updater has already been registered with the frontend")); return Err(HostError::Specific(Error::new("A mouse updater has already been registered with the frontend")));
} }
self.mouse = Some(sender); self.mouse = Some(sender);
Ok(()) Ok(())

View File

@ -11,6 +11,7 @@ femtos = "0.1"
moa-core = { path = "../../core" } moa-core = { path = "../../core" }
moa-common = { path = "../common", features = ["audio"] } moa-common = { path = "../common", features = ["audio"] }
moa-host = { path = "../../libraries/host" }
moa-systems-genesis = { path = "../../systems/genesis" } moa-systems-genesis = { path = "../../systems/genesis" }

View File

@ -5,7 +5,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, ControllerDevice, ControllerInput, ControllerEvent, EventSender, Audio, DummyAudio, FrameReceiver}; use moa_host::{Host, HostError, PixelEncoding, Frame, ControllerDevice, ControllerInput, ControllerEvent, EventSender, Audio, DummyAudio, FrameReceiver};
use moa_common::{AudioMixer, AudioSource, CpalAudioOutput}; use moa_common::{AudioMixer, AudioSource, CpalAudioOutput};
use crate::settings; use crate::settings;
@ -45,17 +45,19 @@ impl PixelsFrontend {
} }
impl Host for PixelsFrontend { impl Host for PixelsFrontend {
fn add_video_source(&mut self, receiver: FrameReceiver) -> Result<(), Error> { type Error = Error;
fn add_video_source(&mut self, receiver: FrameReceiver) -> Result<(), HostError<Self::Error>> {
self.video = Some(receiver); self.video = Some(receiver);
Ok(()) Ok(())
} }
fn register_controllers(&mut self, sender: EventSender<ControllerEvent>) -> Result<(), Error> { fn register_controllers(&mut self, sender: EventSender<ControllerEvent>) -> Result<(), HostError<Self::Error>> {
self.controllers = Some(sender); self.controllers = Some(sender);
Ok(()) Ok(())
} }
fn add_audio_source(&mut self) -> Result<Box<dyn Audio>, Error> { fn add_audio_source(&mut self) -> Result<Box<dyn Audio>, HostError<Self::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()))

View File

@ -14,7 +14,7 @@ use wasm_bindgen::closure::Closure;
use femtos::{Duration as FemtosDuration}; use femtos::{Duration as FemtosDuration};
use moa_core::{System, Device}; use moa_core::{System, Device};
use moa_core::host::{ControllerInput, ControllerDevice, ControllerEvent, EventSender}; use moa_host::{ControllerInput, ControllerDevice, ControllerEvent, EventSender};
use crate::settings; use crate::settings;
use crate::frontend::{self, PixelsFrontend, LoadSystemFn}; use crate::frontend::{self, PixelsFrontend, LoadSystemFn};

View File

@ -0,0 +1,7 @@
[package]
name = "moa-debugger"
version = "0.1.0"
edition = "2021"
[dependencies]
moa-core = { path = "../../core" }

View File

@ -1,5 +1,5 @@
use crate::{Error, System, Address, Addressable}; use moa_core::{Error, System, Address, Addressable};
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]

View File

@ -0,0 +1,16 @@
[package]
name = "moa-host"
version = "0.1.0"
edition = "2021"
rust-version = "1.60"
categories = ["emulators"]
keywords = ["emulators"]
description = "traits for abstracting the I/O of an emulated system to the host"
authors = ["transistor fet <trans@jabberwocky.ca>"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/transistorfet/moa"
readme = "README.md"
[dependencies]
femtos = "0.1"
thiserror = "1.0"

View File

@ -1,7 +1,7 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use femtos::Instant; use femtos::Instant;
use crate::host::traits::ClockedQueue; use crate::traits::ClockedQueue;
pub const MASK_COLOUR: u32 = 0xFFFFFFFF; pub const MASK_COLOUR: u32 = 0xFFFFFFFF;

View File

@ -0,0 +1,17 @@
mod audio;
mod controllers;
mod gfx;
mod input;
mod keys;
mod mouse;
mod traits;
pub use crate::audio::{Sample, AudioFrame};
pub use crate::gfx::{Pixel, PixelEncoding, Frame, FrameSender, FrameReceiver, frame_queue};
pub use crate::keys::{Key, KeyEvent};
pub use crate::mouse::{MouseButton, MouseEventType, MouseEvent, MouseState};
pub use crate::controllers::{ControllerDevice, ControllerInput, ControllerEvent};
pub use crate::input::{EventSender, EventReceiver, event_queue};
pub use crate::traits::{Host, HostError, Tty, Audio, ClockedQueue, DummyAudio};

View File

@ -1,40 +1,70 @@
use std::fmt;
use std::error::Error;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use femtos::Instant; use femtos::Instant;
use crate::Error; use crate::gfx::FrameReceiver;
use crate::host::gfx::FrameReceiver; use crate::audio::Sample;
use crate::host::audio::Sample; use crate::keys::KeyEvent;
use crate::host::keys::KeyEvent; use crate::controllers::ControllerEvent;
use crate::host::controllers::ControllerEvent; use crate::mouse::MouseEvent;
use crate::host::mouse::MouseEvent; use crate::input::EventSender;
use crate::host::input::EventSender;
#[derive(Clone, Debug, thiserror::Error)]
pub enum HostError<E> {
TTYNotSupported,
VideoSourceNotSupported,
AudioSourceNotSupported,
ControllerNotSupported,
KeyboardNotSupported,
MouseNotSupported,
#[from(E)]
Specific(E),
}
/*
impl<E> fmt::Display for HostError<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
HostError::TTYNotSupported => write!(f, "This frontend doesn't support PTYs"),
HostError::VideoSourceNotSupported => write!(f, "This frontend doesn't support windows"),
HostError::AudioSourceNotSupported => write!(f, "This frontend doesn't support the sound"),
HostError::ControllerNotSupported => write!(f, "This frontend doesn't support game controllers"),
HostError::KeyboardNotSupported => write!(f, "This frontend doesn't support the keyboard"),
HostError::MouseNotSupported => write!(f, "This frontend doesn't support the mouse"),
HostError::Specific(err) => write!(f, "{}", err),
}
}
}
*/
pub trait Host { pub trait Host {
fn add_pty(&self) -> Result<Box<dyn Tty>, Error> { type Error: Error;
Err(Error::new("This frontend doesn't support PTYs"))
fn add_pty(&self) -> Result<Box<dyn Tty>, HostError<Self::Error>> {
Err(HostError::TTYNotSupported)
} }
fn add_video_source(&mut self, _receiver: FrameReceiver) -> Result<(), Error> { fn add_video_source(&mut self, _receiver: FrameReceiver) -> Result<(), HostError<Self::Error>> {
Err(Error::new("This frontend doesn't support windows")) Err(HostError::VideoSourceNotSupported)
} }
fn add_audio_source(&mut self) -> Result<Box<dyn Audio>, Error> { fn add_audio_source(&mut self) -> Result<Box<dyn Audio>, HostError<Self::Error>> {
Err(Error::new("This frontend doesn't support the sound")) Err(HostError::AudioSourceNotSupported)
} }
fn register_controllers(&mut self, _sender: EventSender<ControllerEvent>) -> Result<(), Error> { fn register_controllers(&mut self, _sender: EventSender<ControllerEvent>) -> Result<(), HostError<Self::Error>> {
Err(Error::new("This frontend doesn't support game controllers")) Err(HostError::ControllerNotSupported)
} }
fn register_keyboard(&mut self, _sender: EventSender<KeyEvent>) -> Result<(), Error> { fn register_keyboard(&mut self, _sender: EventSender<KeyEvent>) -> Result<(), HostError<Self::Error>> {
Err(Error::new("This frontend doesn't support the keyboard")) Err(HostError::KeyboardNotSupported)
} }
fn register_mouse(&mut self, _sender: EventSender<MouseEvent>) -> Result<(), Error> { fn register_mouse(&mut self, _sender: EventSender<MouseEvent>) -> Result<(), HostError<Self::Error>> {
Err(Error::new("This frontend doesn't support the mouse")) Err(HostError::MouseNotSupported)
} }
} }

View File

@ -0,0 +1,7 @@
[package]
name = "moa-signals"
version = "0.1.0"
edition = "2021"
[dependencies]
femtos = "0.1"

View File

@ -7,3 +7,4 @@ edition = "2021"
log = "0.4" log = "0.4"
femtos = "0.1" femtos = "0.1"
moa-core = { path = "../../core" } moa-core = { path = "../../core" }
moa-signals = { path = "../../libraries/signals" }

View File

@ -1,8 +1,8 @@
use femtos::{Instant, Duration}; use femtos::{Instant, Duration};
use moa_core::{Error, System, Address, Addressable, Steppable, Transmutable, Signal, ObservableSignal, Observable}; use moa_core::{Error, System, Address, Addressable, Steppable, Transmutable};
use moa_signals::{Signal, ObservableSignal, Observable};
const REG_OUTPUT_B: Address = 0x00; const REG_OUTPUT_B: Address = 0x00;
const REG_OUTPUT_A: Address = 0x01; const REG_OUTPUT_A: Address = 0x01;

View File

@ -7,3 +7,4 @@ edition = "2021"
log = "0.4" log = "0.4"
femtos = "0.1" femtos = "0.1"
moa-core = { path = "../../core" } moa-core = { path = "../../core" }
moa-host = { path = "../../libraries/host" }

View File

@ -2,7 +2,7 @@
use femtos::{Instant, Duration, Frequency}; use femtos::{Instant, Duration, Frequency};
use moa_core::{System, Error, Address, Steppable, Addressable, Transmutable}; use moa_core::{System, Error, Address, Steppable, Addressable, Transmutable};
use moa_core::host::Tty; use moa_host::Tty;
const REG_MR1A_MR2A: Address = 0x01; const REG_MR1A_MR2A: Address = 0x01;

View File

@ -7,5 +7,6 @@ edition = "2021"
log = "^0.4" log = "^0.4"
femtos = "0.1" femtos = "0.1"
moa-core = { path = "../../core" } moa-core = { path = "../../core" }
moa-host = { path = "../../libraries/host" }
moa-audio = { path = "../../libraries/audio" } moa-audio = { path = "../../libraries/audio" }
lazy_static = "1.4.0" lazy_static = "1.4.0"

View File

@ -2,7 +2,7 @@
use femtos::{Instant, Duration, Frequency}; use femtos::{Instant, Duration, Frequency};
use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable}; use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable};
use moa_core::host::{Host, Audio, Sample}; use moa_host::{Host, HostError, Audio, Sample};
use moa_audio::SquareWave; use moa_audio::SquareWave;
@ -94,7 +94,10 @@ pub struct Sn76489 {
} }
impl Sn76489 { impl Sn76489 {
pub fn new<H: Host>(host: &mut H, _clock_frequency: Frequency) -> Result<Self, Error> { pub fn new<H, E>(host: &mut H, _clock_frequency: Frequency) -> Result<Self, HostError<E>>
where
H: Host<Error = E>
{
let source = host.add_audio_source()?; let source = host.add_audio_source()?;
let sample_rate = source.samples_per_second(); let sample_rate = source.samples_per_second();

View File

@ -21,7 +21,7 @@ use lazy_static::lazy_static;
use femtos::{Instant, Duration, Frequency}; use femtos::{Instant, Duration, Frequency};
use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable}; use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable};
use moa_core::host::{Host, Audio, Sample}; use moa_host::{Host, HostError, Audio, Sample};
/// Table of shift values for each possible rate angle /// Table of shift values for each possible rate angle
@ -739,7 +739,10 @@ pub struct Ym2612 {
} }
impl Ym2612 { impl Ym2612 {
pub fn new<H: Host>(host: &mut H, clock_frequency: Frequency) -> Result<Self, Error> { pub fn new<H, E>(host: &mut H, clock_frequency: Frequency) -> Result<Self, HostError<E>>
where
H: Host<Error = E>,
{
let source = host.add_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();

View File

@ -7,6 +7,7 @@ edition = "2021"
log = "0.4" log = "0.4"
femtos = "0.1" femtos = "0.1"
moa-core = { path = "../../core" } moa-core = { path = "../../core" }
moa-host = { path = "../../libraries/host" }
moa-m68k = { path = "../../cpus/m68k" } moa-m68k = { path = "../../cpus/m68k" }
moa-peripherals-generic = { path = "../../peripherals/generic" } moa-peripherals-generic = { path = "../../peripherals/generic" }
moa-peripherals-motorola = { path = "../../peripherals/motorola" } moa-peripherals-motorola = { path = "../../peripherals/motorola" }

View File

@ -2,7 +2,7 @@
use femtos::Frequency; use femtos::Frequency;
use moa_core::{System, Error, Debuggable, MemoryBlock, Device}; use moa_core::{System, Error, Debuggable, MemoryBlock, Device};
use moa_core::host::Host; use moa_host::Host;
use moa_m68k::{M68k, M68kType}; use moa_m68k::{M68k, M68kType};
use moa_peripherals_generic::AtaDevice; use moa_peripherals_generic::AtaDevice;

View File

@ -7,6 +7,8 @@ edition = "2021"
log = "0.4" log = "0.4"
femtos = "0.1" femtos = "0.1"
moa-core = { path = "../../core" } moa-core = { path = "../../core" }
moa-signals = { path = "../../libraries/signals" }
moa-host = { path = "../../libraries/host" }
moa-peripherals-yamaha = { path = "../../peripherals/yamaha" } moa-peripherals-yamaha = { path = "../../peripherals/yamaha" }
moa-m68k = { path = "../../cpus/m68k" } moa-m68k = { path = "../../cpus/m68k" }
moa-z80 = { path = "../../cpus/z80" } moa-z80 = { path = "../../cpus/z80" }

View File

@ -1,9 +1,9 @@
use femtos::{Instant, Duration}; use femtos::{Instant, Duration};
use moa_core::{System, Error, Signal, Address, Addressable, Steppable, Transmutable}; use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable};
use moa_core::host::{self, Host, ControllerDevice, ControllerInput, ControllerEvent, EventReceiver}; use moa_host::{self, Host, HostError, ControllerDevice, ControllerInput, ControllerEvent, EventReceiver};
use moa_signals::{Signal};
const REG_VERSION: Address = 0x01; const REG_VERSION: Address = 0x01;
const REG_DATA1: Address = 0x03; const REG_DATA1: Address = 0x03;
@ -97,8 +97,11 @@ pub struct GenesisControllers {
} }
impl GenesisControllers { impl GenesisControllers {
pub fn new<H: Host>(host: &mut H) -> Result<Self, Error> { pub fn new<H, E>(host: &mut H) -> Result<Self, HostError<E>>
let (sender, receiver) = host::event_queue(); where
H: Host<Error = E>,
{
let (sender, receiver) = moa_host::event_queue();
host.register_controllers(sender)?; host.register_controllers(sender)?;
Ok(Self { Ok(Self {

View File

@ -3,8 +3,8 @@ use std::rc::Rc;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use femtos::Instant; use femtos::Instant;
use moa_core::{Bus, Signal, Error, Address, Addressable, Transmutable}; use moa_core::{Bus, Error, Address, Addressable, Transmutable};
use moa_signals::Signal;
const DEV_NAME: &str = "coprocessor"; const DEV_NAME: &str = "coprocessor";

View File

@ -1,9 +1,9 @@
use femtos::{Instant, Duration, Frequency}; use femtos::{Instant, Duration, Frequency};
use moa_core::{System, Error, EdgeSignal, Signal, Address, Addressable, Steppable, Inspectable, Transmutable, Device, read_beu16, dump_slice}; use moa_core::{System, Error, Address, Addressable, Steppable, Inspectable, Transmutable, Device, read_beu16, dump_slice};
use moa_core::host::{self, Host, Pixel, PixelEncoding, Frame, FrameSender}; use moa_host::{self, Host, HostError, Pixel, PixelEncoding, Frame, FrameSender};
use moa_signals::{EdgeSignal, Signal};
const DEV_NAME: &str = "ym7101"; const DEV_NAME: &str = "ym7101";
@ -717,17 +717,20 @@ pub struct Ym7101 {
} }
impl Ym7101 { impl Ym7101 {
pub fn new<H: Host>(host: &mut H, external_interrupt: Signal<bool>, sn_sound: Device) -> Ym7101 { pub fn new<H, E>(host: &mut H, external_interrupt: Signal<bool>, sn_sound: Device) -> Result<Ym7101, HostError<E>>
let (sender, receiver) = host::frame_queue(320, 224); where
host.add_video_source(receiver).unwrap(); H: Host<Error = E>,
{
let (sender, receiver) = moa_host::frame_queue(320, 224);
host.add_video_source(receiver)?;
Ym7101 { Ok(Ym7101 {
sender, sender,
state: Ym7101State::default(), state: Ym7101State::default(),
sn_sound, sn_sound,
external_interrupt, external_interrupt,
vsync_interrupt: EdgeSignal::default(), vsync_interrupt: EdgeSignal::default(),
} })
} }
fn set_register(&mut self, word: u16) { fn set_register(&mut self, word: u16) {

View File

@ -6,7 +6,7 @@ use std::cell::RefCell;
use femtos::Frequency; use femtos::Frequency;
use moa_core::{System, Error, MemoryBlock, Bus, Address, Addressable, Device}; use moa_core::{System, Error, MemoryBlock, Bus, Address, Addressable, Device};
use moa_core::host::Host; use moa_host::Host;
use moa_m68k::{M68k, M68kType}; use moa_m68k::{M68k, M68kType};
use moa_z80::{Z80, Z80Type}; use moa_z80::{Z80, Z80Type};
@ -45,13 +45,13 @@ pub fn build_genesis<H: Host>(host: &mut H, mut options: SegaGenesisOptions) ->
let rom = MemoryBlock::new(rom_data); let rom = MemoryBlock::new(rom_data);
//rom.read_only(); //rom.read_only();
let rom_end = rom.size(); let rom_end = rom.size();
system.add_addressable_device(0x00000000, Device::new(rom)).unwrap(); system.add_addressable_device(0x00000000, Device::new(rom))?;
let cartridge_nvram = MemoryBlock::new(vec![0; 0x400000 - rom_end]); let cartridge_nvram = MemoryBlock::new(vec![0; 0x400000 - rom_end]);
system.add_addressable_device(rom_end as Address, Device::new(cartridge_nvram)).unwrap(); system.add_addressable_device(rom_end as Address, Device::new(cartridge_nvram))?;
let ram = MemoryBlock::new(vec![0; 0x00010000]); let ram = MemoryBlock::new(vec![0; 0x00010000]);
system.add_addressable_device(0x00ff0000, Device::new(ram)).unwrap(); system.add_addressable_device(0x00ff0000, Device::new(ram))?;
// Build the Coprocessor's Bus // Build the Coprocessor's Bus
@ -86,16 +86,16 @@ pub fn build_genesis<H: Host>(host: &mut H, mut options: SegaGenesisOptions) ->
let controllers = GenesisControllers::new(host)?; let controllers = GenesisControllers::new(host)?;
let interrupt = controllers.get_interrupt_signal(); let interrupt = controllers.get_interrupt_signal();
system.add_addressable_device(0x00a10000, Device::new(controllers)).unwrap(); system.add_addressable_device(0x00a10000, Device::new(controllers))?;
let coproc = CoprocessorCoordinator::new(reset, bus_request); let coproc = CoprocessorCoordinator::new(reset, bus_request);
system.add_addressable_device(0x00a11000, Device::new(coproc)).unwrap(); system.add_addressable_device(0x00a11000, Device::new(coproc))?;
let vdp = Ym7101::new(host, interrupt, coproc_sn_sound); let vdp = Ym7101::new(host, interrupt, coproc_sn_sound)?;
system.add_peripheral("vdp", 0x00c00000, Device::new(vdp)).unwrap(); system.add_peripheral("vdp", 0x00c00000, Device::new(vdp))?;
let cpu = M68k::from_type(M68kType::MC68000, Frequency::from_hz(7_670_454), system.bus.clone(), 0); let cpu = M68k::from_type(M68kType::MC68000, Frequency::from_hz(7_670_454), system.bus.clone(), 0);
system.add_interruptable_device("cpu", Device::new(cpu)).unwrap(); system.add_interruptable_device("cpu", Device::new(cpu))?;
Ok(system) Ok(system)
} }

View File

@ -7,6 +7,8 @@ edition = "2021"
log = "0.4" log = "0.4"
femtos = "0.1" femtos = "0.1"
moa-core = { path = "../../core" } moa-core = { path = "../../core" }
moa-host = { path = "../../libraries/host" }
moa-signals = { path = "../../libraries/signals" }
moa-m68k = { path = "../../cpus/m68k" } moa-m68k = { path = "../../cpus/m68k" }
moa-peripherals-mos = { path = "../../peripherals/mos" } moa-peripherals-mos = { path = "../../peripherals/mos" }
moa-peripherals-zilog = { path = "../../peripherals/zilog" } moa-peripherals-zilog = { path = "../../peripherals/zilog" }

View File

@ -3,7 +3,8 @@ use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;
use femtos::{Instant, Duration}; use femtos::{Instant, Duration};
use moa_core::{System, Bus, Error, Observable, Address, Addressable, AddressRepeater, Steppable, Transmutable, Device}; use moa_core::{System, Bus, Error, Address, Addressable, AddressRepeater, Steppable, Transmutable, Device};
use moa_signals::Observable;
use moa_peripherals_mos::Mos6522; use moa_peripherals_mos::Mos6522;
use moa_peripherals_zilog::Z8530; use moa_peripherals_zilog::Z8530;

View File

@ -2,7 +2,7 @@
use femtos::Duration; use femtos::Duration;
use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable}; use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable};
use moa_core::host::{self, Host, Frame, FrameSender, Pixel}; use moa_host::{self, Host, HostError, Frame, FrameSender, Pixel};
const SCRN_BASE: u32 = 0x07A700; const SCRN_BASE: u32 = 0x07A700;
@ -13,8 +13,11 @@ pub struct MacVideo {
} }
impl MacVideo { impl MacVideo {
pub fn new<H: Host>(host: &mut H) -> Result<Self, Error> { pub fn new<H, E>(host: &mut H) -> Result<Self, HostError<E>>
let (frame_sender, frame_receiver) = host::frame_queue(SCRN_SIZE.0, SCRN_SIZE.1); where
H: Host<Error = E>,
{
let (frame_sender, frame_receiver) = moa_host::frame_queue(SCRN_SIZE.0, SCRN_SIZE.1);
host.add_video_source(frame_receiver)?; host.add_video_source(frame_receiver)?;

View File

@ -2,7 +2,7 @@
use femtos::Frequency; use femtos::Frequency;
use moa_core::{System, Error, MemoryBlock, Debuggable, Device}; use moa_core::{System, Error, MemoryBlock, Debuggable, Device};
use moa_core::host::Host; use moa_host::Host;
use moa_m68k::{M68k, M68kType}; use moa_m68k::{M68k, M68kType};

View File

@ -7,5 +7,6 @@ edition = "2021"
log = "0.4" log = "0.4"
femtos = "0.1" femtos = "0.1"
moa-core = { path = "../../core" } moa-core = { path = "../../core" }
moa-host = { path = "../../libraries/host" }
moa-z80 = { path = "../../cpus/z80" } moa-z80 = { path = "../../cpus/z80" }

View File

@ -650,7 +650,7 @@ const CHARACTERS: [[u8; 8]; 64] = [
]; ];
use moa_core::host::Pixel; use moa_host::Pixel;
pub struct CharacterGenerator { pub struct CharacterGenerator {
pub row: i8, pub row: i8,

View File

@ -1,5 +1,5 @@
use moa_core::host::Key; use moa_host::Key;
#[inline(always)] #[inline(always)]
pub fn set_bit(data: &mut [u8; 8], index: usize, bit: u8, state: bool) { pub fn set_bit(data: &mut [u8; 8], index: usize, bit: u8, state: bool) {

View File

@ -2,7 +2,7 @@
use femtos::{Instant, Duration}; use femtos::{Instant, Duration};
use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable}; use moa_core::{System, Error, Address, Addressable, Steppable, Transmutable};
use moa_core::host::{self, Host, Frame, FrameSender, KeyEvent, EventReceiver}; use moa_host::{self, Host, HostError, Frame, FrameSender, KeyEvent, EventReceiver};
use super::keymap; use super::keymap;
use super::charset::CharacterGenerator; use super::charset::CharacterGenerator;
@ -18,8 +18,11 @@ pub struct Model1Keyboard {
} }
impl Model1Keyboard { impl Model1Keyboard {
pub fn new<H: Host>(host: &mut H) -> Result<Self, Error> { pub fn new<H, E>(host: &mut H) -> Result<Self, HostError<E>>
let (sender, receiver) = host::event_queue(); where
H: Host<Error = E>,
{
let (sender, receiver) = moa_host::event_queue();
host.register_keyboard(sender)?; host.register_keyboard(sender)?;
Ok(Self { Ok(Self {
@ -86,8 +89,11 @@ pub struct Model1Video {
} }
impl Model1Video { impl Model1Video {
pub fn new<H: Host>(host: &mut H) -> Result<Self, Error> { pub fn new<H, E>(host: &mut H) -> Result<Self, HostError<E>>
let (frame_sender, frame_receiver) = host::frame_queue(SCREEN_SIZE.0, SCREEN_SIZE.1); where
H: Host<Error = E>,
{
let (frame_sender, frame_receiver) = moa_host::frame_queue(SCREEN_SIZE.0, SCREEN_SIZE.1);
host.add_video_source(frame_receiver)?; host.add_video_source(frame_receiver)?;

View File

@ -2,7 +2,7 @@
use femtos::Frequency; use femtos::Frequency;
use moa_core::{System, Error, MemoryBlock, Device}; use moa_core::{System, Error, MemoryBlock, Device};
use moa_core::host::Host; use moa_host::Host;
use moa_z80::{Z80, Z80Type}; use moa_z80::{Z80, Z80Type};