Refactored signals and added a signal to break at the end of a frame draw

This commit is contained in:
transistor 2021-12-08 19:07:27 -08:00
parent 8db32ab9b3
commit 0247279e4b
6 changed files with 126 additions and 34 deletions

View File

@ -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<H: Host>(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();

View File

@ -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<bool>,
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 {

View File

@ -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;

View File

@ -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<Port>,
pub port_b: Register<Port>,
pub port_a: ObservableSignal<Port>,
pub port_b: ObservableSignal<Port>,
pub peripheral_ctrl: u8,
pub interrupt: Signal<bool>,
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,

View File

@ -2,6 +2,17 @@
use std::rc::Rc;
use std::cell::{Cell, RefCell, RefMut};
pub trait Observable<T> {
fn set_observer<F>(&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<S>
type Output<T> = Signal<T>;
type Input<T> = Signal<T>;
type TriState<T> = Signal<T>;
#[derive(Clone, Debug)]
pub struct Signal<T: Copy>(Rc<Cell<T>>);
@ -14,29 +25,51 @@ impl<T: Copy> Signal<T> {
self.0.set(value);
}
pub fn get(&mut self) -> T {
pub fn get(&self) -> T {
self.0.get()
}
}
#[derive(Clone)]
//pub struct Register<T>(Rc<RefCell<T>>);
pub struct Register<T>(Rc<RefCell<(T, Option<Box<dyn Fn(&T)>>)>>);
impl<T> Register<T> {
pub fn new(init: T) -> Register<T> {
Register(Rc::new(RefCell::new((init, None))))
#[derive(Clone, Debug)]
pub struct EdgeSignal(Signal<bool>);
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<T>(Rc<RefCell<(T, Option<Box<dyn Fn(&T)>>)>>);
impl<T> ObservableSignal<T> {
pub fn new(init: T) -> ObservableSignal<T> {
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<F>(&self, f: F) where F: Fn(&T) + 'static {
impl<T> Observable<T> for ObservableSignal<T> {
fn set_observer<F>(&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<T> Register<T> {
}
}
pub struct ObservableEdgeSignal(ObservableSignal<bool>);
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<bool> for ObservableEdgeSignal {
fn set_observer<F>(&self, f: F) where F: Fn(&bool) + 'static {
self.0.set_observer(f)
}
fn notify(&self) {
self.0.notify()
}
}

View File

@ -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<RefCell<Bus>>,
pub interrupt_controller: RefCell<InterruptController>,
pub break_signal: Option<EdgeSignal>,
}
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(())
}