From f9e018742b1d087aa85c37f59e20154921bde612 Mon Sep 17 00:00:00 2001 From: transistor Date: Thu, 21 Oct 2021 21:55:27 -0700 Subject: [PATCH] Refactored how UI interfacing will work --- Cargo.toml | 3 +- frontends/moa-console/src/bin/moa-bench.rs | 52 +++ frontends/moa-console/src/bin/moa-computie.rs | 5 +- frontends/moa-console/src/lib.rs | 13 +- src/host/frontend/mod.rs | 11 - src/host/frontend/traits.rs | 345 ------------------ src/host/mod.rs | 2 +- src/host/traits.rs | 73 ++++ src/machines/computie.rs | 14 +- src/system.rs | 15 + todo.txt | 6 + 11 files changed, 166 insertions(+), 373 deletions(-) create mode 100644 frontends/moa-console/src/bin/moa-bench.rs delete mode 100644 src/host/frontend/mod.rs delete mode 100644 src/host/frontend/traits.rs create mode 100644 src/host/traits.rs diff --git a/Cargo.toml b/Cargo.toml index fe558f0..38dbccd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,10 +4,11 @@ version = "0.1.0" edition = "2018" [workspace] -members = [".", "frontends/moa-console", "frontends/moa-piston"] +members = [".", "frontends/moa-console"] default-members = ["frontends/moa-console"] [features] +default = ["tty"] tty = ["nix"] [dependencies] diff --git a/frontends/moa-console/src/bin/moa-bench.rs b/frontends/moa-console/src/bin/moa-bench.rs new file mode 100644 index 0000000..4beadf3 --- /dev/null +++ b/frontends/moa-console/src/bin/moa-bench.rs @@ -0,0 +1,52 @@ + +use std::thread; +use std::time::Duration; + +use moa::error::Error; +use moa::system::System; +use moa::memory::MemoryBlock; +use moa::devices::wrap_transmutable; + +use moa::cpus::m68k::{M68k, M68kType}; +use moa::peripherals::ata::AtaDevice; +use moa::peripherals::mc68681::MC68681; + +use moa::machines::computie::build_computie; + +fn main() { + thread::spawn(|| { + let mut system = System::new(); + + let monitor = MemoryBlock::load("binaries/monitor.bin").unwrap(); + system.add_addressable_device(0x00000000, wrap_transmutable(monitor)).unwrap(); + + let mut ram = MemoryBlock::new(vec![0; 0x00100000]); + ram.load_at(0, "binaries/kernel.bin").unwrap(); + system.add_addressable_device(0x00100000, wrap_transmutable(ram)).unwrap(); + + let mut ata = AtaDevice::new(); + ata.load("binaries/disk-with-partition-table.img").unwrap(); + system.add_addressable_device(0x00600000, wrap_transmutable(ata)).unwrap(); + + let mut serial = MC68681::new(); + system.add_addressable_device(0x00700000, wrap_transmutable(serial)).unwrap(); + + + let mut cpu = M68k::new(M68kType::MC68030); + + //cpu.enable_tracing(); + //cpu.add_breakpoint(0x10781a); + //cpu.add_breakpoint(0x10bc9c); + //cpu.add_breakpoint(0x106a94); + //cpu.add_breakpoint(0x1015b2); + //cpu.add_breakpoint(0x103332); + //cpu.decoder.dump_disassembly(&mut system, 0x100000, 0x2000); + //cpu.decoder.dump_disassembly(&mut system, 0x2ac, 0x200); + + system.add_interruptable_device(wrap_transmutable(cpu)).unwrap(); + + system.run_loop(); + }); + thread::sleep(Duration::from_secs(10)); +} + diff --git a/frontends/moa-console/src/bin/moa-computie.rs b/frontends/moa-console/src/bin/moa-computie.rs index 6bdabd3..7547f11 100644 --- a/frontends/moa-console/src/bin/moa-computie.rs +++ b/frontends/moa-console/src/bin/moa-computie.rs @@ -1,10 +1,11 @@ use moa_console::ConsoleFrontend; -use moa::machines::computie::run_computie; +use moa::machines::computie::build_computie; fn main() { let mut frontend = ConsoleFrontend; - run_computie(&mut frontend); + let mut system = build_computie(&mut frontend).unwrap(); + system.run_loop(); } diff --git a/frontends/moa-console/src/lib.rs b/frontends/moa-console/src/lib.rs index bf62020..47718ec 100644 --- a/frontends/moa-console/src/lib.rs +++ b/frontends/moa-console/src/lib.rs @@ -1,16 +1,13 @@ use moa::error::Error; -use moa::host::frontend::{Frontend, SharedCanvas, SharedAudio}; +use moa::host::traits::{Host, WindowUpdater}; pub struct ConsoleFrontend; -impl Frontend for ConsoleFrontend { - fn get_canvas(&mut self) -> Result { - Err(Error::new("Console frontend doesn't support canvas")) - } - - fn get_audio(&mut self) -> Result { - Err(Error::new("Console frontend doesn't support audio")) +impl Host for ConsoleFrontend { + fn add_window(&self, updater: Box) -> Result<(), Error> { + println!("console: add_window() is not supported from the console; ignoring request..."); + Ok(()) } } diff --git a/src/host/frontend/mod.rs b/src/host/frontend/mod.rs deleted file mode 100644 index 3ac59d1..0000000 --- a/src/host/frontend/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ - -pub mod traits; - -pub use self::traits::{ - Frontend, - Canvas, - SharedCanvas, - Audio, - SharedAudio, -}; - diff --git a/src/host/frontend/traits.rs b/src/host/frontend/traits.rs deleted file mode 100644 index e38e910..0000000 --- a/src/host/frontend/traits.rs +++ /dev/null @@ -1,345 +0,0 @@ - -use std::sync::{Arc, Mutex}; - -use crate::error::Error; - -//pub trait Canvas: Send { -//} - -//pub trait Audio { -// -//} - -//pub type SharedCanvas = Arc>>; -//pub type SharedAudio = Arc>>; - -// TODO instead make something like HostAdapter, or a representation of the backend, which it's given to the builder function -pub trait Frontend { - //fn set_size(&mut self, x: u32, y: u32); - //fn draw_bitmap(&mut self, x: u32, y: u32, bitmap: &[u8]); - //fn set_update_callback(&mut self, update: Box ()>); - fn request_update(&self, x: u32, y: u32, bitmap: &[u8]); -} - -struct HostAdapter { - bitmap: Mutex>, -} - - - -// Types: -// Window (gfx out + input) -// Audio -// TTY -// Network - - -/* - -// Opt 1 - Simple Callback - -pub trait Window { - fn draw_bitmap(&self, x: u32, y: u32, bitmap: &[u32]); -} - -pub trait Host { - fn register_update(&mut self, func: fn(T, W), data: T); -} - -// TODO how will the object data be shared with the device - -*/ - - -/* -// Opt 4 - The Host Generic Device Method - -pub trait Window { - fn request_update(&self, x: u32, y: u32, bitmap: &[u32]); -} - -pub trait Host { - fn create_window(&mut self) -> W; -} - -pub struct YmDevice { - pub window: W, - pub buffer: Vec, -} - -impl YmDevice { - pub fn new(host: &mut H) -> YmDevice { - YmDevice { - window: host.create_window(), - buffer: vec![0; 200 * 200], - } - } - - pub fn step(&mut self) { - self.window.request_update(200, 200, self.buffer.as_slice()); - } -} - -pub struct CustomWindow { - pub buffer: Mutex>, -} - -impl CustomWindow { - fn request_update(&self, x: u32, y: u32, bitmap: &[u32]) { - let mut target = self.buffer.lock().unwrap(); - for i in 0..target.len() { - target[i] = bitmap[i]; - } - } -} -*/ - - - -/* -// Opt 2 - The Callback Through Trait Method - -pub trait Window { - fn render(&self, x: u32, y: u32, bitmap: &mut [u8]); -} - -pub trait Host { - fn register_window(&mut self, window: Arc) -> Result<(), Error>; -} - - - -pub struct YmDevice(Arc); - -pub struct YmDeviceInternal { - //pub window: Window, - // some things -} - -impl YmDevice { - pub fn new(host: &mut H) -> YmDevice { - let device = Arc::new(YmDeviceInternal { - - }); - - host.register_window(device.clone()).unwrap(); - YmDevice(device) - } -} - -impl Window for YmDeviceInternal { - fn render(&self, x: u32, y: u32, bitmap: &mut [u8]) { - println!("here"); - } -} - -impl Addressable for YmDevice { - -} - -*/ - - -/* -// Opt 3 - The Callback Through Common Backend-defined Object Method - -pub struct Window { - width: u32, - height: u32, - buffer: Vec -} - -impl Window { - fn render(&self, x: u32, y: u32, bitmap: &mut [u8]) { - - } -} - -pub trait Host { - fn register_window(&mut self, window: Arc) -> Result<(), Error>; -} - - - -pub struct YmDevice(Arc); - -pub struct YmDeviceInternal { - //pub window: Window, - // some things -} - -impl YmDevice { - pub fn new(host: &mut H) -> YmDevice { - let device = Arc::new(YmDeviceInternal { - - }); - - host.register_window(device.clone()).unwrap(); - YmDevice(device) - } -} - -impl Window for YmDeviceInternal { - fn render(&self, x: u32, y: u32, bitmap: &mut [u8]) { - println!("here"); - } -} - -//impl Addressable for YmDevice { -// -//} -*/ - -pub trait Host { - fn add_window(&self, window: Box); - //fn create_pty(&self) -> Tty; -} - -// TODO should you rename this Drawable, FrameUpdater, WindowUpdater? -pub trait Window: Send { - fn update_frame(&mut self, width: u32, height: u32, bitmap: &mut [u32]); -} - - - -#[derive(Clone)] -pub struct Frame { - pub width: u32, - pub height: u32, - pub bitmap: Vec, -} - -pub struct FrameSwapper { - pub current: Frame, - pub previous: Frame, -} - -impl FrameSwapper { - pub fn new() -> FrameSwapper { - FrameSwapper { - current: Frame { width: 0, height: 0, bitmap: vec![] }, - previous: Frame { width: 0, height: 0, bitmap: vec![] }, - } - } -} - -impl Window for FrameSwapper { - fn update_frame(&mut self, width: u32, height: u32, bitmap: &mut [u32]) { - std::mem::swap(&mut self.current, &mut self.previous); - println!("{} {}", self.current.width, self.current.height); - if self.current.width != width || self.current.height != height { - self.current.width = width; - self.current.height = height; - self.current.bitmap.resize((width * height) as usize, 0); - self.previous = self.current.clone(); - return; - } - - for i in 0..(width as usize * height as usize) { - bitmap[i] = self.current.bitmap[i]; - } - } -} - -pub struct FrameSwapperWrapper(Arc>); - -impl Window for FrameSwapperWrapper { - fn update_frame(&mut self, width: u32, height: u32, bitmap: &mut [u32]) { - self.0.lock().map(|mut swapper| swapper.update_frame(width, height, bitmap)); - } -} - - -pub struct YmDeviceTransmutable(YmDevice); - -pub struct YmDevice { - pub count2: u32, - pub count: Mutex, - pub frame_swapper: Arc>, -} - -impl YmDevice { - pub fn new(host: &H) -> YmDeviceTransmutable { - let frame_swapper = Arc::new(Mutex::new(FrameSwapper::new())); - let device = YmDevice { - count2: 0, - count: Mutex::new(0), - frame_swapper, - }; - - host.add_window(Box::new(FrameSwapperWrapper(device.frame_swapper.clone()))); - YmDeviceTransmutable(device) - } -} - -use crate::system::System; -use crate::devices::{Clock, Address, Transmutable, Steppable, Addressable, MAX_READ}; -impl Transmutable for YmDeviceTransmutable { - fn as_addressable(&mut self) -> Option<&mut dyn Addressable> { - Some(self) - } - - fn as_steppable(&mut self) -> Option<&mut dyn Steppable> { - Some(self) - } -} - -impl Steppable for YmDeviceTransmutable { - fn step(&mut self, system: &System) -> Result { - self.0.count2 += 1; - if self.0.count2 > 1000 { - self.0.count2 = 0; - - let value = match self.0.count.lock() { - Ok(mut value) => { *value = *value + 1; *value } - _ => { 0 }, - }; - - let mut frame = self.0.frame_swapper.lock().unwrap(); - for i in 0..(frame.current.width * frame.current.height) { - if i == value { - frame.current.bitmap[i as usize] = 0; - } else { - frame.current.bitmap[i as usize] = 12465; - } - } - } - Ok(1) - } -} - -impl Addressable for YmDeviceTransmutable { - fn len(&self) -> usize { - 0x20 - } - - fn read(&mut self, addr: Address, _count: usize) -> Result<[u8; MAX_READ], Error> { - let mut data = [0; MAX_READ]; - - debug!("read from register {:x}", addr); - Ok(data) - } - - fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { - debug!("write to register {:x} with {:x}", addr, data[0]); - Ok(()) - } -} - - -/* -pub struct CustomWindow { - pub buffer: Mutex>, -} - -impl CustomWindow { - fn request_update(&self, x: u32, y: u32, bitmap: &[u32]) { - let mut target = self.buffer.lock().unwrap(); - for i in 0..target.len() { - target[i] = bitmap[i]; - } - } -} -*/ - - diff --git a/src/host/mod.rs b/src/host/mod.rs index 7bb6bab..adfbd99 100644 --- a/src/host/mod.rs +++ b/src/host/mod.rs @@ -1,5 +1,5 @@ -pub mod frontend; +pub mod traits; #[cfg(feature = "tty")] pub mod tty; diff --git a/src/host/traits.rs b/src/host/traits.rs new file mode 100644 index 0000000..7e4fb5e --- /dev/null +++ b/src/host/traits.rs @@ -0,0 +1,73 @@ + +use std::sync::{Arc, Mutex}; + +use crate::error::Error; + + +pub trait Host { + fn add_window(&self, updater: Box) -> Result<(), Error>; + //fn create_pty(&self) -> Tty; +} + +// TODO should you rename this Drawable, FrameUpdater, WindowUpdater? +pub trait WindowUpdater: Send { + fn update_frame(&mut self, width: u32, height: u32, bitmap: &mut [u32]); +} + + + +#[derive(Clone)] +pub struct Frame { + pub width: u32, + pub height: u32, + pub bitmap: Vec, +} + +pub struct FrameSwapper { + pub current: Frame, + pub previous: Frame, +} + +impl FrameSwapper { + pub fn new() -> FrameSwapper { + FrameSwapper { + current: Frame { width: 0, height: 0, bitmap: vec![] }, + previous: Frame { width: 0, height: 0, bitmap: vec![] }, + } + } + + pub fn new_shared() -> Arc> { + Arc::new(Mutex::new(FrameSwapper::new())) + } + + pub fn to_boxed(swapper: Arc>) -> Box { + Box::new(FrameSwapperWrapper(swapper)) + } +} + +impl WindowUpdater for FrameSwapper { + fn update_frame(&mut self, width: u32, height: u32, bitmap: &mut [u32]) { + std::mem::swap(&mut self.current, &mut self.previous); + println!("{} {}", self.current.width, self.current.height); + if self.current.width != width || self.current.height != height { + self.current.width = width; + self.current.height = height; + self.current.bitmap.resize((width * height) as usize, 0); + self.previous = self.current.clone(); + return; + } + + for i in 0..(width as usize * height as usize) { + bitmap[i] = self.current.bitmap[i]; + } + } +} + +pub struct FrameSwapperWrapper(Arc>); + +impl WindowUpdater for FrameSwapperWrapper { + fn update_frame(&mut self, width: u32, height: u32, bitmap: &mut [u32]) { + self.0.lock().map(|mut swapper| swapper.update_frame(width, height, bitmap)); + } +} + diff --git a/src/machines/computie.rs b/src/machines/computie.rs index a137ac8..0f0741c 100644 --- a/src/machines/computie.rs +++ b/src/machines/computie.rs @@ -1,15 +1,17 @@ +use crate::error::Error; use crate::system::System; use crate::memory::MemoryBlock; -use crate::host::frontend::Frontend; use crate::devices::wrap_transmutable; use crate::cpus::m68k::{M68k, M68kType}; use crate::peripherals::ata::AtaDevice; use crate::peripherals::mc68681::MC68681; +use crate::host::traits::Host; -pub fn run_computie(frontend: &mut dyn Frontend) { + +pub fn build_computie(host: &H) -> Result { let mut system = System::new(); let monitor = MemoryBlock::load("binaries/monitor.bin").unwrap(); @@ -44,10 +46,11 @@ pub fn run_computie(frontend: &mut dyn Frontend) { //cpu.decoder.dump_disassembly(&mut system, 0x2ac, 0x200); system.add_interruptable_device(wrap_transmutable(cpu)).unwrap(); - system.run_loop(); + + Ok(system) } -pub fn run_computie_k30(frontend: &mut dyn Frontend) { +pub fn build_computie_k30(host: &H) -> Result { let mut system = System::new(); let monitor = MemoryBlock::load("binaries/monitor-68030.bin").unwrap(); @@ -79,7 +82,8 @@ pub fn run_computie_k30(frontend: &mut dyn Frontend) { //cpu.decoder.dump_disassembly(&mut system, 0x2ac, 0x200); system.add_interruptable_device(wrap_transmutable(cpu)).unwrap(); - system.run_loop(); + + Ok(system) } pub fn launch_terminal_emulator(name: String) { diff --git a/src/system.rs b/src/system.rs index 970efb0..b8385f7 100644 --- a/src/system.rs +++ b/src/system.rs @@ -88,5 +88,20 @@ impl System { } } } + + pub fn run_for(&mut self, clocks: Clock) -> Result<(), Error> { + let target = self.clock + clocks; + while self.clock < target { + match self.step() { + Ok(()) => { }, + Err(err) => { + self.exit_error(); + println!("{:?}", err); + return Err(err); + }, + } + } + Ok(()) + } } diff --git a/todo.txt b/todo.txt index 16ca3e3..77a382a 100644 --- a/todo.txt +++ b/todo.txt @@ -1,4 +1,10 @@ + +* generics for the frontend that's passed to the builder functions is much better than a trait object +* you could possibly use a backend representation that is given to the frontened, rather than vice versa +* you could use callbacks in some way (ie. callbacks from the gui loop to the system) + + * should the frontend and simulator parts be separated so that the simulator part can be a library package? * it should be call something other than canvas because it'll have input as well * how will you get the canvas/app shared object between the sim thread and the io thread? It kind of has to be passed through the system-creation