table.rsannotatedtable.rssource1251 lines · 43.1 KB · raw
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}