1use crate::core::instructions::{ 2 BranchCondition, Direction, Instruction, ShiftCount, ShiftDirection, UspDirection, 3}; 4use crate::core::{AddressRegister, AddressingMode, DataRegister, OpSize}; 5use std::sync::LazyLock; 6 7type InstructionTable = Box<[Instruction; 65536]>; 8 9impl OpSize { 10 fn to_bits(self) -> u16 { 11 match self { 12 Self::Byte => 0x0000, 13 Self::Word => 0x0040, 14 Self::LongWord => 0x0080, 15 } 16 } 17 18 // MOVE instructions have a different mapping from bits to size 19 fn to_move_bits(self) -> u16 { 20 match self { 21 Self::Byte => 0x1000, 22 Self::Word => 0x3000, 23 Self::LongWord => 0x2000, 24 } 25 } 26} 27 28impl AddressingMode { 29 fn to_bits(self) -> u16 { 30 match self { 31 Self::DataDirect(register) => register.0.into(), 32 Self::AddressDirect(register) => 0x0008 | u16::from(register.0), 33 Self::AddressIndirect(register) => 0x0010 | u16::from(register.0), 34 Self::AddressIndirectPostincrement(register) => 0x0018 | u16::from(register.0), 35 Self::AddressIndirectPredecrement(register) => 0x0020 | u16::from(register.0), 36 Self::AddressIndirectDisplacement(register) => 0x0028 | u16::from(register.0), 37 Self::AddressIndirectIndexed(register) => 0x0030 | u16::from(register.0), 38 Self::AbsoluteShort => 0x0038, 39 Self::AbsoluteLong => 0x0039, 40 Self::PcRelativeDisplacement => 0x003A, 41 Self::PcRelativeIndexed => 0x003B, 42 Self::Immediate => 0x003C, 43 Self::Quick(..) => { 44 panic!("Quick addressing mode does not have a standardized bit pattern") 45 } 46 } 47 } 48} 49 50impl BranchCondition { 51 fn to_bits(self) -> u16 { 52 match self { 53 Self::True => 0x0000, 54 Self::False => 0x0100, 55 Self::Higher => 0x0200, 56 Self::LowerOrSame => 0x0300, 57 Self::CarryClear => 0x0400, 58 Self::CarrySet => 0x0500, 59 Self::NotEqual => 0x0600, 60 Self::Equal => 0x0700, 61 Self::OverflowClear => 0x0800, 62 Self::OverflowSet => 0x0900, 63 Self::Plus => 0x0A00, 64 Self::Minus => 0x0B00, 65 Self::GreaterOrEqual => 0x0C00, 66 Self::LessThan => 0x0D00, 67 Self::GreaterThan => 0x0E00, 68 Self::LessOrEqual => 0x0F00, 69 } 70 } 71} 72 73pub fn decode(opcode: u16) -> Instruction { 74 static LOOKUP_TABLE: LazyLock<InstructionTable> = LazyLock::new(|| { 75 // Initialize table with every entry set to ILLEGAL 76 let mut table = (0..=u16::MAX) 77 .map(|opcode| Instruction::Illegal { opcode }) 78 .collect::<Vec<_>>() 79 .into_boxed_slice() 80 .try_into() 81 .unwrap(); 82 83 populate_abcd(&mut table); 84 populate_add(&mut table); 85 populate_adda(&mut table); 86 populate_addi(&mut table); 87 populate_addq(&mut table); 88 populate_addx(&mut table); 89 populate_and(&mut table); 90 populate_andi(&mut table); 91 populate_asd(&mut table); 92 populate_bcc(&mut table); 93 populate_bchg(&mut table); 94 populate_bclr(&mut table); 95 populate_bset(&mut table); 96 populate_btst(&mut table); 97 populate_bsr(&mut table); 98 populate_chk(&mut table); 99 populate_clr(&mut table); 100 populate_cmp(&mut table); 101 populate_cmpa(&mut table); 102 populate_cmpi(&mut table); 103 populate_cmpm(&mut table); 104 populate_dbcc(&mut table); 105 populate_divs(&mut table); 106 populate_divu(&mut table); 107 populate_eor(&mut table); 108 populate_eori(&mut table); 109 populate_exg(&mut table); 110 populate_ext(&mut table); 111 populate_jmp(&mut table); 112 populate_jsr(&mut table); 113 populate_lea(&mut table); 114 populate_link(&mut table); 115 populate_lsd(&mut table); 116 populate_move(&mut table); 117 populate_movea(&mut table); 118 populate_movem(&mut table); 119 populate_movep(&mut table); 120 populate_moveq(&mut table); 121 populate_move_ccr_sr_usp(&mut table); 122 populate_muls(&mut table); 123 populate_mulu(&mut table); 124 populate_nbcd(&mut table); 125 populate_neg(&mut table); 126 populate_negx(&mut table); 127 populate_nop(&mut table); 128 populate_not(&mut table); 129 populate_or(&mut table); 130 populate_ori(&mut table); 131 populate_pea(&mut table); 132 populate_reset(&mut table); 133 populate_rod(&mut table); 134 populate_roxd(&mut table); 135 populate_rte_rtr_rts(&mut table); 136 populate_sbcd(&mut table); 137 populate_scc(&mut table); 138 populate_stop(&mut table); 139 populate_sub(&mut table); 140 populate_suba(&mut table); 141 populate_subi(&mut table); 142 populate_subq(&mut table); 143 populate_subx(&mut table); 144 populate_swap(&mut table); 145 populate_tas(&mut table); 146 populate_trap(&mut table); 147 populate_tst(&mut table); 148 populate_unlk(&mut table); 149 150 table 151 }); 152 153 LOOKUP_TABLE[opcode as usize] 154} 155 156fn all_addressing_modes() -> impl Iterator<Item = AddressingMode> { 157 DataRegister::ALL 158 .iter() 159 .copied() 160 .map(AddressingMode::DataDirect) 161 .chain(AddressRegister::ALL.iter().copied().flat_map(|register| { 162 [ 163 AddressingMode::AddressDirect(register), 164 AddressingMode::AddressIndirect(register), 165 AddressingMode::AddressIndirectPostincrement(register), 166 AddressingMode::AddressIndirectPredecrement(register), 167 AddressingMode::AddressIndirectDisplacement(register), 168 AddressingMode::AddressIndirectIndexed(register), 169 ] 170 })) 171 .chain([ 172 AddressingMode::AbsoluteShort, 173 AddressingMode::AbsoluteLong, 174 AddressingMode::Immediate, 175 AddressingMode::PcRelativeDisplacement, 176 AddressingMode::PcRelativeIndexed, 177 ]) 178} 179 180fn all_addressing_modes_no_address_direct() -> impl Iterator<Item = AddressingMode> { 181 // Does not include address direct 182 all_addressing_modes() 183 .filter(|addressing_mode| !matches!(addressing_mode, AddressingMode::AddressDirect(..))) 184} 185 186fn jump_addressing_modes() -> impl Iterator<Item = AddressingMode> { 187 // Does not include data direct, address direct, address indirect postincrement, 188 // address indirect predecrement, or immediate 189 all_addressing_modes().filter(|mode| { 190 !matches!( 191 mode, 192 AddressingMode::DataDirect(..) 193 | AddressingMode::AddressDirect(..) 194 | AddressingMode::AddressIndirectPostincrement(..) 195 | AddressingMode::AddressIndirectPredecrement(..) 196 | AddressingMode::Immediate 197 ) 198 }) 199} 200 201fn dest_addressing_modes() -> impl Iterator<Item = AddressingMode> { 202 // Does not include immediate, PC relative displacement, or PC relative indexed 203 all_addressing_modes().filter(|mode| { 204 !matches!( 205 mode, 206 AddressingMode::Immediate 207 | AddressingMode::PcRelativeDisplacement 208 | AddressingMode::PcRelativeIndexed 209 ) 210 }) 211} 212 213fn dest_addressing_modes_no_address_direct() -> impl Iterator<Item = AddressingMode> { 214 // Does not include address direct, immediate, PC relative displacement, or PC relative indexed 215 dest_addressing_modes() 216 .filter(|addressing_mode| !matches!(addressing_mode, AddressingMode::AddressDirect(..))) 217} 218 219fn dest_addressing_modes_no_direct() -> impl Iterator<Item = AddressingMode> { 220 // Does not include data direct, address direct, immediate, PC relative displacement, or PC relative indexed 221 dest_addressing_modes().filter(|addressing_mode| { 222 !matches!( 223 addressing_mode, 224 AddressingMode::DataDirect(..) | AddressingMode::AddressDirect(..) 225 ) 226 }) 227} 228 229fn populate_abcd(table: &mut InstructionTable) { 230 for rx in 0..8_u8 { 231 for ry in 0..8_u8 { 232 // ABCD Dx, Dy 233 let data_opcode = 0xC100 | u16::from(ry) | (u16::from(rx) << 9); 234 table[data_opcode as usize] = Instruction::AddDecimal { 235 source: AddressingMode::DataDirect(DataRegister(ry)), 236 dest: AddressingMode::DataDirect(DataRegister(rx)), 237 }; 238 239 // ABCD -(Ax), -(Ay) 240 let predec_opcode = data_opcode | 0x0008; 241 table[predec_opcode as usize] = Instruction::AddDecimal { 242 source: AddressingMode::AddressIndirectPredecrement(AddressRegister(ry)), 243 dest: AddressingMode::AddressIndirectPredecrement(AddressRegister(rx)), 244 }; 245 } 246 } 247} 248 249fn populate_add(table: &mut InstructionTable) { 250 // ADD <ea>, Dn 251 for source in all_addressing_modes() { 252 for dest in DataRegister::ALL { 253 for size in OpSize::ALL { 254 if size == OpSize::Byte && source.is_address_direct() { 255 // ADD.B does not support address direct source 256 continue; 257 } 258 259 let opcode = 0xD000 | size.to_bits() | source.to_bits() | (u16::from(dest.0) << 9); 260 table[opcode as usize] = Instruction::Add { 261 size, 262 source, 263 dest: AddressingMode::DataDirect(dest), 264 with_extend: false, 265 }; 266 } 267 } 268 } 269 270 // ADD Dn, <ea> 271 for source in DataRegister::ALL { 272 for dest in dest_addressing_modes_no_direct() { 273 for size in OpSize::ALL { 274 let opcode = 0xD100 | size.to_bits() | dest.to_bits() | (u16::from(source.0) << 9); 275 table[opcode as usize] = Instruction::Add { 276 size, 277 source: AddressingMode::DataDirect(source), 278 dest, 279 with_extend: false, 280 }; 281 } 282 } 283 } 284} 285 286fn populate_adda(table: &mut InstructionTable) { 287 // ADDA <ea>, An 288 for source in all_addressing_modes() { 289 for dest in AddressRegister::ALL { 290 for size in [OpSize::Word, OpSize::LongWord] { 291 let size_bit = u16::from(size == OpSize::LongWord) << 8; 292 let opcode = 0xD0C0 | size_bit | source.to_bits() | (u16::from(dest.0) << 9); 293 table[opcode as usize] = Instruction::Add { 294 size, 295 source, 296 dest: AddressingMode::AddressDirect(dest), 297 with_extend: false, 298 }; 299 } 300 } 301 } 302} 303 304fn populate_addi(table: &mut InstructionTable) { 305 // ADDI #<d>, <ea> 306 for dest in dest_addressing_modes_no_address_direct() { 307 for size in OpSize::ALL { 308 let opcode = 0x0600 | size.to_bits() | dest.to_bits(); 309 table[opcode as usize] = Instruction::Add { 310 size, 311 source: AddressingMode::Immediate, 312 dest, 313 with_extend: false, 314 }; 315 } 316 } 317} 318 319fn populate_addq(table: &mut InstructionTable) { 320 // ADDQ #<d>, <ea> 321 for q_value in 0..8 { 322 for dest in dest_addressing_modes() { 323 for size in OpSize::ALL { 324 if size == OpSize::Byte && dest.is_address_direct() { 325 // ADDQ.B does not support address direct destinations 326 continue; 327 } 328 329 let opcode = 0x5000 | size.to_bits() | dest.to_bits() | (q_value << 9); 330 let source = if q_value == 0 { 331 AddressingMode::Quick(8) 332 } else { 333 AddressingMode::Quick(q_value as u8) 334 }; 335 table[opcode as usize] = 336 Instruction::Add { size, source, dest, with_extend: false }; 337 } 338 } 339 } 340} 341 342fn populate_addx(table: &mut InstructionTable) { 343 // ADDX Dy, Dx 344 for source in DataRegister::ALL { 345 for dest in DataRegister::ALL { 346 for size in OpSize::ALL { 347 let opcode = 348 0xD100 | size.to_bits() | u16::from(source.0) | (u16::from(dest.0) << 9); 349 table[opcode as usize] = Instruction::Add { 350 size, 351 source: AddressingMode::DataDirect(source), 352 dest: AddressingMode::DataDirect(dest), 353 with_extend: true, 354 }; 355 } 356 } 357 } 358 359 // ADDX -(Ay), -(Ax) 360 for source in AddressRegister::ALL { 361 for dest in AddressRegister::ALL { 362 for size in OpSize::ALL { 363 let opcode = 364 0xD108 | size.to_bits() | u16::from(source.0) | (u16::from(dest.0) << 9); 365 table[opcode as usize] = Instruction::Add { 366 size, 367 source: AddressingMode::AddressIndirectPredecrement(source), 368 dest: AddressingMode::AddressIndirectPredecrement(dest), 369 with_extend: true, 370 }; 371 } 372 } 373 } 374} 375 376fn populate_and(table: &mut InstructionTable) { 377 // AND <ea>, Dn 378 for source in all_addressing_modes_no_address_direct() { 379 for dest in DataRegister::ALL { 380 for size in OpSize::ALL { 381 let opcode = 0xC000 | size.to_bits() | source.to_bits() | (u16::from(dest.0) << 9); 382 table[opcode as usize] = 383 Instruction::And { size, source, dest: AddressingMode::DataDirect(dest) }; 384 } 385 } 386 } 387 388 // AND Dn, <ea> 389 for source in DataRegister::ALL { 390 for dest in dest_addressing_modes_no_direct() { 391 for size in OpSize::ALL { 392 let opcode = 0xC100 | size.to_bits() | dest.to_bits() | (u16::from(source.0) << 9); 393 table[opcode as usize] = 394 Instruction::And { size, source: AddressingMode::DataDirect(source), dest }; 395 } 396 } 397 } 398} 399 400fn populate_andi(table: &mut InstructionTable) { 401 // ANDI #<d>, <ea> 402 for dest in dest_addressing_modes_no_address_direct() { 403 for size in OpSize::ALL { 404 let opcode = 0x0200 | size.to_bits() | dest.to_bits(); 405 table[opcode as usize] = 406 Instruction::And { size, source: AddressingMode::Immediate, dest }; 407 } 408 } 409 410 // ANDI to CCR/SR 411 table[0x023C] = Instruction::AndToCcr; 412 table[0x027C] = Instruction::AndToSr; 413} 414 415macro_rules! impl_populate_bit_shift { 416 ($name:ident, $imm_opcode_base:expr, $reg_opcode_base:expr, $mem_opcode_base:expr, $register_instr:ident, $memory_instr:ident) => { 417 fn $name(table: &mut InstructionTable) { 418 for dest in DataRegister::ALL { 419 for size in OpSize::ALL { 420 for count_value in 0..8_u8 { 421 // xxL/xxR #<d>, Dy 422 { 423 let shift = if count_value == 0 { 424 ShiftCount::Constant(8) 425 } else { 426 ShiftCount::Constant(count_value) 427 }; 428 let r_opcode = $imm_opcode_base 429 | size.to_bits() 430 | u16::from(dest.0) 431 | (u16::from(count_value) << 9); 432 let l_opcode = r_opcode | 0x0100; 433 434 table[r_opcode as usize] = Instruction::$register_instr( 435 size, 436 ShiftDirection::Right, 437 dest, 438 shift, 439 ); 440 table[l_opcode as usize] = Instruction::$register_instr( 441 size, 442 ShiftDirection::Left, 443 dest, 444 shift, 445 ); 446 } 447 448 // xxl/xxR Dx, Dy 449 { 450 let shift = ShiftCount::Register(DataRegister(count_value)); 451 let r_opcode = $reg_opcode_base 452 | size.to_bits() 453 | u16::from(dest.0) 454 | (u16::from(count_value) << 9); 455 let l_opcode = r_opcode | 0x0100; 456 457 table[r_opcode as usize] = Instruction::$register_instr( 458 size, 459 ShiftDirection::Right, 460 dest, 461 shift, 462 ); 463 table[l_opcode as usize] = Instruction::$register_instr( 464 size, 465 ShiftDirection::Left, 466 dest, 467 shift, 468 ); 469 } 470 } 471 } 472 } 473 474 // xxL/xxR <ea> 475 for dest in dest_addressing_modes_no_direct() { 476 let r_opcode = $mem_opcode_base | dest.to_bits(); 477 let l_opcode = r_opcode | 0x0100; 478 479 table[r_opcode as usize] = Instruction::$memory_instr(ShiftDirection::Right, dest); 480 table[l_opcode as usize] = Instruction::$memory_instr(ShiftDirection::Left, dest); 481 } 482 } 483 }; 484} 485 486impl_populate_bit_shift!( 487 populate_asd, 488 0xE000, 489 0xE020, 490 0xE0C0, 491 ArithmeticShiftRegister, 492 ArithmeticShiftMemory 493); 494impl_populate_bit_shift!( 495 populate_lsd, 496 0xE008, 497 0xE028, 498 0xE2C0, 499 LogicalShiftRegister, 500 LogicalShiftMemory 501); 502impl_populate_bit_shift!(populate_rod, 0xE018, 0xE038, 0xE6C0, RotateRegister, RotateMemory); 503impl_populate_bit_shift!( 504 populate_roxd, 505 0xE010, 506 0xE030, 507 0xE4C0, 508 RotateThruExtendRegister, 509 RotateThruExtendMemory 510); 511 512fn populate_bcc(table: &mut InstructionTable) { 513 // Bcc #<d> 514 for condition in BranchCondition::ALL { 515 for displacement in 0..=0xFF_u16 { 516 let opcode = 0x6000 | displacement | condition.to_bits(); 517 table[opcode as usize] = Instruction::Branch(condition, displacement as i8); 518 } 519 } 520} 521 522macro_rules! impl_populate_bit_test { 523 ($name:ident, $imm_opcode_base:expr, $reg_opcode_base:expr, $instruction:ident) => { 524 fn $name(table: &mut InstructionTable) { 525 for dest in dest_addressing_modes_no_address_direct() { 526 // Bxxx #<d>, <ea> 527 let imm_opcode = $imm_opcode_base | dest.to_bits(); 528 table[imm_opcode as usize] = 529 Instruction::$instruction { source: AddressingMode::Immediate, dest }; 530 531 // Bxxx Dn, <ea> 532 for source in DataRegister::ALL { 533 let reg_opcode = $reg_opcode_base | dest.to_bits() | (u16::from(source.0) << 9); 534 table[reg_opcode as usize] = Instruction::$instruction { 535 source: AddressingMode::DataDirect(source), 536 dest, 537 }; 538 } 539 } 540 } 541 }; 542} 543 544impl_populate_bit_test!(populate_bchg, 0x0840, 0x0140, BitTestAndChange); 545impl_populate_bit_test!(populate_bclr, 0x0880, 0x0180, BitTestAndClear); 546impl_populate_bit_test!(populate_bset, 0x08C0, 0x01C0, BitTestAndSet);
Not using the macro because BTST supports PC relative addressing modes
549fn populate_btst(table: &mut InstructionTable) { 550 for dest in 551 all_addressing_modes_no_address_direct().filter(|&am| am != AddressingMode::Immediate) 552 { 553 // BTST #<d>, <ea> 554 let imm_opcode = 0x0800 | dest.to_bits(); 555 table[imm_opcode as usize] = 556 Instruction::BitTest { source: AddressingMode::Immediate, dest }; 557 } 558 559 for dest in all_addressing_modes_no_address_direct() { 560 // BTST Dn, <ea> 561 for source in DataRegister::ALL { 562 let reg_opcode = 0x0100 | dest.to_bits() | (u16::from(source.0) << 9); 563 table[reg_opcode as usize] = 564 Instruction::BitTest { source: AddressingMode::DataDirect(source), dest }; 565 } 566 } 567}
569fn populate_bsr(table: &mut InstructionTable) { 570 // BSR #<d> 571 for displacement in 0..=0xFF_u16 { 572 let opcode = 0x6100 | displacement; 573 table[opcode as usize] = Instruction::BranchToSubroutine(displacement as i8); 574 } 575} 576 577fn populate_chk(table: &mut InstructionTable) { 578 // CHK <ea>, Dn 579 for addressing_mode in all_addressing_modes_no_address_direct() { 580 for register in DataRegister::ALL { 581 let opcode = 0x4180 | addressing_mode.to_bits() | (u16::from(register.0) << 9); 582 table[opcode as usize] = Instruction::CheckRegister(register, addressing_mode); 583 } 584 } 585} 586 587fn populate_clr(table: &mut InstructionTable) { 588 // CLR <ea> 589 for dest in dest_addressing_modes_no_address_direct() { 590 for size in OpSize::ALL { 591 let opcode = 0x4200 | size.to_bits() | dest.to_bits(); 592 table[opcode as usize] = Instruction::Clear(size, dest); 593 } 594 } 595} 596 597fn populate_cmp(table: &mut InstructionTable) { 598 // CMP <ea>, Dn 599 for source in all_addressing_modes() { 600 for dest in DataRegister::ALL { 601 for size in OpSize::ALL { 602 if size == OpSize::Byte && source.is_address_direct() { 603 // CMP.B does not support address direct source 604 continue; 605 } 606 607 let opcode = 0xB000 | size.to_bits() | source.to_bits() | (u16::from(dest.0) << 9); 608 table[opcode as usize] = 609 Instruction::Compare { size, source, dest: AddressingMode::DataDirect(dest) }; 610 } 611 } 612 } 613} 614 615fn populate_cmpa(table: &mut InstructionTable) { 616 // CMPA <ea>, An 617 for source in all_addressing_modes() { 618 for dest in AddressRegister::ALL { 619 for size in [OpSize::Word, OpSize::LongWord] { 620 let size_bit = u16::from(size == OpSize::LongWord) << 8; 621 let opcode = 0xB0C0 | size_bit | source.to_bits() | (u16::from(dest.0) << 9); 622 table[opcode as usize] = Instruction::Compare { 623 size, 624 source, 625 dest: AddressingMode::AddressDirect(dest), 626 }; 627 } 628 } 629 } 630} 631 632fn populate_cmpi(table: &mut InstructionTable) { 633 // CMPI #<d>, <ea> 634 for dest in dest_addressing_modes_no_address_direct() { 635 for size in OpSize::ALL { 636 let opcode = 0x0C00 | size.to_bits() | dest.to_bits(); 637 table[opcode as usize] = 638 Instruction::Compare { size, source: AddressingMode::Immediate, dest }; 639 } 640 } 641} 642 643fn populate_cmpm(table: &mut InstructionTable) { 644 // CMPM (Ay)+, (Ax)+ 645 for source in AddressRegister::ALL { 646 for dest in AddressRegister::ALL { 647 for size in OpSize::ALL { 648 let opcode = 649 0xB108 | size.to_bits() | u16::from(source.0) | (u16::from(dest.0) << 9); 650 table[opcode as usize] = Instruction::Compare { 651 size, 652 source: AddressingMode::AddressIndirectPostincrement(source), 653 dest: AddressingMode::AddressIndirectPostincrement(dest), 654 }; 655 } 656 } 657 } 658} 659 660fn populate_dbcc(table: &mut InstructionTable) { 661 // DBcc Dn, #<d> 662 for condition in BranchCondition::ALL { 663 for dest in DataRegister::ALL { 664 let opcode = 0x50C8 | condition.to_bits() | u16::from(dest.0); 665 table[opcode as usize] = Instruction::BranchDecrement(condition, dest); 666 } 667 } 668} 669 670fn populate_divs(table: &mut InstructionTable) { 671 // DIVS <ea>, Dn 672 for source in all_addressing_modes_no_address_direct() { 673 for dest in DataRegister::ALL { 674 let opcode = 0x81C0 | source.to_bits() | (u16::from(dest.0) << 9); 675 table[opcode as usize] = Instruction::DivideSigned(dest, source); 676 } 677 } 678} 679 680fn populate_divu(table: &mut InstructionTable) { 681 // DIVU <ea>, Dn 682 for source in all_addressing_modes_no_address_direct() { 683 for dest in DataRegister::ALL { 684 let opcode = 0x80C0 | source.to_bits() | (u16::from(dest.0) << 9); 685 table[opcode as usize] = Instruction::DivideUnsigned(dest, source); 686 } 687 } 688} 689 690fn populate_eor(table: &mut InstructionTable) { 691 // EOR Dn, <ea> 692 for source in DataRegister::ALL { 693 for dest in dest_addressing_modes_no_address_direct() { 694 for size in OpSize::ALL { 695 let opcode = 0xB100 | size.to_bits() | dest.to_bits() | (u16::from(source.0) << 9); 696 table[opcode as usize] = Instruction::ExclusiveOr { 697 size, 698 source: AddressingMode::DataDirect(source), 699 dest, 700 }; 701 } 702 } 703 } 704} 705 706fn populate_eori(table: &mut InstructionTable) { 707 // EORI #<d>, <ea> 708 for dest in dest_addressing_modes_no_address_direct() { 709 for size in OpSize::ALL { 710 let opcode = 0x0A00 | size.to_bits() | dest.to_bits(); 711 table[opcode as usize] = 712 Instruction::ExclusiveOr { size, source: AddressingMode::Immediate, dest }; 713 } 714 } 715 716 // EORI to CCR/SR 717 table[0x0A3C] = Instruction::ExclusiveOrToCcr; 718 table[0x0A7C] = Instruction::ExclusiveOrToSr; 719} 720 721fn populate_exg(table: &mut InstructionTable) { 722 for rx in 0..8_u8 { 723 for ry in 0..8_u8 { 724 // EXG Dx, Dy 725 let data_opcode = 0xC140 | u16::from(ry) | (u16::from(rx) << 9); 726 table[data_opcode as usize] = 727 Instruction::ExchangeData(DataRegister(rx), DataRegister(ry)); 728 729 // EXG Ax, Ay 730 let address_opcode = data_opcode | 0x0008; 731 table[address_opcode as usize] = 732 Instruction::ExchangeAddress(AddressRegister(rx), AddressRegister(ry)); 733 734 // EXG Dx, Ay 735 let mixed_opcode = 0xC188 | u16::from(ry) | (u16::from(rx) << 9); 736 table[mixed_opcode as usize] = 737 Instruction::ExchangeDataAddress(DataRegister(rx), AddressRegister(ry)); 738 } 739 } 740} 741 742fn populate_ext(table: &mut InstructionTable) { 743 // EXT Dn 744 for register in DataRegister::ALL { 745 for size in [OpSize::Word, OpSize::LongWord] { 746 let size_bit = u16::from(size == OpSize::LongWord) << 6; 747 let opcode = 0x4880 | size_bit | u16::from(register.0); 748 table[opcode as usize] = Instruction::Extend(size, register); 749 } 750 } 751} 752 753fn populate_jmp(table: &mut InstructionTable) { 754 // JMP <ea> 755 for dest in jump_addressing_modes() { 756 let opcode = 0x4EC0 | dest.to_bits(); 757 table[opcode as usize] = Instruction::Jump(dest); 758 } 759} 760 761fn populate_jsr(table: &mut InstructionTable) { 762 // JSR <ea> 763 for dest in jump_addressing_modes() { 764 let opcode = 0x4E80 | dest.to_bits(); 765 table[opcode as usize] = Instruction::JumpToSubroutine(dest); 766 } 767} 768 769fn populate_lea(table: &mut InstructionTable) { 770 // LEA <ea>, An 771 for source in jump_addressing_modes() { 772 for dest in AddressRegister::ALL { 773 let opcode = 0x41C0 | source.to_bits() | (u16::from(dest.0) << 9); 774 table[opcode as usize] = Instruction::LoadEffectiveAddress(source, dest); 775 } 776 } 777} 778 779fn populate_link(table: &mut InstructionTable) { 780 // LINK An, #<d> 781 for source in AddressRegister::ALL { 782 let opcode = 0x4E50 | u16::from(source.0); 783 table[opcode as usize] = Instruction::Link(source); 784 } 785} 786 787fn populate_move(table: &mut InstructionTable) { 788 // MOVE <ea>, <ea> 789 for source in all_addressing_modes() { 790 for dest in dest_addressing_modes_no_address_direct() { 791 for size in OpSize::ALL { 792 if size == OpSize::Byte && source.is_address_direct() { 793 // MOVE.B does not support address direct source 794 continue; 795 } 796 797 // Dest bits are shifted left 6, and mode/register are flipped 798 let raw_dest_bits = dest.to_bits(); 799 let dest_bits = ((raw_dest_bits & 0x07) << 9) | ((raw_dest_bits & 0x38) << 3); 800 801 let opcode = size.to_move_bits() | source.to_bits() | dest_bits; 802 table[opcode as usize] = Instruction::Move { size, source, dest }; 803 } 804 } 805 } 806} 807 808fn populate_movea(table: &mut InstructionTable) { 809 // MOVEA <ea>, An 810 for source in all_addressing_modes() { 811 for dest in AddressRegister::ALL { 812 for size in [OpSize::Word, OpSize::LongWord] { 813 let opcode = 814 0x0040 | size.to_move_bits() | source.to_bits() | (u16::from(dest.0) << 9); 815 table[opcode as usize] = 816 Instruction::Move { size, source, dest: AddressingMode::AddressDirect(dest) }; 817 } 818 } 819 } 820} 821 822fn populate_movem(table: &mut InstructionTable) { 823 // MOVEM <registers>, <ea> 824 // Register-to-memory MOVEM does not support data/address direct, address indirect postincrement, 825 // immediate, or PC relative displacement/indexed 826 for dest in dest_addressing_modes_no_direct() 827 .filter(|mode| !matches!(mode, AddressingMode::AddressIndirectPostincrement(..))) 828 { 829 for size in [OpSize::Word, OpSize::LongWord] { 830 let size_bit = u16::from(size == OpSize::LongWord) << 6; 831 let opcode = 0x4880 | size_bit | dest.to_bits(); 832 table[opcode as usize] = 833 Instruction::MoveMultiple(size, dest, Direction::RegisterToMemory); 834 } 835 } 836 837 // MOVEM <ea>, <registers> 838 // Memory-to-register MOVEM does not support data/address direct, address indirect predecrement, 839 // or immediate 840 for source in all_addressing_modes().filter(|mode| { 841 !matches!( 842 mode, 843 AddressingMode::DataDirect(..) 844 | AddressingMode::AddressDirect(..) 845 | AddressingMode::AddressIndirectPredecrement(..) 846 | AddressingMode::Immediate 847 ) 848 }) { 849 for size in [OpSize::Word, OpSize::LongWord] { 850 let size_bit = u16::from(size == OpSize::LongWord) << 6; 851 let opcode = 0x4C80 | size_bit | source.to_bits(); 852 table[opcode as usize] = 853 Instruction::MoveMultiple(size, source, Direction::MemoryToRegister); 854 } 855 } 856} 857 858fn populate_movep(table: &mut InstructionTable) { 859 for d_register in DataRegister::ALL { 860 for a_register in AddressRegister::ALL { 861 for size in [OpSize::Word, OpSize::LongWord] { 862 let size_bit = u16::from(size == OpSize::LongWord) << 6; 863 let to_register_opcode = 864 0x0108 | size_bit | u16::from(a_register.0) | (u16::from(d_register.0) << 9); 865 let from_register_opcode = to_register_opcode | 0x0080; 866 867 // MOVEP (d, Ay), Dx 868 table[to_register_opcode as usize] = Instruction::MovePeripheral( 869 size, 870 d_register, 871 a_register, 872 Direction::MemoryToRegister, 873 ); 874 875 // MOVEP Dx, (D, Ay) 876 table[from_register_opcode as usize] = Instruction::MovePeripheral( 877 size, 878 d_register, 879 a_register, 880 Direction::RegisterToMemory, 881 ); 882 } 883 } 884 } 885} 886 887fn populate_moveq(table: &mut InstructionTable) { 888 // MOVEQ #<d>, Dn 889 for dest in DataRegister::ALL { 890 for immediate_value in 0..=0xFF_u16 { 891 let opcode = 0x7000 | immediate_value | (u16::from(dest.0) << 9); 892 table[opcode as usize] = Instruction::MoveQuick(immediate_value as i8, dest); 893 } 894 } 895} 896 897fn populate_move_ccr_sr_usp(table: &mut InstructionTable) { 898 // MOVE <ea>, CCR 899 for source in all_addressing_modes_no_address_direct() { 900 let opcode = 0x44C0 | source.to_bits(); 901 table[opcode as usize] = Instruction::MoveToCcr(source); 902 } 903 904 // MOVE SR, <ea> 905 for dest in dest_addressing_modes_no_address_direct() { 906 let opcode = 0x40C0 | dest.to_bits(); 907 table[opcode as usize] = Instruction::MoveFromSr(dest); 908 } 909 910 // MOVE <ea>, SR 911 for source in all_addressing_modes_no_address_direct() { 912 let opcode = 0x46C0 | source.to_bits(); 913 table[opcode as usize] = Instruction::MoveToSr(source); 914 } 915 916 // MOVE An, USP 917 // MOVE USP, An 918 for register in AddressRegister::ALL { 919 let to_usp_opcode = 0x4E60 | u16::from(register.0); 920 let from_usp_opcode = to_usp_opcode | 0x0008; 921 922 table[to_usp_opcode as usize] = Instruction::MoveUsp(UspDirection::RegisterToUsp, register); 923 table[from_usp_opcode as usize] = 924 Instruction::MoveUsp(UspDirection::UspToRegister, register); 925 } 926} 927 928fn populate_muls(table: &mut InstructionTable) { 929 // MULS <ea>, Dn 930 for source in all_addressing_modes_no_address_direct() { 931 for dest in DataRegister::ALL { 932 let opcode = 0xC1C0 | source.to_bits() | (u16::from(dest.0) << 9); 933 table[opcode as usize] = Instruction::MultiplySigned(dest, source); 934 } 935 } 936} 937 938fn populate_mulu(table: &mut InstructionTable) { 939 // MULU <ea>, Dn 940 for source in all_addressing_modes_no_address_direct() { 941 for dest in DataRegister::ALL { 942 let opcode = 0xC0C0 | source.to_bits() | (u16::from(dest.0) << 9); 943 table[opcode as usize] = Instruction::MultiplyUnsigned(dest, source); 944 } 945 } 946} 947 948fn populate_nbcd(table: &mut InstructionTable) { 949 // NBCD <ea> 950 for dest in dest_addressing_modes_no_address_direct() { 951 let opcode = 0x4800 | dest.to_bits(); 952 table[opcode as usize] = Instruction::NegateDecimal(dest); 953 } 954} 955 956fn populate_neg(table: &mut InstructionTable) { 957 // NEG <ea> 958 for dest in dest_addressing_modes_no_address_direct() { 959 for size in OpSize::ALL { 960 let opcode = 0x4400 | size.to_bits() | dest.to_bits(); 961 table[opcode as usize] = Instruction::Negate { size, dest, with_extend: false }; 962 } 963 } 964} 965 966fn populate_negx(table: &mut InstructionTable) { 967 // NEGX <ea> 968 for dest in dest_addressing_modes_no_address_direct() { 969 for size in OpSize::ALL { 970 let opcode = 0x4000 | size.to_bits() | dest.to_bits(); 971 table[opcode as usize] = Instruction::Negate { size, dest, with_extend: true }; 972 } 973 } 974} 975 976fn populate_nop(table: &mut InstructionTable) { 977 // NOP 978 table[0x4E71] = Instruction::NoOp; 979} 980 981fn populate_not(table: &mut InstructionTable) { 982 // NOT <ea> 983 for dest in dest_addressing_modes_no_address_direct() { 984 for size in OpSize::ALL { 985 let opcode = 0x4600 | size.to_bits() | dest.to_bits(); 986 table[opcode as usize] = Instruction::Not(size, dest); 987 } 988 } 989} 990 991fn populate_or(table: &mut InstructionTable) { 992 // OR <ea>, Dn 993 for source in all_addressing_modes_no_address_direct() { 994 for dest in DataRegister::ALL { 995 for size in OpSize::ALL { 996 let opcode = 0x8000 | size.to_bits() | source.to_bits() | (u16::from(dest.0) << 9); 997 table[opcode as usize] = 998 Instruction::Or { size, source, dest: AddressingMode::DataDirect(dest) }; 999 } 1000 } 1001 } 1002 1003 // OR Dn, <ea> 1004 for source in DataRegister::ALL { 1005 for dest in dest_addressing_modes_no_direct() { 1006 for size in OpSize::ALL { 1007 let opcode = 0x8100 | size.to_bits() | dest.to_bits() | (u16::from(source.0) << 9); 1008 table[opcode as usize] = 1009 Instruction::Or { size, source: AddressingMode::DataDirect(source), dest }; 1010 } 1011 } 1012 } 1013} 1014 1015fn populate_ori(table: &mut InstructionTable) { 1016 // ORI #<d>, <ea> 1017 for dest in dest_addressing_modes_no_address_direct() { 1018 for size in OpSize::ALL { 1019 let opcode = size.to_bits() | dest.to_bits(); 1020 table[opcode as usize] = 1021 Instruction::Or { size, source: AddressingMode::Immediate, dest }; 1022 } 1023 } 1024 1025 // ORI to CCR/SR 1026 table[0x003C] = Instruction::OrToCcr; 1027 table[0x007C] = Instruction::OrToSr; 1028} 1029 1030fn populate_pea(table: &mut InstructionTable) { 1031 for source in jump_addressing_modes() { 1032 let opcode = 0x4840 | source.to_bits(); 1033 table[opcode as usize] = Instruction::PushEffectiveAddress(source); 1034 } 1035} 1036 1037fn populate_reset(table: &mut InstructionTable) { 1038 // RESET 1039 table[0x4E70] = Instruction::Reset; 1040} 1041 1042fn populate_rte_rtr_rts(table: &mut InstructionTable) { 1043 // RTE 1044 table[0x4E73] = Instruction::ReturnFromException; 1045 1046 // RTR 1047 table[0x4E77] = Instruction::Return { restore_ccr: true }; 1048 1049 // RTS 1050 table[0x4E75] = Instruction::Return { restore_ccr: false }; 1051} 1052 1053fn populate_sbcd(table: &mut InstructionTable) { 1054 for rx in 0..8_u8 { 1055 for ry in 0..8_u8 { 1056 // SBCD Dx, Dy 1057 let data_opcode = 0x8100 | u16::from(ry) | (u16::from(rx) << 9); 1058 table[data_opcode as usize] = Instruction::SubtractDecimal { 1059 source: AddressingMode::DataDirect(DataRegister(ry)), 1060 dest: AddressingMode::DataDirect(DataRegister(rx)), 1061 }; 1062 1063 // SBCD -(Ax), -(Ay) 1064 let predec_opcode = data_opcode | 0x0008; 1065 table[predec_opcode as usize] = Instruction::SubtractDecimal { 1066 source: AddressingMode::AddressIndirectPredecrement(AddressRegister(ry)), 1067 dest: AddressingMode::AddressIndirectPredecrement(AddressRegister(rx)), 1068 }; 1069 } 1070 } 1071} 1072 1073fn populate_scc(table: &mut InstructionTable) { 1074 // Scc <ea> 1075 for dest in dest_addressing_modes_no_address_direct() { 1076 for condition in BranchCondition::ALL { 1077 let opcode = 0x50C0 | condition.to_bits() | dest.to_bits(); 1078 table[opcode as usize] = Instruction::Set(condition, dest); 1079 } 1080 } 1081} 1082 1083fn populate_stop(table: &mut InstructionTable) { 1084 // STOP 1085 table[0x4E72] = Instruction::Stop; 1086} 1087 1088fn populate_sub(table: &mut InstructionTable) { 1089 // SUB <ea>, Dn 1090 for source in all_addressing_modes() { 1091 for dest in DataRegister::ALL { 1092 for size in OpSize::ALL { 1093 if size == OpSize::Byte && source.is_address_direct() { 1094 // SUB.B does not support address direct source 1095 continue; 1096 } 1097 1098 let opcode = 0x9000 | size.to_bits() | source.to_bits() | (u16::from(dest.0) << 9); 1099 table[opcode as usize] = Instruction::Subtract { 1100 size, 1101 source, 1102 dest: AddressingMode::DataDirect(dest), 1103 with_extend: false, 1104 }; 1105 } 1106 } 1107 } 1108 1109 // SUB Dn, <ea> 1110 for source in DataRegister::ALL { 1111 for dest in dest_addressing_modes_no_direct() { 1112 for size in OpSize::ALL { 1113 let opcode = 0x9100 | size.to_bits() | dest.to_bits() | (u16::from(source.0) << 9); 1114 table[opcode as usize] = Instruction::Subtract { 1115 size, 1116 source: AddressingMode::DataDirect(source), 1117 dest, 1118 with_extend: false, 1119 }; 1120 } 1121 } 1122 } 1123} 1124 1125fn populate_suba(table: &mut InstructionTable) { 1126 // SUBA <ea>, An 1127 for source in all_addressing_modes() { 1128 for dest in AddressRegister::ALL { 1129 for size in [OpSize::Word, OpSize::LongWord] { 1130 let size_bit = u16::from(size == OpSize::LongWord) << 8; 1131 let opcode = 0x90C0 | size_bit | source.to_bits() | (u16::from(dest.0) << 9); 1132 table[opcode as usize] = Instruction::Subtract { 1133 size, 1134 source, 1135 dest: AddressingMode::AddressDirect(dest), 1136 with_extend: false, 1137 }; 1138 } 1139 } 1140 } 1141} 1142 1143fn populate_subi(table: &mut InstructionTable) { 1144 // SUBI #<d>, <ea> 1145 for dest in dest_addressing_modes_no_address_direct() { 1146 for size in OpSize::ALL { 1147 let opcode = 0x0400 | size.to_bits() | dest.to_bits(); 1148 table[opcode as usize] = Instruction::Subtract { 1149 size, 1150 source: AddressingMode::Immediate, 1151 dest, 1152 with_extend: false, 1153 }; 1154 } 1155 } 1156} 1157 1158fn populate_subq(table: &mut InstructionTable) { 1159 // SUBQ #<d>, <ea> 1160 for dest in dest_addressing_modes() { 1161 for size in OpSize::ALL { 1162 if size == OpSize::Byte && dest.is_address_direct() { 1163 // SUBQ.B does not support address direct destinations 1164 continue; 1165 } 1166 1167 for q_value in 0..8_u16 { 1168 let opcode = 0x5100 | size.to_bits() | dest.to_bits() | (q_value << 9); 1169 let source = if q_value == 0 { 1170 AddressingMode::Quick(8) 1171 } else { 1172 AddressingMode::Quick(q_value as u8) 1173 }; 1174 1175 table[opcode as usize] = 1176 Instruction::Subtract { size, source, dest, with_extend: false }; 1177 } 1178 } 1179 } 1180} 1181 1182fn populate_subx(table: &mut InstructionTable) { 1183 for rx in 0..8_u8 { 1184 for ry in 0..8_u8 { 1185 for size in OpSize::ALL { 1186 // SUBX Dx, Dy 1187 let data_opcode = 0x9100 | size.to_bits() | u16::from(rx) | (u16::from(ry) << 9); 1188 table[data_opcode as usize] = Instruction::Subtract { 1189 size, 1190 source: AddressingMode::DataDirect(DataRegister(rx)), 1191 dest: AddressingMode::DataDirect(DataRegister(ry)), 1192 with_extend: true, 1193 }; 1194 1195 // SUBX -(Ax), -(Ay) 1196 let predec_opcode = data_opcode | 0x0008; 1197 table[predec_opcode as usize] = Instruction::Subtract { 1198 size, 1199 source: AddressingMode::AddressIndirectPredecrement(AddressRegister(rx)), 1200 dest: AddressingMode::AddressIndirectPredecrement(AddressRegister(ry)), 1201 with_extend: true, 1202 }; 1203 } 1204 } 1205 } 1206} 1207 1208fn populate_swap(table: &mut InstructionTable) { 1209 // SWAP Dn 1210 for dest in DataRegister::ALL { 1211 let opcode = 0x4840 | u16::from(dest.0); 1212 table[opcode as usize] = Instruction::Swap(dest); 1213 } 1214} 1215 1216fn populate_tas(table: &mut InstructionTable) { 1217 // TAS <ea> 1218 for dest in dest_addressing_modes_no_address_direct() { 1219 let opcode = 0x4AC0 | dest.to_bits(); 1220 table[opcode as usize] = Instruction::TestAndSet(dest); 1221 } 1222} 1223 1224fn populate_trap(table: &mut InstructionTable) { 1225 // TRAP #<vector> 1226 for vector in 0..=0xF_u16 { 1227 let opcode = 0x4E40 | vector; 1228 table[opcode as usize] = Instruction::Trap(vector.into()); 1229 } 1230 1231 // TRAPV 1232 table[0x4E76] = Instruction::TrapOnOverflow; 1233} 1234 1235fn populate_tst(table: &mut InstructionTable) { 1236 // TST <ea> 1237 for source in dest_addressing_modes_no_address_direct() { 1238 for size in OpSize::ALL { 1239 let opcode = 0x4A00 | size.to_bits() | source.to_bits(); 1240 table[opcode as usize] = Instruction::Test(size, source); 1241 } 1242 } 1243} 1244 1245fn populate_unlk(table: &mut InstructionTable) { 1246 // UNLK An 1247 for register in AddressRegister::ALL { 1248 let opcode = 0x4E58 | u16::from(register.0); 1249 table[opcode as usize] = Instruction::Unlink(register); 1250 } 1251}