main
68kinst.c
1/*
2 Copyright 2013 Michael Pavone
3 This file is part of BlastEm.
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
5*/
6#include "68kinst.h"
7#include <string.h>
8#include <stdio.h>
9
10uint32_t sign_extend16(uint32_t val)
11{
12 return (val & 0x8000) ? val | 0xFFFF0000 : val;
13}
14
15uint32_t sign_extend8(uint32_t val)
16{
17 return (val & 0x80) ? val | 0xFFFFFF00 : val;
18}
19
20uint16_t *m68k_decode_op_ex(uint16_t *cur, uint8_t mode, uint8_t reg, uint8_t size, m68k_op_info *dst)
21{
22 uint16_t ext, tmp;
23 dst->addr_mode = mode;
24 switch(mode)
25 {
26 case MODE_REG:
27 case MODE_AREG:
28 case MODE_AREG_INDIRECT:
29 case MODE_AREG_POSTINC:
30 case MODE_AREG_PREDEC:
31 dst->params.regs.pri = reg;
32 break;
33 case MODE_AREG_DISPLACE:
34 ext = *(++cur);
35 dst->params.regs.pri = reg;
36 dst->params.regs.displacement = sign_extend16(ext);
37 break;
38 case MODE_AREG_INDEX_MEM:
39 dst->params.regs.pri = reg;
40 ext = *(++cur);
41 dst->params.regs.sec = ext >> 11;//includes areg/dreg bit, reg num and word/long bit
42#ifdef M68020
43 dst->params.regs.scale = ext >> 9 & 3;
44 if (ext & 0x100)
45 {
46 dst->params.regs.disp_sizes = ext >> 4 & 3;
47 switch (dst->params.regs.disp_sizes)
48 {
49 case 0:
50 //reserved
51 return NULL;
52 case 1:
53 dst->params.regs.displacement = 0;
54 break;
55 case 2:
56 dst->params.regs.displacement = sign_extend16(*(cur++));
57 break;
58 case 3:
59 tmp = *(cur++);
60 dst->params.regs.displacement = tmp << 16 | *(cur++);
61 break;
62 }
63 if (ext & 0x3)
64 {
65 //memory indirect
66 switch (ext & 0xC4)
67 {
68 case 0x00:
69 dst->addr_mode = MODE_AREG_PREINDEX;
70 break;
71 case 0x04:
72 dst->addr_mode = MODE_AREG_POSTINDEX;
73 break;
74 case 0x40:
75 dst->addr_mode = MODE_AREG_MEM_INDIRECT;
76 break;
77 case 0x80:
78 dst->addr_mode = MODE_PREINDEX;
79 break;
80 case 0x84:
81 dst->addr_mode = MODE_POSTINDEX;
82 break;
83 case 0xC0:
84 dst->addr_mode = MODE_MEM_INDIRECT;
85 break;
86 }
87 dst->params.regs.disp_sizes |= ext << 4 & 0x30;
88 switch (ext & 0x3)
89 {
90 case 0:
91 //reserved
92 return NULL;
93 case 1:
94 dst->params.regs.outer_disp = 0;
95 break;
96 case 2:
97 dst->params.regs.outer_disp = sign_extend16(*(cur++));
98 break;
99 case 3:
100 tmp = *(cur++);
101 dst->params.regs.outer_disp = tmp << 16 | *(cur++);
102 break;
103 }
104 } else {
105 switch (ext >> 6 & 3)
106 {
107 case 0:
108 dst->addr_mode = MODE_AREG_INDEX_BASE_DISP;
109 break;
110 case 1:
111 dst->addr_mode = MODE_AREG_BASE_DISP;
112 break;
113 case 2:
114 dst->addr_mode = MODE_INDEX_BASE_DISP;
115 break;
116 case 3:
117 dst->addr_mode = MODE_BASE_DISP;
118 break;
119 }
120 }
121 } else {
122#endif
123 dst->addr_mode = MODE_AREG_INDEX_DISP8;
124 dst->params.regs.displacement = sign_extend8(ext&0xFF);
125#ifdef M68020
126 }
127#endif
128 break;
129 case MODE_PC_INDIRECT_ABS_IMMED:
130 switch(reg)
131 {
132 case 0:
133 dst->addr_mode = MODE_ABSOLUTE_SHORT;
134 ext = *(++cur);
135 dst->params.immed = sign_extend16(ext);
136 break;
137 case 1:
138 dst->addr_mode = MODE_ABSOLUTE;
139 ext = *(++cur);
140 dst->params.immed = ext << 16 | *(++cur);
141 break;
142 case 3:
143 ext = *(++cur);
144 dst->params.regs.sec = ext >> 11;//includes areg/dreg bit, reg num and word/long bit
145#ifdef M68020
146 dst->params.regs.scale = ext >> 9 & 3;
147 if (ext & 0x100)
148 {
149 dst->params.regs.disp_sizes = ext >> 4 & 3;
150 switch (dst->params.regs.disp_sizes)
151 {
152 case 0:
153 //reserved
154 return NULL;
155 case 1:
156 dst->params.regs.displacement = 0;
157 break;
158 case 2:
159 dst->params.regs.displacement = sign_extend16(*(cur++));
160 break;
161 case 3:
162 tmp = *(cur++);
163 dst->params.regs.displacement = tmp << 16 | *(cur++);
164 break;
165 }
166 if (ext & 0x3)
167 {
168 //memory indirect
169 switch (ext & 0xC4)
170 {
171 case 0x00:
172 dst->addr_mode = MODE_PC_PREINDEX;
173 break;
174 case 0x04:
175 dst->addr_mode = MODE_PC_POSTINDEX;
176 break;
177 case 0x40:
178 dst->addr_mode = MODE_PC_MEM_INDIRECT;
179 break;
180 case 0x80:
181 dst->addr_mode = MODE_ZPC_PREINDEX;
182 break;
183 case 0x84:
184 dst->addr_mode = MODE_ZPC_POSTINDEX;
185 break;
186 case 0xC0:
187 dst->addr_mode = MODE_ZPC_MEM_INDIRECT;
188 break;
189 }
190 dst->params.regs.disp_sizes |= ext << 4 & 0x30;
191 switch (ext & 0x3)
192 {
193 case 0:
194 //reserved
195 return NULL;
196 case 1:
197 dst->params.regs.outer_disp = 0;
198 break;
199 case 2:
200 dst->params.regs.outer_disp = sign_extend16(*(cur++));
201 break;
202 case 3:
203 tmp = *(cur++);
204 dst->params.regs.outer_disp = tmp << 16 | *(cur++);
205 break;
206 }
207 } else {
208 switch (ext >> 6 & 3)
209 {
210 case 0:
211 dst->addr_mode = MODE_PC_INDEX_BASE_DISP;
212 break;
213 case 1:
214 dst->addr_mode = MODE_PC_BASE_DISP;
215 break;
216 case 2:
217 dst->addr_mode = MODE_ZPC_INDEX_BASE_DISP;
218 break;
219 case 3:
220 dst->addr_mode = MODE_ZPC_BASE_DISP;
221 break;
222 }
223 }
224 } else {
225#endif
226 dst->addr_mode = MODE_PC_INDEX_DISP8;
227 dst->params.regs.displacement = sign_extend8(ext&0xFF);
228#ifdef M68020
229 }
230#endif
231 break;
232 case 2:
233 dst->addr_mode = MODE_PC_DISPLACE;
234 ext = *(++cur);
235 dst->params.regs.displacement = sign_extend16(ext);
236 break;
237 case 4:
238 dst->addr_mode = MODE_IMMEDIATE;
239 ext = *(++cur);
240 switch (size)
241 {
242 case OPSIZE_BYTE:
243 dst->params.immed = ext & 0xFF;
244 break;
245 case OPSIZE_WORD:
246 dst->params.immed = ext;
247 break;
248 case OPSIZE_LONG:
249 dst->params.immed = ext << 16 | *(++cur);
250 break;
251 }
252 break;
253 default:
254 return NULL;
255 }
256 break;
257 }
258 return cur;
259}
260
261uint8_t m68k_valid_immed_dst(m68k_op_info *dst)
262{
263 if (dst->addr_mode == MODE_AREG || dst->addr_mode == MODE_IMMEDIATE) {
264 return 0;
265 }
266 return 1;
267}
268
269uint8_t m68k_valid_immed_limited_dst(m68k_op_info *dst)
270{
271 if (dst->addr_mode == MODE_AREG || dst->addr_mode > MODE_ABSOLUTE) {
272 return 0;
273 }
274 return 1;
275}
276
277uint8_t m68k_valid_full_arith_dst(m68k_op_info *dst)
278{
279 if (dst->addr_mode < MODE_AREG_INDIRECT || dst->addr_mode > MODE_ABSOLUTE) {
280 return 0;
281 }
282 return 1;
283}
284
285uint8_t m68k_valid_movem_dst(m68k_op_info *dst)
286{
287 if (dst->addr_mode == MODE_REG || dst->addr_mode == MODE_AREG_POSTINC) {
288 return 0;
289 }
290 return m68k_valid_immed_limited_dst(dst);
291}
292
293uint16_t *m68k_decode_op(uint16_t *cur, uint8_t size, m68k_op_info *dst)
294{
295 uint8_t mode = (*cur >> 3) & 0x7;
296 uint8_t reg = *cur & 0x7;
297 return m68k_decode_op_ex(cur, mode, reg, size, dst);
298}
299
300void m68k_decode_cond(uint16_t op, m68kinst * decoded)
301{
302 decoded->extra.cond = (op >> 0x8) & 0xF;
303}
304
305uint8_t m68k_reg_quick_field(uint16_t op)
306{
307 return (op >> 9) & 0x7;
308}
309
310uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address)
311{
312 uint16_t *start = istream;
313 uint8_t optype = *istream >> 12;
314 uint8_t size;
315 uint8_t reg;
316 uint8_t opmode;
317 uint32_t immed;
318 decoded->op = M68K_INVALID;
319 decoded->src.addr_mode = decoded->dst.addr_mode = MODE_UNUSED;
320 decoded->variant = VAR_NORMAL;
321 decoded->address = address;
322 switch(optype)
323 {
324 case BIT_MOVEP_IMMED:
325 if ((*istream & 0x138) == 0x108) {
326 //MOVEP
327 decoded->op = M68K_MOVEP;
328 decoded->extra.size = *istream & 0x40 ? OPSIZE_LONG : OPSIZE_WORD;
329 if (*istream & 0x80) {
330 //memory dest
331 decoded->src.addr_mode = MODE_REG;
332 decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
333 decoded->dst.addr_mode = MODE_AREG_DISPLACE;
334 decoded->dst.params.regs.pri = *istream & 0x7;
335 decoded->dst.params.regs.displacement = *(++istream);
336 } else {
337 //memory source
338 decoded->dst.addr_mode = MODE_REG;
339 decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
340 decoded->src.addr_mode = MODE_AREG_DISPLACE;
341 decoded->src.params.regs.pri = *istream & 0x7;
342 decoded->src.params.regs.displacement = *(++istream);
343 }
344 } else if (*istream & 0x100) {
345 //BTST, BCHG, BCLR, BSET
346 switch ((*istream >> 6) & 0x3)
347 {
348 case 0:
349 decoded->op = M68K_BTST;
350 break;
351 case 1:
352 decoded->op = M68K_BCHG;
353 break;
354 case 2:
355 decoded->op = M68K_BCLR;
356 break;
357 case 3:
358 decoded->op = M68K_BSET;
359 break;
360 }
361 decoded->src.addr_mode = MODE_REG;
362 decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
363 decoded->extra.size = OPSIZE_BYTE;
364 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst));
365 if (
366 !istream || decoded->dst.addr_mode == MODE_AREG
367 || (decoded->op != M68K_BTST && !m68k_valid_immed_limited_dst(&decoded->dst))
368 ) {
369 decoded->op = M68K_INVALID;
370 break;
371 }
372 if (decoded->dst.addr_mode == MODE_REG) {
373 decoded->extra.size = OPSIZE_LONG;
374 }
375 } else if ((*istream & 0xF00) == 0x800) {
376 //BTST, BCHG, BCLR, BSET
377 switch ((*istream >> 6) & 0x3)
378 {
379 case 0:
380 decoded->op = M68K_BTST;
381 break;
382 case 1:
383 decoded->op = M68K_BCHG;
384 break;
385 case 2:
386 decoded->op = M68K_BCLR;
387 break;
388 case 3:
389 decoded->op = M68K_BSET;
390 break;
391 }
392 opmode = (*istream >> 3) & 0x7;
393 reg = *istream & 0x7;
394 decoded->src.addr_mode = MODE_IMMEDIATE_WORD;
395 decoded->src.params.immed = *(++istream) & 0xFF;
396 decoded->extra.size = OPSIZE_BYTE;
397 istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
398 if (
399 !istream || !m68k_valid_immed_dst(&decoded->dst)
400 || (decoded->op != M68K_BTST && !m68k_valid_immed_limited_dst(&decoded->dst))
401 ) {
402 decoded->op = M68K_INVALID;
403 break;
404 }
405 if (decoded->dst.addr_mode == MODE_REG) {
406 decoded->extra.size = OPSIZE_LONG;
407 }
408 } else if ((*istream & 0xC0) == 0xC0) {
409#ifdef M68020
410 //CMP2, CHK2, CAS, CAS2, RTM, CALLM
411#endif
412 } else {
413 switch ((*istream >> 9) & 0x7)
414 {
415 case 0:
416 if ((*istream & 0xFF) == 0x3C) {
417 decoded->op = M68K_ORI_CCR;
418 decoded->extra.size = OPSIZE_BYTE;
419 decoded->src.addr_mode = MODE_IMMEDIATE;
420 decoded->src.params.immed = *(++istream) & 0xFF;
421 } else if((*istream & 0xFF) == 0x7C) {
422 decoded->op = M68K_ORI_SR;
423 decoded->extra.size = OPSIZE_WORD;
424 decoded->src.addr_mode = MODE_IMMEDIATE;
425 decoded->src.params.immed = *(++istream);
426 } else {
427 decoded->op = M68K_OR;
428 decoded->variant = VAR_IMMEDIATE;
429 decoded->src.addr_mode = MODE_IMMEDIATE;
430 decoded->extra.size = size = (*istream >> 6) & 3;
431 reg = *istream & 0x7;
432 opmode = (*istream >> 3) & 0x7;
433 switch (size)
434 {
435 case OPSIZE_BYTE:
436 decoded->src.params.immed = *(++istream) & 0xFF;
437 break;
438 case OPSIZE_WORD:
439 decoded->src.params.immed = *(++istream);
440 break;
441 case OPSIZE_LONG:
442 immed = *(++istream);
443 decoded->src.params.immed = immed << 16 | *(++istream);
444 break;
445 }
446 istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
447 if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
448 decoded->op = M68K_INVALID;
449 break;
450 }
451 }
452 break;
453 case 1:
454 //ANDI, ANDI to CCR, ANDI to SR
455 if ((*istream & 0xFF) == 0x3C) {
456 decoded->op = M68K_ANDI_CCR;
457 decoded->extra.size = OPSIZE_BYTE;
458 decoded->src.addr_mode = MODE_IMMEDIATE;
459 decoded->src.params.immed = *(++istream) & 0xFF;
460 } else if((*istream & 0xFF) == 0x7C) {
461 decoded->op = M68K_ANDI_SR;
462 decoded->extra.size = OPSIZE_WORD;
463 decoded->src.addr_mode = MODE_IMMEDIATE;
464 decoded->src.params.immed = *(++istream);
465 } else {
466 decoded->op = M68K_AND;
467 decoded->variant = VAR_IMMEDIATE;
468 decoded->src.addr_mode = MODE_IMMEDIATE;
469 decoded->extra.size = size = (*istream >> 6) & 3;
470 reg = *istream & 0x7;
471 opmode = (*istream >> 3) & 0x7;
472 switch (size)
473 {
474 case OPSIZE_BYTE:
475 decoded->src.params.immed = *(++istream) & 0xFF;
476 break;
477 case OPSIZE_WORD:
478 decoded->src.params.immed = *(++istream);
479 break;
480 case OPSIZE_LONG:
481 immed = *(++istream);
482 decoded->src.params.immed = immed << 16 | *(++istream);
483 break;
484 }
485 istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
486 if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
487 decoded->op = M68K_INVALID;
488 break;
489 }
490 }
491 break;
492 case 2:
493 decoded->op = M68K_SUB;
494 decoded->variant = VAR_IMMEDIATE;
495 decoded->src.addr_mode = MODE_IMMEDIATE;
496 decoded->extra.size = size = (*istream >> 6) & 3;
497 reg = *istream & 0x7;
498 opmode = (*istream >> 3) & 0x7;
499 switch (size)
500 {
501 case OPSIZE_BYTE:
502 decoded->src.params.immed = *(++istream) & 0xFF;
503 break;
504 case OPSIZE_WORD:
505 decoded->src.params.immed = *(++istream);
506 break;
507 case OPSIZE_LONG:
508 immed = *(++istream);
509 decoded->src.params.immed = immed << 16 | *(++istream);
510 break;
511 }
512 istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
513 if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
514 decoded->op = M68K_INVALID;
515 break;
516 }
517 break;
518 case 3:
519 decoded->op = M68K_ADD;
520 decoded->variant = VAR_IMMEDIATE;
521 decoded->src.addr_mode = MODE_IMMEDIATE;
522 decoded->extra.size = size = (*istream >> 6) & 3;
523 reg = *istream & 0x7;
524 opmode = (*istream >> 3) & 0x7;
525 switch (size)
526 {
527 case OPSIZE_BYTE:
528 decoded->src.params.immed = *(++istream) & 0xFF;
529 break;
530 case OPSIZE_WORD:
531 decoded->src.params.immed = *(++istream);
532 break;
533 case OPSIZE_LONG:
534 immed = *(++istream);
535 decoded->src.params.immed = immed << 16 | *(++istream);
536 break;
537 }
538 istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
539 if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
540 decoded->op = M68K_INVALID;
541 break;
542 }
543 break;
544 case 4:
545 //BTST, BCHG, BCLR, BSET
546 //Seems like this should be unnecessary since bit instructions are explicitly handled above
547 //Possible this is redundant or the case above is overly restrictive
548 //TODO: Investigate whether this can be removed
549 switch ((*istream >> 6) & 0x3)
550 {
551 case 0:
552 decoded->op = M68K_BTST;
553 break;
554 case 1:
555 decoded->op = M68K_BCHG;
556 break;
557 case 2:
558 decoded->op = M68K_BCLR;
559 break;
560 case 3:
561 decoded->op = M68K_BSET;
562 break;
563 }
564 decoded->src.addr_mode = MODE_IMMEDIATE_WORD;
565 decoded->src.params.immed = *(++istream) & 0xFF;
566 istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst));
567 if (
568 !istream || !m68k_valid_immed_dst(&decoded->dst)
569 || (decoded->op != M68K_BTST && !m68k_valid_immed_limited_dst(&decoded->dst))
570 ) {
571 decoded->op = M68K_INVALID;
572 break;
573 }
574 break;
575 case 5:
576 //EORI, EORI to CCR, EORI to SR
577 if ((*istream & 0xFF) == 0x3C) {
578 decoded->op = M68K_EORI_CCR;
579 decoded->extra.size = OPSIZE_BYTE;
580 decoded->src.addr_mode = MODE_IMMEDIATE;
581 decoded->src.params.immed = *(++istream) & 0xFF;
582 } else if((*istream & 0xFF) == 0x7C) {
583 decoded->op = M68K_EORI_SR;
584 decoded->extra.size = OPSIZE_WORD;
585 decoded->src.addr_mode = MODE_IMMEDIATE;
586 decoded->src.params.immed = *(++istream);
587 } else {
588 decoded->op = M68K_EOR;
589 decoded->variant = VAR_IMMEDIATE;
590 decoded->src.addr_mode = MODE_IMMEDIATE;
591 decoded->extra.size = size = (*istream >> 6) & 3;
592 reg = *istream & 0x7;
593 opmode = (*istream >> 3) & 0x7;
594 switch (size)
595 {
596 case OPSIZE_BYTE:
597 decoded->src.params.immed = *(++istream) & 0xFF;
598 break;
599 case OPSIZE_WORD:
600 decoded->src.params.immed = *(++istream);
601 break;
602 case OPSIZE_LONG:
603 immed = *(++istream);
604 decoded->src.params.immed = immed << 16 | *(++istream);
605 break;
606 }
607 istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst));
608 if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
609 decoded->op = M68K_INVALID;
610 break;
611 }
612 }
613 break;
614 case 6:
615 decoded->op = M68K_CMP;
616 decoded->variant = VAR_IMMEDIATE;
617 decoded->extra.size = (*istream >> 6) & 0x3;
618 decoded->src.addr_mode = MODE_IMMEDIATE;
619 reg = *istream & 0x7;
620 opmode = (*istream >> 3) & 0x7;
621 switch (decoded->extra.size)
622 {
623 case OPSIZE_BYTE:
624 decoded->src.params.immed = *(++istream) & 0xFF;
625 break;
626 case OPSIZE_WORD:
627 decoded->src.params.immed = *(++istream);
628 break;
629 case OPSIZE_LONG:
630 immed = *(++istream);
631 decoded->src.params.immed = (immed << 16) | *(++istream);
632 break;
633 }
634 istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
635 if (!istream || !m68k_valid_immed_limited_dst(&(decoded->dst))) {
636 decoded->op = M68K_INVALID;
637 break;
638 }
639 break;
640 case 7:
641#ifdef M68010
642 decoded->op = M68K_MOVES;
643 decoded->extra.size = *istream >> 6 & 0x3;
644 immed = *(++istream);
645 reg = immed >> 12 & 0x7;
646 opmode = immed & 0x8000 ? MODE_AREG : MODE_REG;
647 if (immed & 0x800) {
648 decoded->src.addr_mode = opmode;
649 decoded->src.params.regs.pri = reg;
650 m68k_decode_op_ex(istream, *start >> 3 & 0x7, *start & 0x7, decoded->extra.size, &(decoded->dst));
651 } else {
652 m68k_decode_op_ex(istream, *start >> 3 & 0x7, *start & 0x7, decoded->extra.size, &(decoded->src));
653 decoded->dst.addr_mode = opmode;
654 decoded->dst.params.regs.pri = reg;
655 }
656#endif
657 break;
658 }
659 }
660 break;
661 case MOVE_BYTE:
662 case MOVE_LONG:
663 case MOVE_WORD:
664 decoded->op = M68K_MOVE;
665 decoded->extra.size = optype == MOVE_BYTE ? OPSIZE_BYTE : (optype == MOVE_WORD ? OPSIZE_WORD : OPSIZE_LONG);
666 opmode = (*istream >> 6) & 0x7;
667 reg = m68k_reg_quick_field(*istream);
668 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
669 if (!istream || (decoded->src.addr_mode == MODE_AREG && optype == MOVE_BYTE)) {
670 decoded->op = M68K_INVALID;
671 break;
672 }
673 istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
674 if (!istream || decoded->dst.addr_mode > MODE_ABSOLUTE || (decoded->dst.addr_mode == MODE_AREG && optype == MOVE_BYTE)) {
675 decoded->op = M68K_INVALID;
676 break;
677 }
678 break;
679 case MISC:
680
681 if ((*istream & 0x1C0) == 0x1C0) {
682 decoded->op = M68K_LEA;
683 decoded->extra.size = OPSIZE_LONG;
684 decoded->dst.addr_mode = MODE_AREG;
685 decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
686 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
687 if (
688 !istream || decoded->src.addr_mode == MODE_REG || decoded->src.addr_mode == MODE_AREG
689 || decoded->src.addr_mode == MODE_AREG_POSTINC || decoded->src.addr_mode == MODE_AREG_PREDEC
690 || decoded->src.addr_mode == MODE_IMMEDIATE
691 ) {
692 decoded->op = M68K_INVALID;
693 break;
694 }
695 } else {
696 if (*istream & 0x100) {
697 decoded->op = M68K_CHK;
698 if ((*istream & 0x180) == 0x180) {
699 decoded->extra.size = OPSIZE_WORD;
700 } else {
701 //only on M68020+
702#ifdef M68020
703 decoded->extra.size = OPSIZE_LONG;
704#else
705 decoded->op = M68K_INVALID;
706 break;
707#endif
708 }
709 decoded->dst.addr_mode = MODE_REG;
710 decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
711 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
712 if (!istream || decoded->src.addr_mode == MODE_AREG) {
713 decoded->op = M68K_INVALID;
714 break;
715 }
716 } else {
717 opmode = (*istream >> 3) & 0x7;
718 if ((*istream & 0xB80) == 0x880 && opmode != MODE_REG && opmode != MODE_AREG) {
719 //TODO: Check for invalid modes that are dependent on direction
720 decoded->op = M68K_MOVEM;
721 decoded->extra.size = *istream & 0x40 ? OPSIZE_LONG : OPSIZE_WORD;
722 reg = *istream & 0x7;
723 if(*istream & 0x400) {
724 decoded->dst.addr_mode = MODE_REG;
725 decoded->dst.params.immed = *(++istream);
726 istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->src));
727 if (!istream || decoded->src.addr_mode == MODE_AREG_PREDEC || decoded->src.addr_mode == MODE_IMMEDIATE) {
728 decoded->op = M68K_INVALID;
729 break;
730 }
731 if (decoded->src.addr_mode == MODE_PC_DISPLACE || decoded->src.addr_mode == MODE_PC_INDEX_DISP8) {
732 //adjust displacement to account for extra instruction word
733 decoded->src.params.regs.displacement += 2;
734 }
735 } else {
736 decoded->src.addr_mode = MODE_REG;
737 decoded->src.params.immed = *(++istream);
738 istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst));
739 if (!istream || !m68k_valid_movem_dst(&decoded->dst)) {
740 decoded->op = M68K_INVALID;
741 break;
742 }
743 }
744 } else {
745 optype = (*istream >> 9) & 0x7;
746 size = (*istream >> 6) & 0x3;
747 switch(optype)
748 {
749 case 0:
750 //Move from SR or NEGX
751 if (size == OPSIZE_INVALID) {
752 decoded->op = M68K_MOVE_FROM_SR;
753 size = OPSIZE_WORD;
754 } else {
755 decoded->op = M68K_NEGX;
756 }
757 decoded->extra.size = size;
758 istream= m68k_decode_op(istream, size, &(decoded->dst));
759 if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
760 decoded->op = M68K_INVALID;
761 break;
762 }
763 break;
764 case 1:
765 //MOVE from CCR or CLR
766 if (size == OPSIZE_INVALID) {
767#ifdef M68010
768 decoded->op = M68K_MOVE_FROM_CCR;
769 size = OPSIZE_WORD;
770#else
771 break;
772#endif
773 } else {
774 decoded->op = M68K_CLR;
775 }
776 decoded->extra.size = size;
777 istream= m68k_decode_op(istream, size, &(decoded->dst));
778 if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
779 decoded->op = M68K_INVALID;
780 break;
781 }
782 break;
783 case 2:
784 //MOVE to CCR or NEG
785 if (size == OPSIZE_INVALID) {
786 decoded->op = M68K_MOVE_CCR;
787 size = OPSIZE_WORD;
788 istream= m68k_decode_op(istream, size, &(decoded->src));
789 if (!istream || decoded->src.addr_mode == MODE_AREG) {
790 decoded->op = M68K_INVALID;
791 break;
792 }
793 } else {
794 decoded->op = M68K_NEG;
795 istream= m68k_decode_op(istream, size, &(decoded->dst));
796 if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
797 decoded->op = M68K_INVALID;
798 break;
799 }
800 }
801 decoded->extra.size = size;
802 break;
803 case 3:
804 //MOVE to SR or NOT
805 if (size == OPSIZE_INVALID) {
806 decoded->op = M68K_MOVE_SR;
807 size = OPSIZE_WORD;
808 istream= m68k_decode_op(istream, size, &(decoded->src));
809 if (!istream || decoded->src.addr_mode == MODE_AREG) {
810 decoded->op = M68K_INVALID;
811 break;
812 }
813 } else {
814 decoded->op = M68K_NOT;
815 istream= m68k_decode_op(istream, size, &(decoded->dst));
816 if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
817 decoded->op = M68K_INVALID;
818 break;
819 }
820 }
821 decoded->extra.size = size;
822 break;
823 case 4:
824 //EXT, EXTB, LINK.l, NBCD, SWAP, BKPT, PEA
825 switch((*istream >> 3) & 0x3F)
826 {
827 case 1:
828#ifdef M68020
829 decoded->op = M68K_LINK;
830 decoded->extra.size = OPSIZE_LONG;
831 reg = *istream & 0x7;
832 immed = *(++istream) << 16;
833 immed |= *(++istream);
834#endif
835 break;
836 case 8:
837 decoded->op = M68K_SWAP;
838 decoded->src.addr_mode = MODE_REG;
839 decoded->src.params.regs.pri = *istream & 0x7;
840 decoded->extra.size = OPSIZE_WORD;
841 break;
842 case 9:
843#ifdef M68010
844 decoded->op = M68K_BKPT;
845 decoded->src.addr_mode = MODE_IMMEDIATE;
846 decoded->extra.size = OPSIZE_UNSIZED;
847 decoded->src.params.immed = *istream & 0x7;
848#endif
849 break;
850 case 0x10:
851 decoded->op = M68K_EXT;
852 decoded->dst.addr_mode = MODE_REG;
853 decoded->dst.params.regs.pri = *istream & 0x7;
854 decoded->extra.size = OPSIZE_WORD;
855 break;
856 case 0x18:
857 decoded->op = M68K_EXT;
858 decoded->dst.addr_mode = MODE_REG;
859 decoded->dst.params.regs.pri = *istream & 0x7;
860 decoded->extra.size = OPSIZE_LONG;
861 break;
862 case 0x38:
863#ifdef M68020
864#endif
865 break;
866 default:
867 if (!(*istream & 0x1C0)) {
868 decoded->op = M68K_NBCD;
869 decoded->extra.size = OPSIZE_BYTE;
870 istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst));
871 if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
872 decoded->op = M68K_INVALID;
873 break;
874 }
875 } else if((*istream & 0x1C0) == 0x40) {
876 decoded->op = M68K_PEA;
877 decoded->extra.size = OPSIZE_LONG;
878 istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src));
879 if (
880 !istream || decoded->src.addr_mode == MODE_REG || decoded->src.addr_mode == MODE_AREG
881 || decoded->src.addr_mode == MODE_AREG_POSTINC || decoded->src.addr_mode == MODE_AREG_PREDEC
882 || decoded->src.addr_mode == MODE_IMMEDIATE
883 ) {
884 decoded->op = M68K_INVALID;
885 break;
886 }
887 }
888 }
889 break;
890 case 5:
891 //BGND, ILLEGAL, TAS, TST
892 optype = *istream & 0xFF;
893 if (optype == 0xFA) {
894 //BGND - CPU32 only
895 } else if (optype == 0xFC) {
896 decoded->op = M68K_ILLEGAL;
897 decoded->extra.size = OPSIZE_UNSIZED;
898 } else {
899 if (size == OPSIZE_INVALID) {
900 decoded->op = M68K_TAS;
901 decoded->extra.size = OPSIZE_BYTE;
902 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst));
903 if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
904 decoded->op = M68K_INVALID;
905 break;
906 }
907 } else {
908 decoded->op = M68K_TST;
909 decoded->extra.size = size;
910 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
911 if (!istream) {
912 decoded->op = M68K_INVALID;
913 break;
914 }
915#ifndef M68020
916 if (!m68k_valid_immed_limited_dst(&decoded->src)) {
917 decoded->op = M68K_INVALID;
918 break;
919 }
920#endif
921 }
922 }
923 break;
924 case 6:
925 //MULU, MULS, DIVU, DIVUL, DIVS, DIVSL
926#ifdef M68020
927 //TODO: Implement these for 68020+ support
928#endif
929 break;
930 case 7:
931 //TRAP, LINK.w, UNLNK, MOVE USP, RESET, NOP, STOP, RTE, RTD, RTS, TRAPV, RTR, MOVEC, JSR, JMP
932 if (*istream & 0x80) {
933 //JSR, JMP
934 if (*istream & 0x40) {
935 decoded->op = M68K_JMP;
936 } else {
937 decoded->op = M68K_JSR;
938 }
939 decoded->extra.size = OPSIZE_UNSIZED;
940 istream = m68k_decode_op(istream, OPSIZE_UNSIZED, &(decoded->src));
941 if (
942 !istream
943 || (decoded->src.addr_mode < MODE_AREG_DISPLACE && decoded->src.addr_mode != MODE_AREG_INDIRECT)
944 || decoded->src.addr_mode == MODE_IMMEDIATE
945 ) {
946 decoded->op = M68K_INVALID;
947 break;
948 }
949 } else {
950 //it would appear bit 6 needs to be set for it to be a valid instruction here
951 if (!(*istream & 0x40)) {
952 decoded->op = M68K_INVALID;
953 break;
954 }
955 switch((*istream >> 3) & 0x7)
956 {
957 case 0:
958 case 1:
959 //TRAP
960 decoded->op = M68K_TRAP;
961 decoded->extra.size = OPSIZE_UNSIZED;
962 decoded->src.addr_mode = MODE_IMMEDIATE;
963 decoded->src.params.immed = *istream & 0xF;
964 break;
965 case 2:
966 //LINK.w
967 decoded->op = M68K_LINK;
968 decoded->extra.size = OPSIZE_WORD;
969 decoded->src.addr_mode = MODE_AREG;
970 decoded->src.params.regs.pri = *istream & 0x7;
971 decoded->dst.addr_mode = MODE_IMMEDIATE;
972 decoded->dst.params.immed = sign_extend16(*(++istream));
973 break;
974 case 3:
975 //UNLK
976 decoded->op = M68K_UNLK;
977 decoded->extra.size = OPSIZE_UNSIZED;
978 decoded->dst.addr_mode = MODE_AREG;
979 decoded->dst.params.regs.pri = *istream & 0x7;
980 break;
981 case 4:
982 case 5:
983 //MOVE USP
984 decoded->op = M68K_MOVE_USP;
985 if (*istream & 0x8) {
986 decoded->dst.addr_mode = MODE_AREG;
987 decoded->dst.params.regs.pri = *istream & 0x7;
988 } else {
989 decoded->src.addr_mode = MODE_AREG;
990 decoded->src.params.regs.pri = *istream & 0x7;
991 }
992 break;
993 case 6:
994 decoded->extra.size = OPSIZE_UNSIZED;
995 switch(*istream & 0x7)
996 {
997 case 0:
998 decoded->op = M68K_RESET;
999 break;
1000 case 1:
1001 decoded->op = M68K_NOP;
1002 break;
1003 case 2:
1004 decoded->op = M68K_STOP;
1005 decoded->src.addr_mode = MODE_IMMEDIATE;
1006 decoded->src.params.immed =*(++istream);
1007 break;
1008 case 3:
1009 decoded->op = M68K_RTE;
1010 break;
1011 case 4:
1012#ifdef M68010
1013 decoded->op = M68K_RTD;
1014 decoded->src.addr_mode = MODE_IMMEDIATE;
1015 decoded->src.params.immed =*(++istream);
1016#endif
1017 break;
1018 case 5:
1019 decoded->op = M68K_RTS;
1020 break;
1021 case 6:
1022 decoded->op = M68K_TRAPV;
1023 break;
1024 case 7:
1025 decoded->op = M68K_RTR;
1026 break;
1027 }
1028 break;
1029 case 7:
1030 //MOVEC
1031#ifdef M68010
1032 decoded->op = M68K_MOVEC;
1033 immed = *(++istream);
1034 reg = immed >> 12 & 0x7;
1035 opmode = immed & 0x8000 ? MODE_AREG : MODE_REG;
1036 immed &= 0xFFF;
1037 if (immed & 0x800) {
1038 if (immed > MAX_HIGH_CR) {
1039 decoded->op = M68K_INVALID;
1040 break;
1041 } else {
1042 immed = immed - 0x800 + CR_USP;
1043 }
1044 } else {
1045 if (immed > MAX_LOW_CR) {
1046 decoded->op = M68K_INVALID;
1047 break;
1048 }
1049 }
1050 if (*start & 1) {
1051 decoded->src.addr_mode = opmode;
1052 decoded->src.params.regs.pri = reg;
1053 decoded->dst.params.immed = immed;
1054 } else {
1055 decoded->dst.addr_mode = opmode;
1056 decoded->dst.params.regs.pri = reg;
1057 decoded->src.params.immed = immed;
1058 }
1059#endif
1060 break;
1061 }
1062 }
1063 break;
1064 }
1065 }
1066 }
1067 }
1068 break;
1069 case QUICK_ARITH_LOOP:
1070 size = (*istream >> 6) & 3;
1071 if (size == 0x3) {
1072 //DBcc, TRAPcc or Scc
1073 m68k_decode_cond(*istream, decoded);
1074 if (((*istream >> 3) & 0x7) == 1) {
1075 decoded->op = M68K_DBCC;
1076 decoded->src.addr_mode = MODE_IMMEDIATE;
1077 decoded->dst.addr_mode = MODE_REG;
1078 decoded->dst.params.regs.pri = *istream & 0x7;
1079 decoded->src.params.immed = sign_extend16(*(++istream));
1080 } else if(((*istream >> 3) & 0x7) == 1 && (*istream & 0x7) > 1 && (*istream & 0x7) < 5) {
1081#ifdef M68020
1082 decoded->op = M68K_TRAPCC;
1083 decoded->src.addr_mode = MODE_IMMEDIATE;
1084 //TODO: Figure out what to do with OPMODE and optional extention words
1085#endif
1086 } else {
1087 decoded->op = M68K_SCC;
1088 decoded->extra.cond = (*istream >> 8) & 0xF;
1089 istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst));
1090 if (!istream || !m68k_valid_immed_limited_dst(&decoded->dst)) {
1091 decoded->op = M68K_INVALID;
1092 break;
1093 }
1094 }
1095 } else {
1096 //ADDQ, SUBQ
1097 decoded->variant = VAR_QUICK;
1098 decoded->extra.size = size;
1099 decoded->src.addr_mode = MODE_IMMEDIATE;
1100 immed = m68k_reg_quick_field(*istream);
1101 if (!immed) {
1102 immed = 8;
1103 }
1104 decoded->src.params.immed = immed;
1105 if (*istream & 0x100) {
1106 decoded->op = M68K_SUB;
1107 } else {
1108 decoded->op = M68K_ADD;
1109 }
1110 istream = m68k_decode_op(istream, size, &(decoded->dst));
1111 if (!istream || decoded->dst.addr_mode > MODE_ABSOLUTE || (size == OPSIZE_BYTE && decoded->dst.addr_mode == MODE_AREG)) {
1112 decoded->op = M68K_INVALID;
1113 break;
1114 }
1115 }
1116 break;
1117 case BRANCH:
1118 m68k_decode_cond(*istream, decoded);
1119 decoded->op = decoded->extra.cond == COND_FALSE ? M68K_BSR : M68K_BCC;
1120 decoded->src.addr_mode = MODE_IMMEDIATE;
1121 immed = *istream & 0xFF;
1122 if (immed == 0) {
1123 decoded->variant = VAR_WORD;
1124 immed = *(++istream);
1125 immed = sign_extend16(immed);
1126#ifdef M68020
1127 } else if (immed == 0xFF) {
1128 decoded->variant = VAR_LONG;
1129 immed = *(++istream) << 16;
1130 immed |= *(++istream);
1131#endif
1132 } else {
1133 decoded->variant = VAR_BYTE;
1134 immed = sign_extend8(immed);
1135 }
1136 decoded->src.params.immed = immed;
1137 break;
1138 case MOVEQ:
1139 if (*istream & 0x100) {
1140 decoded->op = M68K_INVALID;
1141 break;
1142 }
1143 decoded->op = M68K_MOVE;
1144 decoded->variant = VAR_QUICK;
1145 decoded->extra.size = OPSIZE_LONG;
1146 decoded->src.addr_mode = MODE_IMMEDIATE;
1147 decoded->src.params.immed = sign_extend8(*istream & 0xFF);
1148 decoded->dst.addr_mode = MODE_REG;
1149 decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1150 immed = *istream & 0xFF;
1151 break;
1152 case OR_DIV_SBCD:
1153 //for OR, if opmode bit 2 is 1, then src = Dn, dst = <ea>
1154 opmode = (*istream >> 6) & 0x7;
1155 size = opmode & 0x3;
1156 if (size == OPSIZE_INVALID || (opmode & 0x4 && !(*istream & 0x30))) {
1157 switch(opmode)
1158 {
1159 case 3:
1160 decoded->op = M68K_DIVU;
1161 decoded->extra.size = OPSIZE_WORD;
1162 decoded->dst.addr_mode = MODE_REG;
1163 decoded->dst.params.regs.pri = (*istream >> 9) & 0x7;
1164 istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
1165 if (!istream || decoded->src.addr_mode == MODE_AREG) {
1166 decoded->op = M68K_INVALID;
1167 break;
1168 }
1169 break;
1170 case 4:
1171 decoded->op = M68K_SBCD;
1172 decoded->extra.size = OPSIZE_BYTE;
1173 decoded->dst.addr_mode = decoded->src.addr_mode = *istream & 0x8 ? MODE_AREG_PREDEC : MODE_REG;
1174 decoded->src.params.regs.pri = *istream & 0x7;
1175 decoded->dst.params.regs.pri = (*istream >> 9) & 0x7;
1176 break;
1177 case 5:
1178 #ifdef M68020
1179 #endif
1180 break;
1181 case 6:
1182 #ifdef M68020
1183 #endif
1184 break;
1185 case 7:
1186 decoded->op = M68K_DIVS;
1187 decoded->extra.size = OPSIZE_WORD;
1188 decoded->dst.addr_mode = MODE_REG;
1189 decoded->dst.params.regs.pri = (*istream >> 9) & 0x7;
1190 istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
1191 if (!istream || decoded->src.addr_mode == MODE_AREG) {
1192 decoded->op = M68K_INVALID;
1193 break;
1194 }
1195 break;
1196 }
1197 } else {
1198 decoded->op = M68K_OR;
1199 decoded->extra.size = size;
1200 if (opmode & 0x4) {
1201 decoded->src.addr_mode = MODE_REG;
1202 decoded->src.params.regs.pri = (*istream >> 9) & 0x7;
1203 istream = m68k_decode_op(istream, size, &(decoded->dst));
1204 if (!istream || !m68k_valid_full_arith_dst(&(decoded->dst))) {
1205 decoded->op = M68K_INVALID;
1206 break;
1207 }
1208 } else {
1209 decoded->dst.addr_mode = MODE_REG;
1210 decoded->dst.params.regs.pri = (*istream >> 9) & 0x7;
1211 istream = m68k_decode_op(istream, size, &(decoded->src));
1212 if (!istream || decoded->src.addr_mode == MODE_AREG) {
1213 decoded->op = M68K_INVALID;
1214 break;
1215 }
1216 }
1217 }
1218 break;
1219 case SUB_SUBX:
1220 size = (*istream >> 6) & 0x3;
1221 decoded->op = M68K_SUB;
1222 if (*istream & 0x100) {
1223 //<ea> destination, SUBA.l or SUBX
1224 if (*istream & 0x30 || size == OPSIZE_INVALID) {
1225 if (size == OPSIZE_INVALID) {
1226 //SUBA.l
1227 decoded->extra.size = OPSIZE_LONG;
1228 decoded->dst.addr_mode = MODE_AREG;
1229 decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1230 istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src));
1231 if (!istream) {
1232 decoded->op = M68K_INVALID;
1233 break;
1234 }
1235 } else {
1236 decoded->extra.size = size;
1237 decoded->src.addr_mode = MODE_REG;
1238 decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
1239 istream = m68k_decode_op(istream, size, &(decoded->dst));
1240 if (!istream || !m68k_valid_full_arith_dst(&decoded->dst)) {
1241 decoded->op = M68K_INVALID;
1242 break;
1243 }
1244 }
1245 } else {
1246 //SUBX
1247 decoded->op = M68K_SUBX;
1248 decoded->extra.size = size;
1249 decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1250 decoded->src.params.regs.pri = *istream & 0x7;
1251 if (*istream & 0x8) {
1252 decoded->dst.addr_mode = decoded->src.addr_mode = MODE_AREG_PREDEC;
1253 } else {
1254 decoded->dst.addr_mode = decoded->src.addr_mode = MODE_REG;
1255 }
1256 }
1257 } else {
1258 if (size == OPSIZE_INVALID) {
1259 //SUBA.w
1260 decoded->extra.size = OPSIZE_WORD;
1261 decoded->dst.addr_mode = MODE_AREG;
1262 } else {
1263 decoded->extra.size = size;
1264 decoded->dst.addr_mode = MODE_REG;
1265 }
1266 decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1267 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
1268 if (!istream || (decoded->src.addr_mode == MODE_AREG && decoded->extra.size == OPSIZE_BYTE)) {
1269 decoded->op = M68K_INVALID;
1270 break;
1271 }
1272 }
1273 break;
1274 case A_LINE:
1275 decoded->op = M68K_A_LINE_TRAP;
1276 break;
1277 case CMP_XOR:
1278 size = (*istream >> 6) & 0x3;
1279 decoded->op = M68K_CMP;
1280 if (*istream & 0x100) {
1281 //CMPM or CMPA.l or EOR
1282 if (size == OPSIZE_INVALID) {
1283 decoded->extra.size = OPSIZE_LONG;
1284 decoded->dst.addr_mode = MODE_AREG;
1285 decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1286 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
1287 if (!istream) {
1288 decoded->op = M68K_INVALID;
1289 break;
1290 }
1291 } else {
1292 reg = m68k_reg_quick_field(*istream);
1293 istream = m68k_decode_op(istream, size, &(decoded->dst));
1294 if (!istream) {
1295 decoded->op = M68K_INVALID;
1296 break;
1297 }
1298 decoded->extra.size = size;
1299 if (decoded->dst.addr_mode == MODE_AREG) {
1300 //CMPM
1301 decoded->src.addr_mode = decoded->dst.addr_mode = MODE_AREG_POSTINC;
1302 decoded->src.params.regs.pri = decoded->dst.params.regs.pri;
1303 decoded->dst.params.regs.pri = reg;
1304 } else if (!m68k_valid_immed_limited_dst(&decoded->dst)){
1305 decoded->op = M68K_INVALID;
1306 break;
1307 } else {
1308 //EOR
1309 decoded->op = M68K_EOR;
1310 decoded->src.addr_mode = MODE_REG;
1311 decoded->src.params.regs.pri = reg;
1312 }
1313 }
1314 } else {
1315 //CMP or CMPA.w
1316 if (size == OPSIZE_INVALID) {
1317 decoded->extra.size = OPSIZE_WORD;
1318 decoded->dst.addr_mode = MODE_AREG;
1319 } else {
1320 decoded->extra.size = size;
1321 decoded->dst.addr_mode = MODE_REG;
1322 }
1323 decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1324 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
1325 if (!istream || (decoded->src.addr_mode == MODE_AREG && decoded->extra.size == OPSIZE_BYTE)) {
1326 decoded->op = M68K_INVALID;
1327 break;
1328 }
1329 }
1330 break;
1331 case AND_MUL_ABCD_EXG:
1332 //page 575 for summary
1333 //EXG opmodes:
1334 //01000 -data regs
1335 //01001 -addr regs
1336 //10001 -one of each
1337 //AND opmodes:
1338 //operand order bit + 2 size bits (00 - 10)
1339 //no address register direct addressing
1340 //data register direct not allowed when <ea> is the source (operand order bit of 1)
1341 if (*istream & 0x100) {
1342 if ((*istream & 0xC0) == 0xC0) {
1343 decoded->op = M68K_MULS;
1344 decoded->extra.size = OPSIZE_WORD;
1345 decoded->dst.addr_mode = MODE_REG;
1346 decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1347 istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
1348 if (!istream || decoded->src.addr_mode == MODE_AREG) {
1349 decoded->op = M68K_INVALID;
1350 break;
1351 }
1352 } else if(!(*istream & 0xF0)) {
1353 decoded->op = M68K_ABCD;
1354 decoded->extra.size = OPSIZE_BYTE;
1355 decoded->src.params.regs.pri = *istream & 0x7;
1356 decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1357 decoded->dst.addr_mode = decoded->src.addr_mode = (*istream & 8) ? MODE_AREG_PREDEC : MODE_REG;
1358 } else if(!(*istream & 0x30)) {
1359 decoded->op = M68K_EXG;
1360 decoded->extra.size = OPSIZE_LONG;
1361 decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
1362 decoded->dst.params.regs.pri = *istream & 0x7;
1363 if (*istream & 0x8) {
1364 if (*istream & 0x80) {
1365 decoded->src.addr_mode = MODE_REG;
1366 decoded->dst.addr_mode = MODE_AREG;
1367 } else {
1368 decoded->src.addr_mode = decoded->dst.addr_mode = MODE_AREG;
1369 }
1370 } else if (*istream & 0x40) {
1371 decoded->src.addr_mode = decoded->dst.addr_mode = MODE_REG;
1372 } else {
1373 decoded->op = M68K_INVALID;
1374 break;
1375 }
1376 } else {
1377 decoded->op = M68K_AND;
1378 decoded->extra.size = (*istream >> 6) & 0x3;
1379 decoded->src.addr_mode = MODE_REG;
1380 decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
1381 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst));
1382 if (!istream || !m68k_valid_full_arith_dst(&(decoded->dst))) {
1383 decoded->op = M68K_INVALID;
1384 break;
1385 }
1386 }
1387 } else {
1388 if ((*istream & 0xC0) == 0xC0) {
1389 decoded->op = M68K_MULU;
1390 decoded->extra.size = OPSIZE_WORD;
1391 decoded->dst.addr_mode = MODE_REG;
1392 decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1393 istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
1394 if (!istream || decoded->src.addr_mode == MODE_AREG) {
1395 decoded->op = M68K_INVALID;
1396 break;
1397 }
1398 } else {
1399 decoded->op = M68K_AND;
1400 decoded->extra.size = (*istream >> 6) & 0x3;
1401 decoded->dst.addr_mode = MODE_REG;
1402 decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1403 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
1404 if (!istream || decoded->src.addr_mode == MODE_AREG) {
1405 decoded->op = M68K_INVALID;
1406 break;
1407 }
1408 }
1409 }
1410 break;
1411 case ADD_ADDX:
1412 size = (*istream >> 6) & 0x3;
1413 decoded->op = M68K_ADD;
1414 if (*istream & 0x100) {
1415 //<ea> destination, ADDA.l or ADDX
1416 if (*istream & 0x30 || size == OPSIZE_INVALID) {
1417 if (size == OPSIZE_INVALID) {
1418 //ADDA.l
1419 decoded->extra.size = OPSIZE_LONG;
1420 decoded->dst.addr_mode = MODE_AREG;
1421 decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1422 istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src));
1423 if (!istream) {
1424 decoded->op = M68K_INVALID;
1425 break;
1426 }
1427 } else {
1428 decoded->extra.size = size;
1429 decoded->src.addr_mode = MODE_REG;
1430 decoded->src.params.regs.pri = m68k_reg_quick_field(*istream);
1431 istream = m68k_decode_op(istream, size, &(decoded->dst));
1432 if (!istream || !m68k_valid_full_arith_dst(&decoded->dst)) {
1433 decoded->op = M68K_INVALID;
1434 break;
1435 }
1436 }
1437 } else {
1438 //ADDX
1439 decoded->op = M68K_ADDX;
1440 decoded->extra.size = size;
1441 decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1442 decoded->src.params.regs.pri = *istream & 0x7;
1443 if (*istream & 0x8) {
1444 decoded->dst.addr_mode = decoded->src.addr_mode = MODE_AREG_PREDEC;
1445 } else {
1446 decoded->dst.addr_mode = decoded->src.addr_mode = MODE_REG;
1447 }
1448 }
1449 } else {
1450 if (size == OPSIZE_INVALID) {
1451 //ADDA.w
1452 decoded->extra.size = OPSIZE_WORD;
1453 decoded->dst.addr_mode = MODE_AREG;
1454 } else {
1455 decoded->extra.size = size;
1456 decoded->dst.addr_mode = MODE_REG;
1457 }
1458 decoded->dst.params.regs.pri = m68k_reg_quick_field(*istream);
1459 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
1460 if (!istream || (decoded->src.addr_mode == MODE_AREG && decoded->extra.size == OPSIZE_BYTE)) {
1461 decoded->op = M68K_INVALID;
1462 break;
1463 }
1464 }
1465 break;
1466 case SHIFT_ROTATE:
1467 if ((*istream & 0x8C0) == 0xC0) {
1468 switch((*istream >> 8) & 0x7)
1469 {
1470 case 0:
1471 decoded->op = M68K_ASR;
1472 break;
1473 case 1:
1474 decoded->op = M68K_ASL;
1475 break;
1476 case 2:
1477 decoded->op = M68K_LSR;
1478 break;
1479 case 3:
1480 decoded->op = M68K_LSL;
1481 break;
1482 case 4:
1483 decoded->op = M68K_ROXR;
1484 break;
1485 case 5:
1486 decoded->op = M68K_ROXL;
1487 break;
1488 case 6:
1489 decoded->op = M68K_ROR;
1490 break;
1491 case 7:
1492 decoded->op = M68K_ROL;
1493 break;
1494 }
1495 decoded->extra.size = OPSIZE_WORD;
1496 istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->dst));
1497 if (!istream || !m68k_valid_full_arith_dst(&decoded->dst)) {
1498 decoded->op = M68K_INVALID;
1499 break;
1500 }
1501 } else if((*istream & 0xC0) != 0xC0) {
1502 switch(((*istream >> 2) & 0x6) | ((*istream >> 8) & 1))
1503 {
1504 case 0:
1505 decoded->op = M68K_ASR;
1506 break;
1507 case 1:
1508 decoded->op = M68K_ASL;
1509 break;
1510 case 2:
1511 decoded->op = M68K_LSR;
1512 break;
1513 case 3:
1514 decoded->op = M68K_LSL;
1515 break;
1516 case 4:
1517 decoded->op = M68K_ROXR;
1518 break;
1519 case 5:
1520 decoded->op = M68K_ROXL;
1521 break;
1522 case 6:
1523 decoded->op = M68K_ROR;
1524 break;
1525 case 7:
1526 decoded->op = M68K_ROL;
1527 break;
1528 }
1529 decoded->extra.size = (*istream >> 6) & 0x3;
1530 immed = (*istream >> 9) & 0x7;
1531 if (*istream & 0x20) {
1532 decoded->src.addr_mode = MODE_REG;
1533 decoded->src.params.regs.pri = immed;
1534 } else {
1535 decoded->src.addr_mode = MODE_IMMEDIATE;
1536 if (!immed) {
1537 immed = 8;
1538 }
1539 decoded->src.params.immed = immed;
1540 decoded->variant = VAR_QUICK;
1541 }
1542 decoded->dst.addr_mode = MODE_REG;
1543 decoded->dst.params.regs.pri = *istream & 0x7;
1544
1545 } else {
1546#ifdef M68020
1547 //TODO: Implement bitfield instructions for M68020+ support
1548 switch (*istream >> 8 & 7)
1549 {
1550 case 0:
1551 decoded->op = M68K_BFTST; //<ea>
1552 break;
1553 case 1:
1554 decoded->op = M68K_BFEXTU; //<ea>, Dn
1555 break;
1556 case 2:
1557 decoded->op = M68K_BFCHG; //<ea>
1558 break;
1559 case 3:
1560 decoded->op = M68K_BFEXTS; //<ea>, Dn
1561 break;
1562 case 4:
1563 decoded->op = M68K_BFCLR; //<ea>
1564 break;
1565 case 5:
1566 decoded->op = M68K_BFFFO; //<ea>, Dn
1567 break;
1568 case 6:
1569 decoded->op = M68K_BFSET; //<ea>
1570 break;
1571 case 7:
1572 decoded->op = M68K_BFINS; //Dn, <ea>
1573 break;
1574 }
1575 opmode = *istream >> 3 & 0x7;
1576 reg = *istream & 0x7;
1577 m68k_op_info *ea, *other;
1578 if (decoded->op == M68K_BFEXTU || decoded->op == M68K_BFEXTS || decoded->op == M68K_BFFFO)
1579 {
1580 ea = &(decoded->src);
1581 other = &(decoded->dst);
1582 } else {
1583 ea = &(decoded->dst);
1584 other = &(decoded->dst);
1585 }
1586 if (*istream & 0x100)
1587 {
1588 immed = *(istream++);
1589 other->addr_mode = MODE_REG;
1590 other->params.regs.pri = immed >> 12 & 0x7;
1591 } else {
1592 immed = *(istream++);
1593 }
1594 decoded->extra.size = OPSIZE_UNSIZED;
1595 istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, ea);
1596 ea->addr_mode |= M68K_FLAG_BITFIELD;
1597 ea->bitfield = immed & 0xFFF;
1598#endif
1599 }
1600 break;
1601 case F_LINE:
1602 //TODO: Decode FPU instructions for members of the 68K family with an FPU
1603 decoded->op = M68K_F_LINE_TRAP;
1604 break;
1605 }
1606 if (decoded->op == M68K_INVALID) {
1607 decoded->src.params.immed = *start;
1608 decoded->bytes = 2;
1609 return start + 1;
1610 }
1611 decoded->bytes = 2 * (istream + 1 - start);
1612 return istream+1;
1613}
1614
1615uint32_t m68k_branch_target(m68kinst * inst, uint32_t *dregs, uint32_t *aregs)
1616{
1617 if(inst->op == M68K_BCC || inst->op == M68K_BSR || inst->op == M68K_DBCC) {
1618 return inst->address + 2 + inst->src.params.immed;
1619 } else if(inst->op == M68K_JMP || inst->op == M68K_JSR) {
1620 uint32_t ret = 0;
1621 switch(inst->src.addr_mode)
1622 {
1623 case MODE_AREG_INDIRECT:
1624 ret = aregs[inst->src.params.regs.pri];
1625 break;
1626 case MODE_AREG_DISPLACE:
1627 ret = aregs[inst->src.params.regs.pri] + inst->src.params.regs.displacement;
1628 break;
1629 case MODE_AREG_INDEX_DISP8: {
1630 uint8_t sec_reg = inst->src.params.regs.sec >> 1 & 0x7;
1631 ret = aregs[inst->src.params.regs.pri];
1632 uint32_t * regfile = inst->src.params.regs.sec & 0x10 ? aregs : dregs;
1633 if (inst->src.params.regs.sec & 1) {
1634 //32-bit index register
1635 ret += regfile[sec_reg];
1636 } else {
1637 //16-bit index register
1638 if (regfile[sec_reg] & 0x8000) {
1639 ret += (0xFFFF0000 | regfile[sec_reg]);
1640 } else {
1641 ret += regfile[sec_reg];
1642 }
1643 }
1644 ret += inst->src.params.regs.displacement;
1645 break;
1646 }
1647 case MODE_PC_DISPLACE:
1648 ret = inst->src.params.regs.displacement + inst->address + 2;
1649 break;
1650 case MODE_PC_INDEX_DISP8: {
1651 uint8_t sec_reg = inst->src.params.regs.sec >> 1 & 0x7;
1652 ret = inst->address + 2;
1653 uint32_t * regfile = inst->src.params.regs.sec & 0x10 ? aregs : dregs;
1654 if (inst->src.params.regs.sec & 1) {
1655 //32-bit index register
1656 ret += regfile[sec_reg];
1657 } else {
1658 //16-bit index register
1659 if (regfile[sec_reg] & 0x8000) {
1660 ret += (0xFFFF0000 | regfile[sec_reg]);
1661 } else {
1662 ret += regfile[sec_reg];
1663 }
1664 }
1665 ret += inst->src.params.regs.displacement;
1666 break;
1667 }
1668 case MODE_ABSOLUTE:
1669 case MODE_ABSOLUTE_SHORT:
1670 ret = inst->src.params.immed;
1671 break;
1672 }
1673 return ret;
1674 }
1675 return 0;
1676}
1677
1678uint8_t m68k_is_branch(m68kinst * inst)
1679{
1680 return (inst->op == M68K_BCC && inst->extra.cond != COND_FALSE)
1681 || (inst->op == M68K_DBCC && inst->extra.cond != COND_TRUE)
1682 || inst->op == M68K_BSR || inst->op == M68K_JMP || inst->op == M68K_JSR;
1683}
1684
1685uint8_t m68k_is_noncall_branch(m68kinst * inst)
1686{
1687 return m68k_is_branch(inst) && inst->op != M68K_BSR && inst->op != M68K_JSR;
1688}
1689
1690
1691char * mnemonics[] = {
1692 "abcd",
1693 "add",
1694 "addx",
1695 "and",
1696 "andi",//ccr
1697 "andi",//sr
1698 "asl",
1699 "asr",
1700 "bcc",
1701 "bchg",
1702 "bclr",
1703 "bset",
1704 "bsr",
1705 "btst",
1706 "chk",
1707 "clr",
1708 "cmp",
1709 "dbcc",
1710 "divs",
1711 "divu",
1712 "eor",
1713 "eori",//ccr
1714 "eori",//sr
1715 "exg",
1716 "ext",
1717 "illegal",
1718 "jmp",
1719 "jsr",
1720 "lea",
1721 "link",
1722 "lsl",
1723 "lsr",
1724 "move",
1725 "move",//ccr
1726 "move",//from_sr
1727 "move",//sr
1728 "move",//usp
1729 "movem",
1730 "movep",
1731 "muls",
1732 "mulu",
1733 "nbcd",
1734 "neg",
1735 "negx",
1736 "nop",
1737 "not",
1738 "or",
1739 "ori",//ccr
1740 "ori",//sr
1741 "pea",
1742 "reset",
1743 "rol",
1744 "ror",
1745 "roxl",
1746 "roxr",
1747 "rte",
1748 "rtr",
1749 "rts",
1750 "sbcd",
1751 "scc",
1752 "stop",
1753 "sub",
1754 "subx",
1755 "swap",
1756 "tas",
1757 "trap",
1758 "trapv",
1759 "tst",
1760 "unlk",
1761 "invalid",
1762#ifdef M68010
1763 "bkpt",
1764 "move", //from ccr
1765 "movec",
1766 "moves",
1767 "rtd",
1768#endif
1769#ifdef M68020
1770 "bfchg",
1771 "bfclr",
1772 "bfexts",
1773 "bfextu",
1774 "bfffo",
1775 "bfins",
1776 "bfset",
1777 "bftst",
1778 "callm",
1779 "cas",
1780 "cas2",
1781 "chk2",
1782 "cmp2",
1783 "cpbcc",
1784 "cpdbcc",
1785 "cpgen",
1786 "cprestore",
1787 "cpsave",
1788 "cpscc",
1789 "cptrapcc",
1790 "divsl",
1791 "divul",
1792 "extb",
1793 "pack",
1794 "rtm",
1795 "trapcc",
1796 "unpk"
1797#endif
1798};
1799
1800char * cond_mnem[] = {
1801 "ra",
1802 "f",
1803 "hi",
1804 "ls",
1805 "cc",
1806 "cs",
1807 "ne",
1808 "eq",
1809 "vc",
1810 "vs",
1811 "pl",
1812 "mi",
1813 "ge",
1814 "lt",
1815 "gt",
1816 "le"
1817};
1818#ifdef M68010
1819char * cr_mnem[] = {
1820 "SFC",
1821 "DFC",
1822#ifdef M68020
1823 "CACR",
1824#endif
1825 "USP",
1826 "VBR",
1827#ifdef M68020
1828 "CAAR",
1829 "MSP",
1830 "ISP"
1831#endif
1832};
1833#endif
1834
1835int m68k_disasm_op(m68k_op_info *decoded, char *dst, int need_comma, uint8_t labels, uint32_t address, format_label_fun label_fun, void * data)
1836{
1837 char * c = need_comma ? "," : "";
1838 int ret = 0;
1839#ifdef M68020
1840 uint8_t addr_mode = decoded->addr_mode & (~M68K_FLAG_BITFIELD);
1841#else
1842 uint8_t addr_mode = decoded->addr_mode;
1843#endif
1844 switch(addr_mode)
1845 {
1846 case MODE_REG:
1847 ret = sprintf(dst, "%s d%d", c, decoded->params.regs.pri);
1848 break;
1849 case MODE_AREG:
1850 ret = sprintf(dst, "%s a%d", c, decoded->params.regs.pri);
1851 break;
1852 case MODE_AREG_INDIRECT:
1853 ret = sprintf(dst, "%s (a%d)", c, decoded->params.regs.pri);
1854 break;
1855 case MODE_AREG_POSTINC:
1856 ret = sprintf(dst, "%s (a%d)+", c, decoded->params.regs.pri);
1857 break;
1858 case MODE_AREG_PREDEC:
1859 ret = sprintf(dst, "%s -(a%d)", c, decoded->params.regs.pri);
1860 break;
1861 case MODE_AREG_DISPLACE:
1862 ret = sprintf(dst, "%s (%d, a%d)", c, decoded->params.regs.displacement, decoded->params.regs.pri);
1863 break;
1864 case MODE_AREG_INDEX_DISP8:
1865#ifdef M68020
1866 if (decoded->params.regs.scale)
1867 {
1868 ret = sprintf(dst, "%s (%d, a%d, %c%d.%c*%d)", c, decoded->params.regs.displacement, decoded->params.regs.pri, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1869 } else {
1870#endif
1871 ret = sprintf(dst, "%s (%d, a%d, %c%d.%c)", c, decoded->params.regs.displacement, decoded->params.regs.pri, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w');
1872#ifdef M68020
1873 }
1874#endif
1875 break;
1876#ifdef M68020
1877 case MODE_AREG_INDEX_BASE_DISP:
1878 if (decoded->params.regs.disp_sizes > 1)
1879 {
1880 ret = sprintf(dst, "%s (%d.%c, a%d, %c%d.%c*%d)", c, decoded->params.regs.displacement,
1881 decoded->params.regs.disp_sizes == 2 ? 'w' : 'l', decoded->params.regs.pri,
1882 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1883 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1884 } else {
1885 ret = sprintf(dst, "%s (a%d, %c%d.%c*%d)", c, decoded->params.regs.pri,
1886 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1887 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1888 }
1889 break;
1890 case MODE_AREG_PREINDEX:
1891 switch (decoded->params.regs.disp_sizes)
1892 {
1893 case 0x11:
1894 //no base displacement or outer displacement
1895 ret = sprintf(dst, "%s ([a%d, %c%d.%c*%d])", c, decoded->params.regs.pri,
1896 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1897 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1898 break;
1899 case 0x12:
1900 case 0x13:
1901 //base displacement only
1902 ret = sprintf(dst, "%s ([%d.%c, a%d, %c%d.%c*%d])", c, decoded->params.regs.displacement,
1903 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri,
1904 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1905 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1906 break;
1907 case 0x21:
1908 case 0x31:
1909 //outer displacement only
1910 ret = sprintf(dst, "%s ([a%d, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.pri,
1911 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1912 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
1913 decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
1914 break;
1915 case 0x22:
1916 case 0x23:
1917 case 0x32:
1918 case 0x33:
1919 //both outer and inner displacement
1920 ret = sprintf(dst, "%s ([%d.%c, a%d, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement,
1921 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri,
1922 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1923 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
1924 decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
1925 break;
1926 }
1927 break;
1928 case MODE_AREG_POSTINDEX:
1929 switch (decoded->params.regs.disp_sizes)
1930 {
1931 case 0x11:
1932 //no base displacement or outer displacement
1933 ret = sprintf(dst, "%s ([a%d], %c%d.%c*%d)", c, decoded->params.regs.pri,
1934 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1935 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1936 break;
1937 case 0x12:
1938 case 0x13:
1939 //base displacement only
1940 ret = sprintf(dst, "%s ([%d.%c, a%d], %c%d.%c*%d)", c, decoded->params.regs.displacement,
1941 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri,
1942 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1943 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
1944 break;
1945 case 0x21:
1946 case 0x31:
1947 //outer displacement only
1948 ret = sprintf(dst, "%s ([a%d], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.pri,
1949 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1950 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
1951 decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
1952 break;
1953 case 0x22:
1954 case 0x23:
1955 case 0x32:
1956 case 0x33:
1957 //both outer and inner displacement
1958 ret = sprintf(dst, "%s ([%d.%c, a%d], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement,
1959 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri,
1960 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
1961 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
1962 decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
1963 break;
1964 }
1965 break;
1966 case MODE_AREG_MEM_INDIRECT:
1967 switch (decoded->params.regs.disp_sizes)
1968 {
1969 case 0x11:
1970 //no base displacement or outer displacement
1971 ret = sprintf(dst, "%s ([a%d])", c, decoded->params.regs.pri);
1972 break;
1973 case 0x12:
1974 case 0x13:
1975 //base displacement only
1976 ret = sprintf(dst, "%s ([%d.%c, a%d])", c, decoded->params.regs.displacement,
1977 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri);
1978 break;
1979 case 0x21:
1980 case 0x31:
1981 //outer displacement only
1982 ret = sprintf(dst, "%s ([a%d], %d.%c)", c, decoded->params.regs.pri, decoded->params.regs.outer_disp,
1983 decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
1984 break;
1985 case 0x22:
1986 case 0x23:
1987 case 0x32:
1988 case 0x33:
1989 //both outer and inner displacement
1990 ret = sprintf(dst, "%s ([%d.%c, a%d], %d.%c)", c, decoded->params.regs.displacement,
1991 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri,
1992 decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
1993 break;
1994 }
1995 break;
1996 case MODE_AREG_BASE_DISP:
1997 if (decoded->params.regs.disp_sizes > 1)
1998 {
1999 ret = sprintf(dst, "%s (%d.%c, a%d)", c, decoded->params.regs.displacement,
2000 decoded->params.regs.disp_sizes == 2 ? 'w' : 'l', decoded->params.regs.pri);
2001 } else {
2002 //this is a lossy representation of the encoded instruction
2003 //not sure if there's a better way to print it though
2004 ret = sprintf(dst, "%s (a%d)", c, decoded->params.regs.pri);
2005 }
2006 break;
2007 case MODE_INDEX_BASE_DISP:
2008 if (decoded->params.regs.disp_sizes > 1)
2009 {
2010 ret = sprintf(dst, "%s (%d.%c, %c%d.%c*%d)", c, decoded->params.regs.displacement,
2011 decoded->params.regs.disp_sizes == 2 ? 'w' : 'l',
2012 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2013 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2014 } else {
2015 ret = sprintf(dst, "%s (%c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2016 (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2017 1 << decoded->params.regs.scale);
2018 }
2019 break;
2020 case MODE_PREINDEX:
2021 switch (decoded->params.regs.disp_sizes)
2022 {
2023 case 0x11:
2024 //no base displacement or outer displacement
2025 ret = sprintf(dst, "%s ([%c%d.%c*%d])", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2026 (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2027 1 << decoded->params.regs.scale);
2028 break;
2029 case 0x12:
2030 case 0x13:
2031 //base displacement only
2032 ret = sprintf(dst, "%s ([%d.%c, %c%d.%c*%d])", c, decoded->params.regs.displacement,
2033 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2034 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2035 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2036 break;
2037 case 0x21:
2038 case 0x31:
2039 //outer displacement only
2040 ret = sprintf(dst, "%s ([%c%d.%c*%d], %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2041 (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2042 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp,
2043 decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2044 break;
2045 case 0x22:
2046 case 0x23:
2047 case 0x32:
2048 case 0x33:
2049 //both outer and inner displacement
2050 ret = sprintf(dst, "%s ([%d.%c, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement,
2051 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2052 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2053 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
2054 decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2055 break;
2056 }
2057 break;
2058 case MODE_POSTINDEX:
2059 switch (decoded->params.regs.disp_sizes)
2060 {
2061 case 0x11:
2062 //no base displacement or outer displacement
2063 ret = sprintf(dst, "%s ([], %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2064 (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2065 1 << decoded->params.regs.scale);
2066 break;
2067 case 0x12:
2068 case 0x13:
2069 //base displacement only
2070 ret = sprintf(dst, "%s ([%d.%c], %c%d.%c*%d)", c, decoded->params.regs.displacement,
2071 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2072 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2073 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2074 break;
2075 case 0x21:
2076 case 0x31:
2077 //outer displacement only
2078 ret = sprintf(dst, "%s ([], %c%d.%c*%d, %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2079 (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2080 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp,
2081 decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2082 break;
2083 case 0x22:
2084 case 0x23:
2085 case 0x32:
2086 case 0x33:
2087 //both outer and inner displacement
2088 ret = sprintf(dst, "%s ([%d.%c], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement,
2089 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2090 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2091 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
2092 decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2093 break;
2094 }
2095 break;
2096 case MODE_MEM_INDIRECT:
2097 switch (decoded->params.regs.disp_sizes)
2098 {
2099 case 0x11:
2100 //no base displacement or outer displacement
2101 ret = sprintf(dst, "%s ([])", c);
2102 break;
2103 case 0x12:
2104 case 0x13:
2105 //base displacement only
2106 ret = sprintf(dst, "%s ([%d.%c])", c, decoded->params.regs.displacement,
2107 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l');
2108 break;
2109 case 0x21:
2110 case 0x31:
2111 //outer displacement only
2112 ret = sprintf(dst, "%s ([], %d.%c)", c, decoded->params.regs.outer_disp,
2113 decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2114 break;
2115 case 0x22:
2116 case 0x23:
2117 case 0x32:
2118 case 0x33:
2119 //both outer and inner displacement
2120 ret = sprintf(dst, "%s ([%d.%c], %d.%c)", c, decoded->params.regs.displacement,
2121 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.outer_disp,
2122 decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2123 break;
2124 }
2125 break;
2126 case MODE_BASE_DISP:
2127 if (decoded->params.regs.disp_sizes > 1)
2128 {
2129 ret = sprintf(dst, "%s (%d.%c)", c, decoded->params.regs.displacement,
2130 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l');
2131 } else {
2132 ret = sprintf(dst, "%s ()", c);
2133 }
2134 break;
2135#endif
2136 case MODE_IMMEDIATE:
2137 case MODE_IMMEDIATE_WORD:
2138 ret = sprintf(dst, (decoded->params.immed <= 128 ? "%s #%d" : "%s #$%X"), c, decoded->params.immed);
2139 break;
2140 case MODE_ABSOLUTE_SHORT:
2141 if (labels) {
2142 ret = sprintf(dst, "%s ", c);
2143 ret += label_fun(dst+ret, decoded->params.immed, data);
2144 strcat(dst+ret, ".w");
2145 ret = ret + 2;
2146 } else {
2147 ret = sprintf(dst, "%s $%X.w", c, decoded->params.immed);
2148 }
2149 break;
2150 case MODE_ABSOLUTE:
2151 if (labels) {
2152 ret = sprintf(dst, "%s ", c);
2153 ret += label_fun(dst+ret, decoded->params.immed, data);
2154 strcat(dst+ret, ".l");
2155 ret = ret + 2;
2156 } else {
2157 ret = sprintf(dst, "%s $%X", c, decoded->params.immed);
2158 }
2159 break;
2160 case MODE_PC_DISPLACE:
2161 if (labels) {
2162 ret = sprintf(dst, "%s ", c);
2163 ret += label_fun(dst+ret, address + 2 + decoded->params.regs.displacement, data);
2164 strcat(dst+ret, "(pc)");
2165 ret = ret + 4;
2166 } else {
2167 ret = sprintf(dst, "%s (%d, pc)", c, decoded->params.regs.displacement);
2168 }
2169 break;
2170 case MODE_PC_INDEX_DISP8:
2171#ifdef M68020
2172 if (decoded->params.regs.scale)
2173 {
2174 ret = sprintf(dst, "%s (%d, pc, %c%d.%c*%d)", c, decoded->params.regs.displacement, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2175 } else {
2176#endif
2177 ret = sprintf(dst, "%s (%d, pc, %c%d.%c)", c, decoded->params.regs.displacement, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w');
2178#ifdef M68020
2179 }
2180#endif
2181 break;
2182#ifdef M68020
2183 case MODE_PC_INDEX_BASE_DISP:
2184 if (decoded->params.regs.disp_sizes > 1)
2185 {
2186 ret = sprintf(dst, "%s (%d.%c, pc, %c%d.%c*%d)", c, decoded->params.regs.displacement,
2187 decoded->params.regs.disp_sizes == 2 ? 'w' : 'l',
2188 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2189 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2190 } else {
2191 ret = sprintf(dst, "%s (pc, %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2192 (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2193 1 << decoded->params.regs.scale);
2194 }
2195 break;
2196 case MODE_PC_PREINDEX:
2197 switch (decoded->params.regs.disp_sizes)
2198 {
2199 case 0x11:
2200 //no base displacement or outer displacement
2201 ret = sprintf(dst, "%s ([pc, %c%d.%c*%d])", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2202 (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2203 1 << decoded->params.regs.scale);
2204 break;
2205 case 0x12:
2206 case 0x13:
2207 //base displacement only
2208 ret = sprintf(dst, "%s ([%d.%c, pc, %c%d.%c*%d])", c, decoded->params.regs.displacement,
2209 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2210 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2211 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2212 break;
2213 case 0x21:
2214 case 0x31:
2215 //outer displacement only
2216 ret = sprintf(dst, "%s ([pc, %c%d.%c*%d], %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2217 (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2218 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp,
2219 decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2220 break;
2221 case 0x22:
2222 case 0x23:
2223 case 0x32:
2224 case 0x33:
2225 //both outer and inner displacement
2226 ret = sprintf(dst, "%s ([%d.%c, pc, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement,
2227 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2228 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2229 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
2230 decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2231 break;
2232 }
2233 break;
2234 case MODE_PC_POSTINDEX:
2235 switch (decoded->params.regs.disp_sizes)
2236 {
2237 case 0x11:
2238 //no base displacement or outer displacement
2239 ret = sprintf(dst, "%s ([pc], %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2240 (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2241 1 << decoded->params.regs.scale);
2242 break;
2243 case 0x12:
2244 case 0x13:
2245 //base displacement only
2246 ret = sprintf(dst, "%s ([%d.%c, pc], %c%d.%c*%d)", c, decoded->params.regs.displacement,
2247 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2248 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2249 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2250 break;
2251 case 0x21:
2252 case 0x31:
2253 //outer displacement only
2254 ret = sprintf(dst, "%s ([pc], %c%d.%c*%d, %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2255 (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2256 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp,
2257 decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2258 break;
2259 case 0x22:
2260 case 0x23:
2261 case 0x32:
2262 case 0x33:
2263 //both outer and inner displacement
2264 ret = sprintf(dst, "%s ([%d.%c, pc], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement,
2265 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2266 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2267 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
2268 decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2269 break;
2270 }
2271 break;
2272 case MODE_PC_MEM_INDIRECT:
2273 switch (decoded->params.regs.disp_sizes)
2274 {
2275 case 0x11:
2276 //no base displacement or outer displacement
2277 ret = sprintf(dst, "%s ([pc])", c);
2278 break;
2279 case 0x12:
2280 case 0x13:
2281 //base displacement only
2282 ret = sprintf(dst, "%s ([%d.%c, pc])", c, decoded->params.regs.displacement,
2283 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l');
2284 break;
2285 case 0x21:
2286 case 0x31:
2287 //outer displacement only
2288 ret = sprintf(dst, "%s ([pc], %d.%c)", c, decoded->params.regs.outer_disp,
2289 decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2290 break;
2291 case 0x22:
2292 case 0x23:
2293 case 0x32:
2294 case 0x33:
2295 //both outer and inner displacement
2296 ret = sprintf(dst, "%s ([%d.%c, pc], %d.%c)", c, decoded->params.regs.displacement,
2297 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.outer_disp,
2298 decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2299 break;
2300 }
2301 break;
2302 case MODE_PC_BASE_DISP:
2303 if (decoded->params.regs.disp_sizes > 1)
2304 {
2305 ret = sprintf(dst, "%s (%d.%c, pc)", c, decoded->params.regs.displacement,
2306 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l');
2307 } else {
2308 ret = sprintf(dst, "%s (pc)", c);
2309 }
2310 break;
2311 case MODE_ZPC_INDEX_BASE_DISP:
2312 if (decoded->params.regs.disp_sizes > 1)
2313 {
2314 ret = sprintf(dst, "%s (%d.%c, zpc, %c%d.%c*%d)", c, decoded->params.regs.displacement,
2315 decoded->params.regs.disp_sizes == 2 ? 'w' : 'l',
2316 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2317 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2318 } else {
2319 ret = sprintf(dst, "%s (zpc, %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2320 (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2321 1 << decoded->params.regs.scale);
2322 }
2323 break;
2324 case MODE_ZPC_PREINDEX:
2325 switch (decoded->params.regs.disp_sizes)
2326 {
2327 case 0x11:
2328 //no base displacement or outer displacement
2329 ret = sprintf(dst, "%s ([zpc, %c%d.%c*%d])", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2330 (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2331 1 << decoded->params.regs.scale);
2332 break;
2333 case 0x12:
2334 case 0x13:
2335 //base displacement only
2336 ret = sprintf(dst, "%s ([%d.%c, zpc, %c%d.%c*%d])", c, decoded->params.regs.displacement,
2337 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2338 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2339 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2340 break;
2341 case 0x21:
2342 case 0x31:
2343 //outer displacement only
2344 ret = sprintf(dst, "%s ([zpc, %c%d.%c*%d], %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2345 (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2346 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp,
2347 decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2348 break;
2349 case 0x22:
2350 case 0x23:
2351 case 0x32:
2352 case 0x33:
2353 //both outer and inner displacement
2354 ret = sprintf(dst, "%s ([%d.%c, zpc, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement,
2355 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2356 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2357 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
2358 decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2359 break;
2360 }
2361 break;
2362 case MODE_ZPC_POSTINDEX:
2363 switch (decoded->params.regs.disp_sizes)
2364 {
2365 case 0x11:
2366 //no base displacement or outer displacement
2367 ret = sprintf(dst, "%s ([zpc], %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2368 (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2369 1 << decoded->params.regs.scale);
2370 break;
2371 case 0x12:
2372 case 0x13:
2373 //base displacement only
2374 ret = sprintf(dst, "%s ([%d.%c, zpc], %c%d.%c*%d)", c, decoded->params.regs.displacement,
2375 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2376 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2377 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale);
2378 break;
2379 case 0x21:
2380 case 0x31:
2381 //outer displacement only
2382 ret = sprintf(dst, "%s ([zpc], %c%d.%c*%d, %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd',
2383 (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w',
2384 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp,
2385 decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2386 break;
2387 case 0x22:
2388 case 0x23:
2389 case 0x32:
2390 case 0x33:
2391 //both outer and inner displacement
2392 ret = sprintf(dst, "%s ([%d.%c, zpc], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement,
2393 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l',
2394 (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7,
2395 (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale,
2396 decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2397 break;
2398 }
2399 break;
2400 case MODE_ZPC_MEM_INDIRECT:
2401 switch (decoded->params.regs.disp_sizes)
2402 {
2403 case 0x11:
2404 //no base displacement or outer displacement
2405 ret = sprintf(dst, "%s ([zpc])", c);
2406 break;
2407 case 0x12:
2408 case 0x13:
2409 //base displacement only
2410 ret = sprintf(dst, "%s ([%d.%c, zpc])", c, decoded->params.regs.displacement,
2411 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l');
2412 break;
2413 case 0x21:
2414 case 0x31:
2415 //outer displacement only
2416 ret = sprintf(dst, "%s ([zpc], %d.%c)", c, decoded->params.regs.outer_disp,
2417 decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2418 break;
2419 case 0x22:
2420 case 0x23:
2421 case 0x32:
2422 case 0x33:
2423 //both outer and inner displacement
2424 ret = sprintf(dst, "%s ([%d.%c, zpc], %d.%c)", c, decoded->params.regs.displacement,
2425 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.outer_disp,
2426 decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l');
2427 break;
2428 }
2429 break;
2430 case MODE_ZPC_BASE_DISP:
2431 if (decoded->params.regs.disp_sizes > 1)
2432 {
2433 ret = sprintf(dst, "%s (%d.%c, zpc)", c, decoded->params.regs.displacement,
2434 decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l');
2435 } else {
2436 ret = sprintf(dst, "%s (zpc)", c);
2437 }
2438 break;
2439#endif
2440 default:
2441 ret = 0;
2442 }
2443#ifdef M68020
2444 if (decoded->addr_mode & M68K_FLAG_BITFIELD)
2445 {
2446 switch (decoded->bitfield & 0x820)
2447 {
2448 case 0:
2449 return ret + sprintf(dst+ret, " {$%X:%d}", decoded->bitfield >> 6 & 0x1F, decoded->bitfield & 0x1F ? decoded->bitfield & 0x1F : 32);
2450 case 0x20:
2451 return ret + sprintf(dst+ret, " {$%X:d%d}", decoded->bitfield >> 6 & 0x1F, decoded->bitfield & 0x7);
2452 case 0x800:
2453 return ret + sprintf(dst+ret, " {d%d:%d}", decoded->bitfield >> 6 & 0x7, decoded->bitfield & 0x1F ? decoded->bitfield & 0x1F : 32);
2454 case 0x820:
2455 return ret + sprintf(dst+ret, " {d%d:d%d}", decoded->bitfield >> 6 & 0x7, decoded->bitfield & 0x7);
2456 }
2457 }
2458#endif
2459 return ret;
2460}
2461
2462int m68k_disasm_movem_op(m68k_op_info *decoded, m68k_op_info *other, char *dst, int need_comma, uint8_t labels, uint32_t address, format_label_fun label_fun, void * data)
2463{
2464 int8_t dir, reg, bit, regnum, last=-1, lastreg, first=-1;
2465 char *rtype, *last_rtype;
2466 int oplen;
2467 if (decoded->addr_mode == MODE_REG) {
2468 if (other->addr_mode == MODE_AREG_PREDEC) {
2469 bit = 15;
2470 dir = -1;
2471 } else {
2472 dir = 1;
2473 bit = 0;
2474 }
2475 if (need_comma) {
2476 strcat(dst, ", ");
2477 oplen = 2;
2478 } else {
2479 strcat(dst, " ");
2480 oplen = 1;
2481 }
2482 for (reg=0; bit < 16 && bit > -1; bit += dir, reg++) {
2483 if (decoded->params.immed & (1 << bit)) {
2484 if (reg > 7) {
2485 rtype = "a";
2486 regnum = reg - 8;
2487 } else {
2488 rtype = "d";
2489 regnum = reg;
2490 }
2491 if (last >= 0 && last == regnum - 1 && lastreg == reg - 1) {
2492 last = regnum;
2493 lastreg = reg;
2494 } else if(last >= 0) {
2495 if (first != last) {
2496 oplen += sprintf(dst + oplen, "-%s%d/%s%d",last_rtype, last, rtype, regnum);
2497 } else {
2498 oplen += sprintf(dst + oplen, "/%s%d", rtype, regnum);
2499 }
2500 first = last = regnum;
2501 last_rtype = rtype;
2502 lastreg = reg;
2503 } else {
2504 oplen += sprintf(dst + oplen, "%s%d", rtype, regnum);
2505 first = last = regnum;
2506 last_rtype = rtype;
2507 lastreg = reg;
2508 }
2509 }
2510 }
2511 if (last >= 0 && last != first) {
2512 oplen += sprintf(dst + oplen, "-%s%d", last_rtype, last);
2513 }
2514 return oplen;
2515 } else {
2516 return m68k_disasm_op(decoded, dst, need_comma, labels, address, label_fun, data);
2517 }
2518}
2519
2520int m68k_default_label_fun(char * dst, uint32_t address, void * data)
2521{
2522 return sprintf(dst, "ADR_%X", address);
2523}
2524
2525int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels, format_label_fun label_fun, void * data)
2526{
2527 int ret,op1len;
2528 uint8_t size;
2529 char * special_op = "CCR";
2530 switch (decoded->op)
2531 {
2532 case M68K_BCC:
2533 case M68K_DBCC:
2534 case M68K_SCC:
2535 ret = strlen(mnemonics[decoded->op]) - 2;
2536 memcpy(dst, mnemonics[decoded->op], ret);
2537 dst[ret] = 0;
2538 strcpy(dst+ret, cond_mnem[decoded->extra.cond]);
2539 ret = strlen(dst);
2540 if (decoded->op != M68K_SCC) {
2541 if (labels) {
2542 if (decoded->op == M68K_DBCC) {
2543 ret += sprintf(dst+ret, " d%d, ", decoded->dst.params.regs.pri);
2544 ret += label_fun(dst+ret, decoded->address + 2 + decoded->src.params.immed, data);
2545 } else {
2546 dst[ret++] = ' ';
2547 ret += label_fun(dst+ret, decoded->address + 2 + decoded->src.params.immed, data);
2548 }
2549 } else {
2550 if (decoded->op == M68K_DBCC) {
2551 ret += sprintf(dst+ret, " d%d, #%d <%X>", decoded->dst.params.regs.pri, decoded->src.params.immed, decoded->address + 2 + decoded->src.params.immed);
2552 } else {
2553 ret += sprintf(dst+ret, " #%d <%X>", decoded->src.params.immed, decoded->address + 2 + decoded->src.params.immed);
2554 }
2555 }
2556 return ret;
2557 }
2558 break;
2559 case M68K_BSR:
2560 if (labels) {
2561 ret = sprintf(dst, "bsr%s ", decoded->variant == VAR_BYTE ? ".s" : "");
2562 ret += label_fun(dst+ret, decoded->address + 2 + decoded->src.params.immed, data);
2563 } else {
2564 ret = sprintf(dst, "bsr%s #%d <%X>", decoded->variant == VAR_BYTE ? ".s" : "", decoded->src.params.immed, decoded->address + 2 + decoded->src.params.immed);
2565 }
2566 return ret;
2567 case M68K_MOVE_FROM_SR:
2568 ret = sprintf(dst, "%s", mnemonics[decoded->op]);
2569 ret += sprintf(dst + ret, " SR");
2570 ret += m68k_disasm_op(&(decoded->dst), dst + ret, 1, labels, decoded->address, label_fun, data);
2571 return ret;
2572 case M68K_ANDI_SR:
2573 case M68K_EORI_SR:
2574 case M68K_MOVE_SR:
2575 case M68K_ORI_SR:
2576 special_op = "SR";
2577 case M68K_ANDI_CCR:
2578 case M68K_EORI_CCR:
2579 case M68K_MOVE_CCR:
2580 case M68K_ORI_CCR:
2581 ret = sprintf(dst, "%s", mnemonics[decoded->op]);
2582 ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data);
2583 ret += sprintf(dst + ret, ", %s", special_op);
2584 return ret;
2585 case M68K_MOVE_USP:
2586 ret = sprintf(dst, "%s", mnemonics[decoded->op]);
2587 if (decoded->src.addr_mode != MODE_UNUSED) {
2588 ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data);
2589 ret += sprintf(dst + ret, ", USP");
2590 } else {
2591 ret += sprintf(dst + ret, "USP, ");
2592 ret += m68k_disasm_op(&(decoded->dst), dst + ret, 0, labels, decoded->address, label_fun, data);
2593 }
2594 return ret;
2595 case M68K_INVALID:
2596 ret = sprintf(dst, "dc.w $%X", decoded->src.params.immed);
2597 return ret;
2598#ifdef M68010
2599 case M68K_MOVEC:
2600 ret = sprintf(dst, "%s ", mnemonics[decoded->op]);
2601 if (decoded->src.addr_mode == MODE_UNUSED) {
2602 ret += sprintf(dst + ret, "%s, ", cr_mnem[decoded->src.params.immed]);
2603 ret += m68k_disasm_op(&(decoded->dst), dst + ret, 0, labels, decoded->address, label_fun, data);
2604 } else {
2605 ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data);
2606 ret += sprintf(dst + ret, ", %s", cr_mnem[decoded->dst.params.immed]);
2607 }
2608 return ret;
2609#endif
2610 default:
2611 size = decoded->extra.size;
2612 uint8_t is_quick = decoded->variant == VAR_QUICK && decoded->op != M68K_ASL && decoded->op != M68K_ASR
2613 && decoded->op != M68K_LSL && decoded->op != M68K_LSR && decoded->op != M68K_ROXR && decoded->op != M68K_ROXL
2614 && decoded->op != M68K_ROR && decoded->op != M68K_ROL;
2615 ret = sprintf(dst, "%s%s%s",
2616 mnemonics[decoded->op],
2617 is_quick ? "q" : (decoded->variant == VAR_IMMEDIATE ? "i" : ""),
2618 size == OPSIZE_BYTE ? ".b" : (size == OPSIZE_WORD ? ".w" : (size == OPSIZE_LONG ? ".l" : "")));
2619 }
2620 if (decoded->op == M68K_MOVEM) {
2621 op1len = m68k_disasm_movem_op(&(decoded->src), &(decoded->dst), dst + ret, 0, labels, decoded->address, label_fun, data);
2622 ret += op1len;
2623 ret += m68k_disasm_movem_op(&(decoded->dst), &(decoded->src), dst + ret, op1len, labels, decoded->address, label_fun, data);
2624 } else {
2625 op1len = m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data);
2626 ret += op1len;
2627 ret += m68k_disasm_op(&(decoded->dst), dst + ret, op1len, labels, decoded->address, label_fun, data);
2628 }
2629 return ret;
2630}
2631
2632int m68k_disasm(m68kinst * decoded, char * dst)
2633{
2634 return m68k_disasm_ex(decoded, dst, 0, NULL, NULL);
2635}
2636
2637int m68k_disasm_labels(m68kinst * decoded, char * dst, format_label_fun label_fun, void * data)
2638{
2639 if (!label_fun)
2640 {
2641 label_fun = m68k_default_label_fun;
2642 }
2643 return m68k_disasm_ex(decoded, dst, 1, label_fun, data);
2644}