1use crate::M68000; 2use crate::core::instructions::{ 3 BranchCondition, Direction, Instruction, ShiftCount, ShiftDirection, UspDirection, 4}; 5use crate::core::{ 6 AddressRegister, AddressingMode, DataRegister, IndexRegister, IndexSize, OpSize, 7}; 8use jgenesis_common::num::GetBit; 9use std::borrow::Cow; 10use std::mem; 11 12const DATA_REGISTERS: &[&str; 8] = &["d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7"]; 13const ADDRESS_REGISTERS: &[&str; 8] = &["a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7"]; 14const ADDRESS_INDIRECT: &[&str; 8] = 15 &["(a0)", "(a1)", "(a2)", "(a3)", "(a4)", "(a5)", "(a6)", "(a7)"]; 16const ADDRESS_POSTINC: &[&str; 8] = 17 &["(a0)+", "(a1)+", "(a2)+", "(a3)+", "(a4)+", "(a5)+", "(a6)+", "(a7)+"]; 18const ADDRESS_PREDEC: &[&str; 8] = 19 &["-(a0)", "-(a1)", "-(a2)", "-(a3)", "-(a4)", "-(a5)", "-(a6)", "-(a7)"]; 20 21fn size_str(size: OpSize) -> &'static str { 22 match size { 23 OpSize::Byte => "b", 24 OpSize::Word => "w", 25 OpSize::LongWord => "l", 26 } 27} 28 29fn condition_suffix(condition: BranchCondition) -> &'static str { 30 match condition { 31 BranchCondition::True => "t", 32 BranchCondition::False => "f", 33 BranchCondition::Higher => "hi", 34 BranchCondition::LowerOrSame => "ls", 35 BranchCondition::CarryClear => "cc", 36 BranchCondition::CarrySet => "cs", 37 BranchCondition::NotEqual => "ne", 38 BranchCondition::Equal => "eq", 39 BranchCondition::OverflowClear => "vc", 40 BranchCondition::OverflowSet => "vs", 41 BranchCondition::Plus => "pl", 42 BranchCondition::Minus => "mi", 43 BranchCondition::GreaterOrEqual => "ge", 44 BranchCondition::LessThan => "lt", 45 BranchCondition::GreaterThan => "gt", 46 BranchCondition::LessOrEqual => "le", 47 } 48} 49 50fn direction_str(direction: ShiftDirection) -> &'static str { 51 match direction { 52 ShiftDirection::Left => "l", 53 ShiftDirection::Right => "r", 54 } 55} 56 57fn shift_count_str(count: ShiftCount) -> Cow<'static, str> { 58 match count { 59 ShiftCount::Constant(value) => format!("#{value}").into(), 60 ShiftCount::Register(r) => DATA_REGISTERS[r.0 as usize].into(), 61 } 62} 63 64#[derive(Debug, Clone, Copy)] 65pub enum DisassembledIndex { 66 Data(u8), 67 Address(u8), 68} 69 70impl From<IndexRegister> for DisassembledIndex { 71 fn from(value: IndexRegister) -> Self { 72 match value { 73 IndexRegister::Data(DataRegister(r)) => Self::Data(r), 74 IndexRegister::Address(AddressRegister(r)) => Self::Address(r), 75 } 76 } 77} 78 79impl DisassembledIndex { 80 #[must_use] 81 pub fn resolve(self, cpu: &M68000, size: IndexSize) -> u32 { 82 let register_value = match self { 83 Self::Data(r) => cpu.data_registers()[r as usize], 84 Self::Address(7) => cpu.stack_pointer(), 85 Self::Address(r) => cpu.address_registers()[r as usize], 86 }; 87 88 match size { 89 IndexSize::SignExtendedWord => register_value as i16 as u32, 90 IndexSize::LongWord => register_value, 91 } 92 } 93} 94 95#[derive(Debug, Clone, Copy)] 96pub enum MemoryAccess { 97 Absolute { 98 address: u32, 99 size: OpSize, 100 }, 101 AddressIndirect { 102 register: u8, 103 displacement: u32, 104 index: Option<(DisassembledIndex, IndexSize)>, 105 size: OpSize, 106 }, 107 AddressIndirectPredecrement { 108 register: u8, 109 size: OpSize, 110 }, 111 PcRelative { 112 pc: u32, 113 displacement: u32, 114 index: Option<(DisassembledIndex, IndexSize)>, 115 size: OpSize, 116 }, 117} 118 119impl MemoryAccess { 120 #[must_use] 121 pub fn resolve_address(self, cpu: &M68000) -> (u32, OpSize) { 122 match self { 123 Self::Absolute { address, size } => (address, size), 124 Self::AddressIndirect { register, displacement, index, size } => { 125 let mut address = address_register(cpu, register).wrapping_add(displacement); 126 if let Some((index, size)) = index { 127 address = address.wrapping_add(index.resolve(cpu, size)); 128 } 129 (address, size) 130 } 131 Self::AddressIndirectPredecrement { register, size } => { 132 let decrement = match (size, register) { 133 (OpSize::Byte, 7) | (OpSize::Word, _) => 2, 134 (OpSize::Byte, _) => 1, 135 (OpSize::LongWord, _) => 4, 136 }; 137 let address = address_register(cpu, register).wrapping_sub(decrement); 138 (address, size) 139 } 140 Self::PcRelative { pc, displacement, index, size } => { 141 let mut address = pc.wrapping_add(displacement); 142 if let Some((index, size)) = index { 143 address = address.wrapping_add(index.resolve(cpu, size)); 144 } 145 (address, size) 146 } 147 } 148 } 149} 150 151fn address_register(cpu: &M68000, register: u8) -> u32 { 152 match register { 153 7 => cpu.stack_pointer(), 154 _ => cpu.address_registers()[register as usize], 155 } 156} 157 158#[derive(Debug, Clone, Copy, PartialEq, Eq)] 159pub enum MemoryReadType { 160 EffectiveAddress, // JMP, JSR, LEA, PEA 161 Read, 162} 163 164#[derive(Debug, Clone)] 165pub struct DisassembledInstruction { 166 pub opcodes: Vec<u16>, 167 pub text: String, 168 pub next_opcode_addr: u32, 169 pub memory_read: Option<MemoryAccess>, 170 pub memory_read_type: MemoryReadType, 171 pub memory_write: Option<MemoryAccess>, 172} 173 174impl DisassembledInstruction { 175 #[must_use] 176 pub fn new() -> Self { 177 Self { 178 opcodes: Vec::new(), 179 text: String::new(), 180 next_opcode_addr: 0, 181 memory_read: None, 182 memory_read_type: MemoryReadType::Read, 183 memory_write: None, 184 } 185 } 186 187 fn clear(&mut self) { 188 self.opcodes.clear(); 189 self.text.clear(); 190 self.memory_read = None; 191 self.memory_read_type = MemoryReadType::Read; 192 self.memory_write = None; 193 } 194} 195 196impl Default for DisassembledInstruction { 197 fn default() -> Self { 198 Self::new() 199 } 200} 201 202struct WordReader<F> { 203 pc: u32, 204 read: F, 205 opcodes: Vec<u16>, 206} 207 208impl<F: FnMut() -> u16> WordReader<F> { 209 fn read_word(&mut self) -> u16 { 210 self.pc = (self.pc + 2) & 0xFFFFFF; 211 212 let word = (self.read)(); 213 self.opcodes.push(word); 214 word 215 } 216} 217 218struct Disassembler<'a, F> { 219 reader: WordReader<F>, 220 out: &'a mut DisassembledInstruction, 221} 222 223pub fn disassemble_into( 224 out: &mut DisassembledInstruction, 225 pc: u32, 226 read_word: impl FnMut() -> u16, 227) { 228 out.clear(); 229 Disassembler::new(pc, read_word, out).disassemble(); 230} 231 232impl<'a, F> Disassembler<'a, F> 233where 234 F: FnMut() -> u16, 235{ 236 fn new(pc: u32, read_word: F, out: &'a mut DisassembledInstruction) -> Self { 237 let reader = WordReader { pc, read: read_word, opcodes: mem::take(&mut out.opcodes) }; 238 Self { reader, out } 239 } 240 241 fn read_word(&mut self) -> u16 { 242 self.reader.read_word() 243 } 244 245 fn disassemble(mut self) { 246 let instruction = Instruction::decode_from(self.read_word()); 247 248 self.out.text = match instruction { 249 Instruction::Add { size, source, dest, with_extend } => { 250 self.add(size, source, dest, with_extend) 251 } 252 Instruction::AddDecimal { source, dest } => self.abcd(source, dest), 253 Instruction::And { size, source, dest } => self.and(size, source, dest), 254 Instruction::AndToCcr => self.andi_to_ccr(), 255 Instruction::AndToSr => self.andi_to_sr(), 256 Instruction::ArithmeticShiftMemory(direction, dest) => { 257 self.asl_asr_memory(direction, dest) 258 } 259 Instruction::ArithmeticShiftRegister(size, direction, register, count) => { 260 Self::asl_asr_register(size, direction, register, count) 261 } 262 Instruction::BitTest { source, dest } => self.btst(source, dest), 263 Instruction::BitTestAndChange { source, dest } => self.bchg(source, dest), 264 Instruction::BitTestAndClear { source, dest } => self.bclr(source, dest), 265 Instruction::BitTestAndSet { source, dest } => self.bset(source, dest), 266 Instruction::Branch(condition, displacement) => self.branch(condition, displacement), 267 Instruction::BranchDecrement(condition, register) => self.dbcc(condition, register), 268 Instruction::BranchToSubroutine(displacement) => self.bsr(displacement), 269 Instruction::CheckRegister(register, source) => self.chk(register, source), 270 Instruction::Clear(size, dest) => self.clr(size, dest), 271 Instruction::Compare { size, source, dest } => self.cmp(size, source, dest), 272 Instruction::DivideSigned(dest, source) => self.divs(dest, source), 273 Instruction::DivideUnsigned(dest, source) => self.divu(dest, source), 274 Instruction::ExchangeAddress(a0, a1) => Self::exg_address(a0, a1), 275 Instruction::ExchangeData(d0, d1) => Self::exg_data(d0, d1), 276 Instruction::ExchangeDataAddress(d, a) => Self::exg_data_address(d, a), 277 Instruction::ExclusiveOr { size, source, dest } => self.eor(size, source, dest), 278 Instruction::ExclusiveOrToCcr => self.eori_to_ccr(), 279 Instruction::ExclusiveOrToSr => self.eori_to_sr(), 280 Instruction::Extend(size, dest) => Self::ext(size, dest), 281 Instruction::Illegal { opcode } => { 282 format!("illegal ;0x{opcode:04X}") 283 } 284 Instruction::Jump(dest) => self.jmp(dest), 285 Instruction::JumpToSubroutine(dest) => self.jsr(dest), 286 Instruction::Link(register) => self.link(register), 287 Instruction::LoadEffectiveAddress(source, dest) => self.lea(source, dest), 288 Instruction::LogicalShiftMemory(direction, dest) => { 289 self.lsl_lsr_memory(direction, dest) 290 } 291 Instruction::LogicalShiftRegister(size, direction, register, count) => { 292 Self::lsl_lsr_register(size, direction, register, count) 293 } 294 Instruction::Move { size, source, dest } => self.move_(size, source, dest), 295 Instruction::MoveFromSr(dest) => self.move_from_sr(dest), 296 Instruction::MoveMultiple(size, am, direction) => self.movem(size, am, direction), 297 Instruction::MovePeripheral(size, data, address, direction) => { 298 self.movep(size, data, address, direction) 299 } 300 Instruction::MoveQuick(value, register) => Self::moveq(value, register), 301 Instruction::MoveToCcr(source) => self.move_to_ccr(source), 302 Instruction::MoveToSr(source) => self.move_to_sr(source), 303 Instruction::MoveUsp(direction, register) => Self::move_usp(direction, register), 304 Instruction::MultiplySigned(dest, source) => self.muls(dest, source), 305 Instruction::MultiplyUnsigned(dest, source) => self.mulu(dest, source), 306 Instruction::Negate { size, dest, with_extend } => self.neg(size, dest, with_extend), 307 Instruction::NegateDecimal(dest) => self.nbcd(dest), 308 Instruction::NoOp => "nop".into(), 309 Instruction::Not(size, dest) => self.not(size, dest), 310 Instruction::Or { size, source, dest } => self.or(size, source, dest), 311 Instruction::OrToCcr => self.ori_to_ccr(), 312 Instruction::OrToSr => self.ori_to_sr(), 313 Instruction::PushEffectiveAddress(source) => self.pea(source), 314 Instruction::Reset => "reset".into(), 315 Instruction::Return { restore_ccr } => { 316 if restore_ccr { 317 "rtr".into() 318 } else { 319 "rts".into() 320 } 321 } 322 Instruction::ReturnFromException => "rte".into(), 323 Instruction::RotateMemory(direction, dest) => self.rol_ror_memory(direction, dest), 324 Instruction::RotateRegister(size, direction, register, count) => { 325 Self::rol_ror_register(size, direction, register, count) 326 } 327 Instruction::RotateThruExtendMemory(direction, dest) => { 328 self.roxl_roxr_memory(direction, dest) 329 } 330 Instruction::RotateThruExtendRegister(size, direction, register, count) => { 331 Self::roxl_roxr_register(size, direction, register, count) 332 } 333 Instruction::Set(condition, dest) => self.scc(condition, dest), 334 Instruction::Subtract { size, source, dest, with_extend } => { 335 self.sub(size, source, dest, with_extend) 336 } 337 Instruction::SubtractDecimal { source, dest } => self.sbcd(source, dest), 338 Instruction::Swap(register) => Self::swap(register), 339 Instruction::Stop => "stop".into(), 340 Instruction::Test(size, source) => self.tst(size, source), 341 Instruction::TestAndSet(dest) => self.tas(dest), 342 Instruction::Trap(vector) => Self::trap(vector), 343 Instruction::TrapOnOverflow => "trapv".into(), 344 Instruction::Unlink(register) => Self::unlk(register), 345 }; 346 347 self.out.opcodes = mem::take(&mut self.reader.opcodes); 348 self.out.next_opcode_addr = self.reader.pc; 349 } 350 351 fn binary_op( 352 &mut self, 353 name: &str, 354 size: OpSize, 355 source: AddressingMode, 356 dest: AddressingMode, 357 ) -> String { 358 let (source_str, source_access) = self.resolve_addressing_mode(source, size); 359 let (dest_str, dest_access) = self.resolve_addressing_mode(dest, size); 360 361 self.out.memory_read = source_access; 362 self.out.memory_write = dest_access; 363 364 format!("{name}.{} {source_str}, {dest_str}", size_str(size)) 365 } 366 367 fn add( 368 &mut self, 369 size: OpSize, 370 source: AddressingMode, 371 dest: AddressingMode, 372 with_extend: bool, 373 ) -> String { 374 let name = if with_extend { 375 "addx" 376 } else { 377 match (source, dest) { 378 (AddressingMode::Quick(_), _) => "addq", 379 (_, AddressingMode::AddressDirect(_)) => "adda", 380 (AddressingMode::Immediate, _) => "addi", 381 _ => "add", 382 } 383 }; 384 385 self.binary_op(name, size, source, dest) 386 } 387 388 fn abcd(&mut self, source: AddressingMode, dest: AddressingMode) -> String { 389 let (source_str, source_access) = self.resolve_addressing_mode(source, OpSize::Byte); 390 let (dest_str, dest_access) = self.resolve_addressing_mode(dest, OpSize::Byte); 391 392 self.out.memory_read = source_access; 393 self.out.memory_write = dest_access; 394 395 format!("abcd {source_str}, {dest_str}") 396 } 397 398 fn and(&mut self, size: OpSize, source: AddressingMode, dest: AddressingMode) -> String { 399 let name = match source { 400 AddressingMode::Immediate => "andi", 401 _ => "and", 402 }; 403 404 self.binary_op(name, size, source, dest) 405 } 406 407 fn andi_to_ccr(&mut self) -> String { 408 let source_str = self.operand_string(AddressingMode::Immediate, OpSize::Byte); 409 format!("andi {source_str}, ccr") 410 } 411 412 fn andi_to_sr(&mut self) -> String { 413 let source_str = self.operand_string(AddressingMode::Immediate, OpSize::Word); 414 format!("andi {source_str}, sr") 415 } 416 417 fn asl_asr_memory(&mut self, direction: ShiftDirection, dest: AddressingMode) -> String { 418 let (dest_str, dest_access) = self.resolve_addressing_mode(dest, OpSize::Word); 419 self.out.memory_read = dest_access; 420 self.out.memory_write = dest_access; 421 format!("as{} {dest_str}", direction_str(direction)) 422 } 423 424 fn asl_asr_register( 425 size: OpSize, 426 direction: ShiftDirection, 427 register: DataRegister, 428 count: ShiftCount, 429 ) -> String { 430 format!( 431 "as{}.{} {}, {}", 432 direction_str(direction), 433 size_str(size), 434 shift_count_str(count), 435 DATA_REGISTERS[register.0 as usize] 436 ) 437 } 438 439 fn bit_op(&mut self, name: &str, source: AddressingMode, dest: AddressingMode) -> String { 440 let source_str = match source { 441 AddressingMode::Immediate => { 442 let bit = self.read_word() & 0xFF; 443 format!("#{bit}").into() 444 } 445 _ => self.operand_string(source, OpSize::Byte), 446 }; 447 let (dest_str, dest_access) = self.resolve_addressing_mode(dest, OpSize::Byte); 448 449 self.out.memory_read = dest_access; 450 self.out.memory_write = dest_access; 451 452 format!("{name} {source_str}, {dest_str}") 453 } 454 455 fn btst(&mut self, source: AddressingMode, dest: AddressingMode) -> String { 456 self.bit_op("btst", source, dest) 457 } 458 459 fn bchg(&mut self, source: AddressingMode, dest: AddressingMode) -> String { 460 self.bit_op("bchg", source, dest) 461 } 462 463 fn bclr(&mut self, source: AddressingMode, dest: AddressingMode) -> String { 464 self.bit_op("bclr", source, dest) 465 } 466 467 fn bset(&mut self, source: AddressingMode, dest: AddressingMode) -> String { 468 self.bit_op("bset", source, dest) 469 } 470 471 fn branch(&mut self, condition: BranchCondition, displacement: i8) -> String { 472 let pc = self.reader.pc; 473 let effective_displacement = match displacement { 474 0 => self.read_word() as i16, 475 _ => displacement.into(), 476 }; 477 478 let name = match condition { 479 BranchCondition::True => "bra".into(), 480 BranchCondition::False => "braf".into(), 481 _ => format!("b{}", condition_suffix(condition)), 482 }; 483 484 format!("{name} ${:06X}", pc.wrapping_add_signed(effective_displacement.into())) 485 } 486 487 fn dbcc(&mut self, condition: BranchCondition, register: DataRegister) -> String { 488 let pc = self.reader.pc; 489 let displacement = self.read_word() as i16; 490 format!( 491 "db{} {}, ${:06X}", 492 condition_suffix(condition), 493 DATA_REGISTERS[register.0 as usize], 494 pc.wrapping_add_signed(displacement.into()) 495 ) 496 } 497 498 fn bsr(&mut self, displacement: i8) -> String { 499 let pc = self.reader.pc; 500 let effective_displacement = match displacement { 501 0 => self.read_word() as i16, 502 _ => displacement.into(), 503 }; 504 505 format!("bsr ${:06X}", pc.wrapping_add_signed(effective_displacement.into())) 506 } 507 508 fn chk(&mut self, register: DataRegister, source: AddressingMode) -> String { 509 let (source_str, source_access) = self.resolve_addressing_mode(source, OpSize::Word); 510 self.out.memory_read = source_access; 511 format!("chk {source_str}, {}", DATA_REGISTERS[register.0 as usize]) 512 } 513 514 fn clr(&mut self, size: OpSize, dest: AddressingMode) -> String { 515 let (dest_str, dest_access) = self.resolve_addressing_mode(dest, size); 516 self.out.memory_write = dest_access; 517 format!("clr.{} {dest_str}", size_str(size)) 518 } 519 520 fn cmp(&mut self, size: OpSize, source: AddressingMode, dest: AddressingMode) -> String { 521 let name = match (source, dest) { 522 (_, AddressingMode::AddressDirect(_)) => "cmpa", 523 (AddressingMode::Immediate, _) => "cmpi", 524 ( 525 AddressingMode::AddressIndirectPostincrement(_), 526 AddressingMode::AddressIndirectPostincrement(_), 527 ) => "cmpm", 528 _ => "cmp", 529 }; 530 531 self.binary_op(name, size, source, dest) 532 } 533 534 fn muldiv_op(&mut self, name: &str, dest: DataRegister, source: AddressingMode) -> String { 535 let (source, source_access) = self.resolve_addressing_mode(source, OpSize::Word); 536 self.out.memory_read = source_access; 537 format!("{name} {source}, {}", DATA_REGISTERS[dest.0 as usize]) 538 } 539 540 fn divs(&mut self, dest: DataRegister, source: AddressingMode) -> String { 541 self.muldiv_op("divs", dest, source) 542 } 543 544 fn divu(&mut self, dest: DataRegister, source: AddressingMode) -> String { 545 self.muldiv_op("divu", dest, source) 546 } 547 548 fn exg_address(a0: AddressRegister, a1: AddressRegister) -> String { 549 format!("exg {}, {}", ADDRESS_REGISTERS[a0.0 as usize], ADDRESS_REGISTERS[a1.0 as usize]) 550 } 551 552 fn exg_data(d0: DataRegister, d1: DataRegister) -> String { 553 format!("exg {}, {}", DATA_REGISTERS[d0.0 as usize], DATA_REGISTERS[d1.0 as usize]) 554 } 555 556 fn exg_data_address(d: DataRegister, a: AddressRegister) -> String { 557 format!("exg {}, {}", DATA_REGISTERS[d.0 as usize], ADDRESS_REGISTERS[a.0 as usize]) 558 } 559 560 fn eor(&mut self, size: OpSize, source: AddressingMode, dest: AddressingMode) -> String { 561 let name = match source { 562 AddressingMode::Immediate => "eori", 563 _ => "eor", 564 }; 565 566 self.binary_op(name, size, source, dest) 567 } 568 569 fn eori_to_ccr(&mut self) -> String { 570 let source_str = self.operand_string(AddressingMode::Immediate, OpSize::Byte); 571 format!("eori {source_str}, ccr") 572 } 573 574 fn eori_to_sr(&mut self) -> String { 575 let source_str = self.operand_string(AddressingMode::Immediate, OpSize::Word); 576 format!("eori {source_str}, sr") 577 } 578 579 fn ext(size: OpSize, dest: DataRegister) -> String { 580 format!("ext.{} {}", size_str(size), DATA_REGISTERS[dest.0 as usize]) 581 } 582 583 fn jmp(&mut self, dest: AddressingMode) -> String { 584 let (dest_str, dest_access) = self.resolve_addressing_mode(dest, OpSize::LongWord); 585 self.out.memory_read = dest_access; 586 self.out.memory_read_type = MemoryReadType::EffectiveAddress; 587 format!("jmp {dest_str}") 588 } 589 590 fn jsr(&mut self, dest: AddressingMode) -> String { 591 let (dest_str, dest_access) = self.resolve_addressing_mode(dest, OpSize::LongWord); 592 self.out.memory_read = dest_access; 593 self.out.memory_read_type = MemoryReadType::EffectiveAddress; 594 format!("jsr {dest_str}") 595 } 596 597 fn link(&mut self, register: AddressRegister) -> String { 598 let displacement = self.read_word() as i16; 599 format!("link {}, {displacement}", ADDRESS_REGISTERS[register.0 as usize]) 600 } 601 602 fn lea(&mut self, source: AddressingMode, dest: AddressRegister) -> String { 603 let (source_str, source_access) = self.resolve_addressing_mode(source, OpSize::LongWord); 604 self.out.memory_read = source_access; 605 self.out.memory_read_type = MemoryReadType::EffectiveAddress; 606 format!("lea {source_str}, {}", ADDRESS_REGISTERS[dest.0 as usize]) 607 } 608 609 fn lsl_lsr_memory(&mut self, direction: ShiftDirection, dest: AddressingMode) -> String { 610 let (dest_str, dest_access) = self.resolve_addressing_mode(dest, OpSize::Word); 611 self.out.memory_read = dest_access; 612 self.out.memory_write = dest_access; 613 format!("ls{} {dest_str}", direction_str(direction)) 614 } 615 616 fn lsl_lsr_register( 617 size: OpSize, 618 direction: ShiftDirection, 619 register: DataRegister, 620 count: ShiftCount, 621 ) -> String { 622 format!( 623 "ls{}.{} {}, {}", 624 direction_str(direction), 625 size_str(size), 626 shift_count_str(count), 627 DATA_REGISTERS[register.0 as usize] 628 ) 629 } 630 631 fn move_(&mut self, size: OpSize, source: AddressingMode, dest: AddressingMode) -> String { 632 let name = match (source, dest) { 633 (AddressingMode::Quick(_), _) => "moveq", 634 (_, AddressingMode::AddressDirect(_)) => "movea", 635 _ => "move", 636 }; 637 638 self.binary_op(name, size, source, dest) 639 } 640 641 fn move_from_sr(&mut self, dest: AddressingMode) -> String { 642 let (dest_str, dest_access) = self.resolve_addressing_mode(dest, OpSize::Word); 643 self.out.memory_write = dest_access; 644 format!("move sr, {dest_str}") 645 } 646 647 fn movem(&mut self, size: OpSize, am: AddressingMode, direction: Direction) -> String { 648 let registers = self.read_word(); 649 let registers_str = movem_registers_str(registers, am); 650 let (memory_str, memory_access) = self.resolve_addressing_mode(am, size); 651 652 match direction { 653 Direction::RegisterToMemory => { 654 self.out.memory_write = memory_access; 655 format!("movem.{} {registers_str}, {memory_str}", size_str(size)) 656 } 657 Direction::MemoryToRegister => { 658 self.out.memory_read = memory_access; 659 format!("movem.{} {memory_str}, {registers_str}", size_str(size)) 660 } 661 } 662 } 663 664 fn movep( 665 &mut self, 666 size: OpSize, 667 data: DataRegister, 668 address: AddressRegister, 669 direction: Direction, 670 ) -> String { 671 let displacement = self.read_word() as i16; 672 673 let memory_access = MemoryAccess::AddressIndirect { 674 register: address.0, 675 displacement: displacement as u32, 676 index: None, 677 size, 678 }; 679 680 match direction { 681 Direction::RegisterToMemory => { 682 self.out.memory_write = Some(memory_access); 683 format!( 684 "movep.{} {}, ({displacement},{})", 685 size_str(size), 686 DATA_REGISTERS[data.0 as usize], 687 ADDRESS_REGISTERS[address.0 as usize] 688 ) 689 } 690 Direction::MemoryToRegister => { 691 self.out.memory_read = Some(memory_access); 692 format!( 693 "movep.{} ({displacement},{}), {}", 694 size_str(size), 695 ADDRESS_REGISTERS[address.0 as usize], 696 DATA_REGISTERS[data.0 as usize] 697 ) 698 } 699 } 700 } 701 702 fn moveq(value: i8, register: DataRegister) -> String { 703 format!("moveq #{value}, {}", DATA_REGISTERS[register.0 as usize]) 704 } 705 706 fn move_to_ccr(&mut self, source: AddressingMode) -> String { 707 let (source_str, source_access) = self.resolve_addressing_mode(source, OpSize::Byte); 708 self.out.memory_read = source_access; 709 format!("move {source_str}, ccr") 710 } 711 712 fn move_to_sr(&mut self, source: AddressingMode) -> String { 713 let (source_str, source_access) = self.resolve_addressing_mode(source, OpSize::Word); 714 self.out.memory_read = source_access; 715 format!("move {source_str}, sr") 716 } 717 718 fn move_usp(direction: UspDirection, register: AddressRegister) -> String { 719 match direction { 720 UspDirection::RegisterToUsp => { 721 format!("move {}, usp", ADDRESS_REGISTERS[register.0 as usize]) 722 } 723 UspDirection::UspToRegister => { 724 format!("move usp, {}", ADDRESS_REGISTERS[register.0 as usize]) 725 } 726 } 727 } 728 729 fn muls(&mut self, dest: DataRegister, source: AddressingMode) -> String { 730 self.muldiv_op("muls", dest, source) 731 } 732 733 fn mulu(&mut self, dest: DataRegister, source: AddressingMode) -> String { 734 self.muldiv_op("mulu", dest, source) 735 } 736 737 fn neg(&mut self, size: OpSize, dest: AddressingMode, with_extend: bool) -> String { 738 let name = if with_extend { "negx" } else { "neg" }; 739 let (dest_str, dest_access) = self.resolve_addressing_mode(dest, size); 740 self.out.memory_read = dest_access; 741 self.out.memory_write = dest_access; 742 format!("{name}.{} {dest_str}", size_str(size)) 743 } 744 745 fn nbcd(&mut self, dest: AddressingMode) -> String { 746 let (dest_str, dest_access) = self.resolve_addressing_mode(dest, OpSize::Byte); 747 self.out.memory_read = dest_access; 748 self.out.memory_write = dest_access; 749 format!("nbcd {dest_str}") 750 } 751 752 fn not(&mut self, size: OpSize, dest: AddressingMode) -> String { 753 let (dest_str, dest_access) = self.resolve_addressing_mode(dest, size); 754 self.out.memory_read = dest_access; 755 self.out.memory_write = dest_access; 756 format!("not.{} {dest_str}", size_str(size)) 757 } 758 759 fn or(&mut self, size: OpSize, source: AddressingMode, dest: AddressingMode) -> String { 760 let name = match source { 761 AddressingMode::Immediate => "ori", 762 _ => "or", 763 }; 764 765 self.binary_op(name, size, source, dest) 766 } 767 768 fn ori_to_ccr(&mut self) -> String { 769 let source_str = self.operand_string(AddressingMode::Immediate, OpSize::Byte); 770 format!("ori {source_str}, ccr") 771 } 772 773 fn ori_to_sr(&mut self) -> String { 774 let source_str = self.operand_string(AddressingMode::Immediate, OpSize::Word); 775 format!("ori {source_str}, sr") 776 } 777 778 fn pea(&mut self, source: AddressingMode) -> String { 779 let (source_str, source_access) = self.resolve_addressing_mode(source, OpSize::LongWord); 780 self.out.memory_read = source_access; 781 self.out.memory_read_type = MemoryReadType::EffectiveAddress; 782 format!("pea {source_str}") 783 } 784 785 fn rol_ror_memory(&mut self, direction: ShiftDirection, dest: AddressingMode) -> String { 786 let (dest_str, dest_access) = self.resolve_addressing_mode(dest, OpSize::Word); 787 self.out.memory_read = dest_access; 788 self.out.memory_write = dest_access; 789 format!("ro{} {dest_str}", direction_str(direction)) 790 } 791 792 fn rol_ror_register( 793 size: OpSize, 794 direction: ShiftDirection, 795 register: DataRegister, 796 count: ShiftCount, 797 ) -> String { 798 format!( 799 "ro{}.{} {}, {}", 800 direction_str(direction), 801 size_str(size), 802 shift_count_str(count), 803 DATA_REGISTERS[register.0 as usize] 804 ) 805 } 806 807 fn roxl_roxr_memory(&mut self, direction: ShiftDirection, dest: AddressingMode) -> String { 808 let (dest_str, dest_access) = self.resolve_addressing_mode(dest, OpSize::Word); 809 self.out.memory_read = dest_access; 810 self.out.memory_write = dest_access; 811 format!("rox{} {dest_str}", direction_str(direction)) 812 } 813 814 fn roxl_roxr_register( 815 size: OpSize, 816 direction: ShiftDirection, 817 register: DataRegister, 818 count: ShiftCount, 819 ) -> String { 820 format!( 821 "rox{}.{} {}, {}", 822 direction_str(direction), 823 size_str(size), 824 shift_count_str(count), 825 DATA_REGISTERS[register.0 as usize] 826 ) 827 } 828 829 fn scc(&mut self, condition: BranchCondition, dest: AddressingMode) -> String { 830 let (dest_str, dest_access) = self.resolve_addressing_mode(dest, OpSize::Byte); 831 self.out.memory_write = dest_access; 832 format!("s{} {dest_str}", condition_suffix(condition)) 833 } 834 835 fn sub( 836 &mut self, 837 size: OpSize, 838 source: AddressingMode, 839 dest: AddressingMode, 840 with_extend: bool, 841 ) -> String { 842 let name = if with_extend { 843 "subx" 844 } else { 845 match (source, dest) { 846 (AddressingMode::Quick(_), _) => "subq", 847 (_, AddressingMode::AddressDirect(_)) => "suba", 848 (AddressingMode::Immediate, _) => "subi", 849 _ => "sub", 850 } 851 }; 852 853 self.binary_op(name, size, source, dest) 854 } 855 856 fn sbcd(&mut self, source: AddressingMode, dest: AddressingMode) -> String { 857 let (source_str, source_access) = self.resolve_addressing_mode(source, OpSize::Byte); 858 let (dest_str, dest_access) = self.resolve_addressing_mode(dest, OpSize::Byte); 859 860 self.out.memory_read = source_access; 861 self.out.memory_write = dest_access; 862 863 format!("sbcd {source_str}, {dest_str}") 864 } 865 866 fn swap(register: DataRegister) -> String { 867 format!("swap {}", DATA_REGISTERS[register.0 as usize]) 868 } 869 870 fn tst(&mut self, size: OpSize, source: AddressingMode) -> String { 871 let (source_str, source_access) = self.resolve_addressing_mode(source, size); 872 self.out.memory_read = source_access; 873 format!("tst.{} {source_str}", size_str(size)) 874 } 875 876 fn tas(&mut self, dest: AddressingMode) -> String { 877 let (dest_str, dest_access) = self.resolve_addressing_mode(dest, OpSize::Byte); 878 self.out.memory_read = dest_access; 879 self.out.memory_write = dest_access; 880 format!("tas {dest_str}") 881 } 882 883 fn trap(vector: u32) -> String { 884 format!("trap #{vector}") 885 } 886 887 fn unlk(register: AddressRegister) -> String { 888 format!("unlk {}", ADDRESS_REGISTERS[register.0 as usize]) 889 } 890 891 fn resolve_addressing_mode( 892 &mut self, 893 am: AddressingMode, 894 size: OpSize, 895 ) -> (Cow<'static, str>, Option<MemoryAccess>) { 896 fn index_register_str(index: IndexRegister) -> &'static str { 897 match index { 898 IndexRegister::Data(r) => DATA_REGISTERS[r.0 as usize], 899 IndexRegister::Address(r) => ADDRESS_REGISTERS[r.0 as usize], 900 } 901 } 902 903 fn index_size_str(size: IndexSize) -> &'static str { 904 match size { 905 IndexSize::SignExtendedWord => "w", 906 IndexSize::LongWord => "l", 907 } 908 } 909 910 match am { 911 AddressingMode::DataDirect(DataRegister(r)) => { 912 (DATA_REGISTERS[r as usize].into(), None) 913 } 914 AddressingMode::AddressDirect(AddressRegister(r)) => { 915 (ADDRESS_REGISTERS[r as usize].into(), None) 916 } 917 AddressingMode::AddressIndirect(AddressRegister(r)) => { 918 let s = ADDRESS_INDIRECT[r as usize]; 919 let access = MemoryAccess::AddressIndirect { 920 register: r, 921 displacement: 0, 922 index: None, 923 size, 924 }; 925 (s.into(), Some(access)) 926 } 927 AddressingMode::AddressIndirectPostincrement(AddressRegister(r)) => { 928 let s = ADDRESS_POSTINC[r as usize]; 929 let access = MemoryAccess::AddressIndirect { 930 register: r, 931 displacement: 0, 932 index: None, 933 size, 934 }; 935 (s.into(), Some(access)) 936 } 937 AddressingMode::AddressIndirectPredecrement(AddressRegister(r)) => { 938 let s = ADDRESS_PREDEC[r as usize]; 939 let access = MemoryAccess::AddressIndirectPredecrement { register: r, size }; 940 (s.into(), Some(access)) 941 } 942 AddressingMode::AddressIndirectDisplacement(AddressRegister(r)) => { 943 let displacement = self.read_word() as i16; 944 let s = format!("({displacement},a{r})"); 945 let access = MemoryAccess::AddressIndirect { 946 register: r, 947 displacement: displacement as u32, 948 index: None, 949 size, 950 }; 951 (s.into(), Some(access)) 952 } 953 AddressingMode::AddressIndirectIndexed(AddressRegister(r)) => { 954 let extension = self.read_word(); 955 let (index_register, index_size) = crate::core::parse_index(extension); 956 let displacement = extension as i8; 957 958 let s = format!( 959 "({displacement},a{r},{}.{})", 960 index_register_str(index_register), 961 index_size_str(index_size) 962 ); 963 let access = MemoryAccess::AddressIndirect { 964 register: r, 965 displacement: displacement as u32, 966 index: Some((index_register.into(), index_size)), 967 size, 968 }; 969 (s.into(), Some(access)) 970 } 971 AddressingMode::PcRelativeDisplacement => { 972 let pc = self.reader.pc; 973 let displacement = self.read_word() as i16; 974 975 let s = format!("({displacement},pc)"); 976 let access = MemoryAccess::PcRelative { 977 pc, 978 displacement: displacement as u32, 979 index: None, 980 size, 981 }; 982 (s.into(), Some(access)) 983 } 984 AddressingMode::PcRelativeIndexed => { 985 let pc = self.reader.pc; 986 let extension = self.read_word(); 987 let (index_register, index_size) = crate::core::parse_index(extension); 988 let displacement = extension as i8; 989 990 let s = format!( 991 "({displacement},pc,{}.{})", 992 index_register_str(index_register), 993 index_size_str(index_size) 994 ); 995 let access = MemoryAccess::PcRelative { 996 pc, 997 displacement: displacement as u32, 998 index: Some((index_register.into(), index_size)), 999 size, 1000 }; 1001 (s.into(), Some(access)) 1002 } 1003 AddressingMode::AbsoluteShort => { 1004 let address = (self.read_word() as i16 as u32) & 0xFFFFFF; 1005 1006 let s = format!("(0x{address:06X})"); 1007 let access = MemoryAccess::Absolute { address, size }; 1008 (s.into(), Some(access)) 1009 } 1010 AddressingMode::AbsoluteLong => { 1011 let high: u32 = self.read_word().into(); 1012 let low: u32 = self.read_word().into(); 1013 let address = (low | (high << 16)) & 0xFFFFFF; 1014 1015 let s = format!("(0x{address:06X})"); 1016 let access = MemoryAccess::Absolute { address, size }; 1017 (s.into(), Some(access)) 1018 } 1019 AddressingMode::Immediate => { 1020 let extension = self.read_word(); 1021 let s = match size { 1022 OpSize::Byte => format!("#0x{:02X}", extension & 0xFF), 1023 OpSize::Word => format!("#0x{extension:04X}"), 1024 OpSize::LongWord => { 1025 let low = self.read_word(); 1026 let immediate = u32::from(low) | (u32::from(extension) << 16); 1027 format!("#0x{immediate:08X}") 1028 } 1029 }; 1030 (s.into(), None) 1031 } 1032 AddressingMode::Quick(value) => (format!("#{value}").into(), None), 1033 } 1034 } 1035 1036 fn operand_string(&mut self, am: AddressingMode, size: OpSize) -> Cow<'static, str> { 1037 self.resolve_addressing_mode(am, size).0 1038 } 1039} 1040 1041fn movem_registers_str(extension: u16, am: AddressingMode) -> String { 1042 let reverse = matches!(am, AddressingMode::AddressIndirectPredecrement(_)); 1043 1044 let data_fn = |i: u8| if reverse { extension.bit(15 - i) } else { extension.bit(i) }; 1045 let address_fn = |i: u8| if reverse { extension.bit(7 - i) } else { extension.bit(8 + i) }; 1046 1047 let mut out = String::new(); 1048 movem_str_half(data_fn, DATA_REGISTERS, &mut out); 1049 movem_str_half(address_fn, ADDRESS_REGISTERS, &mut out); 1050 1051 if out.is_empty() { 1052 // Is this even a valid MOVEM instruction? 1053 return "empty".into(); 1054 } 1055 1056 out 1057} 1058 1059fn movem_str_half(register_fn: impl Fn(u8) -> bool, register_strs: &[&str; 8], out: &mut String) { 1060 let mut last_set: Option<u8> = None; 1061 let mut i = 0; 1062 loop { 1063 if i < 8 && register_fn(i) { 1064 if last_set.is_none() { 1065 last_set = Some(i); 1066 } 1067 } else if let Some(last_set) = last_set.take() { 1068 if !out.is_empty() { 1069 out.push('/'); 1070 } 1071 1072 out.push_str(register_strs[last_set as usize]); 1073 if last_set != i - 1 { 1074 out.push('-'); 1075 out.push_str(register_strs[(i - 1) as usize]); 1076 } 1077 } 1078 1079 if i == 8 { 1080 break; 1081 } 1082 1083 i += 1; 1084 } 1085} 1086 1087#[cfg(test)] 1088mod tests { 1089 use super::*; 1090 use crate::core::{AddressRegister, DataRegister}; 1091 1092 #[test] 1093 fn movem() { 1094 assert_eq!( 1095 movem_registers_str(0x0707, AddressingMode::DataDirect(DataRegister(0))), 1096 "d0-d2/a0-a2" 1097 ); 1098 assert_eq!( 1099 movem_registers_str( 1100 0x0707, 1101 AddressingMode::AddressIndirectPredecrement(AddressRegister(0)) 1102 ), 1103 "d5-d7/a5-a7" 1104 ); 1105 assert_eq!( 1106 movem_registers_str(0xAA55, AddressingMode::DataDirect(DataRegister(0))), 1107 "d0/d2/d4/d6/a1/a3/a5/a7" 1108 ); 1109 assert_eq!( 1110 movem_registers_str(0xFFFF, AddressingMode::DataDirect(DataRegister(0))), 1111 "d0-d7/a0-a7" 1112 ); 1113 } 1114}