m68000/
disassembler.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5//! Disassembler module.
6
7use crate::instruction::{Direction, Instruction};
8use crate::isa::Isa;
9use crate::status_register::disassemble_conditional_test;
10use crate::utils::bits;
11
12pub fn disassemble_unknown_instruction(inst: &Instruction) -> String {
13    format!("Unknown instruction {:04X} at {:#X}", inst.opcode, inst.pc)
14}
15
16pub fn disassemble_abcd(inst: &Instruction) -> String {
17    let (rx, _, mode, ry) = inst.operands.register_size_mode_register();
18    if mode == Direction::MemoryToMemory {
19        format!("ABCD -(A{}), -(A{})", ry, rx)
20    } else {
21        format!("ABCD D{}, D{}", ry, rx)
22    }
23}
24
25pub fn disassemble_add(inst: &Instruction) -> String {
26    let (r, d, s, am) = inst.operands.register_direction_size_effective_address();
27    if d == Direction::DstEa {
28        format!("ADD.{} D{}, {}", s, r, am)
29    } else {
30        format!("ADD.{} {}, D{}", s, am, r)
31    }
32}
33
34pub fn disassemble_adda(inst: &Instruction) -> String {
35    let (r, s, am) = inst.operands.register_size_effective_address();
36    format!("ADDA.{} {}, A{}", s, am, r)
37}
38
39pub fn disassemble_addi(inst: &Instruction) -> String {
40    let (s, am, imm) = inst.operands.size_effective_address_immediate();
41    format!("ADDI.{} #{}, {}", s, imm, am)
42}
43
44pub fn disassemble_addq(inst: &Instruction) -> String {
45    let (d, s, am) = inst.operands.data_size_effective_address();
46    let d = if d == 0 { 8 } else { d };
47    format!("ADDQ.{} #{}, {}", s, d, am)
48}
49
50pub fn disassemble_addx(inst: &Instruction) -> String {
51    let (rx, s, mode, ry) = inst.operands.register_size_mode_register();
52    if mode == Direction::MemoryToMemory {
53        format!("ADDX.{} -(A{}), -(A{})", s, ry, rx)
54    } else {
55        format!("ADDX.{} D{}, D{}", s, ry, rx)
56    }
57}
58
59pub fn disassemble_and(inst: &Instruction) -> String {
60    let (r, d, s, am) = inst.operands.register_direction_size_effective_address();
61    if d == Direction::DstEa {
62        format!("AND.{} D{}, {}", s, r, am)
63    } else {
64        format!("AND.{} {}, D{}", s, am, r)
65    }
66}
67
68pub fn disassemble_andi(inst: &Instruction) -> String {
69    let (s, am, imm) = inst.operands.size_effective_address_immediate();
70    format!("ANDI.{} #{}, {}", s, imm, am)
71}
72
73pub fn disassemble_andiccr(inst: &Instruction) -> String {
74    let imm = inst.operands.immediate();
75    format!("ANDI {:#X}, CCR", imm)
76}
77
78pub fn disassemble_andisr(inst: &Instruction) -> String {
79    let imm = inst.operands.immediate();
80    format!("ANDI {:#X}, SR", imm)
81}
82
83pub fn disassemble_asm(inst: &Instruction) -> String {
84    let (d, am) = inst.operands.direction_effective_address();
85    format!("AS{} {}", d, am)
86}
87
88pub fn disassemble_asr(inst: &Instruction) -> String {
89    let (rot, d, s, ir, reg) = inst.operands.rotation_direction_size_mode_register();
90    if ir {
91        format!("AS{}.{} D{}, D{}", d, s, rot, reg)
92    } else {
93        let rot = if rot == 0 { 8 } else { rot };
94        format!("AS{}.{} #{}, D{}", d, s, rot, reg)
95    }
96}
97
98pub fn disassemble_bcc(inst: &Instruction) -> String {
99    let (cc, disp) = inst.operands.condition_displacement();
100    format!("B{} {} <{:#X}>", disassemble_conditional_test(cc), disp, inst.pc.wrapping_add(2).wrapping_add(disp as u32))
101}
102
103pub fn disassemble_bchg(inst: &Instruction) -> String {
104    let (am, count) = inst.operands.effective_address_count();
105    if bits(inst.opcode, 8, 8) != 0 {
106        format!("BCHG D{}, {}", count, am)
107    } else {
108        format!("BCHG #{}, {}", count, am)
109    }
110}
111
112pub fn disassemble_bclr(inst: &Instruction) -> String {
113    let (am, count) = inst.operands.effective_address_count();
114    if bits(inst.opcode, 8, 8) != 0 {
115        format!("BCLR D{}, {}", count, am)
116    } else {
117        format!("BCLR #{}, {}", count, am)
118    }
119}
120
121pub fn disassemble_bra(inst: &Instruction) -> String {
122    let disp = inst.operands.displacement();
123    format!("BRA {} <{:#X}>", disp, inst.pc.wrapping_add(2).wrapping_add(disp as u32))
124}
125
126pub fn disassemble_bset(inst: &Instruction) -> String {
127    let (am, count) = inst.operands.effective_address_count();
128    if bits(inst.opcode, 8, 8) != 0 {
129        format!("BSET D{}, {}", count, am)
130    } else {
131        format!("BSET #{}, {}", count, am)
132    }
133}
134
135pub fn disassemble_bsr(inst: &Instruction) -> String {
136    let disp = inst.operands.displacement();
137    format!("BSR {} <{:#X}>", disp, inst.pc.wrapping_add(2).wrapping_add(disp as u32))
138}
139
140pub fn disassemble_btst(inst: &Instruction) -> String {
141    let (am, count) = inst.operands.effective_address_count();
142    if bits(inst.opcode, 8, 8) != 0 {
143        format!("BTST D{}, {}", count, am)
144    } else {
145        format!("BTST #{}, {}", count, am)
146    }
147}
148
149pub fn disassemble_chk(inst: &Instruction) -> String {
150    let (r, am) = inst.operands.register_effective_address();
151    format!("CHK.W {}, D{}", am, r)
152}
153
154pub fn disassemble_clr(inst: &Instruction) -> String {
155    let (s, am) = inst.operands.size_effective_address();
156    format!("CLR.{} {}", s, am)
157}
158
159pub fn disassemble_cmp(inst: &Instruction) -> String {
160    let (r, _, s, am) = inst.operands.register_direction_size_effective_address();
161    format!("CMP.{} {}, D{}", s, am, r)
162}
163
164pub fn disassemble_cmpa(inst: &Instruction) -> String {
165    let (r, s, am) = inst.operands.register_size_effective_address();
166    format!("CMPA.{} {}, A{}", s, am, r)
167}
168
169pub fn disassemble_cmpi(inst: &Instruction) -> String {
170    let (s, am, imm) = inst.operands.size_effective_address_immediate();
171    format!("CMPI.{} #{}, {}", s, imm, am)
172}
173
174pub fn disassemble_cmpm(inst: &Instruction) -> String {
175    let (rx, s, ry) = inst.operands.register_size_register();
176    format!("CMPM.{} (A{})+, (A{})+", s, ry, rx)
177}
178
179pub fn disassemble_dbcc(inst: &Instruction) -> String {
180    let (cc, r, disp) = inst.operands.condition_register_displacement();
181    format!("DB{} D{}, {} <{:#X}>", disassemble_conditional_test(cc), r, disp, inst.pc.wrapping_add(2).wrapping_add(disp as u32))
182}
183
184pub fn disassemble_divs(inst: &Instruction) -> String {
185    let (r, am) = inst.operands.register_effective_address();
186    format!("DIVS.W {}, D{}", am, r)
187}
188
189pub fn disassemble_divu(inst: &Instruction) -> String {
190    let (r, am) = inst.operands.register_effective_address();
191    format!("DIVU.W {}, D{}", am, r)
192}
193
194pub fn disassemble_eor(inst: &Instruction) -> String {
195    let (r, _, s, am) = inst.operands.register_direction_size_effective_address();
196    format!("EOR.{} D{}, {}", s, r, am)
197}
198
199pub fn disassemble_eori(inst: &Instruction) -> String {
200    let (s, am, imm) = inst.operands.size_effective_address_immediate();
201    format!("EORI.{} #{}, {}", s, imm, am)
202}
203
204pub fn disassemble_eoriccr(inst: &Instruction) -> String {
205    let imm = inst.operands.immediate();
206    format!("EORI {:#X}, CCR", imm)
207}
208
209pub fn disassemble_eorisr(inst: &Instruction) -> String {
210    let imm = inst.operands.immediate();
211    format!("EORI {:#X}, SR", imm)
212}
213
214pub fn disassemble_exg(inst: &Instruction) -> String {
215    let (rx, mode, ry) = inst.operands.register_opmode_register();
216    if mode == Direction::ExchangeData {
217        format!("EXG D{}, D{}", rx, ry)
218    } else if mode == Direction::ExchangeAddress {
219        format!("EXG A{}, A{}", rx, ry)
220    } else {
221        format!("EXG D{}, A{}", rx, ry)
222    }
223}
224
225pub fn disassemble_ext(inst: &Instruction) -> String {
226    let (mode, r) = inst.operands.opmode_register();
227    if mode == 0b010 {
228        format!("EXT.W D{}", r)
229    } else {
230        format!("EXT.L D{}", r)
231    }
232}
233
234pub fn disassemble_illegal(_: &Instruction) -> String {
235    "ILLEGAL".to_string()
236}
237
238pub fn disassemble_jmp(inst: &Instruction) -> String {
239    let am = inst.operands.effective_address();
240    format!("JMP {}", am)
241}
242
243pub fn disassemble_jsr(inst: &Instruction) -> String {
244    let am = inst.operands.effective_address();
245    format!("JSR {}", am)
246}
247
248pub fn disassemble_lea(inst: &Instruction) -> String {
249    let (r, am) = inst.operands.register_effective_address();
250    format!("LEA {}, A{}", am, r)
251}
252
253pub fn disassemble_link(inst: &Instruction) -> String {
254    let (r, disp) = inst.operands.register_displacement();
255    format!("LINK.W A{}, #{}", r, disp)
256}
257
258pub fn disassemble_lsm(inst: &Instruction) -> String {
259    let (d, am) = inst.operands.direction_effective_address();
260    format!("LS{} {}", d, am)
261}
262
263pub fn disassemble_lsr(inst: &Instruction) -> String {
264    let (rot, d, s, ir, reg) = inst.operands.rotation_direction_size_mode_register();
265    if ir {
266        format!("LS{}.{} D{}, D{}", d, s, rot, reg)
267    } else {
268        let rot = if rot == 0 { 8 } else { rot };
269        format!("LS{}.{} #{}, D{}", d, s, rot, reg)
270    }
271}
272
273pub fn disassemble_move(inst: &Instruction) -> String {
274    let (s, dst, src) = inst.operands.size_effective_address_effective_address();
275    format!("MOVE.{} {}, {}", s, src, dst)
276}
277
278pub fn disassemble_movea(inst: &Instruction) -> String {
279    let (s, r, am) = inst.operands.size_register_effective_address();
280    format!("MOVEA.{} {:#X}, A{}", s, am, r)
281}
282
283pub fn disassemble_moveccr(inst: &Instruction) -> String {
284    let am = inst.operands.effective_address();
285    format!("MOVE {:#X}, CCR", am)
286}
287
288pub fn disassemble_movefsr(inst: &Instruction) -> String {
289    let am = inst.operands.effective_address();
290    format!("MOVE SR, {:#X}", am)
291}
292
293pub fn disassemble_movesr(inst: &Instruction) -> String {
294    let am = inst.operands.effective_address();
295    format!("MOVE {:#X}, SR", am)
296}
297
298pub fn disassemble_moveusp(inst: &Instruction) -> String {
299    let (dir, reg) = inst.operands.direction_register();
300    if dir == Direction::UspToRegister {
301        format!("MOVE USP, A{}", reg)
302    } else {
303        format!("MOVE A{}, USP", reg)
304    }
305}
306
307pub fn disassemble_movem(inst: &Instruction) -> String {
308    // TODO: disassemble register list.
309    let (d, s, am, list) = inst.operands.direction_size_effective_address_list();
310    if d == Direction::MemoryToRegister {
311        format!("MOVEM.{} {}, {:#X}", s, am, list)
312    } else {
313        format!("MOVEM.{} {:#X}, {}", s, list, am)
314    }
315}
316
317pub fn disassemble_movep(inst: &Instruction) -> String {
318    let (dreg, d, s, areg, disp) = inst.operands.register_direction_size_register_displacement();
319    if d == Direction::RegisterToMemory {
320        format!("MOVEP.{} D{}, ({}, A{})", s, dreg, disp, areg)
321    } else {
322        format!("MOVEP.{} ({}, A{}), D{}", s, disp, areg, dreg)
323    }
324}
325
326pub fn disassemble_moveq(inst: &Instruction) -> String {
327    let (r, d) = inst.operands.register_data();
328    format!("MOVEQ.L #{}, D{}", d, r)
329}
330
331pub fn disassemble_muls(inst: &Instruction) -> String {
332    let (r, am) = inst.operands.register_effective_address();
333    format!("MULS.W {}, D{}", am, r)
334}
335
336pub fn disassemble_mulu(inst: &Instruction) -> String {
337    let (r, am) = inst.operands.register_effective_address();
338    format!("MULU.W {}, D{}", am, r)
339}
340
341pub fn disassemble_nbcd(inst: &Instruction) -> String {
342    let am = inst.operands.effective_address();
343    format!("NBCD {}", am)
344}
345
346pub fn disassemble_neg(inst: &Instruction) -> String {
347    let (s, am) = inst.operands.size_effective_address();
348    format!("NEG.{} {}", s, am)
349}
350
351pub fn disassemble_negx(inst: &Instruction) -> String {
352    let (s, am) = inst.operands.size_effective_address();
353    format!("NEGX.{} {}", s, am)
354}
355
356pub fn disassemble_nop(_: &Instruction) -> String {
357    "NOP".to_string()
358}
359
360pub fn disassemble_not(inst: &Instruction) -> String {
361    let (s, am) = inst.operands.size_effective_address();
362    format!("NOT.{} {}", s, am)
363}
364
365pub fn disassemble_or(inst: &Instruction) -> String {
366    let (r, d, s, am) = inst.operands.register_direction_size_effective_address();
367    if d == Direction::DstEa {
368        format!("OR.{} D{}, {}", s, r, am)
369    } else {
370        format!("OR.{} {}, D{}", s, am, r)
371    }
372}
373
374pub fn disassemble_ori(inst: &Instruction) -> String {
375    let (s, am, imm) = inst.operands.size_effective_address_immediate();
376    format!("ORI.{} #{}, {}", s, imm, am)
377}
378
379pub fn disassemble_oriccr(inst: &Instruction) -> String {
380    let imm = inst.operands.immediate();
381    format!("ORI {:#X}, CCR", imm)
382}
383
384pub fn disassemble_orisr(inst: &Instruction) -> String {
385    let imm = inst.operands.immediate();
386    format!("ORI {:#X}, SR", imm)
387}
388
389pub fn disassemble_pea(inst: &Instruction) -> String {
390    let am = inst.operands.effective_address();
391    format!("PEA {}", am)
392}
393
394pub fn disassemble_reset(_: &Instruction) -> String {
395    "RESET".to_owned()
396}
397
398pub fn disassemble_rom(inst: &Instruction) -> String {
399    let (d, am) = inst.operands.direction_effective_address();
400    format!("RO{} {}", d, am)
401}
402
403pub fn disassemble_ror(inst: &Instruction) -> String {
404    let (rot, d, s, ir, reg) = inst.operands.rotation_direction_size_mode_register();
405    if ir {
406        format!("RO{}.{} D{}, D{}", d, s, rot, reg)
407    } else {
408        let rot = if rot == 0 { 8 } else { rot };
409        format!("RO{}.{} #{}, D{}", d, s, rot, reg)
410    }
411}
412
413pub fn disassemble_roxm(inst: &Instruction) -> String {
414    let (d, am) = inst.operands.direction_effective_address();
415    format!("ROX{} {}", d, am)
416}
417
418pub fn disassemble_roxr(inst: &Instruction) -> String {
419    let (rot, d, s, ir, reg) = inst.operands.rotation_direction_size_mode_register();
420    if ir {
421        format!("ROX{}.{} D{}, D{}", d, s, rot, reg)
422    } else {
423        let rot = if rot == 0 { 8 } else { rot };
424        format!("ROX{}.{} #{}, D{}", d, s, rot, reg)
425    }
426}
427
428pub fn disassemble_rte(_: &Instruction) -> String {
429    "RTE".to_string()
430}
431
432pub fn disassemble_rtr(_: &Instruction) -> String {
433    "RTR".to_string()
434}
435
436pub fn disassemble_rts(_: &Instruction) -> String {
437    "RTS".to_string()
438}
439
440pub fn disassemble_sbcd(inst: &Instruction) -> String {
441    let (ry, _, mode, rx) = inst.operands.register_size_mode_register();
442    if mode == Direction::MemoryToMemory {
443        format!("SBCD -(A{}), -(A{})", rx, ry)
444    } else {
445        format!("SBCD D{}, D{}", rx, ry)
446    }
447}
448
449pub fn disassemble_scc(inst: &Instruction) -> String {
450    let (cc, am) = inst.operands.condition_effective_address();
451    format!("S{} {}", disassemble_conditional_test(cc), am)
452}
453
454pub fn disassemble_stop(inst: &Instruction) -> String {
455    let imm = inst.operands.immediate();
456    format!("STOP #{:#X}", imm)
457}
458
459pub fn disassemble_sub(inst: &Instruction) -> String {
460    let (r, d, s, am) = inst.operands.register_direction_size_effective_address();
461    if d == Direction::DstEa {
462        format!("SUB.{} D{}, {}", s, r, am)
463    } else {
464        format!("SUB.{} {}, D{}", s, am, r)
465    }
466}
467
468pub fn disassemble_suba(inst: &Instruction) -> String {
469    let (r, s, am) = inst.operands.register_size_effective_address();
470    format!("SUBA.{} {}, A{}", s, am, r)
471}
472
473pub fn disassemble_subi(inst: &Instruction) -> String {
474    let (s, am, imm) = inst.operands.size_effective_address_immediate();
475    format!("SUBI.{} #{}, {}", s, imm, am)
476}
477
478pub fn disassemble_subq(inst: &Instruction) -> String {
479    let (d, s, am) = inst.operands.data_size_effective_address();
480    let d = if d == 0 { 8 } else { d };
481    format!("SUBQ.{} #{}, {}", s, d, am)
482}
483
484pub fn disassemble_subx(inst: &Instruction) -> String {
485    let (ry, s, mode, rx) = inst.operands.register_size_mode_register();
486    if mode == Direction::MemoryToMemory {
487        format!("SUBX.{} -(A{}), -(A{})", s, rx, ry)
488    } else {
489        format!("SUBX.{} D{}, D{}", s, rx, ry)
490    }
491}
492
493pub fn disassemble_swap(inst: &Instruction) -> String {
494    let r = inst.operands.register();
495    format!("SWAP D{}", r)
496}
497
498pub fn disassemble_tas(inst: &Instruction) -> String {
499    let am = inst.operands.effective_address();
500    format!("TAS {}", am)
501}
502
503pub fn disassemble_trap(inst: &Instruction) -> String {
504    let v = inst.operands.vector();
505    format!("TRAP #{}", v)
506}
507
508pub fn disassemble_trapv(_: &Instruction) -> String {
509    "TRAPV".to_string()
510}
511
512pub fn disassemble_tst(inst: &Instruction) -> String {
513    let (s, am) = inst.operands.size_effective_address();
514    format!("TST.{} {}", s, am)
515}
516
517pub fn disassemble_unlk(inst: &Instruction) -> String {
518    let r = inst.operands.register();
519    format!("UNLK A{}", r)
520}
521
522/// Disassembler function Look-Up Table.
523///
524/// # Usage
525///
526/// ```
527/// use m68000::decoder::DECODER;
528/// use m68000::disassembler::DLUT;
529/// use m68000::instruction::Instruction;
530/// use m68000::memory_access::MemoryAccess;
531///
532/// let mut data: Vec<u8> = Vec::new();
533/// data.resize(4, 0); // Load the binary in data.
534/// let mut iter = data.iter_u16(0);
535/// let inst = Instruction::from_memory(&mut iter).unwrap();
536/// let disassemble = DLUT[DECODER[inst.opcode as usize] as usize];
537/// println!("{:#X} {}", inst.pc, disassemble(&inst));
538/// ```
539pub const DLUT: [fn(&Instruction) -> String; Isa::_Size as usize] = [
540    disassemble_unknown_instruction,
541    disassemble_abcd,
542    disassemble_add,
543    disassemble_adda,
544    disassemble_addi,
545    disassemble_addq,
546    disassemble_addx,
547    disassemble_and,
548    disassemble_andi,
549    disassemble_andiccr,
550    disassemble_andisr,
551    disassemble_asm,
552    disassemble_asr,
553    disassemble_bcc,
554    disassemble_bchg,
555    disassemble_bclr,
556    disassemble_bra,
557    disassemble_bset,
558    disassemble_bsr,
559    disassemble_btst,
560    disassemble_chk,
561    disassemble_clr,
562    disassemble_cmp,
563    disassemble_cmpa,
564    disassemble_cmpi,
565    disassemble_cmpm,
566    disassemble_dbcc,
567    disassemble_divs,
568    disassemble_divu,
569    disassemble_eor,
570    disassemble_eori,
571    disassemble_eoriccr,
572    disassemble_eorisr,
573    disassemble_exg,
574    disassemble_ext,
575    disassemble_illegal,
576    disassemble_jmp,
577    disassemble_jsr,
578    disassemble_lea,
579    disassemble_link,
580    disassemble_lsm,
581    disassemble_lsr,
582    disassemble_move,
583    disassemble_movea,
584    disassemble_moveccr,
585    disassemble_movefsr,
586    disassemble_movesr,
587    disassemble_moveusp,
588    disassemble_movem,
589    disassemble_movep,
590    disassemble_moveq,
591    disassemble_muls,
592    disassemble_mulu,
593    disassemble_nbcd,
594    disassemble_neg,
595    disassemble_negx,
596    disassemble_nop,
597    disassemble_not,
598    disassemble_or,
599    disassemble_ori,
600    disassemble_oriccr,
601    disassemble_orisr,
602    disassemble_pea,
603    disassemble_reset,
604    disassemble_rom,
605    disassemble_ror,
606    disassemble_roxm,
607    disassemble_roxr,
608    disassemble_rte,
609    disassemble_rtr,
610    disassemble_rts,
611    disassemble_sbcd,
612    disassemble_scc,
613    disassemble_stop,
614    disassemble_sub,
615    disassemble_suba,
616    disassemble_subi,
617    disassemble_subq,
618    disassemble_subx,
619    disassemble_swap,
620    disassemble_tas,
621    disassemble_trap,
622    disassemble_trapv,
623    disassemble_tst,
624    disassemble_unlk,
625];