comparison 68kinst.c @ 2:5df303bf72e6

Improve 68K instruction decoding. Add simple disassembler.
author Mike Pavone <pavone@retrodev.com>
date Sat, 03 Nov 2012 21:38:28 -0700
parents 2432d177e1ac
children a4ad0e3e3e0e
comparison
equal deleted inserted replaced
1:5a2c1da6dd0f 2:5df303bf72e6
1 #include "68kinst.h" 1 #include "68kinst.h"
2 2 #include <string.h>
3 void m68k_decode_op(uint16_t op, m68k_op_info *dst) 3 #include <stdio.h>
4 { 4
5 uint8_t mode = (op >> 3) & 0x7; 5 uint32_t sign_extend16(uint32_t val)
6 uint8_t reg = op & 0x7; 6 {
7 return (val & 0x8000) ? val | 0xFFFF0000 : val;
8 }
9
10 uint32_t sign_extend8(uint32_t val)
11 {
12 return (val & 0x80) ? val | 0xFFFFFF00 : val;
13 }
14
15 uint16_t *m68k_decode_op_ex(uint16_t *cur, uint8_t mode, uint8_t reg, uint8_t size, m68k_op_info *dst)
16 {
17 uint16_t ext;
7 dst->addr_mode = mode; 18 dst->addr_mode = mode;
8 switch(mode) 19 switch(mode)
9 { 20 {
10 case MODE_REG: 21 case MODE_REG:
11 case MODE_AREG: 22 case MODE_AREG:
23 case MODE_AREG_INDIRECT:
24 case MODE_AREG_POSTINC:
25 case MODE_AREG_PREDEC:
12 dst->params.regs.pri = reg; 26 dst->params.regs.pri = reg;
13 break; 27 break;
14 case MODE_ 28 case MODE_AREG_DISPLACE:
29 ext = *(++cur);
30 dst->params.regs.pri = reg;
31 dst->params.regs.displacement = sign_extend16(ext);
32 break;
33 case MODE_AREG_INDEX_MEM:
34 //TODO: implement me
35 break;
36 case MODE_PC_INDIRECT_ABS_IMMED:
37 switch(reg)
38 {
39 case 0:
40 dst->addr_mode = MODE_ABSOLUTE_SHORT;
41 ext = *(++cur);
42 dst->params.u32 = sign_extend16(ext);
43 break;
44 case 1:
45 dst->addr_mode = MODE_ABSOLUTE;
46 ext = *(++cur);
47 dst->params.u32 = ext << 16 | *(++cur);
48 break;
49 case 2:
50 dst->addr_mode = MODE_PC_DISPLACE;
51 ext = *(++cur);
52 dst->params.regs.displacement = sign_extend16(ext);
53 break;
54 case 4:
55 dst->addr_mode = MODE_IMMEDIATE;
56 ext = *(++cur);
57 switch (size)
58 {
59 case OPSIZE_BYTE:
60 dst->params.u8 = ext;
61 break;
62 case OPSIZE_WORD:
63 dst->params.u16 = ext;
64 break;
65 case OPSIZE_LONG:
66 dst->params.u32 = ext << 16 | *(++cur);
67 break;
68 }
69 break;
70 //TODO: implement the rest of these
71 }
72 break;
15 } 73 }
74 return cur;
75 }
76
77 uint16_t *m68k_decode_op(uint16_t *cur, uint8_t size, m68k_op_info *dst)
78 {
79 uint8_t mode = (*cur >> 3) & 0x7;
80 uint8_t reg = *cur & 0x7;
81 return m68k_decode_op_ex(cur, mode, reg, size, dst);
82 }
83
84 void m68k_decode_cond(uint16_t op, m68kinst * decoded)
85 {
86 decoded->extra.cond = (op >> 0x8) & 0xF;
87 }
88
89 uint8_t m68K_reg_quick_field(uint16_t op)
90 {
91 return (op >> 9) & 0x7;
16 } 92 }
17 93
18 uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded) 94 uint16_t * m68K_decode(uint16_t * istream, m68kinst * decoded)
19 { 95 {
20 uint8_t optype = *istream >> 12; 96 uint8_t optype = *istream >> 12;
21 uint8_t size; 97 uint8_t size;
22 uint8_t immed; 98 uint32_t immed;
99 decoded->op = M68K_INVALID;
100 decoded->src.addr_mode = decoded->dst.addr_mode = MODE_UNUSED;
101 decoded->variant = VAR_NORMAL;
23 switch(optype) 102 switch(optype)
24 { 103 {
25 case BIT_MOVEP_IMMED: 104 case BIT_MOVEP_IMMED:
26 //TODO: Implement me 105 //TODO: Implement me
27 break; 106 break;
28 case MOVE_BYTE: 107 case MOVE_BYTE:
29 case MOVE_LONG: 108 case MOVE_LONG:
30 case MOVE_WORD: 109 case MOVE_WORD:
31 decoded->op = M68K_MOVE; 110 decoded->op = M68K_MOVE;
32 decoded->extra.size = optype == MOVE_BYTE ? OPSIZE_BYTE : (optype == MOVE_WORD ? OPSIZE_WORD : OPSIZE_LONG); 111 decoded->extra.size = optype == MOVE_BYTE ? OPSIZE_BYTE : (optype == MOVE_WORD ? OPSIZE_WORD : OPSIZE_LONG);
33 m68k_decode_op(*istream, &(decoded->src)); 112 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
34 m68k_decode_op(((*istream >> 9) & 0x7) | , &(decoded->dst)); 113 istream = m68k_decode_op_ex(istream, (*istream >> 6) & 0x7, m68K_reg_quick_field(*istream), decoded->extra.size, &(decoded->dst));
35 break; 114 break;
36 case MISC: 115 case MISC:
37 //TODO: Implement me 116
117 if ((*istream & 0x1C0) == 0x1C0) {
118 decoded->op = M68K_LEA;
119 decoded->extra.size = OPSIZE_LONG;
120 decoded->dst.addr_mode = MODE_AREG;
121 decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
122 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
123 } else {
124 if (*istream & 0x100) {
125 decoded->op = M68K_CHK;
126 if ((*istream & 0x180) == 0x180) {
127 decoded->extra.size = OPSIZE_WORD;
128 } else {
129 //only on M68020+
130 decoded->extra.size = OPSIZE_LONG;
131 }
132 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
133 decoded->dst.addr_mode = MODE_REG;
134 decoded->dst.addr_mode = m68K_reg_quick_field(*istream);
135 } else {
136 optype = (*istream >> 9) & 0x7;
137 switch(optype)
138 {
139 case 0:
140 //Move from SR or NEGX
141 break;
142 case 1:
143 //MOVE from CCR or CLR
144 break;
145 case 2:
146 //MOVE to CCR or NEG
147 break;
148 case 3:
149 //MOVE to SR or NOT
150 break;
151 case 4:
152 //EXT, EXTB, LINK.l, NBCD, SWAP, BKPT, PEA, MOVEM
153 break;
154 case 5:
155 //BGND, ILLEGAL, TAS, TST
156 optype = *istream & 0xFF;
157 if (optype == 0xFA) {
158 //BGND - CPU32 only
159 } else if (optype == 0xFC) {
160 decoded->op = M68K_ILLEGAL;
161 } else {
162 size = (*istream & 0xC0) >> 6;
163 if (size == OPSIZE_INVALID) {
164 decoded->op = M68K_TAS;
165 } else {
166 decoded->op = M68K_TST;
167 decoded->extra.size = size;
168 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
169 }
170 }
171 break;
172 case 6:
173 //MULU, MULS, DIVU, DIVUL, DIVS, DIVSL, MOVEM
174 break;
175 case 7:
176 //TRAP, LINK.w, UNLNK, MOVE USP, RESET, NOP, STOP, RTE, RTD, RTS, TRAPV, RTR, MOVEC, JSR, JMP
177 if (*istream & 0x80) {
178 //JSR, JMP
179 } else {
180 //it would appear bit 6 needs to be set for it to be a valid instruction here
181 switch((*istream >> 3) & 0x7)
182 {
183 case 0:
184 case 1:
185 //TRAP
186 break;
187 case 2:
188 //LINK.w
189 break;
190 case 3:
191 //UNLNK
192 break;
193 case 4:
194 case 5:
195 //MOVE USP
196 break;
197 case 6:
198 switch(*istream & 0x7)
199 {
200 case 0:
201 decoded->op = M68K_RESET;
202 break;
203 case 1:
204 decoded->op = M68K_NOP;
205 break;
206 case 2:
207 decoded->op = M68K_STOP;
208 decoded->extra.size = OPSIZE_WORD;
209 decoded->src.addr_mode = MODE_IMMEDIATE;
210 decoded->src.params.u16 =*(++istream);
211 break;
212 case 3:
213 decoded->op = M68K_RTE;
214 break;
215 case 4:
216 #ifdef M68010
217 decoded->op = M68K_RTD;
218 decoded->extra.size = OPSIZE_WORD;
219 decoded->src.addr_mode = MODE_IMMEDIATE;
220 decoded->src.params.u16 =*(++istream);
221 #endif
222 break;
223 case 5:
224 decoded->op = M68K_RTS;
225 break;
226 case 6:
227 decoded->op = M68K_TRAPV;
228 break;
229 case 7:
230 decoded->op = M68K_RTR;
231 break;
232 }
233 break;
234 case 7:
235 //MOVEC
236 break;
237 }
238 }
239 break;
240 }
241 }
242 }
38 break; 243 break;
39 case QUICK_ARITH_LOOP: 244 case QUICK_ARITH_LOOP:
40 size = (*istream >> 6) & 3; 245 size = (*istream >> 6) & 3;
41 if (size == 0x3) { 246 if (size == 0x3) {
42 //DBcc, TRAPcc or Scc 247 //DBcc, TRAPcc or Scc
43 decoded->extra.cond = (*istream >> 0x8) & 0xF; 248 m68k_decode_cond(*istream, decoded);
44 switch ((*istream >> 3) & 0x7) 249 switch ((*istream >> 3) & 0x7)
45 { 250 {
46 case 1: //DBcc 251 case 1: //DBcc
47 decoded->op = M68K_DBCC; 252 decoded->op = M68K_DBCC;
253 decoded->src.addr_mode = MODE_IMMEDIATE;
254 decoded->src.params.u16 = *(++istream);
48 decoded->dst.addr_mode = MODE_REG; 255 decoded->dst.addr_mode = MODE_REG;
49 decoded->dst.regs.pri = *istream & 0x7; 256 decoded->dst.params.regs.pri = *istream & 0x7;
50 break; 257 break;
51 case 7: //TRAPcc 258 case 7: //TRAPcc
259 #ifdef M68020
52 decoded->op = M68K_TRAPCC; 260 decoded->op = M68K_TRAPCC;
53 decoded->src.addr_mode = MODE_PC_INDIRECT_ABS_IMMED; 261 decoded->src.addr_mode = MODE_IMMEDIATE;
54 decoded->src.regs.pri = MODE_IMMEDIATE;
55 //TODO: Figure out what to do with OPMODE and optional extention words 262 //TODO: Figure out what to do with OPMODE and optional extention words
263 #endif
56 break; 264 break;
57 default: //Scc 265 default: //Scc
58 decoded->op = M68K_SCC; 266 decoded->op = M68K_SCC;
59 M68k_decode_op(*istream, &(decoded->dst)); 267 istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst));
60 break; 268 break;
61 } 269 }
62 } else { 270 } else {
63 //ADDQ, SUBQ 271 //ADDQ, SUBQ
64 decoded->variant = VAR_QUICK; 272 decoded->variant = VAR_QUICK;
65 decoded->extra.size = size; 273 decoded->extra.size = size;
66 decoded->src.addr_mode = MODE_PC_INDIRECT_ABS_IMMED; 274 decoded->src.addr_mode = MODE_IMMEDIATE;
67 decoded->src.regs.pri = MODE_IMMEDIATE; 275 istream = m68k_decode_op(istream, size, &(decoded->dst));
68 immed = (*istream >> 9) & 0x7 276 immed = m68K_reg_quick_field(*istream);
69 if (!immed) { 277 if (!immed) {
70 immed = 8; 278 immed = 8;
71 } 279 }
72 switch (size) 280 switch (size)
73 { 281 {
74 case OPSIZE_BYTE; 282 case OPSIZE_BYTE:
75 decoded->src.params.u8 = immed; 283 decoded->src.params.u8 = immed;
76 break; 284 break;
77 case OPSIZE_WORD: 285 case OPSIZE_WORD:
78 decoded->src.params.u16 = immed; 286 decoded->src.params.u16 = immed;
79 break; 287 break;
80 case OPSIZE_LONG: 288 case OPSIZE_LONG:
81 decoded->src.params.u38 = immed; 289 decoded->src.params.u32 = immed;
82 break; 290 break;
83 } 291 }
84 if (*istream & 0x10) { 292 if (*istream & 0x100) {
85 decoded->op = M68K_SUB; 293 decoded->op = M68K_SUB;
86 } else { 294 } else {
87 decoded->op = M68K_ADD; 295 decoded->op = M68K_ADD;
88 } 296 }
89 } 297 }
90 break; 298 break;
299 case BRANCH:
300 m68k_decode_cond(*istream, decoded);
301 decoded->op = decoded->extra.cond == COND_FALSE ? M68K_BSR : M68K_BCC;
302 decoded->src.addr_mode = MODE_IMMEDIATE;
303 immed = *istream & 0xFF;
304 if (immed == 0) {
305 decoded->variant = VAR_WORD;
306 immed = *(++istream);
307 immed = sign_extend16(immed);
308 } else if (immed == 0xFF) {
309 decoded->variant = VAR_LONG;
310 immed = *(++istream) << 16;
311 immed |= *(++istream);
312 } else {
313 decoded->variant = VAR_BYTE;
314 immed = sign_extend8(immed);
315 }
316 decoded->src.params.u32 = immed;
317 break;
318 case MOVEQ:
319 decoded->op = M68K_MOVE;
320 decoded->variant = VAR_QUICK;
321 decoded->src.addr_mode = MODE_IMMEDIATE;
322 decoded->src.params.u32 = sign_extend8(*istream & 0xFF);
323 decoded->dst.addr_mode = MODE_REG;
324 decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
325 immed = *istream & 0xFF;
326 break;
327 case OR_DIV_SBCD:
328 //TODO: Implement me
329 break;
330 case SUB_SUBX:
331 size = *istream >> 6 & 0x3;
332 decoded->op = M68K_SUB;
333 if (*istream & 0x100) {
334 //<ea> destination, SUBA.l or SUBX
335 if (*istream & 0x6) {
336 if (size == OPSIZE_INVALID) {
337 //SUBA.l
338 decoded->extra.size = OPSIZE_LONG;
339 decoded->dst.addr_mode = MODE_AREG;
340 istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src));
341 } else {
342 decoded->extra.size = size;
343 decoded->src.addr_mode = MODE_REG;
344 istream = m68k_decode_op(istream, size, &(decoded->dst));
345 }
346 } else {
347 //SUBX
348 decoded->op = M68K_SUBX;
349 decoded->extra.size = size;
350 istream = m68k_decode_op(istream, size, &(decoded->src));
351 decoded->dst.addr_mode = decoded->src.addr_mode;
352 decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
353 }
354 } else {
355 if (size == OPSIZE_INVALID) {
356 //SUBA.w
357 decoded->extra.size = OPSIZE_WORD;
358 decoded->dst.addr_mode = MODE_AREG;
359 } else {
360 decoded->extra.size = size;
361 decoded->dst.addr_mode = MODE_REG;
362 }
363 decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
364 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
365 }
366 break;
367 case RESERVED:
368 //TODO: implement me
369 break;
370 case CMP_XOR:
371 size = *istream >> 6 & 0x3;
372 decoded->op = M68K_CMP;
373 if (*istream & 0x100) {
374 //CMPM or EOR
375 istream = m68k_decode_op(istream, size, &(decoded->dst));
376 if (decoded->src.addr_mode == MODE_AREG) {
377 //CMPM
378 decoded->src.addr_mode = decoded->dst.addr_mode = MODE_AREG_POSTINC;
379 decoded->src.params.regs.pri = decoded->dst.params.regs.pri;
380 decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
381 } else {
382 //EOR
383 decoded->op = M68K_EOR;
384 decoded->extra.size = size;
385 decoded->src.addr_mode = MODE_REG;
386 decoded->src.params.regs.pri = m68K_reg_quick_field(*istream);
387 }
388 } else {
389 //CMP
390 decoded->extra.size = size;
391 decoded->dst.addr_mode = MODE_REG;
392 decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
393 istream = m68k_decode_op(istream, size, &(decoded->src));
394 }
395 break;
396 case AND_MUL_ABCD_EXG:
397 //page 575 for summary
398 //EXG opmodes:
399 //01000 -data regs
400 //01001 -addr regs
401 //10001 -one of each
402 //AND opmodes:
403 //operand order bit + 2 size bits (00 - 10)
404 //no address register direct addressing
405 //data register direct not allowed when <ea> is the source (operand order bit of 1)
406 if (*istream & 0x100) {
407 if ((*istream & 0xC0) == 0xC0) {
408 decoded->op = M68K_MULS;
409 decoded->extra.size = OPSIZE_WORD;
410 istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
411 } else if(!(*istream & 0xF0)) {
412 decoded->op = M68K_ABCD;
413 } else if(!(*istream & 0x30)) {
414 decoded->op = M68K_EXG;
415 decoded->extra.size = OPSIZE_LONG;
416 decoded->src.params.regs.pri = m68K_reg_quick_field(*istream);
417 decoded->dst.params.regs.pri = *istream & 0x7;
418 if (*istream & 0x8) {
419 if (*istream & 0x80) {
420 decoded->src.addr_mode = MODE_REG;
421 decoded->dst.addr_mode = MODE_AREG;
422 } else {
423 decoded->src.addr_mode = decoded->dst.addr_mode = MODE_AREG;
424 }
425 } else {
426 decoded->src.addr_mode = decoded->dst.addr_mode = MODE_REG;
427 }
428 } else {
429 decoded->op = M68K_AND;
430 decoded->extra.size = (*istream >> 6);
431 decoded->dst.addr_mode = MODE_REG;
432 decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
433 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
434 }
435 } else {
436 if ((*istream & 0xC0) == 0xC0) {
437 decoded->op = M68K_MULU;
438 decoded->extra.size = OPSIZE_WORD;
439 istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src));
440 } else {
441 decoded->op = M68K_AND;
442 decoded->extra.size = (*istream >> 6);
443 decoded->src.addr_mode = MODE_REG;
444 decoded->src.params.regs.pri = m68K_reg_quick_field(*istream);
445 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst));
446 }
447 }
448 break;
449 case ADD_ADDX:
450 size = *istream >> 6 & 0x3;
451 decoded->op = M68K_ADD;
452 if (*istream & 0x100) {
453 //<ea> destination, ADDA.l or ADDX
454 if (*istream & 0x6) {
455 if (size == OPSIZE_INVALID) {
456 //ADDA.l
457 decoded->extra.size = OPSIZE_LONG;
458 decoded->dst.addr_mode = MODE_AREG;
459 istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src));
460 } else {
461 decoded->extra.size = size;
462 decoded->src.addr_mode = MODE_REG;
463 istream = m68k_decode_op(istream, size, &(decoded->dst));
464 }
465 } else {
466 //ADDX
467 decoded->op = M68K_ADDX;
468 //FIXME: Size is not technically correct
469 decoded->extra.size = size;
470 istream = m68k_decode_op(istream, size, &(decoded->src));
471 decoded->dst.addr_mode = decoded->src.addr_mode;
472 decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
473 }
474 } else {
475 if (size == OPSIZE_INVALID) {
476 //ADDA.w
477 decoded->extra.size = OPSIZE_WORD;
478 decoded->dst.addr_mode = MODE_AREG;
479 } else {
480 decoded->extra.size = size;
481 decoded->dst.addr_mode = MODE_REG;
482 }
483 decoded->dst.params.regs.pri = m68K_reg_quick_field(*istream);
484 istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src));
485 }
486 break;
487 case SHIFT_ROTATE:
488 //TODO: Implement me
489 break;
490 case COPROC:
491 //TODO: Implement me
492 break;
91 } 493 }
92 } 494 return istream+1;
495 }
496
497 char * mnemonics[] = {
498 "abcd",
499 "add",
500 "addx",
501 "and",
502 "andi_ccr",
503 "andi_sr",
504 "asl",
505 "asr",
506 "bcc",
507 "bchg",
508 "bclr",
509 "bset",
510 "bsr",
511 "btst",
512 "chk",
513 "clr",
514 "cmp",
515 "dbcc",
516 "divs",
517 "divu",
518 "eor",
519 "eori_ccr",
520 "eori_sr",
521 "exg",
522 "ext",
523 "illegal",
524 "jmp",
525 "jsr",
526 "lea",
527 "link",
528 "lsl",
529 "lsr",
530 "move",
531 "move_ccr",
532 "move_from_sr",
533 "move_sr",
534 "move_usp",
535 "movem",
536 "movep",
537 "muls",
538 "mulu",
539 "nbcd",
540 "neg",
541 "negx",
542 "nop",
543 "not",
544 "or",
545 "ori_ccr",
546 "ori_sr",
547 "pea",
548 "reset",
549 "rol",
550 "ror",
551 "roxl",
552 "roxr",
553 "rte",
554 "rtr",
555 "rts",
556 "sbcd",
557 "scc",
558 "stop",
559 "sub",
560 "subx",
561 "swap",
562 "tas",
563 "trap",
564 "trapv",
565 "tst",
566 "unlnk",
567 "invalid"
568 };
569
570 char * cond_mnem[] = {
571 "ra",
572 "f",
573 "hi",
574 "ls",
575 "cc",
576 "cs",
577 "ne",
578 "eq",
579 "vc",
580 "vs",
581 "pl",
582 "mi",
583 "ge",
584 "lt",
585 "gt",
586 "le"
587 };
588
589 int m68K_disasm_op(m68k_op_info *decoded, uint8_t size, char *dst, int need_comma)
590 {
591 char * c = need_comma ? "," : "";
592 switch(decoded->addr_mode)
593 {
594 case MODE_REG:
595 return sprintf(dst, "%s d%d", c, decoded->params.regs.pri);
596 case MODE_AREG:
597 return sprintf(dst, "%s a%d", c, decoded->params.regs.pri);
598 case MODE_AREG_INDIRECT:
599 return sprintf(dst, "%s (a%d)", c, decoded->params.regs.pri);
600 case MODE_AREG_POSTINC:
601 return sprintf(dst, "%s (a%d)+", c, decoded->params.regs.pri);
602 case MODE_AREG_PREDEC:
603 return sprintf(dst, "%s -(a%d)", c, decoded->params.regs.pri);
604 case MODE_IMMEDIATE:
605 return sprintf(dst, "%s #%d", c, size == OPSIZE_LONG ? decoded->params.u32 : (size == OPSIZE_WORD ? decoded->params.u16 : decoded->params.u8));
606 default:
607 return 0;
608 }
609 }
610
611 int m68k_disasm(m68kinst * decoded, char * dst)
612 {
613 int ret,op1len;
614 uint8_t size;
615 if (decoded->op == M68K_BCC || decoded->op == M68K_DBCC || decoded->op == M68K_SCC) {
616 ret = strlen(mnemonics[decoded->op]) - 2;
617 memcpy(dst, mnemonics[decoded->op], ret);
618 dst[ret] = 0;
619 strcat(dst, cond_mnem[decoded->extra.cond]);
620 ret = strlen(dst);
621 size = decoded->op = M68K_BCC ? OPSIZE_LONG : OPSIZE_WORD;
622 } else if (decoded->op == M68K_BSR) {
623 size = OPSIZE_LONG;
624 ret = sprintf(dst, "bsr%s", decoded->variant == VAR_BYTE ? ".s" : "");
625 } else {
626 size = decoded->extra.size;
627 ret = sprintf(dst, "%s%s.%c",
628 mnemonics[decoded->op],
629 decoded->variant == VAR_QUICK ? "q" : "",
630 decoded->extra.size == OPSIZE_BYTE ? 'b' : (size == OPSIZE_WORD ? 'w' : 'l'));
631 }
632 op1len = m68K_disasm_op(&(decoded->src), size, dst + ret, 0);
633 ret += op1len;
634 ret += m68K_disasm_op(&(decoded->dst), size, dst + ret, op1len);
635 return ret;
636 }
637