1use crate::core::instructions::BranchCondition;
2use crate::core::{
3    AddressRegister, AddressingMode, ConditionCodes, DataRegister, Exception, ExecuteResult,
4    InstructionExecutor, OpSize, ResolvedAddress,
5};
6use crate::traits::BusInterface;
7
8const TRAP_VECTOR_OFFSET: u32 = 32;
9const OVERFLOW_VECTOR: u32 = 7;
10
11impl<B: BusInterface> InstructionExecutor<'_, '_, B> {
12    fn resolve_to_memory_address(&mut self, source: AddressingMode) -> ExecuteResult<u32> {
13        let resolved = self.resolve_address(source, OpSize::LongWord)?;
14        let ResolvedAddress::Memory(address) = resolved else {
15            panic!(
16                "effective address operations should only accept addressing modes that resolve to an effective address"
17            );
18        };
19
20        Ok(address)
21    }
22
23    pub(super) fn lea(
24        &mut self,
25        source: AddressingMode,
26        register: AddressRegister,
27    ) -> ExecuteResult<u32> {
28        let address = self.resolve_to_memory_address(source)?;
29        register.write_long_word_to(&mut self.cpu.registers, address);
30
31        Ok(effective_address_cycles(source))
32    }
33
34    pub(super) fn pea(&mut self, source: AddressingMode) -> ExecuteResult<u32> {
35        let address = self.resolve_to_memory_address(source)?;
36        self.push_stack_u32(address)?;
37
38        Ok(8 + effective_address_cycles(source))
39    }
40
41    pub(super) fn jmp(&mut self, source: AddressingMode) -> ExecuteResult<u32> {
42        let address = self.resolve_to_memory_address(source)?;
43        self.jump_to_address(address)?;
44
45        Ok(jump_cycles(source))
46    }
47
48    pub(super) fn jsr(&mut self, source: AddressingMode) -> ExecuteResult<u32> {
49        let address = self.resolve_to_memory_address(source)?;
50        let old_pc = self.cpu.registers.pc;
51        self.jump_to_address(address)?;
52        self.push_stack_u32(old_pc)?;
53
54        Ok(8 + jump_cycles(source))
55    }
56
57    pub(super) fn link(&mut self, register: AddressRegister) -> ExecuteResult<u32> {
58        let extension = self.fetch_operand()?;
59        let displacement = extension as i16;
60
61        if register.is_stack_pointer() {
62            self.push_stack_u32(self.cpu.registers.sp().wrapping_sub(4))?;
63        } else {
64            self.push_stack_u32(register.read_from(&self.cpu.registers))?;
65        }
66
67        let sp = self.cpu.registers.sp();
68        register.write_long_word_to(&mut self.cpu.registers, sp);
69        self.cpu.registers.set_sp(sp.wrapping_add(displacement as u32));
70
71        Ok(16)
72    }
73
74    pub(super) fn unlk(&mut self, register: AddressRegister) -> ExecuteResult<u32> {
75        self.cpu.registers.set_sp(register.read_from(&self.cpu.registers));
76
77        let address = self.pop_stack_u32()?;
78        register.write_long_word_to(&mut self.cpu.registers, address);
79
80        Ok(12)
81    }
82
83    pub(super) fn ret(&mut self, restore_ccr: bool) -> ExecuteResult<u32> {
84        if restore_ccr {
85            let word = self.pop_stack_u16()?;
86            self.cpu.registers.ccr = (word as u8).into();
87        }
88
89        let pc = self.pop_stack_u32()?;
90        self.jump_to_address(pc)?;
91
92        Ok(if restore_ccr { 20 } else { 16 })
93    }
94
95    pub(super) fn rte(&mut self) -> ExecuteResult<u32> {
96        if !self.cpu.registers.supervisor_mode {
97            return Err(Exception::PrivilegeViolation);
98        }
99
100        let sr = self.pop_stack_u16()?;
101
102        let pc = self.pop_stack_u32()?;
103        self.cpu.registers.set_status_register(sr);
104        self.jump_to_address(pc)?;
105
106        Ok(20)
107    }
108
109    pub(super) fn trapv(&self) -> ExecuteResult<u32> {
110        if self.cpu.registers.ccr.overflow { Err(Exception::Trap(OVERFLOW_VECTOR)) } else { Ok(4) }
111    }
112
113    pub(super) fn chk(
114        &mut self,
115        register: DataRegister,
116        source: AddressingMode,
117    ) -> ExecuteResult<u32> {
118        let upper_bound = self.read_word(source)? as i16;
119
120        let value = register.read_from(&self.cpu.registers) as i16;
121
122        self.cpu.registers.ccr =
123            ConditionCodes { carry: false, overflow: false, zero: false, ..self.cpu.registers.ccr };
124
125        let address_cycles = source.address_calculation_cycles(OpSize::Word);
126
127        if value > upper_bound {
128            self.cpu.registers.ccr.negative = value < 0;
129            Err(Exception::CheckRegister { cycles: address_cycles + 8 })
130        } else if value < 0 {
131            self.cpu.registers.ccr.negative = true;
132            Err(Exception::CheckRegister { cycles: address_cycles + 10 })
133        } else {
134            Ok(address_cycles + 10)
135        }
136    }
137
138    fn fetch_branch_displacement(&mut self, displacement: i8) -> ExecuteResult<(i16, bool)> {
139        Ok(if displacement == 0 {
140            let extension = self.fetch_operand()?;
141            (extension as i16, true)
142        } else {
143            (displacement.into(), false)
144        })
145    }
146
147    pub(super) fn branch(
148        &mut self,
149        condition: BranchCondition,
150        displacement: i8,
151    ) -> ExecuteResult<u32> {
152        let pc = self.cpu.registers.pc;
153        let (displacement, fetched_extension) = self.fetch_branch_displacement(displacement)?;
154
155        if condition.check(self.cpu.registers.ccr) {
156            let address = pc.wrapping_add(displacement as u32);
157            self.jump_to_address(address)?;
158
159            Ok(10)
160        } else if fetched_extension {
161            Ok(12)
162        } else {
163            Ok(8)
164        }
165    }
166
167    pub(super) fn bsr(&mut self, displacement: i8) -> ExecuteResult<u32> {
168        let pc = self.cpu.registers.pc;
169        let (displacement, _) = self.fetch_branch_displacement(displacement)?;
170
171        self.push_stack_u32(self.cpu.registers.pc)?;
172
173        let address = pc.wrapping_add(displacement as u32);
174        self.jump_to_address(address)?;
175
176        Ok(18)
177    }
178
179    pub(super) fn dbcc(
180        &mut self,
181        condition: BranchCondition,
182        register: DataRegister,
183    ) -> ExecuteResult<u32> {
184        let pc = self.cpu.registers.pc;
185        let displacement = self.fetch_operand()? as i16;
186
187        if !condition.check(self.cpu.registers.ccr) {
188            let value = register.read_from(&self.cpu.registers) as u16;
189            register.write_word_to(&mut self.cpu.registers, value.wrapping_sub(1));
190
191            if value != 0 {
192                let address = pc.wrapping_add(displacement as u32);
193                self.jump_to_address(address)?;
194
195                Ok(10)
196            } else {
197                Ok(14)
198            }
199        } else {
200            Ok(12)
201        }
202    }
203
204    pub(super) fn scc(
205        &mut self,
206        condition: BranchCondition,
207        dest: AddressingMode,
208    ) -> ExecuteResult<u32> {
209        let cc = condition.check(self.cpu.registers.ccr);
210        let value = if cc { 0xFF } else { 0x00 };
211
212        self.write_byte(dest, value)?;
213
214        Ok(if dest.is_data_direct() {
215            4 + if cc { 2 } else { 0 }
216        } else {
217            8 + dest.address_calculation_cycles(OpSize::Byte)
218        })
219    }
220
221    pub(super) fn stop(&mut self) -> ExecuteResult<u32> {
222        if !self.cpu.registers.supervisor_mode {
223            return Err(Exception::PrivilegeViolation);
224        }
225
226        let sr = self.fetch_operand()?;
227        self.cpu.registers.set_status_register(sr);
228        self.cpu.registers.stopped = true;
229
230        Ok(4)
231    }
232}
233
234fn jump_cycles(addressing_mode: AddressingMode) -> u32 {
235    match addressing_mode {
236        AddressingMode::AddressIndirect(..) => 8,
237        AddressingMode::AddressIndirectDisplacement(..)
238        | AddressingMode::PcRelativeDisplacement
239        | AddressingMode::AbsoluteShort => 10,
240        AddressingMode::AddressIndirectIndexed(..) | AddressingMode::PcRelativeIndexed => 14,
241        AddressingMode::AbsoluteLong => 12,
242        _ => panic!("invalid jump addressing mode: {addressing_mode:?}"),
243    }
244}
245
246fn effective_address_cycles(addressing_mode: AddressingMode) -> u32 {
247    match addressing_mode {
248        AddressingMode::AddressIndirectIndexed(..) | AddressingMode::PcRelativeIndexed => 12,
249        _ => addressing_mode.address_calculation_cycles(OpSize::Byte),
250    }
251}
252
253pub(super) const fn nop() -> u32 {
254    4
255}
256
257pub(super) const fn reset() -> u32 {
258    // The RESET instruction is intended to reset external devices, but this functionality isn't
259    // used in the Genesis, so treat it as an extremely long NOP
260    132
261}
262
263pub(super) fn trap(vector: u32) -> ExecuteResult<u32> {
264    Err(Exception::Trap(TRAP_VECTOR_OFFSET + vector))
265}