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}