mirror of
https://github.com/transistorfet/moa.git
synced 2024-11-21 19:30:52 +00:00
Refactored signals and added a signal to break at the end of a frame draw
This commit is contained in:
parent
8db32ab9b3
commit
0247279e4b
@ -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();
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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(())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user