Cleaned up warnings

This commit is contained in:
transistor 2021-12-13 12:00:24 -08:00
parent 92468b485f
commit 148b4dcf2c
28 changed files with 172 additions and 227 deletions

View File

@ -1,6 +1,6 @@
use moa::host::traits::{HostData, Audio}; use moa::host::traits::{HostData, Audio};
use cpal::{Data, Sample, Stream, SampleRate, SampleFormat, StreamConfig, traits::{DeviceTrait, HostTrait, StreamTrait}}; use cpal::{Sample, Stream, SampleRate, SampleFormat, StreamConfig, traits::{DeviceTrait, HostTrait, StreamTrait}};
const SAMPLE_RATE: usize = 48000; const SAMPLE_RATE: usize = 48000;
@ -122,8 +122,8 @@ impl AudioSource {
} }
} }
pub fn fill_with(&mut self, samples: usize, iter: &mut Iterator<Item=f32>) { pub fn fill_with(&mut self, samples: usize, iter: &mut dyn Iterator<Item=f32>) {
for i in 0..samples { for _ in 0..samples {
let sample = 0.25 * iter.next().unwrap(); let sample = 0.25 * iter.next().unwrap();
self.buffer.insert(sample); self.buffer.insert(sample);
self.buffer.insert(sample); self.buffer.insert(sample);
@ -156,7 +156,7 @@ impl Audio for AudioSource {
self.sample_rate self.sample_rate
} }
fn write_samples(&mut self, samples: usize, iter: &mut Iterator<Item=f32>) { fn write_samples(&mut self, samples: usize, iter: &mut dyn Iterator<Item=f32>) {
self.fill_with(samples, iter); self.fill_with(samples, iter);
} }
} }
@ -254,7 +254,7 @@ impl AudioMixer {
// it's running fast. (If it's running slow, you can insert silence) // it's running fast. (If it's running slow, you can insert silence)
} }
#[allow(dead_code)]
pub struct AudioOutput { pub struct AudioOutput {
stream: Stream, stream: Stream,
mixer: HostData<AudioMixer>, mixer: HostData<AudioMixer>,
@ -274,7 +274,7 @@ impl AudioOutput {
.with_sample_rate(SampleRate(SAMPLE_RATE as u32)) .with_sample_rate(SampleRate(SAMPLE_RATE as u32))
.into(); .into();
let channels = config.channels as usize; //let channels = config.channels as usize;
let data_callback = { let data_callback = {
let mixer = mixer.clone(); let mixer = mixer.clone();
@ -308,8 +308,7 @@ impl AudioOutput {
&config, &config,
data_callback, data_callback,
move |err| { move |err| {
// react to errors here. println!("ERROR: {:?}", err);
println!("ERROR");
}, },
).unwrap(); ).unwrap();

View File

@ -3,6 +3,7 @@ use std::thread;
use std::sync::mpsc; use std::sync::mpsc;
use std::time::Duration; use std::time::Duration;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::os::unix::io::AsRawFd;
use nix::fcntl::OFlag; use nix::fcntl::OFlag;
use nix::pty::{self, PtyMaster}; use nix::pty::{self, PtyMaster};

View File

@ -10,7 +10,7 @@ impl Host for ConsoleFrontend {
Ok(Box::new(SimplePty::open()?)) Ok(Box::new(SimplePty::open()?))
} }
fn add_window(&mut self, updater: Box<dyn WindowUpdater>) -> Result<(), Error> { fn add_window(&mut self, _updater: Box<dyn WindowUpdater>) -> Result<(), 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(())
} }

View File

@ -9,7 +9,7 @@ use clap::{App, ArgMatches};
use moa::error::Error; use moa::error::Error;
use moa::system::System; use moa::system::System;
use moa::host::traits::{Host, HostData, ControllerUpdater, KeyboardUpdater, WindowUpdater, Audio}; use moa::host::traits::{Host, HostData, ControllerUpdater, KeyboardUpdater, WindowUpdater, Audio};
use moa::host::controllers::{ControllerDevice, ControllerEvent}; use moa::host::controllers::{ControllerDevice};
use moa_common::audio::{AudioOutput, AudioMixer, AudioSource}; use moa_common::audio::{AudioOutput, AudioMixer, AudioSource};

View File

@ -7,9 +7,9 @@ use crate::devices::{Address, Addressable, Debuggable, TransmutableBox};
pub struct Debugger { pub struct Debugger {
pub last_command: Option<String>, last_command: Option<String>,
pub repeat: u32, repeat: u32,
pub trace_only: bool, trace_only: bool,
} }

View File

@ -50,7 +50,7 @@ pub trait KeyboardUpdater: Send {
pub trait Audio { pub trait Audio {
fn samples_per_second(&self) -> usize; fn samples_per_second(&self) -> usize;
fn write_samples(&mut self, samples: usize, iter: &mut Iterator<Item=f32>); fn write_samples(&mut self, samples: usize, iter: &mut dyn Iterator<Item=f32>);
} }
pub trait BlitableSurface { pub trait BlitableSurface {

View File

@ -4,9 +4,9 @@ use crate::devices::TransmutableBox;
pub struct InterruptController { pub struct InterruptController {
pub target: Option<TransmutableBox>, target: Option<TransmutableBox>,
pub interrupts: Vec<(bool, u8)>, interrupts: Vec<(bool, u8)>,
pub highest: u8, highest: u8,
} }
impl InterruptController { impl InterruptController {

View File

@ -69,7 +69,7 @@ pub fn build_computie_k30<H: Host>(host: &H) -> Result<System, Error> {
system.add_addressable_device(0x00700000, wrap_transmutable(serial))?; system.add_addressable_device(0x00700000, wrap_transmutable(serial))?;
let mut cpu = M68k::new(M68kType::MC68030, 10_000_000, BusPort::new(0, 32, 32, system.bus.clone())); let cpu = M68k::new(M68kType::MC68030, 10_000_000, BusPort::new(0, 32, 32, system.bus.clone()));
//cpu.enable_tracing(); //cpu.enable_tracing();
//cpu.add_breakpoint(0x10781a); //cpu.add_breakpoint(0x10781a);

View File

@ -4,9 +4,9 @@ use std::cell::RefCell;
use crate::error::Error; use crate::error::Error;
use crate::system::System; use crate::system::System;
use crate::signals::{Signal, Observable}; use crate::signals::{Signal};
use crate::memory::{MemoryBlock, Bus, BusPort}; use crate::memory::{MemoryBlock, Bus, BusPort};
use crate::devices::{wrap_transmutable, Address, Addressable, Debuggable}; use crate::devices::{wrap_transmutable, Address, Addressable};
use crate::cpus::m68k::{M68k, M68kType}; use crate::cpus::m68k::{M68k, M68kType};
use crate::cpus::z80::{Z80, Z80Type}; use crate::cpus::z80::{Z80, Z80Type};
@ -33,7 +33,7 @@ impl SegaGenesisOptions {
pub fn build_genesis<H: Host>(host: &mut H, options: SegaGenesisOptions) -> Result<System, Error> { pub fn build_genesis<H: Host>(host: &mut H, options: SegaGenesisOptions) -> Result<System, Error> {
let mut system = System::new(); let mut system = System::new();
let mut rom = MemoryBlock::load(&options.rom).unwrap(); let rom = MemoryBlock::load(&options.rom).unwrap();
//let mut rom = MemoryBlock::load("binaries/genesis/GenTestV3.0.bin").unwrap(); //let mut rom = MemoryBlock::load("binaries/genesis/GenTestV3.0.bin").unwrap();
//let mut rom = MemoryBlock::load("binaries/genesis/HDRV_Genesis_Test_v1_4.bin").unwrap(); //let mut rom = MemoryBlock::load("binaries/genesis/HDRV_Genesis_Test_v1_4.bin").unwrap();
//let mut rom = MemoryBlock::load("binaries/genesis/ComradeOj's tiny demo.bin").unwrap(); //let mut rom = MemoryBlock::load("binaries/genesis/ComradeOj's tiny demo.bin").unwrap();
@ -99,7 +99,7 @@ pub fn build_genesis<H: Host>(host: &mut H, options: SegaGenesisOptions) -> Resu
system.break_signal = Some(vdp.frame_complete.clone()); system.break_signal = Some(vdp.frame_complete.clone());
system.add_peripheral("vdp", 0x00c00000, wrap_transmutable(vdp)).unwrap(); system.add_peripheral("vdp", 0x00c00000, wrap_transmutable(vdp)).unwrap();
let mut cpu = M68k::new(M68kType::MC68000, 7_670_454, BusPort::new(0, 24, 16, system.bus.clone())); let cpu = M68k::new(M68kType::MC68000, 7_670_454, BusPort::new(0, 24, 16, system.bus.clone()));
system.add_interruptable_device("cpu", wrap_transmutable(cpu)).unwrap(); system.add_interruptable_device("cpu", wrap_transmutable(cpu)).unwrap();
Ok(system) Ok(system)

View File

@ -2,12 +2,9 @@
use crate::error::Error; use crate::error::Error;
use crate::system::System; use crate::system::System;
use crate::devices::{wrap_transmutable, Debuggable}; use crate::devices::{wrap_transmutable, Debuggable};
use crate::memory::{MemoryBlock, AddressAdapter, BusPort}; use crate::memory::{MemoryBlock, BusPort};
use crate::cpus::m68k::{M68k, M68kType}; use crate::cpus::m68k::{M68k, M68kType};
use crate::peripherals::mos6522::Mos6522;
use crate::peripherals::z8530::Z8530;
use crate::peripherals::macintosh::iwm::IWM;
use crate::peripherals::macintosh::video::MacVideo; use crate::peripherals::macintosh::video::MacVideo;
use crate::peripherals::macintosh::mainboard::Mainboard; use crate::peripherals::macintosh::mainboard::Mainboard;
@ -18,6 +15,10 @@ pub fn build_macintosh_512k<H: Host>(host: &mut H) -> Result<System, Error> {
let mut system = System::new(); let mut system = System::new();
/* /*
use crate::peripherals::mos6522::Mos6522;
use crate::peripherals::z8530::Z8530;
use crate::peripherals::macintosh::iwm::IWM;
let mut ram = MemoryBlock::new(vec![0; 0x00100000]); let mut ram = MemoryBlock::new(vec![0; 0x00100000]);
ram.load_at(0, "binaries/macintosh/Macintosh 128k.rom")?; ram.load_at(0, "binaries/macintosh/Macintosh 128k.rom")?;
let boxed_ram = wrap_transmutable(ram); let boxed_ram = wrap_transmutable(ram);
@ -60,7 +61,7 @@ pub fn build_macintosh_512k<H: Host>(host: &mut H) -> Result<System, Error> {
system.add_addressable_device(0x00EFE000, wrap_transmutable(adapter))?; system.add_addressable_device(0x00EFE000, wrap_transmutable(adapter))?;
*/ */
let mut ram = MemoryBlock::new(vec![0; 0x00080000]); let ram = MemoryBlock::new(vec![0; 0x00080000]);
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();

View File

@ -1,7 +1,7 @@
use crate::error::Error; use crate::error::Error;
use crate::system::System; use crate::system::System;
use crate::devices::{Debuggable, wrap_transmutable}; use crate::devices::wrap_transmutable;
use crate::memory::{MemoryBlock, BusPort}; use crate::memory::{MemoryBlock, BusPort};
use crate::cpus::z80::{Z80, Z80Type}; use crate::cpus::z80::{Z80, Z80Type};
@ -42,7 +42,7 @@ pub fn build_trs80<H: Host>(host: &mut H, options: Trs80Options) -> Result<Syste
let model1 = trs80::model1::Model1Peripherals::create(host)?; let model1 = trs80::model1::Model1Peripherals::create(host)?;
system.add_addressable_device(0x37E0, wrap_transmutable(model1)).unwrap(); system.add_addressable_device(0x37E0, wrap_transmutable(model1)).unwrap();
let mut 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()));
//cpu.add_breakpoint(0x0); //cpu.add_breakpoint(0x0);
//cpu.add_breakpoint(0xb55); //cpu.add_breakpoint(0xb55);
//cpu.add_breakpoint(0xb76); //cpu.add_breakpoint(0xb76);

View File

@ -8,8 +8,8 @@ use crate::devices::{Address, Addressable, Transmutable, TransmutableBox, read_b
pub struct MemoryBlock { pub struct MemoryBlock {
pub read_only: bool, read_only: bool,
pub contents: Vec<u8>, contents: Vec<u8>,
} }
impl MemoryBlock { impl MemoryBlock {
@ -76,8 +76,8 @@ impl Transmutable for MemoryBlock {
pub struct AddressAdapter { pub struct AddressAdapter {
pub subdevice: TransmutableBox, subdevice: TransmutableBox,
pub shift: u8, shift: u8,
} }
impl AddressAdapter { impl AddressAdapter {
@ -118,7 +118,7 @@ pub struct Block {
} }
pub struct Bus { pub struct Bus {
pub blocks: Vec<Block>, blocks: Vec<Block>,
} }
impl Bus { impl Bus {
@ -128,6 +128,10 @@ impl Bus {
} }
} }
pub fn clear_all_bus_devices(&mut self) {
self.blocks.clear();
}
pub fn insert(&mut self, base: Address, dev: TransmutableBox) { pub fn insert(&mut self, base: Address, dev: TransmutableBox) {
let length = dev.borrow_mut().as_addressable().unwrap().len(); let length = dev.borrow_mut().as_addressable().unwrap().len();
let block = Block { base, length, dev }; let block = Block { base, length, dev };
@ -189,10 +193,10 @@ impl Addressable for Bus {
} }
pub struct BusPort { pub struct BusPort {
pub offset: Address, offset: Address,
pub address_mask: Address, address_mask: Address,
pub data_width: u8, data_width: u8,
pub subdevice: Rc<RefCell<Bus>>, subdevice: Rc<RefCell<Bus>>,
} }
impl BusPort { impl BusPort {

View File

@ -34,10 +34,10 @@ const ATA_SECTOR_SIZE: u32 = 512;
const DEV_NAME: &'static str = "ata"; const DEV_NAME: &'static str = "ata";
pub struct AtaDevice { pub struct AtaDevice {
pub selected_sector: u32, selected_sector: u32,
pub selected_count: u32, selected_count: u32,
pub last_error: u8, last_error: u8,
pub contents: Vec<u8>, contents: Vec<u8>,
} }

View File

@ -1,7 +1,6 @@
use crate::error::Error; use crate::error::Error;
use crate::system::System; use crate::devices::{Address, Addressable, Transmutable};
use crate::devices::{Clock, ClockElapsed, Address, Addressable, Steppable, Transmutable};
use crate::host::controllers::{ControllerDevice, ControllerEvent}; use crate::host::controllers::{ControllerDevice, ControllerEvent};
use crate::host::traits::{Host, ControllerUpdater, HostData}; use crate::host::traits::{Host, ControllerUpdater, HostData};
@ -24,13 +23,13 @@ pub struct GenesisControllerPort {
/// Data contains bits: /// Data contains bits:
/// 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 /// 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
/// X | Y | Z | MODE | START | A | C | B | RIGHT | LEFT | DOWN | UP /// X | Y | Z | MODE | START | A | C | B | RIGHT | LEFT | DOWN | UP
pub buttons: HostData<u16>, buttons: HostData<u16>,
pub ctrl: u8, ctrl: u8,
pub outputs: u8, outputs: u8,
pub th_count: u8, th_count: u8,
pub s_ctrl: u8, s_ctrl: u8,
} }
impl GenesisControllerPort { impl GenesisControllerPort {
@ -113,12 +112,12 @@ impl ControllerUpdater for GenesisControllerUpdater {
pub struct GenesisController { pub struct GenesisController {
pub port_1: GenesisControllerPort, port_1: GenesisControllerPort,
pub port_2: GenesisControllerPort, port_2: GenesisControllerPort,
pub expansion: GenesisControllerPort, expansion: GenesisControllerPort,
pub interrupt: HostData<bool>, interrupt: HostData<bool>,
pub last_clock: Clock, //last_clock: Clock,
pub last_write: Clock, //last_write: Clock,
} }
impl GenesisController { impl GenesisController {
@ -128,8 +127,8 @@ impl GenesisController {
port_2: GenesisControllerPort::new(), port_2: GenesisControllerPort::new(),
expansion: GenesisControllerPort::new(), expansion: GenesisControllerPort::new(),
interrupt: HostData::new(false), interrupt: HostData::new(false),
last_clock: 0, //last_clock: 0,
last_write: 0, //last_write: 0,
} }
} }

View File

@ -5,14 +5,14 @@ use std::cell::RefCell;
use crate::memory::Bus; use crate::memory::Bus;
use crate::error::Error; use crate::error::Error;
use crate::signals::Signal; use crate::signals::Signal;
use crate::devices::{Address, Addressable, Transmutable, TransmutableBox}; use crate::devices::{Address, Addressable, Transmutable};
const DEV_NAME: &'static str = "coprocessor"; const DEV_NAME: &'static str = "coprocessor";
pub struct CoprocessorCoordinator { pub struct CoprocessorCoordinator {
pub bus_request: Signal<bool>, bus_request: Signal<bool>,
pub reset: Signal<bool>, reset: Signal<bool>,
} }
@ -73,7 +73,7 @@ impl Transmutable for CoprocessorCoordinator {
pub struct CoprocessorBankRegister { pub struct CoprocessorBankRegister {
pub base: Signal<Address>, base: Signal<Address>,
} }
impl CoprocessorBankRegister { impl CoprocessorBankRegister {
@ -89,12 +89,13 @@ impl Addressable for CoprocessorBankRegister {
0x01 0x01
} }
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { fn read(&mut self, _addr: Address, _data: &mut [u8]) -> Result<(), Error> {
Ok(()) Ok(())
} }
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { fn write(&mut self, _addr: Address, data: &[u8]) -> Result<(), Error> {
let value = ((self.base.get() >> 1) | ((data[0] as Address) << 23)) & 0xFF8000; let value = ((self.base.get() >> 1) | ((data[0] as Address) << 23)) & 0xFF8000;
//let value = ((self.base.get() << 1) | ((data[0] as Address) << 15)) & 0xFF8000;
println!("New base is {:x}", value); println!("New base is {:x}", value);
self.base.set(value); self.base.set(value);
Ok(()) Ok(())
@ -109,8 +110,8 @@ impl Transmutable for CoprocessorBankRegister {
pub struct CoprocessorBankArea { pub struct CoprocessorBankArea {
pub base: Signal<Address>, base: Signal<Address>,
pub bus: Rc<RefCell<Bus>>, bus: Rc<RefCell<Bus>>,
} }
impl CoprocessorBankArea { impl CoprocessorBankArea {

View File

@ -1,12 +1,11 @@
use std::iter::Iterator; use std::iter::Iterator;
use std::sync::{Arc, Mutex};
use crate::error::Error; use crate::error::Error;
use crate::system::System; use crate::system::System;
use crate::memory::dump_slice; use crate::memory::dump_slice;
use crate::signals::{Signal, EdgeSignal}; use crate::signals::{EdgeSignal};
use crate::devices::{Clock, ClockElapsed, Address, Addressable, Steppable, Inspectable, Transmutable, read_beu16, read_beu32, write_beu16}; use crate::devices::{Clock, ClockElapsed, Address, Addressable, Steppable, Inspectable, Transmutable, read_beu16};
use crate::host::traits::{Host, BlitableSurface, HostData}; use crate::host::traits::{Host, BlitableSurface, HostData};
use crate::host::gfx::{Frame, FrameSwapper}; use crate::host::gfx::{Frame, FrameSwapper};
@ -37,18 +36,18 @@ const REG_DMA_ADDR_MID: usize = 0x16;
const REG_DMA_ADDR_HIGH: usize = 0x17; const REG_DMA_ADDR_HIGH: usize = 0x17;
const STATUS_PAL_MODE: u16 = 0x0001; //const STATUS_PAL_MODE: u16 = 0x0001;
const STATUS_DMA_BUSY: u16 = 0x0002; const STATUS_DMA_BUSY: u16 = 0x0002;
const STATUS_IN_HBLANK: u16 = 0x0004; const STATUS_IN_HBLANK: u16 = 0x0004;
const STATUS_IN_VBLANK: u16 = 0x0008; const STATUS_IN_VBLANK: u16 = 0x0008;
const STATUS_ODD_FRAME: u16 = 0x0010; //const STATUS_ODD_FRAME: u16 = 0x0010;
const STATUS_SPRITE_COLLISION: u16 = 0x0020; //const STATUS_SPRITE_COLLISION: u16 = 0x0020;
const STATUS_SPRITE_OVERFLOW: u16 = 0x0040; //const STATUS_SPRITE_OVERFLOW: u16 = 0x0040;
const STATUS_V_INTERRUPT: u16 = 0x0080; //const STATUS_V_INTERRUPT: u16 = 0x0080;
const STATUS_FIFO_FULL: u16 = 0x0100; //const STATUS_FIFO_FULL: u16 = 0x0100;
const STATUS_FIFO_EMPTY: u16 = 0x0200; const STATUS_FIFO_EMPTY: u16 = 0x0200;
const MODE1_BF_ENABLE_HV_COUNTER: u8 = 0x02; //const MODE1_BF_ENABLE_HV_COUNTER: u8 = 0x02;
const MODE1_BF_HSYNC_INTERRUPT: u8 = 0x10; const MODE1_BF_HSYNC_INTERRUPT: u8 = 0x10;
const MODE2_BF_V_CELL_MODE: u8 = 0x08; const MODE2_BF_V_CELL_MODE: u8 = 0x08;
@ -60,7 +59,7 @@ const MODE3_BF_V_SCROLL_MODE: u8 = 0x04;
const MODE3_BF_H_SCROLL_MODE: u8 = 0x03; const MODE3_BF_H_SCROLL_MODE: u8 = 0x03;
const MODE4_BF_H_CELL_MODE: u8 = 0x01; const MODE4_BF_H_CELL_MODE: u8 = 0x01;
const MODE4_BF_SHADOW_HIGHLIGHT: u8 = 0x08; //const MODE4_BF_SHADOW_HIGHLIGHT: u8 = 0x08;
@ -387,7 +386,6 @@ impl Ym7101State {
pub fn draw_scrolls(&mut self, frame: &mut Frame) { pub fn draw_scrolls(&mut self, frame: &mut Frame) {
let (scroll_h, scroll_v) = self.scroll_size; let (scroll_h, scroll_v) = self.scroll_size;
let (cells_h, cells_v) = self.screen_size; let (cells_h, cells_v) = self.screen_size;
let (offset_x, offset_y) = self.window_offset;
if scroll_h == 0 || scroll_v == 0 { if scroll_h == 0 || scroll_v == 0 {
return; return;
@ -458,7 +456,6 @@ impl Ym7101State {
let (size_h, size_v) = (((size >> 2) & 0x03) as u16 + 1, (size & 0x03) as u16 + 1); let (size_h, size_v) = (((size >> 2) & 0x03) as u16 + 1, (size & 0x03) as u16 + 1);
let h_rev = (pattern_name & 0x0800) != 0; let h_rev = (pattern_name & 0x0800) != 0;
let v_rev = (pattern_name & 0x1000) != 0; let v_rev = (pattern_name & 0x1000) != 0;
//println!("i: {} ({} {}) {:x} ({}, {}) {:x}", i, h_pos, v_pos, size, size_h, size_v, pattern_name);
for ih in 0..size_h { for ih in 0..size_h {
for iv in 0..size_v { for iv in 0..size_v {
@ -467,7 +464,6 @@ impl Ym7101State {
if x > 128 && x < pos_limit_h && y > 128 && y < pos_limit_v { if x > 128 && x < pos_limit_h && y > 128 && y < pos_limit_v {
let iter = self.get_pattern_iter(((pattern_name & 0x07FF) + (h * size_v) + v) | (pattern_name & 0xF800)); let iter = self.get_pattern_iter(((pattern_name & 0x07FF) + (h * size_v) + v) | (pattern_name & 0xF800));
//println!("{}: ({} {}), {:x}", i, x, y, ((pattern_name & 0x07FF) + (h * size_v) + v));
frame.blit(x as u32 - 128, y as u32 - 128, iter, 8, 8); frame.blit(x as u32 - 128, y as u32 - 128, iter, 8, 8);
} }
} }
@ -540,8 +536,9 @@ impl<'a> Iterator for PatternIterator<'a> {
pub struct Ym7101 { pub struct Ym7101 {
pub swapper: FrameSwapper, swapper: FrameSwapper,
pub state: Ym7101State, state: Ym7101State,
pub external_interrupt: HostData<bool>, pub external_interrupt: HostData<bool>,
pub frame_complete: EdgeSignal, pub frame_complete: EdgeSignal,
} }
@ -613,63 +610,6 @@ impl Steppable for Ym7101 {
let mut frame = self.swapper.current.lock().unwrap(); let mut frame = self.swapper.current.lock().unwrap();
self.state.draw_frame(&mut frame); self.state.draw_frame(&mut frame);
//let mut frame = self.swapper.current.lock().unwrap();
//let iter = PatternIterator::new(&self.state, 0x260, 0, true, true);
//frame.blit(0, 0, iter, 8, 8);
/*
// Print Palette
for i in 0..16 {
println!("{:x}", self.state.get_palette_colour(0, i));
}
*/
/*
// Print Pattern Table
let mut frame = self.swapper.current.lock().unwrap();
let (cells_h, cells_v) = self.state.get_screen_size();
for cell_y in 0..cells_v {
for cell_x in 0..cells_h {
let pattern_addr = (cell_x + (cell_y * cells_h)) * 32;
let iter = PatternIterator::new(&self.state, pattern_addr as u32, 0, false, false);
frame.blit((cell_x << 3) as u32, (cell_y << 3) as u32, iter, 8, 8);
}
}
*/
/*
// Print Sprite
let mut frame = self.swapper.current.lock().unwrap();
self.state.draw_background(&mut frame);
let sprite_table = self.get_vram_sprites_addr();
let (cells_h, cells_v) = self.state.get_screen_size();
let sprite = 0;
println!("{:?}", &self.state.vram[(sprite_table + (sprite * 8))..(sprite_table + (sprite * 8) + 8)].iter().map(|byte| format!("{:02x}", byte)).collect::<Vec<String>>());
let size = self.state.vram[sprite_table + (sprite * 8) + 2];
let (size_h, size_v) = (((size >> 2) & 0x03) as u16 + 1, (size & 0x03) as u16 + 1);
let pattern_name = ((self.state.vram[sprite_table + (sprite * 8) + 4] as u16) << 8) | (self.state.vram[sprite_table + (sprite * 8) + 5] as u16);
let pattern_gen = pattern_name & 0x7FF;
println!("{:x}", pattern_name);
for cell_y in 0..size_v {
for cell_x in 0..size_h {
let pattern_addr = (pattern_gen + (cell_y * size_h) + cell_x) as u32;
println!("pattern: ({}, {}) {:x}", cell_x, cell_y, pattern_addr);
let iter = PatternIterator::new(&self.state, pattern_addr * 32, 3, true, true);
frame.blit((cell_x << 3) as u32, (cell_y << 3) as u32, iter, 8, 8);
}
}
*/
//let mut frame = self.swapper.current.lock().unwrap();
//frame.blit(0, 0, PatternIterator::new(&self.state, 0x408 * 32, 3, false, false), 8, 8);
//frame.blit(0, 8, PatternIterator::new(&self.state, 0x409 * 32, 3, false, false), 8, 8);
//frame.blit(8, 0, PatternIterator::new(&self.state, 0x402 * 32, 3, false, false), 8, 8);
//frame.blit(8, 8, PatternIterator::new(&self.state, 0x403 * 32, 3, false, false), 8, 8);
//frame.blit(16, 0, PatternIterator::new(&self.state, 0x404 * 32, 3, false, false), 8, 8);
//frame.blit(16, 8, PatternIterator::new(&self.state, 0x405 * 32, 3, false, false), 8, 8);
self.frame_complete.signal(); self.frame_complete.signal();
} }
@ -810,7 +750,7 @@ impl Addressable for Ym7101 {
impl Inspectable for Ym7101 { impl Inspectable for Ym7101 {
fn inspect(&mut self, system: &System, args: &[&str]) -> Result<(), Error> { fn inspect(&mut self, _system: &System, args: &[&str]) -> Result<(), Error> {
match args[0] { match args[0] {
"" | "state" => { "" | "state" => {
self.state.dump_state(); self.state.dump_state();

View File

@ -4,21 +4,21 @@ use crate::system::System;
use crate::devices::{ClockElapsed, Address, Addressable, Steppable, Transmutable}; use crate::devices::{ClockElapsed, Address, Addressable, Steppable, Transmutable};
const CA0: u8 = 0x01; //const CA0: u8 = 0x01;
const CA1: u8 = 0x02; //const CA1: u8 = 0x02;
const CA2: u8 = 0x04; //const CA2: u8 = 0x04;
const LSTRB: u8 = 0x08; //const LSTRB: u8 = 0x08;
const ENABLE: u8 = 0x10; const ENABLE: u8 = 0x10;
const SELECT: u8 = 0x20; //const SELECT: u8 = 0x20;
const Q6: u8 = 0x40; const Q6: u8 = 0x40;
const Q7: u8 = 0x80; const Q7: u8 = 0x80;
const DEV_NAME: &'static str = "iwm"; const DEV_NAME: &'static str = "iwm";
pub struct IWM { pub struct IWM {
pub state: u8, state: u8,
pub mode: u8, mode: u8,
pub handshake: u8, handshake: u8,
} }
impl IWM { impl IWM {
@ -102,14 +102,20 @@ impl Addressable for IWM {
} }
} }
impl Steppable for IWM {
fn step(&mut self, _system: &System) -> Result<ClockElapsed, Error> {
Ok(1_000_000_00)
}
}
impl Transmutable for IWM { impl Transmutable for IWM {
fn as_addressable(&mut self) -> Option<&mut dyn Addressable> { fn as_addressable(&mut self) -> Option<&mut dyn Addressable> {
Some(self) Some(self)
} }
//fn as_steppable(&mut self) -> Option<&mut dyn Steppable> { fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
// Some(self) Some(self)
//} }
} }

View File

@ -5,25 +5,24 @@ use std::cell::RefCell;
use crate::memory::Bus; use crate::memory::Bus;
use crate::error::Error; use crate::error::Error;
use crate::system::System; use crate::system::System;
use crate::signals::{Signal, Observable}; use crate::signals::Observable;
use crate::devices::{Clock, ClockElapsed, Address, Addressable, Steppable, Transmutable, TransmutableBox, wrap_transmutable}; use crate::devices::{Clock, ClockElapsed, Address, Addressable, Steppable, Transmutable, TransmutableBox, wrap_transmutable};
use crate::peripherals::z8530::Z8530; use crate::peripherals::z8530::Z8530;
use crate::peripherals::mos6522::Mos6522; use crate::peripherals::mos6522::Mos6522;
use crate::peripherals::macintosh::iwm::IWM; use crate::peripherals::macintosh::iwm::IWM;
use crate::peripherals::macintosh::video::MacVideo;
const DEV_NAME: &'static str = "mac"; const DEV_NAME: &'static str = "mac";
pub struct Mainboard { pub struct Mainboard {
pub lower_bus: Rc<RefCell<Bus>>, lower_bus: Rc<RefCell<Bus>>,
pub scc1: Z8530, scc1: Z8530,
pub scc2: Z8530, scc2: Z8530,
pub iwm: IWM, iwm: IWM,
pub via: Mos6522, via: Mos6522,
pub phase_read: PhaseRead, phase_read: PhaseRead,
pub last_sec: Clock, last_sec: Clock,
} }
impl Mainboard { impl Mainboard {
@ -35,8 +34,6 @@ impl Mainboard {
let phase_read = PhaseRead::new(); let phase_read = PhaseRead::new();
let lower_bus = Rc::new(RefCell::new(Bus::new())); let lower_bus = Rc::new(RefCell::new(Bus::new()));
let ram_len = ram.borrow_mut().as_addressable().unwrap().len();
let rom_len = rom.borrow_mut().as_addressable().unwrap().len();
let mainboard = Self { let mainboard = Self {
lower_bus: lower_bus.clone(), lower_bus: lower_bus.clone(),
@ -51,13 +48,13 @@ impl Mainboard {
mainboard.via.port_a.set_observer(move |port| { mainboard.via.port_a.set_observer(move |port| {
if (port.data & 0x10) == 0 { if (port.data & 0x10) == 0 {
println!("{}: overlay is 0 (normal)", DEV_NAME); println!("{}: overlay is 0 (normal)", DEV_NAME);
lower_bus.borrow_mut().blocks.clear(); lower_bus.borrow_mut().clear_all_bus_devices();
lower_bus.borrow_mut().insert(0x000000, wrap_transmutable(AddressRepeater::new(ram.clone(), 32))); lower_bus.borrow_mut().insert(0x000000, wrap_transmutable(AddressRepeater::new(ram.clone(), 32)));
lower_bus.borrow_mut().insert(0x400000, wrap_transmutable(AddressRepeater::new(rom.clone(), 16))); lower_bus.borrow_mut().insert(0x400000, wrap_transmutable(AddressRepeater::new(rom.clone(), 16)));
lower_bus.borrow_mut().insert(0x600000, wrap_transmutable(AddressRepeater::new(rom.clone(), 16))); lower_bus.borrow_mut().insert(0x600000, wrap_transmutable(AddressRepeater::new(rom.clone(), 16)));
} else { } else {
println!("{}: overlay is 1 (startup)", DEV_NAME); println!("{}: overlay is 1 (startup)", DEV_NAME);
lower_bus.borrow_mut().blocks.clear(); lower_bus.borrow_mut().clear_all_bus_devices();
lower_bus.borrow_mut().insert(0x000000, wrap_transmutable(AddressRepeater::new(rom.clone(), 16))); lower_bus.borrow_mut().insert(0x000000, wrap_transmutable(AddressRepeater::new(rom.clone(), 16)));
lower_bus.borrow_mut().insert(0x200000, wrap_transmutable(AddressRepeater::new(rom.clone(), 16))); lower_bus.borrow_mut().insert(0x200000, wrap_transmutable(AddressRepeater::new(rom.clone(), 16)));
lower_bus.borrow_mut().insert(0x400000, wrap_transmutable(AddressRepeater::new(rom.clone(), 16))); lower_bus.borrow_mut().insert(0x400000, wrap_transmutable(AddressRepeater::new(rom.clone(), 16)));
@ -82,14 +79,13 @@ impl Addressable for Mainboard {
} else if addr >= 0x900000 && addr < 0xA00000 { } else if addr >= 0x900000 && addr < 0xA00000 {
self.scc1.read((addr >> 9) & 0x0F, data) self.scc1.read((addr >> 9) & 0x0F, data)
} else if addr >= 0xB00000 && addr < 0xC00000 { } else if addr >= 0xB00000 && addr < 0xC00000 {
self.scc1.read((addr >> 9) & 0x0F, data) self.scc2.read((addr >> 9) & 0x0F, data)
} else if addr >= 0xD00000 && addr < 0xE00000 { } else if addr >= 0xD00000 && addr < 0xE00000 {
self.iwm.read((addr >> 9) & 0x0F, data) self.iwm.read((addr >> 9) & 0x0F, data)
} else if addr >= 0xE80000 && addr < 0xF00000 { } else if addr >= 0xE80000 && addr < 0xF00000 {
self.via.read((addr >> 9) & 0x0F, data) self.via.read((addr >> 9) & 0x0F, data)
} else if addr >= 0xF00000 && addr < 0xF80000 { } else if addr >= 0xF00000 && addr < 0xF80000 {
// TODO phase read self.phase_read.read(addr, data)
Ok(())
} else if addr >= 0xF80000 && addr < 0xF80010 { } else if addr >= 0xF80000 && addr < 0xF80010 {
// Debugger // Debugger
Ok(()) Ok(())
@ -104,14 +100,13 @@ impl Addressable for Mainboard {
} else if addr >= 0x900000 && addr < 0xA00000 { } else if addr >= 0x900000 && addr < 0xA00000 {
self.scc1.write((addr >> 9) & 0x0F, data) self.scc1.write((addr >> 9) & 0x0F, data)
} else if addr >= 0xB00000 && addr < 0xC00000 { } else if addr >= 0xB00000 && addr < 0xC00000 {
self.scc1.write((addr >> 9) & 0x0F, data) self.scc2.write((addr >> 9) & 0x0F, data)
} else if addr >= 0xD00000 && addr < 0xE00000 { } else if addr >= 0xD00000 && addr < 0xE00000 {
self.iwm.write((addr >> 9) & 0x0F, data) self.iwm.write((addr >> 9) & 0x0F, data)
} else if addr >= 0xE80000 && addr < 0xF00000 { } else if addr >= 0xE80000 && addr < 0xF00000 {
self.via.write((addr >> 9) & 0x0F, data) self.via.write((addr >> 9) & 0x0F, data)
} else if addr >= 0xF00000 && addr < 0xF80000 { } else if addr >= 0xF00000 && addr < 0xF80000 {
// TODO phase read self.phase_read.write(addr, data)
Ok(())
} else { } else {
Err(Error::new(&format!("Error writing address {:#010x}", addr))) Err(Error::new(&format!("Error writing address {:#010x}", addr)))
} }
@ -161,13 +156,14 @@ impl Addressable for PhaseRead {
0x80000 0x80000
} }
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { fn read(&mut self, _addr: Address, data: &mut [u8]) -> Result<(), Error> {
// TODO I'm not sure how this is supposed to work
data[0] = 0x00;
Ok(()) Ok(())
} }
fn write(&mut self, addr: Address, data: &[u8]) -> Result<(), Error> { fn write(&mut self, _addr: Address, _data: &[u8]) -> Result<(), Error> {
// TODO I'm not sure how this is supposed to work
Ok(()) Ok(())
} }
} }
@ -175,8 +171,8 @@ impl Addressable for PhaseRead {
pub struct AddressRepeater { pub struct AddressRepeater {
pub subdevice: TransmutableBox, subdevice: TransmutableBox,
pub repeat: u8, repeat: u8,
} }
impl AddressRepeater { impl AddressRepeater {

View File

@ -12,7 +12,7 @@ use crate::host::traits::{Host, BlitableSurface};
const SCRN_BASE: u32 = 0x07A700; const SCRN_BASE: u32 = 0x07A700;
pub struct MacVideo { pub struct MacVideo {
pub frame: Arc<Mutex<Frame>>, frame: Arc<Mutex<Frame>>,
} }
impl MacVideo { impl MacVideo {
@ -28,8 +28,8 @@ impl MacVideo {
} }
pub struct BitIter { pub struct BitIter {
pub bit: i8, bit: i8,
pub data: u16, data: u16,
} }
impl BitIter { impl BitIter {

View File

@ -58,12 +58,12 @@ const SR_RX_READY: u8 = 0x01;
// Interrupt Status/Mask Bits (ISR/IVR) // Interrupt Status/Mask Bits (ISR/IVR)
const ISR_INPUT_CHANGE: u8 = 0x80; //const ISR_INPUT_CHANGE: u8 = 0x80;
const ISR_CH_B_BREAK_CHANGE: u8 = 0x40; //const ISR_CH_B_BREAK_CHANGE: u8 = 0x40;
const ISR_CH_B_RX_READY_FULL: u8 = 0x20; const ISR_CH_B_RX_READY_FULL: u8 = 0x20;
const ISR_CH_B_TX_READY: u8 = 0x10; const ISR_CH_B_TX_READY: u8 = 0x10;
const ISR_TIMER_CHANGE: u8 = 0x08; const ISR_TIMER_CHANGE: u8 = 0x08;
const ISR_CH_A_BREAK_CHANGE: u8 = 0x04; //const ISR_CH_A_BREAK_CHANGE: u8 = 0x04;
const ISR_CH_A_RX_READY_FULL: u8 = 0x02; const ISR_CH_A_RX_READY_FULL: u8 = 0x02;
const ISR_CH_A_TX_READY: u8 = 0x01; const ISR_CH_A_TX_READY: u8 = 0x01;
@ -71,13 +71,13 @@ const ISR_CH_A_TX_READY: u8 = 0x01;
const DEV_NAME: &'static str = "mc68681"; const DEV_NAME: &'static str = "mc68681";
pub struct MC68681Port { pub struct MC68681Port {
pub tty: Option<Box<dyn Tty>>, tty: Option<Box<dyn Tty>>,
pub status: u8, status: u8,
pub tx_enabled: bool, tx_enabled: bool,
pub rx_enabled: bool, rx_enabled: bool,
pub input: u8, input: u8,
} }
impl MC68681Port { impl MC68681Port {
@ -164,23 +164,23 @@ impl MC68681Port {
} }
pub struct MC68681 { pub struct MC68681 {
pub acr: u8, acr: u8,
pub port_a: MC68681Port, pub port_a: MC68681Port,
pub port_b: MC68681Port, pub port_b: MC68681Port,
pub int_mask: u8, int_mask: u8,
pub int_status: u8, int_status: u8,
pub int_vector: u8, int_vector: u8,
pub timer_preload: u16, timer_preload: u16,
pub timer_count: u16, timer_count: u16,
pub is_timing: bool, is_timing: bool,
pub timer_divider: u16, timer_divider: u16,
pub input_pin_change: u8, input_pin_change: u8,
pub input_state: u8, input_state: u8,
pub output_conf: u8, output_conf: u8,
pub output_state: u8, output_state: u8,
} }
impl MC68681 { impl MC68681 {

View File

@ -102,7 +102,7 @@ impl Addressable for Mos6522 {
} }
impl Steppable for Mos6522 { impl Steppable for Mos6522 {
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> { fn step(&mut self, _system: &System) -> Result<ClockElapsed, Error> {
Ok(16_600_000) Ok(16_600_000)
} }

View File

@ -2,26 +2,12 @@
use crate::error::Error; use crate::error::Error;
use crate::system::System; use crate::system::System;
use crate::devices::{ClockElapsed, Address, Addressable, Steppable, Transmutable}; use crate::devices::{ClockElapsed, Address, Addressable, Steppable, Transmutable};
use crate::host::audio::{SineWave, SquareWave}; use crate::host::audio::{SquareWave};
use crate::host::traits::{Host, Audio}; use crate::host::traits::{Host, Audio};
const DEV_NAME: &'static str = "sn76489"; const DEV_NAME: &'static str = "sn76489";
/*
pub struct Sn76489Updater(HostData<SineWave>);
impl AudioUpdater for Sn76489Updater {
fn update_audio_frame(&mut self, samples: usize, sample_rate: usize, buffer: &mut [f32]) {
let mut sine = self.0.lock();
//for i in 0..samples {
// buffer[i] = sine.next().unwrap();
//}
}
}
*/
pub struct Sn76489 { pub struct Sn76489 {
pub regs: [u8; 8], pub regs: [u8; 8],
pub first_byte: Option<u8>, pub first_byte: Option<u8>,
@ -52,8 +38,8 @@ impl Steppable for Sn76489 {
self.sine.frequency -= 1.0; self.sine.frequency -= 1.0;
} }
let rate = self.source.samples_per_second(); //let rate = self.source.samples_per_second();
self.source.write_samples(rate / 1000, &mut self.sine); //self.source.write_samples(rate / 1000, &mut self.sine);
//println!("{}", self.sine.frequency); //println!("{}", self.sine.frequency);
Ok(1_000_000) // Every 1ms of simulated time Ok(1_000_000) // Every 1ms of simulated time
} }
@ -64,7 +50,7 @@ impl Addressable for Sn76489 {
0x01 0x01
} }
fn read(&mut self, addr: Address, data: &mut [u8]) -> Result<(), Error> { fn read(&mut self, _addr: Address, _data: &mut [u8]) -> Result<(), Error> {
warning!("{}: !!! device can't be read", DEV_NAME); warning!("{}: !!! device can't be read", DEV_NAME);
Ok(()) Ok(())
} }

View File

@ -16,9 +16,9 @@ use super::charset::CharacterGenerator;
const DEV_NAME: &'static str = "model1"; const DEV_NAME: &'static str = "model1";
pub struct Model1Peripherals { pub struct Model1Peripherals {
pub frame: Arc<Mutex<Frame>>, frame: Arc<Mutex<Frame>>,
pub keyboard_mem: Arc<Mutex<[u8; 8]>>, keyboard_mem: Arc<Mutex<[u8; 8]>>,
pub video_mem: [u8; 1024], video_mem: [u8; 1024],
} }
impl Model1Peripherals { impl Model1Peripherals {

View File

@ -4,7 +4,7 @@ use std::num::NonZeroU8;
use crate::error::Error; use crate::error::Error;
use crate::system::System; use crate::system::System;
use crate::devices::{ClockElapsed, Address, Addressable, Steppable, Transmutable}; use crate::devices::{ClockElapsed, Address, Addressable, Steppable, Transmutable};
use crate::host::audio::{SineWave, SquareWave}; use crate::host::audio::{SquareWave};
use crate::host::traits::{Host, Audio}; use crate::host::traits::{Host, Audio};
const DEV_NAME: &'static str = "ym2612"; const DEV_NAME: &'static str = "ym2612";
@ -53,7 +53,7 @@ impl Ym2612 {
Ok(Self { Ok(Self {
source, source,
selected_reg: None, selected_reg: None,
channels: vec![Channel::new(sample_rate); 6], channels: vec![Channel::new(sample_rate); 7],
}) })
} }
@ -64,6 +64,9 @@ impl Ym2612 {
self.channels[ch].on = data >> 4; self.channels[ch].on = data >> 4;
println!("Note: {}: {:x}", ch, self.channels[ch].on); println!("Note: {}: {:x}", ch, self.channels[ch].on);
}, },
0x30 => {
let _op = if bank == 0 { 0 } else { 3 };
}
_ => warning!("{}: !!! unhandled write to register {:0x} with {:0x}", DEV_NAME, reg, data), _ => warning!("{}: !!! unhandled write to register {:0x} with {:0x}", DEV_NAME, reg, data),
} }
} }

View File

@ -43,15 +43,21 @@ impl Addressable for Z8530 {
} }
} }
impl Steppable for Z8530 {
fn step(&mut self, _system: &System) -> Result<ClockElapsed, Error> {
Ok(1_000_000_00)
}
}
impl Transmutable for Z8530 { impl Transmutable for Z8530 {
fn as_addressable(&mut self) -> Option<&mut dyn Addressable> { fn as_addressable(&mut self) -> Option<&mut dyn Addressable> {
Some(self) Some(self)
} }
//fn as_steppable(&mut self) -> Option<&mut dyn Steppable> { fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
// Some(self) Some(self)
//} }
} }

View File

@ -9,10 +9,14 @@ pub trait Observable<T> {
// TODO these could be used to imply how it should be used, or they could even be shorthands for T=bool, except TriState which would have 3 // TODO these could be used to imply how it should be used, or they could even be shorthands for T=bool, except TriState which would have 3
// TODO or maybe even tristate is T=Option<S> // TODO or maybe even tristate is T=Option<S>
#[allow(dead_code)]
type Output<T> = Signal<T>; type Output<T> = Signal<T>;
#[allow(dead_code)]
type Input<T> = Signal<T>; type Input<T> = Signal<T>;
#[allow(dead_code)]
type TriState<T> = Signal<T>; type TriState<T> = Signal<T>;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Signal<T: Copy>(Rc<Cell<T>>); pub struct Signal<T: Copy>(Rc<Cell<T>>);

View File

@ -99,7 +99,7 @@ impl System {
pub fn step(&mut self) -> Result<(), Error> { pub fn step(&mut self) -> Result<(), Error> {
if self.debug_enabled.get() && self.event_queue[self.event_queue.len() - 1].device.borrow_mut().as_debuggable().is_some() { if self.debug_enabled.get() && self.event_queue[self.event_queue.len() - 1].device.borrow_mut().as_debuggable().is_some() {
self.debugger.borrow_mut().run_debugger(&self, self.event_queue[self.event_queue.len() - 1].device.clone()); self.debugger.borrow_mut().run_debugger(&self, self.event_queue[self.event_queue.len() - 1].device.clone()).unwrap();
} }
match self.process_one_event() { match self.process_one_event() {

View File

@ -16,7 +16,6 @@
a callback with the frontend sound system that is called when it needs data, or you write to a shared buffer which is passed back to the a callback with the frontend sound system that is called when it needs data, or you write to a shared buffer which is passed back to the
frontend when it needs it, or it has a copy it can use directly frontend when it needs it, or it has a copy it can use directly
* add sound
* should you rename devices.rs traits.rs? * should you rename devices.rs traits.rs?
* add command line arguments to speed up or slow down either the frame rate limiter or the simulated time per frame * add command line arguments to speed up or slow down either the frame rate limiter or the simulated time per frame