diff --git a/src/machines/genesis.rs b/src/machines/genesis.rs index 0a3c755..b85e5fe 100644 --- a/src/machines/genesis.rs +++ b/src/machines/genesis.rs @@ -4,7 +4,7 @@ use std::cell::RefCell; use crate::error::Error; use crate::system::System; -use crate::signals::Signal; +use crate::signals::{Signal, Observable}; use crate::memory::{MemoryBlock, Bus, BusPort}; use crate::devices::{wrap_transmutable, Address, Addressable, Debuggable}; @@ -95,9 +95,9 @@ pub fn build_genesis(host: &mut H, options: SegaGenesisOptions) -> Resu system.add_addressable_device(0x00a11000, wrap_transmutable(coproc)).unwrap(); let vdp = genesis::ym7101::Ym7101::new(host, interrupt); + system.break_signal = Some(vdp.frame_complete.clone()); 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())); system.add_interruptable_device("cpu", wrap_transmutable(cpu)).unwrap(); diff --git a/src/peripherals/genesis/ym7101.rs b/src/peripherals/genesis/ym7101.rs index efb440e..1103c37 100644 --- a/src/peripherals/genesis/ym7101.rs +++ b/src/peripherals/genesis/ym7101.rs @@ -5,6 +5,7 @@ use std::sync::{Arc, Mutex}; use crate::error::Error; use crate::system::System; use crate::memory::dump_slice; +use crate::signals::{Signal, EdgeSignal}; use crate::devices::{Clock, ClockElapsed, Address, Addressable, Steppable, Inspectable, Transmutable, read_beu16, read_beu32, write_beu16}; use crate::host::traits::{Host, BlitableSurface, HostData}; use crate::host::gfx::{Frame, FrameSwapper}; @@ -542,6 +543,7 @@ pub struct Ym7101 { pub swapper: FrameSwapper, pub state: Ym7101State, pub external_interrupt: HostData, + pub frame_complete: EdgeSignal, } impl Ym7101 { @@ -554,6 +556,7 @@ impl Ym7101 { swapper, state: Ym7101State::new(), external_interrupt, + frame_complete: EdgeSignal::new(), } } } @@ -602,7 +605,7 @@ impl Steppable for Ym7101 { } if self.state.v_clock > 16_630_000 { self.state.status &= !STATUS_IN_VBLANK; - self.state.v_clock = 0; + self.state.v_clock -= 16_630_000; if self.state.vsync_int_enabled() { system.get_interrupt_controller().set(true, 6, 30)?; } @@ -666,6 +669,8 @@ impl Steppable for Ym7101 { //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(); } if self.state.transfer_run != DmaType::None && (self.state.mode_2 & MODE2_BF_DMA_ENABLED) != 0 { diff --git a/src/peripherals/macintosh/mainboard.rs b/src/peripherals/macintosh/mainboard.rs index 4706574..721fc5a 100644 --- a/src/peripherals/macintosh/mainboard.rs +++ b/src/peripherals/macintosh/mainboard.rs @@ -5,7 +5,7 @@ use std::cell::RefCell; use crate::memory::Bus; use crate::error::Error; use crate::system::System; -use crate::signals::Signal; +use crate::signals::{Signal, Observable}; use crate::devices::{Clock, ClockElapsed, Address, Addressable, Steppable, Transmutable, TransmutableBox, wrap_transmutable}; use crate::peripherals::z8530::Z8530; diff --git a/src/peripherals/mos6522.rs b/src/peripherals/mos6522.rs index 80e52df..f92eba8 100644 --- a/src/peripherals/mos6522.rs +++ b/src/peripherals/mos6522.rs @@ -1,7 +1,7 @@ use crate::error::Error; use crate::system::System; -use crate::signals::{Signal, Register}; +use crate::signals::{Signal, ObservableSignal, Observable}; use crate::devices::{ClockElapsed, Address, Addressable, Steppable, Transmutable}; @@ -34,8 +34,8 @@ impl Port { pub struct Mos6522 { - pub port_a: Register, - pub port_b: Register, + pub port_a: ObservableSignal, + pub port_b: ObservableSignal, pub peripheral_ctrl: u8, pub interrupt: Signal, pub interrupt_flags: u8, @@ -45,8 +45,8 @@ pub struct Mos6522 { impl Mos6522 { pub fn new() -> Self { Self { - port_a: Register::new(Port::new()), - port_b: Register::new(Port::new()), + port_a: ObservableSignal::new(Port::new()), + port_b: ObservableSignal::new(Port::new()), peripheral_ctrl: 0, interrupt: Signal::new(false), interrupt_flags: 0, diff --git a/src/signals.rs b/src/signals.rs index e6bd23b..7c5967a 100644 --- a/src/signals.rs +++ b/src/signals.rs @@ -2,6 +2,17 @@ use std::rc::Rc; use std::cell::{Cell, RefCell, RefMut}; +pub trait Observable { + fn set_observer(&self, f: F) where F: Fn(&T) + 'static; + fn notify(&self); +} + +// 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 +type Output = Signal; +type Input = Signal; +type TriState = Signal; + #[derive(Clone, Debug)] pub struct Signal(Rc>); @@ -14,29 +25,51 @@ impl Signal { self.0.set(value); } - pub fn get(&mut self) -> T { + pub fn get(&self) -> T { self.0.get() } } -#[derive(Clone)] -//pub struct Register(Rc>); -pub struct Register(Rc>)>>); -impl Register { - pub fn new(init: T) -> Register { - Register(Rc::new(RefCell::new((init, None)))) +#[derive(Clone, Debug)] +pub struct EdgeSignal(Signal); + +impl EdgeSignal { + pub fn new() -> Self { + EdgeSignal(Signal::new(false)) + } + + pub fn signal(&mut self) { + self.0.set(true); + } + + pub fn get(&mut self) -> bool { + let value = self.0.get(); + self.0.set(false); + value + } +} + + +#[derive(Clone)] +pub struct ObservableSignal(Rc>)>>); + +impl ObservableSignal { + pub fn new(init: T) -> ObservableSignal { + ObservableSignal(Rc::new(RefCell::new((init, None)))) } pub fn borrow_mut(&self) -> RefMut<'_, T> { RefMut::map(self.0.borrow_mut(), |v| &mut v.0) } +} - pub fn set_observer(&self, f: F) where F: Fn(&T) + 'static { +impl Observable for ObservableSignal { + fn set_observer(&self, f: F) where F: Fn(&T) + 'static { self.0.borrow_mut().1 = Some(Box::new(f)); } - pub fn notify(&self) { + fn notify(&self) { let data = self.0.borrow(); if let Some(closure) = &data.1 { closure(&data.0); @@ -44,3 +77,35 @@ impl Register { } } + +pub struct ObservableEdgeSignal(ObservableSignal); + +impl ObservableEdgeSignal { + pub fn new() -> Self { + ObservableEdgeSignal(ObservableSignal::new(false)) + } + + pub fn set(&mut self) { + *self.0.borrow_mut() = true; + self.0.notify(); + } + + pub fn get(&mut self) -> bool { + let mut addr = self.0.borrow_mut(); + let value = *addr; + *addr = false; + value + } +} + +impl Observable for ObservableEdgeSignal { + fn set_observer(&self, f: F) where F: Fn(&bool) + 'static { + self.0.set_observer(f) + } + + fn notify(&self) { + self.0.notify() + } +} + + diff --git a/src/system.rs b/src/system.rs index 5a0ecf5..d972857 100644 --- a/src/system.rs +++ b/src/system.rs @@ -5,6 +5,7 @@ use std::collections::HashMap; use crate::memory::Bus; use crate::debugger::Debugger; +use crate::signals::EdgeSignal; use crate::error::{Error, ErrorType}; use crate::interrupts::InterruptController; use crate::devices::{Clock, ClockElapsed, Address, TransmutableBox}; @@ -20,6 +21,8 @@ pub struct System { pub bus: Rc>, pub interrupt_controller: RefCell, + + pub break_signal: Option, } impl System { @@ -34,6 +37,8 @@ impl System { bus: Rc::new(RefCell::new(Bus::new())), interrupt_controller: RefCell::new(InterruptController::new()), + + break_signal: None, } } @@ -78,7 +83,7 @@ impl System { self.debug_enabled.set(false); } - pub fn step(&mut self) -> Result<(), Error> { + fn process_one_event(&mut self) -> Result<(), Error> { let mut event_device = self.event_queue.pop().unwrap(); self.clock = event_device.next_clock; let result = match event_device.device.borrow_mut().as_steppable().unwrap().step(&self) { @@ -92,26 +97,43 @@ impl System { result } + 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() { + self.debugger.borrow_mut().run_debugger(&self, self.event_queue[self.event_queue.len() - 1].device.clone()); + } + + match self.process_one_event() { + Ok(()) => { } + Err(err) if err.err == ErrorType::Breakpoint => { + println!("Breakpoint reached: {}", err.msg); + self.enable_debugging(); + }, + Err(err) => { + self.exit_error(); + println!("{:?}", err); + return Err(err); + }, + } + Ok(()) + } + pub fn run_for(&mut self, elapsed: ClockElapsed) -> Result<(), Error> { let target = self.clock + elapsed; while self.clock < target { - 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.step()?; + } + Ok(()) + } - match self.step() { - Ok(()) => { } - Err(err) if err.err == ErrorType::Breakpoint => { - println!("Breakpoint reached: {}", err.msg); - self.enable_debugging(); - }, - Err(err) => { - self.exit_error(); - println!("{:?}", err); - return Err(err); - }, - } + pub fn run_until_break(&mut self) -> Result<(), Error> { + let mut signal = match &self.break_signal { + Some(signal) => signal.clone(), + None => return Ok(()), + }; + + while !signal.get() { + self.step()?; } Ok(()) }