spectrusty/memory/
single_page.rs1#[cfg(feature = "snapshot")]
9use serde::{Serialize, Deserialize};
10#[cfg(feature = "snapshot")]
11use super::serde::{serialize_mem, deserialize_mem};
12
13use super::{
14 MemPageOffset,
15 MemoryKind,
16 Result,
17 ZxMemory,
18 ZxMemoryError,
19 SCREEN_SIZE,
20 ScreenArray,
21 screen_slice_to_array_ref, screen_slice_to_array_mut
22};
23
24#[derive(Clone)]
25#[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
26pub struct SinglePageMemory<const MEM_SIZE: usize, const RAM_BOT: u16> {
27 #[cfg_attr(feature = "snapshot", serde(serialize_with = "serialize_mem", deserialize_with = "deserialize_mem"))]
28 mem: Box<[u8;MEM_SIZE]>
29}
30
31pub const ROM_SIZE: u16 = 0x4000;
32pub const ROM_TOP: u16 = ROM_SIZE - 1;
33
34pub type Memory16k = SinglePageMemory<0x8000, ROM_SIZE>;
36
37pub type Memory48k = SinglePageMemory<0x10000, ROM_SIZE>;
39
40pub type Memory64k = SinglePageMemory<0x10000, 0>;
45
46impl<const MEM_SIZE: usize, const RAM_BOT: u16> Default for SinglePageMemory<MEM_SIZE, RAM_BOT> {
47 fn default() -> Self {
48 Self { mem: Box::new([0; MEM_SIZE]) }
49 }
50}
51
52impl<const MEM_SIZE: usize, const RAM_BOT: u16> ZxMemory for SinglePageMemory<MEM_SIZE, RAM_BOT> {
53 const ROM_SIZE: usize = ROM_SIZE as usize;
54 const RAMTOP: u16 = (MEM_SIZE - 1) as u16;
55 const PAGES_MAX: u8 = 1;
56 const SCR_BANKS_MAX: usize = 1;
57 const ROM_BANKS_MAX: usize = 0;
58 const RAM_BANKS_MAX: usize = 0;
59
60 #[inline(always)]
61 fn reset(&mut self) {}
62
63 #[inline(always)]
64 fn read(&self, addr: u16) -> u8 {
65 self.mem.get(addr as usize).copied().unwrap_or(u8::max_value())
66 }
67
68 #[inline]
70 fn read16(&self, addr: u16) -> u16 {
71 match addr {
72 a if a < Self::RAMTOP => unsafe {
73 let ptr: *const u8 = self.mem.as_ptr().add(a as usize);
74 let ptr16 = ptr as *const u16;
75 ptr16.read_unaligned().to_le()
76 }
77 a if a == Self::RAMTOP || a == std::u16::MAX => {
78 u16::from_le_bytes([self.read(addr), self.read(addr.wrapping_add(1))])
79 }
80 _ => {
81 u16::max_value()
82 }
83 }
84 }
85
86 #[inline(always)]
87 fn write(&mut self, addr: u16, val: u8) {
88 if addr >= RAM_BOT && addr <= Self::RAMTOP {
89 self.mem[addr as usize] = val;
90 }
91 }
92
93 #[inline]
95 fn write16(&mut self, addr: u16, val: u16) {
96 match addr {
97 #[allow(unused_comparisons)]
98 a if a >= RAM_BOT && a < Self::RAMTOP => unsafe {
99 let ptr: *mut u8 = self.mem.as_mut_ptr().add(a as usize);
100 let ptr16 = ptr as *mut u16;
101 ptr16.write_unaligned(val.to_le());
102 }
103 a if a == ROM_TOP => {
104 self.write(a.wrapping_add(1), (val >> 8) as u8);
105 }
106 a if a == Self::RAMTOP => {
107 self.write(a, (val & 0xff) as u8);
108 self.write(a.wrapping_add(1), (val >> 8) as u8);
109 }
110 _ => {}
111 }
112 }
113 #[inline]
114 fn read_screen(&self, _screen_bank: usize, addr: u16) -> u8 {
115 if addr < SCREEN_SIZE {
116 self.mem[0x4000 + addr as usize]
117 }
118 else {
119 panic!("trying to read outside of screen area");
120 }
121 }
122 #[inline]
123 fn mem_ref(&self) -> &[u8] {
124 &self.mem[..]
125 }
126 #[inline]
127 fn mem_mut(&mut self) -> &mut[u8] {
128 &mut self.mem[..]
129 }
130 #[inline]
131 fn screen_ref(&self, screen_bank: usize) -> Result<&ScreenArray> {
132 let start = match screen_bank {
133 0 => 0x4000,
134 1 => 0x6000,
135 _ => return Err(ZxMemoryError::InvalidBankIndex)
136 };
137 Ok(screen_slice_to_array_ref(
138 &self.mem[start..start+SCREEN_SIZE as usize]))
139 }
140 #[inline]
141 fn screen_mut(&mut self, screen_bank: usize) -> Result<&mut ScreenArray> {
142 let start = match screen_bank {
143 0 => 0x4000,
144 1 => 0x6000,
145 _ => return Err(ZxMemoryError::InvalidBankIndex)
146 };
147 Ok(screen_slice_to_array_mut(
148 &mut self.mem[start..start+SCREEN_SIZE as usize]))
149 }
150 #[inline]
151 fn page_kind(&self, page: u8) -> Result<MemoryKind> {
152 match page {
153 0 => Ok(MemoryKind::Rom),
154 1 => Ok(MemoryKind::Ram),
155 _ => Err(ZxMemoryError::InvalidPageIndex)
156 }
157 }
158 fn page_bank(&self, page: u8) -> Result<(MemoryKind, usize)> {
159 self.page_kind(page).map(|kind| (kind, 0))
160 }
161 #[inline]
162 fn page_ref(&self, page: u8) -> Result<&[u8]> {
163 match page {
164 0 => Ok(&self.mem[..Self::ROM_SIZE]),
165 1 => Ok(&self.mem[Self::ROM_SIZE..]),
166 _ => Err(ZxMemoryError::InvalidPageIndex)
167 }
168 }
169 #[inline]
170 fn page_mut(&mut self, page: u8) -> Result<&mut[u8]> {
171 match page {
172 0 => Ok(&mut self.mem[..Self::ROM_SIZE]),
173 1 => Ok(&mut self.mem[Self::ROM_SIZE..]),
174 _ => Err(ZxMemoryError::InvalidPageIndex)
175 }
176 }
177 fn rom_bank_ref(&self, rom_bank: usize) -> Result<&[u8]> {
178 if rom_bank > Self::ROM_BANKS_MAX {
179 return Err(ZxMemoryError::InvalidBankIndex)
180 }
181 Ok(&self.mem[..Self::ROM_SIZE])
182 }
183
184 fn rom_bank_mut(&mut self, rom_bank: usize) -> Result<&mut[u8]> {
185 if rom_bank > Self::ROM_BANKS_MAX {
186 return Err(ZxMemoryError::InvalidBankIndex)
187 }
188 Ok(&mut self.mem[..Self::ROM_SIZE])
189 }
190
191 fn ram_bank_ref(&self, ram_bank: usize) -> Result<&[u8]> {
192 if ram_bank > Self::RAM_BANKS_MAX {
193 return Err(ZxMemoryError::InvalidBankIndex)
194 }
195 Ok(&self.mem[Self::ROM_SIZE..=Self::RAMTOP as usize])
196 }
197
198 fn ram_bank_mut(&mut self, ram_bank: usize) -> Result<&mut[u8]> {
199 if ram_bank > Self::RAM_BANKS_MAX {
200 return Err(ZxMemoryError::InvalidBankIndex)
201 }
202 Ok(&mut self.mem[Self::ROM_SIZE..=Self::RAMTOP as usize])
203 }
204
205 fn map_rom_bank(&mut self, rom_bank: usize, page: u8) -> Result<()> {
206 if rom_bank > Self::ROM_BANKS_MAX {
207 return Err(ZxMemoryError::InvalidBankIndex)
208 }
209 if page != 0 {
210 return Err(ZxMemoryError::InvalidPageIndex)
211 }
212 Ok(())
213 }
214
215 fn map_ram_bank(&mut self, ram_bank: usize, page: u8) -> Result<()> {
216 if ram_bank > Self::RAM_BANKS_MAX {
217 return Err(ZxMemoryError::InvalidBankIndex)
218 }
219 if page != 1 {
220 return Err(ZxMemoryError::InvalidPageIndex)
221 }
222 Ok(())
223 }
224
225 fn page_index_at(&self, address: u16) -> Result<MemPageOffset> {
226 #[allow(unreachable_patterns)]
227 if address < Self::ROM_SIZE as u16 {
228 Ok(MemPageOffset {kind: MemoryKind::Rom, index: 0, offset: address})
229 }
230 else if address <= Self::RAMTOP {
231 Ok(MemPageOffset {kind: MemoryKind::Ram, index: 1, offset: address - Self::ROM_SIZE as u16})
232 }
233 else {
234 Err(ZxMemoryError::UnsupportedAddressRange)
235 }
236 }
237}
238
239#[cfg(test)]
240mod tests {
241 use crate::memory::*;
242 use super::*;
243
244 #[test]
245 fn test_memory_single_page_work() {
246 memory_single_page_work::<Memory16k>();
247 memory_single_page_work::<Memory48k>();
248 memory_single_page_work::<Memory64k>();
249
250 memory_single_page_rom::<Memory16k>(true);
251 memory_single_page_rom::<Memory48k>(true);
252 memory_single_page_rom::<Memory64k>(false);
253 }
254
255 fn memory_single_page_rom<M: ZxMemory + Default>(is_ro: bool) {
256 let mut mem = M::default();
257 for addr in 0..=ROM_TOP {
258 assert_eq!(mem.read(addr), 0);
259 mem.write(addr, 201);
260 if is_ro {
261 assert_eq!(mem.read(addr), 0);
262 }
263 else {
264 assert_eq!(mem.read(addr), 201);
265 }
266 }
267 for addr in ROM_TOP + 1..=M::RAMTOP {
268 assert_eq!(mem.read(addr), 0);
269 mem.write(addr, 201);
270 assert_eq!(mem.read(addr), 201);
271 }
272 }
273
274 fn memory_single_page_work<M: ZxMemory + Default + Clone>() {
275 assert_eq!(M::ROM_SIZE, 0x4000);
276 assert_eq!(M::PAGE_SIZE, 0x4000);
277 assert_eq!(M::PAGES_MAX, 1);
278 assert_eq!(M::SCR_BANKS_MAX, 1);
279 assert_eq!(M::RAM_BANKS_MAX, 0);
280 assert_eq!(M::ROM_BANKS_MAX, 0);
281 let mut mem = M::default();
282 let mut mem1 = mem.clone();
283 let mut index = 0;
284 mem.for_each_page_mut(.., |page| {
285 if index == 0 {
286 assert!(page.is_rom());
287 }
288 else {
289 assert!(page.is_ram());
290 }
291 assert_eq!(page.into_mut_slice(), mem1.page_mut(index).unwrap());
292 index += 1;
293 Ok(())
294 }).unwrap();
295 assert_eq!(index, 2);
296 }
297}