Mercurial > repos > blastem
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 |