rgy/
device.rs

1use alloc::rc::Rc;
2use core::cell::{Ref, RefCell, RefMut};
3
4use crate::mmu::{MemHandler, MemRead, MemWrite, Mmu};
5
6/// The wrapper type for I/O handlers to register to MMU.
7pub struct Device<T>(Rc<RefCell<T>>, bool);
8
9impl<T> Device<T> {
10    /// Create a new device.
11    pub fn new(inner: T) -> Self {
12        Self::inner(inner, false)
13    }
14
15    /// Create a new mediater device.
16    pub fn mediate(inner: T) -> Self {
17        Self::inner(inner, true)
18    }
19
20    fn inner(inner: T, debug: bool) -> Self {
21        Self(Rc::new(RefCell::new(inner)), debug)
22    }
23
24    /// Immutably borrow the underlying I/O handler.
25    pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
26        self.0.borrow()
27    }
28
29    /// Mutabully borrow the underlying I/O handler.
30    pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
31        self.0.borrow_mut()
32    }
33}
34
35impl<T: IoHandler> Device<T> {
36    /// Return the memory-mapped I/O handler of the device.
37    pub fn handler(&self) -> IoMemHandler<T> {
38        IoMemHandler(self.0.clone(), self.1)
39    }
40}
41
42/// The trait which allows to hook I/O access from the CPU.
43pub trait IoHandler {
44    /// The function is called when the CPU attempts to read the memory-mapped I/O.
45    fn on_read(&mut self, mmu: &Mmu, addr: u16) -> MemRead;
46
47    /// The function is called when the CPU attempts to write the memory-mapped I/O.
48    fn on_write(&mut self, mmu: &Mmu, addr: u16, value: u8) -> MemWrite;
49}
50
51/// The handler to intercept memory-mapped I/O.
52pub struct IoMemHandler<T>(Rc<RefCell<T>>, bool);
53
54impl<T: IoHandler> MemHandler for IoMemHandler<T> {
55    fn on_read(&self, mmu: &Mmu, addr: u16) -> MemRead {
56        // Don't hook if it's already hooked
57        match self.0.try_borrow_mut() {
58            Ok(mut inner) => inner.on_read(mmu, addr),
59            Err(e) => {
60                if self.1 {
61                    // In mediator mode, allow to recursive read
62                    MemRead::PassThrough
63                } else {
64                    panic!("Recursive read from {:04x}: {}", addr, e)
65                }
66            }
67        }
68    }
69
70    fn on_write(&self, mmu: &Mmu, addr: u16, value: u8) -> MemWrite {
71        // Don't hook if it's already hooked
72        match self.0.try_borrow_mut() {
73            Ok(mut inner) => inner.on_write(mmu, addr, value),
74            Err(e) => {
75                if self.1 {
76                    // In mediator mode, allow to recursive write
77                    MemWrite::PassThrough
78                } else {
79                    panic!("Recursive write to {:04x}: {}", addr, e)
80                }
81            }
82        }
83    }
84}