load.rsannotatedload.rssource432 lines · 15.2 KB · raw
1use crate::core::instructions::{Direction, UspDirection};
2use crate::core::{
3    AddressRegister, AddressingMode, ConditionCodes, DataRegister, Exception, ExecuteResult,
4    InstructionExecutor, OpSize, Registers, ResolvedAddress,
5};
6use crate::debug::BusDebugExt;
7use crate::traits::BusInterface;
8use jgenesis_common::num::{GetBit, SignBit};
9
10macro_rules! impl_move {
11    ($name:ident, $read_method:ident, $write_method:ident, $size:expr) => {
12        pub(super) fn $name(
13            &mut self,
14            source: AddressingMode,
15            dest: AddressingMode,
16        ) -> ExecuteResult<u32> {
17            let value = self.$read_method(source)?;
18
19            if !dest.is_address_direct() {
20                self.cpu.registers.ccr = ConditionCodes {
21                    carry: false,
22                    overflow: false,
23                    zero: value == 0,
24                    negative: value.sign_bit(),
25                    ..self.cpu.registers.ccr
26                };
27            }
28
29            self.$write_method(dest, value)?;
30
31            // -(An) destinations take 2 fewer cycles than they do in other operations
32            let base_cycles = match dest {
33                AddressingMode::AddressIndirectPredecrement(..) => 2,
34                _ => 4,
35            };
36
37            Ok(base_cycles
38                + source.address_calculation_cycles($size)
39                + dest.address_calculation_cycles($size))
40        }
41    };
42}
43
44macro_rules! impl_exg {
45    ($name:ident, $tx:ty, $ty:ty) => {
46        pub(super) fn $name(&mut self, rx: $tx, ry: $ty) -> u32 {
47            let x_val = rx.read_from(&self.cpu.registers);
48            let y_val = ry.read_from(&self.cpu.registers);
49
50            rx.write_long_word_to(&mut self.cpu.registers, y_val);
51            ry.write_long_word_to(&mut self.cpu.registers, x_val);
52
53            6
54        }
55    };
56}
57
58impl<B: BusInterface> InstructionExecutor<'_, '_, B> {
59    #[inline]
60    fn write_long_word_for_move(&mut self, dest: AddressingMode, value: u32) -> ExecuteResult<()> {
61        match dest {
62            AddressingMode::AddressIndirectPredecrement(register) => {
63                let high_word = (value >> 16) as u16;
64                let low_word = value as u16;
65
66                let address = register.read_from(&self.cpu.registers).wrapping_sub(2);
67                register.write_long_word_to(&mut self.cpu.registers, address);
68                self.write_bus_word(address, low_word)?;
69
70                let address = address.wrapping_sub(2);
71                register.write_long_word_to(&mut self.cpu.registers, address);
72                self.write_bus_word(address, high_word)?;
73
74                Ok(())
75            }
76            _ => self.write_long_word(dest, value),
77        }
78    }
79
80    impl_move!(move_byte, read_byte, write_byte, OpSize::Byte);
81    impl_move!(move_word, read_word, write_word, OpSize::Word);
82    impl_move!(move_long_word, read_long_word, write_long_word_for_move, OpSize::LongWord);
83
84    pub(super) fn move_from_sr(&mut self, dest: AddressingMode) -> ExecuteResult<u32> {
85        let dest_resolved = self.resolve_address_with_post(dest, OpSize::Word)?;
86        self.write_word_resolved(dest_resolved, self.cpu.registers.status_register())?;
87
88        Ok(if dest.is_data_direct() {
89            6
90        } else {
91            8 + dest.address_calculation_cycles(OpSize::Word)
92        })
93    }
94
95    pub(super) fn move_to_ccr(&mut self, source: AddressingMode) -> ExecuteResult<u32> {
96        let value = self.read_word(source)?;
97
98        self.cpu.registers.ccr = (value as u8).into();
99
100        Ok(12 + source.address_calculation_cycles(OpSize::Word))
101    }
102
103    pub(super) fn move_to_sr(&mut self, source: AddressingMode) -> ExecuteResult<u32> {
104        if !self.cpu.registers.supervisor_mode {
105            return Err(Exception::PrivilegeViolation);
106        }
107
108        let value = self.read_word(source)?;
109
110        self.cpu.registers.set_status_register(value);
111
112        Ok(12 + source.address_calculation_cycles(OpSize::Word))
113    }
114
115    pub(super) fn moveq(&mut self, data: i8, register: DataRegister) -> u32 {
116        register.write_long_word_to(&mut self.cpu.registers, data as u32);
117
118        self.cpu.registers.ccr = ConditionCodes {
119            carry: false,
120            overflow: false,
121            zero: data == 0,
122            negative: data < 0,
123            ..self.cpu.registers.ccr
124        };
125
126        4
127    }
128
129    pub(super) fn move_usp(
130        &mut self,
131        direction: UspDirection,
132        register: AddressRegister,
133    ) -> ExecuteResult<u32> {
134        if !self.cpu.registers.supervisor_mode {
135            return Err(Exception::PrivilegeViolation);
136        }
137
138        match direction {
139            UspDirection::RegisterToUsp => {
140                let value = register.read_from(&self.cpu.registers);
141                self.cpu.registers.usp = value;
142            }
143            UspDirection::UspToRegister => {
144                let usp = self.cpu.registers.usp;
145                register.write_long_word_to(&mut self.cpu.registers, usp);
146            }
147        }
148
149        Ok(4)
150    }
151
152    pub(super) fn movem(
153        &mut self,
154        size: OpSize,
155        addressing_mode: AddressingMode,
156        direction: Direction,
157    ) -> ExecuteResult<u32> {
158        let extension = self.fetch_operand()?;
159        log::trace!("Extension {extension:04X}");
160        if let AddressingMode::AddressIndirectPredecrement(register) = addressing_mode {
161            return self.movem_predecrement(size, register, extension);
162        }
163
164        let resolved_address = self.resolve_address(addressing_mode, size)?;
165
166        let iter = MultipleRegisterIter::new(extension);
167        let (mut address, postinc_register) = match resolved_address {
168            ResolvedAddress::Memory(address) => (address, None),
169            ResolvedAddress::MemoryPostincrement { address, register, .. } => {
170                (address, Some(register))
171            }
172            _ => panic!("MOVEM only supports addressing modes that resolve to a memory address"),
173        };
174
175        let mut count = 0;
176        match direction {
177            Direction::RegisterToMemory => {
178                for register in iter {
179                    let value = register.read_from(&self.cpu.registers);
180                    match size {
181                        OpSize::Word => {
182                            self.write_bus_word(address, value as u16)?;
183                            address = address.wrapping_add(2);
184                        }
185                        OpSize::LongWord => {
186                            self.write_bus_long_word(address, value)?;
187                            address = address.wrapping_add(4);
188                        }
189                        OpSize::Byte => panic!("MOVEM does not support size byte"),
190                    }
191
192                    count += 1;
193                }
194            }
195            Direction::MemoryToRegister => {
196                for register in iter {
197                    match size {
198                        OpSize::Word => {
199                            if let Some(postinc_register) = postinc_register {
200                                postinc_register.write_long_word_to(
201                                    &mut self.cpu.registers,
202                                    address.wrapping_add(2),
203                                );
204                            }
205
206                            let value = self.read_bus_word(address)? as i16 as u32;
207                            match register {
208                                Register::Address(register)
209                                    if Some(register) == postinc_register => {}
210                                _ => {
211                                    register.write_to(&mut self.cpu.registers, value);
212                                }
213                            }
214
215                            address = address.wrapping_add(2);
216                        }
217                        OpSize::LongWord => {
218                            if let Some(postinc_register) = postinc_register {
219                                postinc_register.write_long_word_to(
220                                    &mut self.cpu.registers,
221                                    address.wrapping_add(2),
222                                );
223                            }
224
225                            let value = self.read_bus_long_word(address)?;
226                            match register {
227                                Register::Address(register)
228                                    if Some(register) == postinc_register => {}
229                                _ => {
230                                    register.write_to(&mut self.cpu.registers, value);
231                                }
232                            }
233
234                            address = address.wrapping_add(4);
235                        }
236                        OpSize::Byte => panic!("MOVEM does not support size byte"),
237                    }
238
239                    count += 1;
240                }
241
242                // Spurious read at the end of memory-to-register MOVEM (based on test ROM)
243                self.read_bus_word(address)?;
244
245                if let Some(postinc_register) = postinc_register {
246                    postinc_register.write_long_word_to(&mut self.cpu.registers, address);
247                }
248            }
249        }
250
251        let count_cycles = match size {
252            OpSize::Word => 4 * count,
253            OpSize::LongWord => 8 * count,
254            OpSize::Byte => panic!("MOVEM does not support size byte"),
255        };
256        Ok(match direction {
257            Direction::MemoryToRegister => {
258                8 + addressing_mode.address_calculation_cycles(OpSize::Word) + count_cycles
259            }
260            Direction::RegisterToMemory => {
261                4 + addressing_mode.address_calculation_cycles(OpSize::Word) + count_cycles
262            }
263        })
264    }
265
266    fn movem_predecrement(
267        &mut self,
268        size: OpSize,
269        predec_register: AddressRegister,
270        extension: u16,
271    ) -> ExecuteResult<u32> {
272        let iter = MultipleRegisterIter::new_reverse(extension);
273        let mut address = predec_register.read_from(&self.cpu.registers);
274
275        let mut count = 0;
276        for register in iter {
277            log::trace!("  Copy {register:?}");
278            match size {
279                OpSize::Word => {
280                    address = address.wrapping_sub(2);
281                    let value = register.read_from(&self.cpu.registers) as u16;
282                    self.write_bus_word(address, value)?;
283                }
284                OpSize::LongWord => {
285                    let value = register.read_from(&self.cpu.registers);
286                    let high_word = (value >> 16) as u16;
287                    let low_word = value as u16;
288
289                    address = address.wrapping_sub(2);
290                    self.write_bus_word(address, low_word)?;
291
292                    address = address.wrapping_sub(2);
293                    self.write_bus_word(address, high_word)?;
294                }
295                OpSize::Byte => panic!("MOVEM does not support size byte"),
296            }
297
298            count += 1;
299        }
300
301        predec_register.write_long_word_to(&mut self.cpu.registers, address);
302
303        Ok(8 + match size {
304            OpSize::Word => 4 * count,
305            OpSize::LongWord => 8 * count,
306            OpSize::Byte => panic!("MOVEM does not support size byte"),
307        })
308    }
309
310    pub(super) fn movep(
311        &mut self,
312        size: OpSize,
313        d_register: DataRegister,
314        a_register: AddressRegister,
315        direction: Direction,
316    ) -> ExecuteResult<u32> {
317        let extension = self.fetch_operand()?;
318        let displacement = extension as i16;
319        let address = a_register.read_from(&self.cpu.registers).wrapping_add(displacement as u32);
320
321        match (size, direction) {
322            (OpSize::Word, Direction::RegisterToMemory) => {
323                let value = d_register.read_from(&self.cpu.registers);
324                let [msb, lsb] = (value as u16).to_be_bytes();
325                self.bus.write_byte_debug(address, msb, self.cpu);
326                self.bus.write_byte_debug(address.wrapping_add(2), lsb, self.cpu);
327            }
328            (OpSize::Word, Direction::MemoryToRegister) => {
329                let msb = self.bus.read_byte_debug(address, self.cpu);
330                let lsb = self.bus.read_byte_debug(address.wrapping_add(2), self.cpu);
331                d_register.write_word_to(&mut self.cpu.registers, u16::from_be_bytes([msb, lsb]));
332            }
333            (OpSize::LongWord, Direction::RegisterToMemory) => {
334                let value = d_register.read_from(&self.cpu.registers);
335                let mut address = address;
336                for byte in value.to_be_bytes() {
337                    self.bus.write_byte_debug(address, byte, self.cpu);
338                    address = address.wrapping_add(2);
339                }
340            }
341            (OpSize::LongWord, Direction::MemoryToRegister) => {
342                let b3 = self.bus.read_byte_debug(address, self.cpu);
343                let b2 = self.bus.read_byte_debug(address.wrapping_add(2), self.cpu);
344                let b1 = self.bus.read_byte_debug(address.wrapping_add(4), self.cpu);
345                let b0 = self.bus.read_byte_debug(address.wrapping_add(6), self.cpu);
346                let value = u32::from_be_bytes([b3, b2, b1, b0]);
347                d_register.write_long_word_to(&mut self.cpu.registers, value);
348            }
349            (OpSize::Byte, _) => panic!("MOVEP does not support size byte"),
350        }
351
352        Ok(match size {
353            OpSize::Word => 16,
354            OpSize::LongWord => 24,
355            OpSize::Byte => panic!("MOVEP does not support size byte"),
356        })
357    }
358
359    impl_exg!(exg_data, DataRegister, DataRegister);
360    impl_exg!(exg_address, AddressRegister, AddressRegister);
361    impl_exg!(exg_data_address, DataRegister, AddressRegister);
362}
363
364#[derive(Debug, Clone, Copy, PartialEq, Eq)]
365enum Register {
366    Data(DataRegister),
367    Address(AddressRegister),
368}
369
370impl Register {
371    fn read_from(self, registers: &Registers) -> u32 {
372        match self {
373            Self::Data(register) => register.read_from(registers),
374            Self::Address(register) => register.read_from(registers),
375        }
376    }
377
378    fn write_to(self, registers: &mut Registers, value: u32) {
379        match self {
380            Self::Data(register) => {
381                register.write_long_word_to(registers, value);
382            }
383            Self::Address(register) => {
384                register.write_long_word_to(registers, value);
385            }
386        }
387    }
388}
389
390#[derive(Debug, Clone)]
391struct MultipleRegisterIter {
392    mask: u16,
393    i: u8,
394    reverse: bool,
395}
396
397impl MultipleRegisterIter {
398    fn new(extension: u16) -> Self {
399        Self { mask: extension, i: 0, reverse: false }
400    }
401
402    fn new_reverse(extension: u16) -> Self {
403        Self { mask: extension, i: 0, reverse: true }
404    }
405}
406
407impl Iterator for MultipleRegisterIter {
408    type Item = Register;
409
410    fn next(&mut self) -> Option<Self::Item> {
411        while self.i < 16 {
412            let i = self.i;
413            let bit = self.mask.bit(i);
414            self.i += 1;
415
416            if bit {
417                let i = if self.reverse { 15 - i } else { i };
418                return Some(to_register(i));
419            }
420        }
421
422        None
423    }
424
425    fn size_hint(&self) -> (usize, Option<usize>) {
426        (0, Some(16))
427    }
428}
429
430fn to_register(i: u8) -> Register {
431    if i < 8 { Register::Data(DataRegister(i)) } else { Register::Address(AddressRegister(i - 8)) }
432}