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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
use alloc::rc::Rc;
use alloc::{vec, vec::Vec};
use hashbrown::HashMap;
/// The variants to control memory read access from the CPU.
pub enum MemRead {
/// Replaces the value passed from the memory to the CPU.
Replace(u8),
/// Shows the actual value passed from the memory to the CPU.
PassThrough,
}
/// The variants to control memory write access from the CPU.
pub enum MemWrite {
/// Replaces the value to be written by the CPU to the memory.
Replace(u8),
/// Allows to write the original value from the CPU to the memory.
PassThrough,
/// Discard the write access from the CPU.
Block,
}
/// The handler to intercept memory access from the CPU.
pub trait MemHandler {
/// The function is called when the CPU attempts to read from the memory.
fn on_read(&self, mmu: &Mmu, addr: u16) -> MemRead;
/// The function is called when the CPU attempts to write to the memory.
fn on_write(&self, mmu: &Mmu, addr: u16, value: u8) -> MemWrite;
}
/// The handle of a memory handler.
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Handle(u64);
/// The memory management unit (MMU)
///
/// This unit holds a memory byte array which represents address space of the memory.
/// It provides the logic to intercept access from the CPU to the memory byte array,
/// and to modify the memory access behaviour.
pub struct Mmu {
ram: Vec<u8>,
handles: HashMap<Handle, (u16, u16)>,
handlers: HashMap<u16, Vec<(Handle, Rc<dyn MemHandler>)>>,
hdgen: u64,
}
impl Mmu {
/// Create a new MMU instance.
pub fn new() -> Mmu {
Mmu {
ram: vec![0u8; 0x10000],
handles: HashMap::new(),
handlers: HashMap::new(),
hdgen: 0,
}
}
fn next_handle(&mut self) -> Handle {
let handle = self.hdgen;
self.hdgen += 1;
Handle(handle)
}
/// Add a new memory handler.
pub fn add_handler<T>(&mut self, range: (u16, u16), handler: T) -> Handle
where
T: MemHandler + 'static,
{
let handle = self.next_handle();
let handler = Rc::new(handler);
self.handles.insert(handle.clone(), range);
for i in range.0..=range.1 {
if self.handlers.contains_key(&i) {
match self.handlers.get_mut(&i) {
Some(v) => v.push((handle.clone(), handler.clone())),
None => {}
}
} else {
self.handlers
.insert(i, vec![(handle.clone(), handler.clone())]);
}
}
handle
}
/// Remove a memory handler.
#[allow(unused)]
pub fn remove_handler<T>(&mut self, handle: &Handle)
where
T: MemHandler + 'static,
{
let range = match self.handles.remove(&handle) {
Some(range) => range,
None => return,
};
for i in range.0..range.1 {
match self.handlers.get_mut(&i) {
Some(v) => v.retain(|(hd, _)| hd != handle),
None => {}
}
}
}
/// Reads one byte from the given address in the memory.
pub fn get8(&self, addr: u16) -> u8 {
if let Some(handlers) = self.handlers.get(&addr) {
for (_, handler) in handlers {
match handler.on_read(self, addr) {
MemRead::Replace(alt) => return alt,
MemRead::PassThrough => {}
}
}
}
if addr >= 0xe000 && addr <= 0xfdff {
// echo ram
self.ram[addr as usize - 0x2000]
} else {
self.ram[addr as usize]
}
}
/// Writes one byte at the given address in the memory.
pub fn set8(&mut self, addr: u16, v: u8) {
if let Some(handlers) = self.handlers.get(&addr) {
for (_, handler) in handlers {
match handler.on_write(self, addr, v) {
MemWrite::Replace(alt) => {
self.ram[addr as usize] = alt;
return;
}
MemWrite::PassThrough => {}
MemWrite::Block => return,
}
}
}
if addr >= 0xe000 && addr <= 0xfdff {
// echo ram
self.ram[addr as usize - 0x2000] = v
} else {
self.ram[addr as usize] = v
}
}
/// Reads two bytes from the given addresss in the memory.
pub fn get16(&self, addr: u16) -> u16 {
let l = self.get8(addr);
let h = self.get8(addr + 1);
(h as u16) << 8 | l as u16
}
/// Writes two bytes at the given address in the memory.
pub fn set16(&mut self, addr: u16, v: u16) {
self.set8(addr, v as u8);
self.set8(addr + 1, (v >> 8) as u8);
}
}