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}