mirror of
https://github.com/transistorfet/moa.git
synced 2025-01-08 00:29:29 +00:00
Refactored how UI interfacing will work
This commit is contained in:
parent
fab763a867
commit
f9e018742b
@ -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]
|
||||
|
52
frontends/moa-console/src/bin/moa-bench.rs
Normal file
52
frontends/moa-console/src/bin/moa-bench.rs
Normal file
@ -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));
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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<SharedCanvas, Error> {
|
||||
Err(Error::new("Console frontend doesn't support canvas"))
|
||||
}
|
||||
|
||||
fn get_audio(&mut self) -> Result<SharedAudio, Error> {
|
||||
Err(Error::new("Console frontend doesn't support audio"))
|
||||
impl Host for ConsoleFrontend {
|
||||
fn add_window(&self, updater: Box<dyn WindowUpdater>) -> Result<(), Error> {
|
||||
println!("console: add_window() is not supported from the console; ignoring request...");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
|
||||
pub mod traits;
|
||||
|
||||
pub use self::traits::{
|
||||
Frontend,
|
||||
Canvas,
|
||||
SharedCanvas,
|
||||
Audio,
|
||||
SharedAudio,
|
||||
};
|
||||
|
@ -1,345 +0,0 @@
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
//pub trait Canvas: Send {
|
||||
//}
|
||||
|
||||
//pub trait Audio {
|
||||
//
|
||||
//}
|
||||
|
||||
//pub type SharedCanvas = Arc<Mutex<Box<dyn Canvas>>>;
|
||||
//pub type SharedAudio = Arc<Mutex<Box<dyn Audio>>>;
|
||||
|
||||
// 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(&mut [u8]) -> ()>);
|
||||
fn request_update(&self, x: u32, y: u32, bitmap: &[u8]);
|
||||
}
|
||||
|
||||
struct HostAdapter {
|
||||
bitmap: Mutex<Vec<u32>>,
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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<T, W: Window>(&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<W: Window>(&mut self) -> W;
|
||||
}
|
||||
|
||||
pub struct YmDevice<W: Window> {
|
||||
pub window: W,
|
||||
pub buffer: Vec<u32>,
|
||||
}
|
||||
|
||||
impl<W: Window> YmDevice<W> {
|
||||
pub fn new<H: Host>(host: &mut H) -> YmDevice<W> {
|
||||
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<Vec<u32>>,
|
||||
}
|
||||
|
||||
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<W: Window>(&mut self, window: Arc<W>) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub struct YmDevice(Arc<YmDeviceInternal>);
|
||||
|
||||
pub struct YmDeviceInternal {
|
||||
//pub window: Window,
|
||||
// some things
|
||||
}
|
||||
|
||||
impl YmDevice {
|
||||
pub fn new<H: Host>(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<u32>
|
||||
}
|
||||
|
||||
impl Window {
|
||||
fn render(&self, x: u32, y: u32, bitmap: &mut [u8]) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Host {
|
||||
fn register_window<W: Window>(&mut self, window: Arc<W>) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub struct YmDevice(Arc<YmDeviceInternal>);
|
||||
|
||||
pub struct YmDeviceInternal {
|
||||
//pub window: Window,
|
||||
// some things
|
||||
}
|
||||
|
||||
impl YmDevice {
|
||||
pub fn new<H: Host>(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<dyn Window>);
|
||||
//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<u32>,
|
||||
}
|
||||
|
||||
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<Mutex<FrameSwapper>>);
|
||||
|
||||
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<u32>,
|
||||
pub frame_swapper: Arc<Mutex<FrameSwapper>>,
|
||||
}
|
||||
|
||||
impl YmDevice {
|
||||
pub fn new<H: Host>(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<Clock, Error> {
|
||||
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<Vec<u32>>,
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
pub mod frontend;
|
||||
pub mod traits;
|
||||
|
||||
#[cfg(feature = "tty")]
|
||||
pub mod tty;
|
||||
|
73
src/host/traits.rs
Normal file
73
src/host/traits.rs
Normal file
@ -0,0 +1,73 @@
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
|
||||
pub trait Host {
|
||||
fn add_window(&self, updater: Box<dyn WindowUpdater>) -> 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<u32>,
|
||||
}
|
||||
|
||||
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<Mutex<FrameSwapper>> {
|
||||
Arc::new(Mutex::new(FrameSwapper::new()))
|
||||
}
|
||||
|
||||
pub fn to_boxed(swapper: Arc<Mutex<FrameSwapper>>) -> Box<dyn WindowUpdater> {
|
||||
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<Mutex<FrameSwapper>>);
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -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<H: Host>(host: &H) -> Result<System, Error> {
|
||||
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<H: Host>(host: &H) -> Result<System, Error> {
|
||||
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) {
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
6
todo.txt
6
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
|
||||
|
Loading…
Reference in New Issue
Block a user