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