1use std::error;
2use std::fmt;
3use std::result::Result;
4
5pub trait Memory {
6 fn write(&mut self, address: u16, value: u8) -> WriteResult;
10
11 fn read(&self, address: u16) -> ReadResult;
15}
16
17pub type ReadResult = Result<u8, ReadError>;
18
19#[derive(Debug, Clone)]
20pub struct ReadError {
21 pub address: u16,
22}
23
24impl error::Error for ReadError {}
25
26impl fmt::Display for ReadError {
27 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28 write!(f, "Unable to read from address ${:04X}", self.address)
29 }
30}
31
32pub type WriteResult = Result<(), WriteError>;
33
34#[derive(Debug, Clone)]
35pub struct WriteError {
36 pub address: u16,
37 pub value: u8,
38}
39
40impl error::Error for WriteError {}
41
42impl fmt::Display for WriteError {
43 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
44 write!(
45 f,
46 "Unable to write ${:02X} to address ${:04X}",
47 self.value, self.address
48 )
49 }
50}
51
52pub struct SimpleRam {
54 pub bytes: [u8; Self::SIZE],
55}
56
57impl SimpleRam {
58 const SIZE: usize = 0x10000; pub fn new() -> SimpleRam {
61 SimpleRam {
62 bytes: [0; Self::SIZE], }
64 }
65
66 pub fn initialized_with(value: u8) -> SimpleRam {
67 SimpleRam {
68 bytes: [value; Self::SIZE],
69 }
70 }
71
72 pub fn with_test_program(program: &[u8]) -> SimpleRam {
75 Self::with_test_program_at(0xF000, program)
76 }
77
78 pub fn with_test_program_at(address: u16, program: &[u8]) -> SimpleRam {
81 let mut ram = SimpleRam::new();
82 ram.bytes[address as usize..address as usize + program.len()].copy_from_slice(program);
83 ram.bytes[0xFFFC] = address as u8; ram.bytes[0xFFFD] = (address >> 8) as u8; return ram;
86 }
87}
88
89impl Memory for SimpleRam {
90 fn read(&self, address: u16) -> ReadResult {
91 Ok(self.bytes[address as usize])
93 }
94
95 fn write(&mut self, address: u16, value: u8) -> WriteResult {
96 self.bytes[address as usize] = value;
97 Ok(())
98 }
99}
100
101impl fmt::Debug for SimpleRam {
102 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
105 use std::convert::TryInto;
106 let zero_page: [u8; 255] = (&self.bytes[..255]).try_into().unwrap();
107 return f
108 .debug_struct("SimpleRam")
109 .field("zero page", &zero_page)
110 .finish();
111 }
112}
113
114#[derive(Debug)]
117pub struct AtariRam {
118 bytes: [u8; Self::SIZE],
119}
120
121impl AtariRam {
122 const SIZE: usize = 0x80;
123 pub fn new() -> AtariRam {
124 AtariRam {
125 bytes: [0; Self::SIZE],
126 }
127 }
128}
129
130impl Memory for AtariRam {
131 fn read(&self, address: u16) -> ReadResult {
132 Ok(self.bytes[address as usize & 0b0111_1111])
133 }
134 fn write(&mut self, address: u16, value: u8) -> WriteResult {
135 self.bytes[address as usize & 0b0111_1111] = value;
136 Ok(())
137 }
138}
139
140#[derive(Debug, Clone, PartialEq)]
141pub struct RomSizeError {
142 size: usize,
143}
144impl error::Error for RomSizeError {}
145impl fmt::Display for RomSizeError {
146 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
147 write!(
148 f,
149 "Illegal ROM size: {} bytes. Valid sizes: 2048, 4096",
150 self.size
151 )
152 }
153}
154
155pub struct AtariRom {
156 bytes: Vec<u8>,
157 address_mask: u16,
158}
159
160impl AtariRom {
161 pub fn new(bytes: &[u8]) -> Result<Self, RomSizeError> {
162 match bytes.len() {
163 2048 | 4096 => Ok(AtariRom {
164 bytes: bytes.to_vec(),
165 address_mask: match bytes.len() {
166 0x1000 => 0b0000_1111_1111_1111,
167 _ => 0b0000_0111_1111_1111,
168 },
169 }),
170 _ => Err(RomSizeError { size: bytes.len() }),
171 }
172 }
173}
174
175impl Memory for AtariRom {
176 fn read(&self, address: u16) -> ReadResult {
177 Ok(self.bytes[(address & self.address_mask) as usize])
178 }
179 fn write(&mut self, address: u16, value: u8) -> WriteResult {
180 Err(WriteError { address, value })
181 }
182}
183
184impl fmt::Debug for AtariRom {
185 fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
186 f.debug_struct("AtariRom")
187 .field("size", &self.bytes.len())
188 .field("address_mask", &self.address_mask)
189 .finish()
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196
197 #[test]
198 fn creating_empty_simple_ram() {
199 let ram = SimpleRam::with_test_program(&[]);
200 assert_eq!(ram.bytes[..0xFFFC], [0u8; 0xFFFC][..]);
201 }
202
203 #[test]
204 fn simple_ram_with_test_program() {
205 let ram = SimpleRam::with_test_program(&[10, 56, 72, 255]);
206 assert_eq!(ram.bytes[..0xF000], [0u8; 0xF000][..]);
208 assert_eq!(ram.bytes[0xF000..0xF004], [10, 56, 72, 255][..]);
210 assert_eq!(ram.bytes[0xF004..0xFFFC], [0u8; 0xFFFC - 0xF004][..]);
212 assert_eq!(ram.bytes[0xFFFC..0xFFFE], [0x00, 0xF0]);
214 }
215
216 #[test]
217 fn simple_ram_with_test_program_at() {
218 let ram = SimpleRam::with_test_program_at(0xF110, &[10, 56, 72, 255]);
219 assert_eq!(ram.bytes[..0xF110], [0u8; 0xF110][..]);
220 assert_eq!(ram.bytes[0xF110..0xF114], [10, 56, 72, 255][..]);
221 assert_eq!(ram.bytes[0xF114..0xFFFC], [0u8; 0xFFFC - 0xF114][..]);
222 assert_eq!(ram.bytes[0xFFFC..0xFFFE], [0x10, 0xF1]);
223 }
224
225 #[test]
226 fn simple_ram_with_test_program_sets_reset_address() {
227 let ram = SimpleRam::with_test_program(&[0xFF; 0x1000]);
228 assert_eq!(ram.bytes[0xFFFC..0xFFFE], [0x00, 0xF0]); }
230
231 #[test]
232 fn atari_ram_read_write() {
233 let mut ram = AtariRam::new();
234 ram.write(0x00AB, 123).unwrap();
235 ram.write(0x00AC, 234).unwrap();
236 assert_eq!(ram.read(0x00AB).unwrap(), 123);
237 assert_eq!(ram.read(0x00AC).unwrap(), 234);
238 }
239
240 #[test]
241 fn atari_ram_mirroring() {
242 let mut ram = AtariRam::new();
243 ram.write(0x0080, 1).unwrap();
244 assert_eq!(ram.read(0x0080).unwrap(), 1);
245 assert_eq!(ram.read(0x2880).unwrap(), 1);
246 assert_eq!(ram.read(0xCD80).unwrap(), 1);
247 }
248
249 #[test]
250 fn atari_rom_4k() {
251 let mut program = [0u8; 0x1000];
252 program[5] = 1;
253 let rom = AtariRom::new(&program).unwrap();
254 assert_eq!(rom.read(0x1000).unwrap(), 0);
255 assert_eq!(rom.read(0x1005).unwrap(), 1);
256 assert_eq!(rom.read(0x3005).unwrap(), 1);
257 assert_eq!(rom.read(0xF005).unwrap(), 1);
258 }
259
260 #[test]
261 fn atari_rom_2k() {
262 let mut program = [0u8; 0x0800];
263 program[5] = 1;
264 let rom = AtariRom::new(&program).unwrap();
265 assert_eq!(rom.read(0x1000).unwrap(), 0);
266 assert_eq!(rom.read(0x1005).unwrap(), 1);
267 assert_eq!(rom.read(0x3005).unwrap(), 1);
268 assert_eq!(rom.read(0xF005).unwrap(), 1);
269 assert_eq!(rom.read(0xF805).unwrap(), 1);
270 }
271
272 #[test]
273 fn atari_rom_illegal_size() {
274 let rom = AtariRom::new(&[0u8; 0x0900]);
275 assert_eq!(rom.err(), Some(RomSizeError { size: 0x900 }));
276 }
277}