m68000/
memory_access.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5//! Memory access-related traits and structs.
6
7use crate::{CpuDetails, M68000};
8use crate::addressing_modes::{EffectiveAddress, AddressingMode};
9use crate::exception::{ACCESS_ERROR, ADDRESS_ERROR};
10use crate::instruction::Size;
11use crate::utils::IsEven;
12
13/// Return type of M68000's read memory methods. `Err(Vector::AddressError or AccessError as u8)` if an address or
14/// access (bus) error occured. Alias for `Result<T, u8>`.
15type GetResult<T> = Result<T, u8>;
16/// Return type of M68000's write memory methods. `Err(Vector::AddressError or AccessError as u8)` if an address or
17/// access (bus) error occured. Alias for `Result<(), u8>`.
18type SetResult = Result<(), u8>;
19
20/// The trait to be implemented by the memory system that will be used by the core.
21///
22/// If the read is successful, return a `Some()` with the requested value.
23/// If the address of the value asked is not in the memory map of the system, return `None`.
24/// This will trigger an Access (Bus) Error, which will interrupt the current instruction processing.
25///
26/// For word and long accesses, the address is guaranted to be even (16-bits word aligned),
27/// as odd addresses are detected by the library and automatically trigger an Address Error.
28///
29/// The trait is implemented for `[u8]`, `&[u8]`, `[u16]` and `&[u16]`, interpreted as big-endian.
30/// A call of a `set_XXXX` method on a non-mutable slice panics.
31pub trait MemoryAccess {
32    /// Returns a 8-bits integer from the given address.
33    #[must_use]
34    fn get_byte(&mut self, addr: u32) -> Option<u8>;
35
36    /// Returns a big-endian 16-bits integer from the given address.
37    #[must_use]
38    fn get_word(&mut self, addr: u32) -> Option<u16>;
39
40    /// Returns a big-endian 32-bits integer from the given address.
41    ///
42    /// The default implementation is doing 2 calls to [Self::get_word] with the high and low words.
43    #[must_use]
44    fn get_long(&mut self, addr: u32) -> Option<u32> {
45        Some((self.get_word(addr)? as u32) << 16 | self.get_word(addr.wrapping_add(2))? as u32)
46    }
47
48    /// Stores the given 8-bits value at the given address.
49    #[must_use]
50    fn set_byte(&mut self, addr: u32, value: u8) -> Option<()>;
51
52    /// Stores the given 16-bits value at the given address, in big-endian format.
53    #[must_use]
54    fn set_word(&mut self, addr: u32, value: u16) -> Option<()>;
55
56    /// Stores the given 32-bits value at the given address, in big-endian format.
57    ///
58    /// The default implementation is doing 2 calls to [Self::set_word] with the high and low words.
59    #[must_use]
60    fn set_long(&mut self, addr: u32, value: u32) -> Option<()> {
61        self.set_word(addr, (value >> 16) as u16)?;
62        self.set_word(addr.wrapping_add(2), value as u16)
63    }
64
65    /// Not meant to be overridden.
66    /// Returns a [MemoryIter] starting at the given address that will be used to decode instructions.
67    #[must_use]
68    fn iter_u16(&mut self, addr: u32) -> MemoryIter<Self> {
69        MemoryIter { memory: self, next_addr: addr }
70    }
71
72    /// Called when the CPU executes a RESET instruction.
73    fn reset_instruction(&mut self);
74}
75
76/// Iterator over 16-bits values in memory.
77pub struct MemoryIter<'a, M: MemoryAccess + ?Sized> {
78    /// The memory system that will be used to get the values.
79    pub memory: &'a mut M,
80    /// The address of the next value to be returned.
81    pub next_addr: u32,
82}
83
84impl<M: MemoryAccess + ?Sized> Iterator for MemoryIter<'_, M> {
85    type Item = GetResult<u16>;
86
87    fn next(&mut self) -> Option<Self::Item> {
88        if self.next_addr.is_even() {
89            let data = self.memory.get_word(self.next_addr);
90            self.next_addr = self.next_addr.wrapping_add(2);
91            Some(data.ok_or(ACCESS_ERROR))
92        } else {
93            Some(Err(ADDRESS_ERROR))
94        }
95    }
96}
97
98impl<CPU: CpuDetails> M68000<CPU> {
99    pub(super) fn get_byte<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M, ea: &mut EffectiveAddress, exec_time: &mut usize) -> GetResult<u8> {
100        match ea.mode {
101            AddressingMode::Drd(reg) => Ok(self.regs.d[reg as usize].0 as u8),
102            AddressingMode::Immediate(imm) => {
103                *exec_time += CPU::EA_IMMEDIATE;
104                Ok(imm as u8)
105            },
106            _ => memory.get_byte(self.get_effective_address(ea, exec_time)).ok_or(ACCESS_ERROR),
107        }
108    }
109
110    pub(super) fn get_word<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M, ea: &mut EffectiveAddress, exec_time: &mut usize) -> GetResult<u16> {
111        match ea.mode {
112            AddressingMode::Drd(reg) => Ok(self.regs.d[reg as usize].0 as u16),
113            AddressingMode::Ard(reg) => Ok(self.regs.a(reg) as u16),
114            AddressingMode::Immediate(imm) => {
115                *exec_time += CPU::EA_IMMEDIATE;
116                Ok(imm as u16)
117            },
118            _ => {
119                let addr = self.get_effective_address(ea, exec_time).even()?;
120                memory.get_word(addr).ok_or(ACCESS_ERROR)
121            },
122        }
123    }
124
125    pub(super) fn get_long<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M, ea: &mut EffectiveAddress, exec_time: &mut usize) -> GetResult<u32> {
126        match ea.mode {
127            AddressingMode::Drd(reg) => Ok(self.regs.d[reg as usize].0),
128            AddressingMode::Ard(reg) => Ok(self.regs.a(reg)),
129            AddressingMode::Immediate(imm) => {
130                *exec_time += CPU::EA_IMMEDIATE + 4;
131                Ok(imm)
132            },
133            _ => {
134                let addr = self.get_effective_address(ea, exec_time).even()?;
135                let r = memory.get_long(addr).ok_or(ACCESS_ERROR);
136                *exec_time += 4;
137                r
138            },
139        }
140    }
141
142    pub(super) fn set_byte<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M, ea: &mut EffectiveAddress, exec_time: &mut usize, value: u8) -> SetResult {
143        match ea.mode {
144            AddressingMode::Drd(reg) => { self.regs.d_byte(reg, value); Ok(()) },
145            _ => memory.set_byte(self.get_effective_address(ea, exec_time), value).ok_or(ACCESS_ERROR),
146        }
147    }
148
149    pub(super) fn set_word<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M, ea: &mut EffectiveAddress, exec_time: &mut usize, value: u16) -> SetResult {
150        match ea.mode {
151            AddressingMode::Drd(reg) => { self.regs.d_word(reg, value); Ok(()) },
152            AddressingMode::Ard(reg) => { self.regs.a_mut(reg).0 = value as i16 as u32; Ok(()) },
153            _ => {
154                let addr = self.get_effective_address(ea, exec_time).even()?;
155                memory.set_word(addr, value).ok_or(ACCESS_ERROR)
156            },
157        }
158    }
159
160    pub(super) fn set_long<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M, ea: &mut EffectiveAddress, exec_time: &mut usize, value: u32) -> SetResult {
161        match ea.mode {
162            AddressingMode::Drd(reg) => { self.regs.d[reg as usize].0 = value; Ok(()) },
163            AddressingMode::Ard(reg) => { self.regs.a_mut(reg).0 = value; Ok(()) },
164            _ => {
165                let addr = self.get_effective_address(ea, exec_time).even()?;
166                let r = memory.set_long(addr, value).ok_or(ACCESS_ERROR);
167                *exec_time += 4;
168                r
169            },
170        }
171    }
172
173    /// Returns the word at `self.regs.pc` then advances `self.regs.pc` by 2.
174    ///
175    /// Please note that this function advances the program counter so be careful when using it.
176    /// This function is public because it can be useful in some contexts such as OS-9 environments
177    /// where the trap ID is the immediate next word after the TRAP instruction.
178    pub fn get_next_word<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M) -> GetResult<u16> {
179        let data = memory.get_word(self.regs.pc.even()?.0).ok_or(ACCESS_ERROR);
180        self.regs.pc += 2;
181        data
182    }
183
184    /// Returns the long at `self.regs.pc` then advances `self.regs.pc` by 4.
185    ///
186    /// Please note that this function advances the program counter so be careful when using it.
187    pub fn get_next_long<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M) -> GetResult<u32> {
188        let data = memory.get_long(self.regs.pc.even()?.0).ok_or(ACCESS_ERROR);
189        self.regs.pc += 4;
190        data
191    }
192
193    /// Returns the word at `self.regs.pc`.
194    ///
195    /// This function is public because it can be useful in some contexts such as OS-9 environments
196    /// where the trap ID is the immediate next word after the TRAP instruction.
197    pub fn peek_next_word<M: MemoryAccess + ?Sized>(&self, memory: &mut M) -> GetResult<u16> {
198        memory.get_word(self.regs.pc.even()?.0).ok_or(ACCESS_ERROR)
199    }
200
201    /// Pops the 16-bits value from the stack.
202    pub(super) fn pop_word<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M) -> GetResult<u16> {
203        let addr = self.ariwpo(7, Size::Word);
204        memory.get_word(addr.even()?).ok_or(ACCESS_ERROR)
205    }
206
207    /// Pops the 32-bits value from the stack.
208    pub(super) fn pop_long<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M) -> GetResult<u32> {
209        let addr = self.ariwpo(7, Size::Long);
210        memory.get_long(addr.even()?).ok_or(ACCESS_ERROR)
211    }
212
213    /// Pushes the given 16-bits value on the stack.
214    pub(super) fn push_word<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M, value: u16) -> SetResult {
215        let addr = self.ariwpr(7, Size::Word);
216        memory.set_word(addr.even()?, value).ok_or(ACCESS_ERROR)
217    }
218
219    /// Pushes the given 32-bits value on the stack.
220    pub(super) fn push_long<M: MemoryAccess + ?Sized>(&mut self, memory: &mut M, value: u32) -> SetResult {
221        let addr = self.ariwpr(7, Size::Long);
222        memory.set_long(addr.even()?, value).ok_or(ACCESS_ERROR)
223    }
224
225    /// Creates a new memory iterator starting at the current Program Counter.
226    pub(super) fn iter_from_pc<'a, M: MemoryAccess + ?Sized>(&self, memory: &'a mut M) -> MemoryIter<'a, M> {
227        memory.iter_u16(self.regs.pc.0)
228    }
229}
230
231impl MemoryAccess for [u8] {
232    fn get_byte(&mut self, addr: u32) -> Option<u8> {
233        let addr = addr as usize;
234        if addr < self.len() {
235            Some(self[addr])
236        } else {
237            None
238        }
239    }
240
241    fn get_word(&mut self, addr: u32) -> Option<u16> {
242        let addr = addr as usize;
243        if addr < self.len() {
244            Some((self[addr] as u16) << 8 | self[addr.wrapping_add(1)] as u16)
245        } else {
246            None
247        }
248    }
249
250    fn set_byte(&mut self, addr: u32, data: u8) -> Option<()> {
251        let addr = addr as usize;
252        if addr < self.len() {
253            self[addr] = data;
254            Some(())
255        } else {
256            None
257        }
258    }
259
260    fn set_word(&mut self, addr: u32, data: u16) -> Option<()> {
261        let addr = addr as usize;
262        if addr < self.len() {
263            self[addr] = (data >> 8) as u8;
264            self[addr.wrapping_add(1)] = data as u8;
265            Some(())
266        } else {
267            None
268        }
269    }
270
271    fn reset_instruction(&mut self) {}
272}
273
274impl MemoryAccess for &[u8] {
275    fn get_byte(&mut self, addr: u32) -> Option<u8> {
276        let addr = addr as usize;
277        if addr < self.len() {
278            Some(self[addr])
279        } else {
280            None
281        }
282    }
283
284    fn get_word(&mut self, addr: u32) -> Option<u16> {
285        let addr = addr as usize;
286        if addr < self.len() {
287            Some((self[addr] as u16) << 8 | self[addr.wrapping_add(1)] as u16)
288        } else {
289            None
290        }
291    }
292
293    fn set_byte(&mut self, _: u32, _: u8) -> Option<()> {
294        panic!("Can't write in non-mutable buffer");
295    }
296
297    fn set_word(&mut self, _: u32, _: u16) -> Option<()> {
298        panic!("Can't write in non-mutable buffer");
299    }
300
301    fn reset_instruction(&mut self) {}
302}
303
304impl MemoryAccess for [u16] {
305    fn get_byte(&mut self, addr: u32) -> Option<u8> {
306        let a = addr as usize >> 1;
307        if a < self.len() {
308            if addr.is_even() {
309                Some((self[a] >> 8) as u8)
310            } else {
311                Some(self[a] as u8)
312            }
313        } else {
314            None
315        }
316    }
317
318    fn get_word(&mut self, addr: u32) -> Option<u16> {
319        let addr = addr as usize >> 1;
320        if addr < self.len() {
321            Some(self[addr])
322        } else {
323            None
324        }
325    }
326
327    fn set_byte(&mut self, addr: u32, data: u8) -> Option<()> {
328        let a = addr as usize >> 1;
329        if a < self.len() {
330            if addr.is_even() {
331                self[a] &= 0x00FF;
332                self[a] |= (data as u16) << 8;
333            } else {
334                self[a] &= 0xFF00;
335                self[a] |= data as u16;
336            }
337            Some(())
338        } else {
339            None
340        }
341    }
342
343    fn set_word(&mut self, addr: u32, data: u16) -> Option<()> {
344        let addr = addr as usize >> 1;
345        if addr < self.len() {
346            self[addr] = data;
347            Some(())
348        } else {
349            None
350        }
351    }
352
353    fn reset_instruction(&mut self) {}
354}
355
356impl MemoryAccess for &[u16] {
357    fn get_byte(&mut self, addr: u32) -> Option<u8> {
358        let a = addr as usize >> 1;
359        if a < self.len() {
360            if addr.is_even() {
361                Some((self[a] >> 8) as u8)
362            } else {
363                Some(self[a] as u8)
364            }
365        } else {
366            None
367        }
368    }
369
370    fn get_word(&mut self, addr: u32) -> Option<u16> {
371        let addr = addr as usize >> 1;
372        if addr < self.len() {
373            Some(self[addr])
374        } else {
375            None
376        }
377    }
378
379    fn set_byte(&mut self, _: u32, _: u8) -> Option<()> {
380        panic!("Can't write in non-mutable buffer");
381    }
382
383    fn set_word(&mut self, _: u32, _: u16) -> Option<()> {
384        panic!("Can't write in non-mutable buffer");
385    }
386
387    fn reset_instruction(&mut self) {}
388}