1#![allow(clippy::unreadable_literal)]
2
3use crate::err::BusError;
4use crate::mem::Mem;
5use crate::duart::Duart;
6use crate::mouse::Mouse;
7use std::fmt::Debug;
8use std::ops::Range;
9
10const NVRAM_SIZE: usize = 8192;
11
12pub enum AccessCode {
14 MoveTranslated,
15 CoprDataWrite,
16 AutoVectorIrqAck,
17 CoprDataFetch,
18 StopAck,
19 CoprBroadcast,
20 CoprStatusFetch,
21 ReadInterlocked,
22 AddressFetch,
23 OperandFetch,
24 Write,
25 IrqAck,
26 IFAfterPCDisc,
27 InstrPrefetch,
28 InstrFetch,
29 NoOp,
30}
31
32
33pub trait Device: Send + Sync + Debug {
35 fn address_range(&self) -> &Range<usize>;
36 fn name(&self) -> &str;
37 fn is_read_only(&self) -> bool;
38 fn read_byte(&mut self, address: usize, access: AccessCode) -> Result<u8, BusError>;
39 fn read_half(&mut self, address: usize, access: AccessCode) -> Result<u16, BusError>;
40 fn read_word(&mut self, address: usize, access: AccessCode) -> Result<u32, BusError>;
41 fn write_byte(&mut self, address: usize, val: u8, access: AccessCode) -> Result<(), BusError>;
42 fn write_half(&mut self, address: usize, val: u16, access: AccessCode) -> Result<(), BusError>;
43 fn write_word(&mut self, address: usize, val: u32, access: AccessCode) -> Result<(), BusError>;
44 fn load(&mut self, address: usize, data: &[u8]) -> Result<(), BusError>;
45}
46
47pub struct Bus {
60 rom: Mem,
61 duart: Duart,
62 mouse: Mouse,
63 vid: Mem, bbram: Mem, ram: Mem,
66}
67
68impl Bus {
69 pub fn new(mem_size: usize) -> Bus {
70 Bus {
71 rom: Mem::new(0, 0x20000, true),
72 duart: Duart::new(),
73 mouse: Mouse::new(),
74 vid: Mem::new(0x500000, 0x2, false),
75 bbram: Mem::new(0x600000, 0x2000, false),
76 ram: Mem::new(0x700000, mem_size, false),
77 }
78 }
79
80 fn get_device(&mut self, address: usize) -> Result<&mut Device, BusError> {
81 if address < 0x20000 {
82 return Ok(&mut self.rom);
83 }
84
85 if address >= 0x200000 && address < 0x200040 {
86 return Ok(&mut self.duart);
87 }
88
89 if address >= 0x400000 && address < 0x400004 {
90 return Ok(&mut self.mouse);
91 }
92
93 if address >= 0x500000 && address < 0x500002 {
94 return Ok(&mut self.vid);
95 }
96
97 if address >= 0x600000 && address < 0x602000 {
98 return Ok(&mut self.bbram);
99 }
100
101 if address >= 0x700000 && address < 0x800000 {
102 return Ok(&mut self.ram);
103 }
104
105 Err(BusError::NoDevice(address as u32))
106 }
107
108 pub fn read_byte(&mut self, address: usize, access: AccessCode) -> Result<u8, BusError> {
109 self.get_device(address)?.read_byte(address, access)
110 }
111
112 pub fn read_half(&mut self, address: usize, access: AccessCode) -> Result<u16, BusError> {
113 if address & 1 != 0 {
114 return Err(BusError::Alignment);
115 }
116 self.get_device(address)?.read_half(address, access)
117 }
118
119 pub fn read_word(&mut self, address: usize, access: AccessCode) -> Result<u32, BusError> {
120 if address & 3 != 0 {
121 return Err(BusError::Alignment);
122 }
123 self.get_device(address)?.read_word(address, access)
124 }
125
126 pub fn read_op_half(&mut self, address: usize) -> Result<u16, BusError> {
127 let m = self.get_device(address)?;
128
129 Ok(u16::from(m.read_byte(address, AccessCode::OperandFetch)?)
130 | u16::from(m.read_byte(address + 1, AccessCode::OperandFetch)?).wrapping_shl(8))
131 }
132
133 pub fn read_op_word(&mut self, address: usize) -> Result<u32, BusError> {
134 let m = self.get_device(address)?;
135
136 Ok(u32::from(m.read_byte(address, AccessCode::OperandFetch)?)
137 | u32::from(m.read_byte(address + 1, AccessCode::OperandFetch)?).wrapping_shl(8)
138 | u32::from(m.read_byte(address + 2, AccessCode::OperandFetch)?).wrapping_shl(16)
139 | u32::from(m.read_byte(address + 3, AccessCode::OperandFetch)?).wrapping_shl(24))
140 }
141
142 pub fn write_byte(&mut self, address: usize, val: u8) -> Result<(), BusError> {
143 self.get_device(address)?.write_byte(address, val, AccessCode::Write)
144 }
145
146 pub fn write_half(&mut self, address: usize, val: u16) -> Result<(), BusError> {
147 if address & 1 != 0 {
148 return Err(BusError::Alignment);
149 }
150 self.get_device(address)?.write_half(address, val, AccessCode::Write)
151 }
152
153 pub fn write_word(&mut self, address: usize, val: u32) -> Result<(), BusError> {
154 if address & 3 != 0 {
155 return Err(BusError::Alignment);
156 }
157 self.get_device(address)?.write_word(address, val, AccessCode::Write)
158 }
159
160 pub fn load(&mut self, address: usize, data: &[u8]) -> Result<(), BusError> {
161 self.get_device(address)?.load(address, data)
162 }
163
164 pub fn video_ram(&self) -> &[u8] {
165 let vid_register = (u16::from(self.vid[0]) << 8 | u16::from(self.vid[1])) as usize;
166 let start = vid_register * 4;
167 let end = start + 0x19000;
168 self.ram.as_slice(start..end)
169 }
170
171 pub fn service(&mut self) {
172 self.duart.service();
173 }
174
175 pub fn get_interrupts(&mut self) -> Option<u8> {
176 self.duart.get_interrupt()
177 }
178
179 pub fn mouse_move(&mut self, x: u16, y: u16) {
180 self.mouse.x = x;
181 self.mouse.y = y;
182 }
183
184 pub fn mouse_down(&mut self, button: u8) {
185 self.duart.mouse_down(button);
186 }
187
188 pub fn mouse_up(&mut self, button: u8) {
189 self.duart.mouse_up(button);
190 }
191
192 pub fn rs232_tx_poll(&mut self) -> Option<u8> {
193 self.duart.rs232_tx_poll()
194 }
195
196 pub fn kb_tx_poll(&mut self) -> Option<u8> {
197 self.duart.kb_tx_poll()
198 }
199
200 pub fn rx_char(&mut self, char: u8) {
201 self.duart.rx_char(char);
202 }
203
204 pub fn rx_keyboard(&mut self, keycode: u8) {
205 self.duart.rx_keyboard(keycode);
206 }
207
208 pub fn duart_output(&self) -> u8 {
209 self.duart.output_port()
210 }
211
212 pub fn get_nvram(&self) -> &[u8] {
213 self.bbram.as_slice(0..NVRAM_SIZE)
214 }
215
216 pub fn set_nvram(&mut self, nvram: &[u8]) {
217 for (i, b) in nvram.into_iter().enumerate() {
218 self.bbram[i] = *b;
219 }
220 }
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226
227 #[test]
228 fn should_fail_on_alignment_errors() {
229 let mut bus: Bus = Bus::new(0x10000);
230
231 assert!(bus.write_byte(0x700000, 0x1f).is_ok());
232 assert!(bus.write_half(0x700000, 0x1f1f).is_ok());
233 assert!(bus.write_word(0x700000, 0x1f1f1f1f).is_ok());
234 assert!(bus.write_half(0x700001, 0x1f1f).is_err());
235 assert!(bus.write_half(0x700002, 0x1f1f).is_ok());
236 assert!(bus.write_word(0x700001, 0x1f1f1f1f).is_err());
237 assert!(bus.write_word(0x700002, 0x1f1f1f1f).is_err());
238 assert!(bus.write_word(0x700003, 0x1f1f1f1f).is_err());
239 assert!(bus.write_word(0x700004, 0x1f1f1f1f).is_ok());
240 }
241}