1 |
/* |
2 |
* mon_m68k.cpp - 68k disassembler |
3 |
* |
4 |
* (C) 1997-1999 Marc Hellwig |
5 |
*/ |
6 |
|
7 |
/* |
8 |
* TODO |
9 |
* - add missing f-lines |
10 |
* - MULx.L/DIVx.L |
11 |
* - use tab instead of spaces |
12 |
*/ |
13 |
|
14 |
/* |
15 |
* LOG |
16 |
* |
17 |
* 5.11.97 added TODO and LOG section. |
18 |
*/ |
19 |
|
20 |
#include <stdio.h> |
21 |
#include <string.h> |
22 |
|
23 |
#include "mon.h" |
24 |
#include "mon_68k.h" |
25 |
#include "mon_atraps.h" |
26 |
|
27 |
enum t_size {BYTE, WORD, LONG, NOSIZE, BYTE_SILENT, WORD_SILENT, LONG_SILENT}; // "silent" means "don't append size qualifier to opcode" |
28 |
enum t_errors {ER_UNKNOWN_ADDRESS_MODE, ER_UNKNOWN_OPCODE, ER_ILLEGAL_OPCODE}; |
29 |
enum t_address {AD_C=1000, AD_BRANCH, AD_MULT, AD_DATA, AD_DATA_IMM, AD_CACHE}; |
30 |
|
31 |
static void error(t_errors code); |
32 |
static int8 read_int8(void); |
33 |
static uint16 read_uint16(void); |
34 |
static int16 read_int16(void); |
35 |
static int32 read_int32(void); |
36 |
static void parse (); |
37 |
static void add_int32_str (char *old,int32 value); |
38 |
static void add_int16_str (char *old,int16 value); |
39 |
static void add_int8_str (char *old,int8 value); |
40 |
static void add_dec_int_str (char *old,int32 value); |
41 |
static void add_uint16_str (char *old,uint16 value); |
42 |
static void print_range (int from,int to); |
43 |
static int decode_address_mode (uint16 eee,uint16 aaa,t_size size); |
44 |
static void diss (char *ndest,uint16 *nmem,int &npos,unsigned int adr); |
45 |
|
46 |
enum t_control {C_UNKNOWN,C_SR,C_CCR,C_SFC,C_DFC,C_CACR,C_TC,C_ITT0,C_ITT1,C_DTT0,C_DTT1,C_BUSCR,C_USP,C_VBR,C_CAAR,C_MSP,C_ISP,C_MMUSR,C_URP,C_SRP,C_PCR}; |
47 |
static char *con_str[]={"???","sr","ccr","sfc","dfc","cacr","tc","itt0","itt1","dtt0","dtt1","buscr","usp","vbr","caar","msp","isp","mmusr","urp","srp","pcr"}; |
48 |
static char *cc_str[]= {"t","f","hi","ls","cc","cs","ne","eq","vc","vs","pl", |
49 |
"mi","ge","lt","gt","le","ra","sr"}; |
50 |
static uint16 opcode; |
51 |
static uint16 source_eee; |
52 |
static uint16 source_aaa; |
53 |
static uint16 dest_eee; |
54 |
static uint16 dest_aaa; |
55 |
static int32 data_val; |
56 |
static uint16 mask; // for movem !!! aaarrrggglll ... |
57 |
static t_size size; |
58 |
static int count_param; |
59 |
static uint16 *mem; |
60 |
static int mem_pos; |
61 |
static char *dest; |
62 |
static char op_name[50]; |
63 |
static unsigned int adr_off; |
64 |
|
65 |
static void error (t_errors code) { |
66 |
switch (code) { |
67 |
case ER_UNKNOWN_ADDRESS_MODE: |
68 |
printf ("unknown address mode\n"); |
69 |
break; |
70 |
case ER_UNKNOWN_OPCODE: |
71 |
printf ("unknown opcode\n"); |
72 |
break; |
73 |
case ER_ILLEGAL_OPCODE: |
74 |
printf ("illegal opcode\n"); |
75 |
break; |
76 |
default: |
77 |
printf ("general error\n"); |
78 |
} |
79 |
} |
80 |
|
81 |
static int8 read_int8(void) { |
82 |
return mem[mem_pos++]; |
83 |
} |
84 |
|
85 |
static uint16 read_uint16(void) { |
86 |
return mem[mem_pos++]; |
87 |
} |
88 |
|
89 |
static int16 read_int16(void) { |
90 |
return (int16)(mem[mem_pos++]); |
91 |
} |
92 |
|
93 |
static int32 read_int32(void) { |
94 |
int32 val = (mem[mem_pos] << 16) | mem[mem_pos+1]; |
95 |
mem_pos+=2; |
96 |
return val; |
97 |
} |
98 |
|
99 |
// opcode table |
100 |
#define def_param(n,c,s,se,sa,de,da) \ |
101 |
strcpy(op_name,n);\ |
102 |
count_param=c;\ |
103 |
size=s;\ |
104 |
source_eee=se;\ |
105 |
source_aaa=sa;\ |
106 |
dest_eee=de;\ |
107 |
dest_aaa=da; |
108 |
#define no_param(n) \ |
109 |
def_param(n,0,NOSIZE,0,0,0,0) |
110 |
#define bits(pos,count) ((opcode >> pos)&((1<<count)-1)) |
111 |
#define mshort(s) \ |
112 |
if (bits(6,3)==1) \ |
113 |
{def_param("movea",2,s,bits(3,3),bits(0,3),1,bits(9,3))}\ |
114 |
else\ |
115 |
{def_param("move",2,s,bits(3,3),bits(0,3),bits(6,3),bits(9,3))} |
116 |
#define imshort(n) \ |
117 |
if (bits(6,2)<2) data_val = read_int16(); else data_val = read_int32();\ |
118 |
def_param(n,2,(t_size)bits(6,2),AD_DATA_IMM,0,bits(3,3),bits(0,3)) |
119 |
#define imshortcs(n) \ |
120 |
switch (bits(0,8)) { \ |
121 |
case 0x3c: \ |
122 |
data_val = read_int16();\ |
123 |
def_param(n,2,BYTE_SILENT,AD_DATA_IMM,0,AD_C,C_CCR) break; \ |
124 |
case 0x7c: \ |
125 |
data_val = read_int16();\ |
126 |
def_param(n,2,WORD_SILENT,AD_DATA_IMM,0,AD_C,C_SR) break; \ |
127 |
break; \ |
128 |
default: \ |
129 |
imshort(n) \ |
130 |
break;\ |
131 |
} |
132 |
#define addshort(n) \ |
133 |
if (bits(8,1)==0)\ |
134 |
{def_param(n,2,(t_size)bits(6,2),bits(3,3),bits(0,3),0,bits(9,3))}\ |
135 |
else\ |
136 |
{def_param(n,2,(t_size)bits(6,2),0,bits(9,3),bits(3,3),bits(0,3))} |
137 |
#define addxshort(n) \ |
138 |
if (bits(3,1)==0) {\ |
139 |
def_param(n,2,(t_size)bits(6,2),0,bits(0,3),0,bits(9,3))\ |
140 |
} else {\ |
141 |
def_param(n,2,(t_size)bits(6,2),4,bits(0,3),4,bits(9,3))\ |
142 |
} |
143 |
#define addashort(n) \ |
144 |
def_param(n,2,NOSIZE,bits(3,3),bits(0,3),1,bits(9,3))\ |
145 |
if (bits(8,1)==0) size=WORD; else size=LONG; |
146 |
#define deashort(n) \ |
147 |
def_param(n,2,(t_size)bits(6,2),0,bits(9,3),bits(3,3),bits(0,3)) |
148 |
#define bitshort(n) \ |
149 |
def_param(n,2,BYTE_SILENT,AD_DATA_IMM,0,bits(3,3),bits(0,3))\ |
150 |
data_val=read_int8(); |
151 |
#define bitdynshort(n) \ |
152 |
def_param(n,2,BYTE_SILENT,0,bits(9,3),bits(3,3),bits(0,3)) |
153 |
#define prwshort(n) \ |
154 |
if (((op2 >> 9) & 1)==1) \ |
155 |
{def_param(n,2,LONG,AD_C,C_UNKNOWN,bits(3,3),bits(0,3))}\ |
156 |
else\ |
157 |
{def_param(n,2,LONG,bits(3,3),bits(0,3),AD_C,C_UNKNOWN)} |
158 |
#define mshiftshort(n) \ |
159 |
def_param(n,1,WORD,bits(3,3),bits(0,3),0,0)\ |
160 |
if (bits(8,1)==0) {\ |
161 |
strcat(op_name,"r");\ |
162 |
} else {\ |
163 |
strcat(op_name,"l");\ |
164 |
} |
165 |
#define rshiftshort(n) \ |
166 |
if (bits(5,1)==0) {\ |
167 |
data_val=bits(9,3);\ |
168 |
if (data_val==0) data_val=8;\ |
169 |
def_param(n,2,(t_size)bits(6,2),AD_DATA_IMM,0,0,bits(0,3))\ |
170 |
} else {\ |
171 |
def_param(n,2,(t_size)bits(6,2),0,bits(9,3) % 64,0,bits(0,3))\ |
172 |
}\ |
173 |
if (bits(8,1)==0) {\ |
174 |
strcat(op_name,"r");\ |
175 |
} else {\ |
176 |
strcat(op_name,"l");\ |
177 |
} |
178 |
#define abcdshort(n) \ |
179 |
if (bits(3,1)==0) {\ |
180 |
def_param(n,2,BYTE,0,bits(0,3),0,bits(9,3))\ |
181 |
} else {\ |
182 |
def_param(n,2,BYTE,4,bits(0,3),4,bits(9,3))\ |
183 |
} |
184 |
#define cinvpush(n) \ |
185 |
def_param(n,bits(3,2) == 3 ? 1 : 2,NOSIZE,AD_CACHE,bits(6,2),2,bits(0,3))\ |
186 |
switch (bits(3,2)) {\ |
187 |
case 1: strcat(op_name, "l"); break;\ |
188 |
case 2: strcat(op_name, "p"); break;\ |
189 |
case 3: strcat(op_name, "a"); count_param = 1;\ |
190 |
} |
191 |
|
192 |
static void parse () { |
193 |
switch (bits(12,4)) { |
194 |
case 0: // Bit Manipulation/MOVEP/Immediate |
195 |
if (bits(8,1)==0) { // Immediate + Bit Manipulation static |
196 |
if (bits(6,2)==3) { // RTM, CALLM, CMP2, CHK2, BSET, CAS2, CAS |
197 |
switch (bits(9,3)) { |
198 |
case 3: // RTM, CALLM |
199 |
break; |
200 |
case 0: case 1: case 2: // CMP2, CHK2 |
201 |
break; |
202 |
case 4: // BSET ! |
203 |
bitshort("bset") break; |
204 |
default: // CAS2, CAS |
205 |
break; |
206 |
} |
207 |
} else { |
208 |
switch (bits(9,3)) { |
209 |
case 0: // ORI |
210 |
imshortcs("ori") break; |
211 |
case 1: // ANDI |
212 |
imshortcs("andi") break; |
213 |
case 2: // SUBI |
214 |
imshort("subi") break; |
215 |
case 3: // ADDI |
216 |
imshort("addi") break; |
217 |
case 4: // BTST, BCHG, BCLR static |
218 |
switch (bits(6,2)) { |
219 |
case 0: // BTST |
220 |
bitshort("btst") break; |
221 |
case 1: // BCHG |
222 |
bitshort("bchg") break; |
223 |
case 2: // BCLR |
224 |
bitshort ("bclr") break; |
225 |
} |
226 |
break; |
227 |
case 5: // EORI |
228 |
imshortcs("eori"); break; |
229 |
case 6: // CMPI |
230 |
imshort("cmpi"); break; |
231 |
case 7: // MOVES |
232 |
break; |
233 |
} |
234 |
} |
235 |
} else { // Bit Manipulation dynamic, MOVEP |
236 |
if (bits(3,3)==1) { // MOVEP |
237 |
if (bits(7,1)==0) { // MOVEP d(Ay),Dx |
238 |
def_param("movep",2,NOSIZE,5,bits(0,3),0,bits(9,3)) |
239 |
} else { // MOVEP Dx,d(Ay) |
240 |
def_param("movep",2,NOSIZE,0,bits(9,3),5,bits(0,3)) |
241 |
} |
242 |
if (bits(6,1)==0) size=WORD; else size=LONG; |
243 |
} else { // Bit Manipulation |
244 |
switch (bits(6,2)) { |
245 |
case 0: // BTST |
246 |
bitdynshort("btst") break; |
247 |
case 1: // BCHG |
248 |
bitdynshort("bchg") break; |
249 |
case 2: // BCLR |
250 |
bitdynshort ("bclr") break; |
251 |
case 3: // BSET |
252 |
bitdynshort ("bset") break; |
253 |
} |
254 |
} |
255 |
} |
256 |
break; |
257 |
case 1: // Move Byte |
258 |
mshort(BYTE) |
259 |
break; |
260 |
case 2: // Move Long |
261 |
mshort(LONG) |
262 |
break; |
263 |
case 3: // Move Word |
264 |
mshort(WORD) |
265 |
break; |
266 |
case 4: // Miscellaneous |
267 |
switch (bits(0,12)) { // First all fixed opcodes ... |
268 |
case 0xcfa: // BGND |
269 |
no_param("bgnd") |
270 |
break; |
271 |
case 0xafc: // ILLEGAL |
272 |
no_param("illegal") |
273 |
break; |
274 |
case 0xe70: // RESET |
275 |
no_param("reset") |
276 |
break; |
277 |
case 0xe71: // NOP |
278 |
no_param("nop") |
279 |
break; |
280 |
case 0xe72: // STOP |
281 |
data_val=read_int16(); |
282 |
def_param("stop",1,WORD_SILENT,AD_DATA_IMM,0,0,0) break; |
283 |
case 0xe73: // RTE |
284 |
no_param("rte") |
285 |
break; |
286 |
case 0xe74: // RTD |
287 |
data_val=read_int16(); |
288 |
def_param("rtd",1,WORD_SILENT,AD_DATA,0,0,0) break; |
289 |
case 0xe75: // RTS |
290 |
no_param("rts") |
291 |
break; |
292 |
case 0xe76: // TRAPV |
293 |
no_param("trapv") |
294 |
break; |
295 |
case 0xe77: // RTR |
296 |
no_param("rtr") |
297 |
break; |
298 |
case 0xe7a: case 0xe7b: { // MOVEC |
299 |
uint16 op2 = read_uint16(); |
300 |
uint16 val; |
301 |
switch (op2 & 0xfff) { |
302 |
case 0: val=C_SFC; break; |
303 |
case 1: val=C_DFC; break; |
304 |
case 2: val=C_CACR; break; |
305 |
case 3: val=C_TC; break; |
306 |
case 4: val=C_ITT0; break; |
307 |
case 5: val=C_ITT1; break; |
308 |
case 6: val=C_DTT0; break; |
309 |
case 7: val=C_DTT1; break; |
310 |
case 8: val=C_BUSCR; break; |
311 |
case 0x800: val=C_USP; break; |
312 |
case 0x801: val=C_VBR; break; |
313 |
case 0x802: val=C_CAAR; break; |
314 |
case 0x803: val=C_MSP; break; |
315 |
case 0x804: val=C_ISP; break; |
316 |
case 0x805: val=C_MMUSR; break; |
317 |
case 0x806: val=C_URP; break; |
318 |
case 0x807: val=C_SRP; break; |
319 |
case 0x808: val=C_PCR; break; |
320 |
default: val=C_UNKNOWN; break; // ERROR unknown control_reg |
321 |
} |
322 |
if (bits(0,1)==0) { // MOVEC Ctrl,AD |
323 |
def_param("movec",2,NOSIZE,AD_C,val,((op2 >> 15) & 1),((op2 >> 12) & 7)) |
324 |
} else { // MOVEC AD,Ctrl |
325 |
def_param("movec",2,NOSIZE,((op2 >> 15) & 1),((op2 >> 12) & 7),AD_C,val) |
326 |
} |
327 |
break; |
328 |
} |
329 |
default: |
330 |
switch (bits(3,9)) { |
331 |
case 0x110: case 0x118: // EXT maybe more ??? nicht ganz sauber |
332 |
def_param("ext",1,((bits(6,2)==2) ? WORD : LONG),0,bits(0,3),0,0) break; |
333 |
case 0x101: // LINK |
334 |
data_val=read_int32(); |
335 |
def_param("link",2,LONG,1,bits(0,3),AD_DATA_IMM,0) break; |
336 |
case 0x108: // SWAP |
337 |
def_param("swap",1,NOSIZE,0,bits(0,3),0,0) break; |
338 |
case 0x109: // BKPT |
339 |
data_val=bits(0,3); |
340 |
def_param("bkpt",1,BYTE,AD_DATA,0,0,0) break; |
341 |
case 0x1c8: case 0x1c9: // TRAP |
342 |
data_val=bits(0,4); |
343 |
def_param("trap",1,BYTE,AD_DATA,0,0,0) break; |
344 |
case 0x1ca: // LINK |
345 |
data_val=read_int16(); |
346 |
def_param("link",2,WORD_SILENT,1,bits(0,3),AD_DATA_IMM,0) break; |
347 |
case 0x1cb: // UNLK |
348 |
def_param("unlk",1,NOSIZE,1,bits(0,3),0,0) break; |
349 |
case 0x1cc: case 0x1cd: // MOVE USP |
350 |
if (bits(3,1)==0) { // MOVE An,USP |
351 |
def_param("move",2,LONG,1,bits(0,3),AD_C,C_USP) |
352 |
} else { // MOVE USP,An |
353 |
def_param("move",2,LONG,AD_C,C_USP,1,bits(0,3)) |
354 |
} |
355 |
break; |
356 |
default: |
357 |
switch (bits(6,6)) { |
358 |
case 3: // MOVE from SR |
359 |
def_param("move",2,WORD_SILENT,AD_C,C_SR,bits(3,3),bits(0,3)) break; |
360 |
case 0xb: // MOVE from CCR |
361 |
def_param("move",2,WORD_SILENT,AD_C,C_CCR,bits(3,3),bits(0,3)) break; |
362 |
case 0: case 1: case 2: // NEGX |
363 |
def_param("negx",1,(t_size)bits(6,2),bits(3,3),bits(0,3),0,0) break; |
364 |
case 8: case 9: case 0xa: // CLR |
365 |
def_param("clr",1,(t_size)bits(6,2),bits(3,3),bits(0,3),0,0) break; |
366 |
case 0x13: // MOVE to CCR |
367 |
def_param("move",2,WORD_SILENT,bits(3,3),bits(0,3),AD_C,C_CCR) break; |
368 |
case 0x10: case 0x11: case 0x12:// NEG |
369 |
def_param("neg",1,(t_size)bits(6,2),bits(3,3),bits(0,3),0,0) break; |
370 |
case 0x18: case 0x19: case 0x1a:// NOT |
371 |
def_param("not",1,(t_size)bits(6,2),bits(3,3),bits(0,3),0,0) break; |
372 |
case 0x1b: // MOVE to SR |
373 |
def_param("move",2,WORD_SILENT,bits(3,3),bits(0,3),AD_C,C_SR) break; |
374 |
case 0x20: // NBCD |
375 |
def_param("nbcd",1,BYTE,bits(3,3),bits(0,3),0,0) break; |
376 |
case 0x21: // PEA |
377 |
def_param("pea",1,LONG,bits(3,3),bits(0,3),0,0) break; |
378 |
case 0x2b: // TAS |
379 |
def_param("tas",1,BYTE,bits(3,3),bits(0,3),0,0) break; |
380 |
case 0x28: case 0x29: case 0x2a:// TST |
381 |
def_param("tst",1,(t_size)bits(6,2),bits(3,3),bits(0,3),0,0) break; |
382 |
case 0x30: // MULU, MULS, DIVU, DIVUL |
383 |
//!! |
384 |
break; |
385 |
case 0x31: // DIVS, DIVSL |
386 |
//!! |
387 |
break; |
388 |
case 0x3a: // JSR |
389 |
def_param("jsr ",1,NOSIZE,bits(3,3),bits(0,3),0,0) break; |
390 |
case 0x3b: // JMP |
391 |
def_param("jmp ",1,NOSIZE,bits(3,3),bits(0,3),0,0) break; |
392 |
case 0x22: case 0x23: case 0x32: case 0x33:// MOVEM |
393 |
mask=read_uint16(); |
394 |
if (bits(10,1)!=0) |
395 |
{def_param("movem",2,NOSIZE,bits(3,3),bits(0,3),AD_MULT,0)} |
396 |
else |
397 |
{def_param("movem",2,NOSIZE,AD_MULT,((bits(3,3)==4) ? 1 : 0),bits(3,3),bits(0,3))} |
398 |
if (bits(6,1)==0) size=WORD; else size=LONG; |
399 |
break; |
400 |
default: |
401 |
switch (bits(6,3)) { |
402 |
case 7: // LEA |
403 |
def_param("lea",2,NOSIZE,bits(3,3),bits(0,3),1,bits(9,3)) break; |
404 |
case 0: case 2: case 4: case 6:// CHK -> possible error ! check ! |
405 |
def_param("chk",2,WORD,bits(3,3),bits(0,3),0,bits(9,3)) break; |
406 |
default: // ERROR unknown opcode |
407 |
break; |
408 |
} |
409 |
} |
410 |
} |
411 |
} |
412 |
break; |
413 |
case 5: // ADDQ/SUBQ/Scc/DBcc/TRAPcc |
414 |
if (bits(6,2)==3) { // DBcc/TRAPcc/Scc |
415 |
switch (bits(3,3)) { |
416 |
case 1: // DBcc |
417 |
def_param("db",2,WORD_SILENT,0,bits(0,3),AD_BRANCH,bits(8,4)) |
418 |
break; |
419 |
case 7: // TRAPcc |
420 |
// not yet implemented |
421 |
break; |
422 |
default: // Scc |
423 |
def_param("s",1,BYTE,bits(3,3),bits(0,3),AD_BRANCH,bits(8,4)) |
424 |
} |
425 |
} else { // ADDQ/SUBQ |
426 |
if (bits(8,1)==0) { // ADDQ |
427 |
data_val=bits(9,3); |
428 |
def_param("addq",2,(t_size)bits(6,2),AD_DATA_IMM,0,bits(3,3),bits(0,3)) |
429 |
} else { // SUBQ |
430 |
data_val=bits(9,3); |
431 |
def_param("subq",2,(t_size)bits(6,2),AD_DATA_IMM,0,bits(3,3),bits(0,3)) |
432 |
} |
433 |
} |
434 |
break; |
435 |
case 6: // Bcc/BSR/BRA |
436 |
def_param("b",1,NOSIZE,AD_BRANCH,bits(0,8),AD_BRANCH,bits(8,4)) |
437 |
if (dest_aaa < 2) dest_aaa += 16; //Bcc -> BSR,BRA |
438 |
switch (bits(0,8)) { |
439 |
case 0: size = WORD; break; |
440 |
case 0xff: size = LONG; break; |
441 |
default: size = BYTE; |
442 |
} |
443 |
break; |
444 |
case 7: // MOVEQ |
445 |
data_val=bits(0,8); |
446 |
def_param("moveq",2,BYTE_SILENT,AD_DATA_IMM,0,0,bits(9,3)) |
447 |
break; |
448 |
case 8: // OR/DIV/SBCD |
449 |
switch (bits(4,5)) { |
450 |
case 0x10: // SBCD |
451 |
abcdshort("sbcd") break; |
452 |
case 0x14: // PACK |
453 |
break; |
454 |
case 0x18: // UNPK |
455 |
break; |
456 |
default: |
457 |
switch (bits(6,3)) { |
458 |
case 3: // DIVU/DIVUL |
459 |
def_param("divu",2,WORD,bits(3,3),bits(0,3),0,bits(9,3)) break; |
460 |
case 7: // DIVS/DIVSL |
461 |
def_param("divs",2,WORD,bits(3,3),bits(0,3),0,bits(9,3)) break; |
462 |
default: // OR |
463 |
addshort("or") |
464 |
break; |
465 |
} |
466 |
} |
467 |
break; |
468 |
case 9: // SUB/SUBX |
469 |
if (bits(6,2)==3) { // SUBA |
470 |
addashort("suba") |
471 |
} else { |
472 |
if ((bits(4,2)==0)&&(bits(8,1)==1)) {// SUBX |
473 |
addxshort("subx") |
474 |
} else { // SUB |
475 |
addshort("sub") |
476 |
} |
477 |
} |
478 |
break; |
479 |
case 0xa: { // (Unassigned, Reserved) |
480 |
int position = 0; |
481 |
no_param("a-line") |
482 |
while (atraps[position].word!=0) { |
483 |
if (atraps[position].word == opcode) { |
484 |
no_param(atraps[position].name) |
485 |
break; |
486 |
} |
487 |
position++; |
488 |
} |
489 |
break; |
490 |
} |
491 |
case 0xb: // CMP/EOR |
492 |
if (bits(6,2)==3) { // CMPA |
493 |
def_param("cmpa",2,((bits(8,1)==0) ? WORD : LONG),bits(3,3),bits(0,3),1,bits(9,3)) |
494 |
} else { |
495 |
if (bits(8,1)==1) { // CMPM/EOR |
496 |
if (bits(3,3)==1) { // CMPM |
497 |
def_param("cmpm",2,(t_size)bits(6,2),3,bits(0,3),3,bits(9,3)) |
498 |
} else { // EOR |
499 |
deashort("eor") |
500 |
} |
501 |
} else { // CMP |
502 |
deashort("cmp") |
503 |
} |
504 |
} |
505 |
break; |
506 |
case 0xc: // AND/MUL/ABCD/EXG |
507 |
switch (bits(6,3)) { |
508 |
case 3: // MULU |
509 |
def_param("mulu",2,WORD,bits(3,3),bits(0,3),0,bits(9,3)) break; |
510 |
case 7: // MULS |
511 |
def_param("muls",2,WORD,bits(3,3),bits(0,3),0,bits(9,3)) break; |
512 |
default: // ABCD/EXG/AND |
513 |
if (bits(4,5)==0x10) { // ABCD |
514 |
abcdshort("abcd") |
515 |
} else { // EXG/AND |
516 |
if ((bits(3,6)==0x28)||(bits(3,6)==0x29)||(bits(3,6)==0x31)) {//EXG |
517 |
switch (bits(3,5)) { |
518 |
case 8: def_param("exg",2,LONG,0,bits(0,3),0,bits(9,3)) break; |
519 |
case 9: def_param("exg",2,LONG,1,bits(0,3),1,bits(9,3)) break; |
520 |
case 0x11: def_param("exg",2,LONG,1,bits(0,3),0,bits(9,3)) break; |
521 |
} |
522 |
} else { // AND |
523 |
addshort("and") |
524 |
} |
525 |
} |
526 |
} |
527 |
break; |
528 |
case 0xd: // ADD/ADDX |
529 |
if (bits(6,2)==3) { // ADDA |
530 |
addashort("adda") |
531 |
} else { // ADDX/ADD |
532 |
if ((bits(4,2)==0)&&(bits(8,1)==1)) {// ADDX |
533 |
addxshort("addx") |
534 |
} else { // ADD |
535 |
addshort("add") |
536 |
} |
537 |
} |
538 |
break; |
539 |
case 0xe: // Shift/Rotate/Bit Field |
540 |
if (bits(6,2)==3) { // Mem Shift/Rotate, Bit Field |
541 |
if (bits(11,1)==0) { // Mem Shift/Rotate |
542 |
switch (bits(9,2)) { |
543 |
case 0: // ASL/ASR |
544 |
mshiftshort("as") break; |
545 |
case 1: // LSL/LSR |
546 |
mshiftshort("ls") break; |
547 |
case 2: // ROXL/ROXR |
548 |
mshiftshort("rox") break; |
549 |
case 3: // ROL/ROR |
550 |
mshiftshort ("ro") break; |
551 |
} |
552 |
} else { // Bit Field |
553 |
switch (bits(8,3)) { |
554 |
case 0: // BFTST |
555 |
break; |
556 |
case 1: // BFEXTU |
557 |
break; |
558 |
case 2: // BFCHG |
559 |
break; |
560 |
case 3: // BFEXTS |
561 |
break; |
562 |
case 4: // BFCLR |
563 |
break; |
564 |
case 5: // BFFFO |
565 |
break; |
566 |
case 6: // BFSET |
567 |
break; |
568 |
case 7: // BFINS |
569 |
break; |
570 |
} |
571 |
} |
572 |
} else { // Register Shift/Rotate |
573 |
switch (bits(3,2)) { |
574 |
case 0: // ASL/ASR |
575 |
rshiftshort("as") break; |
576 |
case 1: // LSL/LSR |
577 |
rshiftshort("ls") break; |
578 |
case 2: // ROXL/ROXR |
579 |
rshiftshort("rox") break; |
580 |
case 3: // ROL/ROR |
581 |
rshiftshort("ro") break; |
582 |
} |
583 |
} |
584 |
break; |
585 |
case 0xf: // Coprocessor Interface/MC68040 |
586 |
// and CPU32 Extensions |
587 |
switch (bits(6,6)) { |
588 |
case 0: { // P... |
589 |
uint16 op2 = read_uint16(); |
590 |
switch ((op2 >> 13) & 7) { |
591 |
case 0: // PMOVE |
592 |
prwshort("pmove") break; |
593 |
case 1: // PLOAD/PVALID/PFLUSH |
594 |
no_param("pload/pvalid/pflush") break; |
595 |
case 2: // PMOVE |
596 |
prwshort ("pmove") break; |
597 |
case 3: // PMOVE |
598 |
prwshort ("pmove") break; |
599 |
case 4: // PTST |
600 |
prwshort ("ptest") break; |
601 |
case 5: // PFLUSHR |
602 |
def_param ("pflushhr",1,LONG,bits(3,3),bits(0,3),0,0) break; |
603 |
} |
604 |
break; |
605 |
} |
606 |
case 0x10: case 0x11: case 0x12: case 0x13:// Cache |
607 |
if (bits(5,1)==0) { // CINV |
608 |
cinvpush("cinv"); |
609 |
} else { // CPUSH |
610 |
cinvpush("cpush"); |
611 |
} |
612 |
break; |
613 |
} |
614 |
break; |
615 |
default: // should never happen |
616 |
break; |
617 |
}} |
618 |
// |
619 |
|
620 |
static void add_int32_str (char *old,int32 value) { |
621 |
sprintf (&(old[strlen(old)]),"$%08x",value); |
622 |
} |
623 |
|
624 |
static void add_int16_str (char *old,int16 value) { |
625 |
sprintf (&(old[strlen(old)]),"$%04x",value); |
626 |
} |
627 |
|
628 |
static void add_int8_str (char *old,int8 value) { |
629 |
sprintf (&(old[strlen(old)]),"$%02x",value); |
630 |
} |
631 |
|
632 |
static void add_dec_int_str (char *old,int32 value) { |
633 |
sprintf (&(old[strlen(old)]),"%d",value); |
634 |
} |
635 |
|
636 |
static void add_uint16_str (char *old,uint16 value) { |
637 |
sprintf (&(old[strlen(old)]),"$%04x",value); |
638 |
} |
639 |
|
640 |
static void print_range (int from,int to) { |
641 |
if (from < 8) dest = strcat (dest,"d"); else dest = strcat(dest,"a"); |
642 |
add_dec_int_str(dest,from & 7); |
643 |
if (to > from) { |
644 |
dest = strcat(dest,"-"); |
645 |
if (to < 8) dest = strcat (dest,"d"); else dest = strcat(dest,"a"); |
646 |
add_dec_int_str(dest,to & 7); |
647 |
} |
648 |
} |
649 |
|
650 |
static void decode_extended (bool a_reg,uint16 aaa,int32 old_mem) { |
651 |
uint16 value = read_uint16(); |
652 |
uint16 scale = 1 << ((value >> 9) & 3); |
653 |
uint16 d_a = (value >> 15) & 1; |
654 |
uint16 reg = (value >> 12) & 7; |
655 |
uint16 w_l = (value >> 11) & 1; |
656 |
strcat (dest,"("); |
657 |
if (((value >> 8) & 1)==0) { // standard format |
658 |
if (a_reg) { |
659 |
add_int8_str(dest,value & 0xff); |
660 |
strcat (dest,",a"); |
661 |
add_dec_int_str(dest,aaa); |
662 |
} else { |
663 |
add_int32_str(dest,old_mem*2+adr_off+(int32)(int8)(value)); |
664 |
strcat (dest,",pc"); |
665 |
} |
666 |
if (d_a==0) strcat (dest,",d"); else strcat (dest,",a"); |
667 |
add_dec_int_str(dest,reg); |
668 |
if (w_l==0) strcat (dest,".w"); else strcat (dest,".l"); |
669 |
if (scale > 1) { |
670 |
strcat (dest,"*"); |
671 |
add_dec_int_str(dest,scale); |
672 |
} |
673 |
} else { // extended format |
674 |
uint16 i_is = value & 3; |
675 |
uint16 bd_size = (value >> 4) & 3; |
676 |
uint16 bs = (value >> 7) & 1; |
677 |
uint16 is = (value >> 6) & 1; |
678 |
if (i_is!=0) strcat(dest,"["); |
679 |
if (bd_size!=1) { // base displacement |
680 |
switch (bd_size) { |
681 |
case 2: if (a_reg) |
682 |
add_int32_str(dest,read_int16()); |
683 |
else |
684 |
add_int32_str(dest,old_mem*2+adr_off+(int32)read_int16()); |
685 |
break; |
686 |
case 3: if (a_reg) |
687 |
add_int32_str(dest,read_int32()); |
688 |
else |
689 |
add_int32_str(dest,old_mem*2+adr_off+read_int32()); |
690 |
break; |
691 |
default: |
692 |
strcat (dest,"illegal base displacement "); |
693 |
} |
694 |
} |
695 |
if (bs==0) { |
696 |
if (bd_size!=1) strcat(dest,","); |
697 |
if (a_reg) { |
698 |
strcat (dest,"a"); |
699 |
add_dec_int_str(dest,aaa); |
700 |
} else { |
701 |
strcat (dest,"pc"); |
702 |
} |
703 |
} |
704 |
if ((is==0)&&(i_is>4)&&(i_is<8)) strcat(dest,"]"); |
705 |
if (is==0) { |
706 |
if (bs==0||bd_size!=1) strcat(dest,","); |
707 |
if (d_a==0) strcat (dest,",d"); else strcat (dest,",a"); |
708 |
add_dec_int_str(dest,reg); |
709 |
if (w_l==0) strcat (dest,".w"); else strcat (dest,".l"); |
710 |
if (scale > 1) { |
711 |
strcat (dest,"*"); |
712 |
add_dec_int_str(dest,scale); |
713 |
} |
714 |
} |
715 |
if ((i_is>0)&&(i_is<4)) strcat(dest,"]"); |
716 |
if (((is==0)&&(i_is==4))||((is==1)&&(i_is>4))) strcat(dest,"reserved"); else |
717 |
switch (i_is & 3) { |
718 |
case 2: strcat(dest,","); |
719 |
add_int32_str(dest,read_int16()); |
720 |
break; |
721 |
case 3: strcat(dest,","); |
722 |
add_int32_str(dest,read_int32()); |
723 |
break; |
724 |
} |
725 |
} |
726 |
strcat (dest,")"); |
727 |
} |
728 |
|
729 |
static int decode_address_mode (uint16 eee,uint16 aaa,t_size size) { |
730 |
int32 old_mem = mem_pos; |
731 |
switch (eee) { |
732 |
case 0: strcat (dest,"d"); |
733 |
add_dec_int_str(dest,aaa); |
734 |
break; |
735 |
case 1: strcat (dest,"a"); |
736 |
add_dec_int_str(dest,aaa); |
737 |
break; |
738 |
case 2: strcat (dest,"(a"); |
739 |
add_dec_int_str(dest,aaa); |
740 |
strcat (dest,")"); |
741 |
break; |
742 |
case 3: strcat (dest,"(a"); |
743 |
add_dec_int_str(dest,aaa); |
744 |
strcat (dest,")+"); |
745 |
break; |
746 |
case 4: strcat (dest,"-(a"); |
747 |
add_dec_int_str(dest,aaa); |
748 |
strcat (dest,")"); |
749 |
break; |
750 |
case 5: strcat (dest,"("); |
751 |
add_int16_str(dest,read_int16()); |
752 |
strcat (dest,",a"); |
753 |
add_dec_int_str(dest,aaa); |
754 |
strcat (dest,")"); |
755 |
break; |
756 |
case 6: decode_extended(true,aaa,0); |
757 |
break; |
758 |
case 7: switch (aaa) { |
759 |
case 0: add_int16_str(dest,read_int16()); |
760 |
strcat (dest,".w"); |
761 |
break; |
762 |
case 1: add_int32_str(dest,read_int32()); |
763 |
strcat (dest,".l"); |
764 |
break; |
765 |
case 2: strcat (dest,"("); |
766 |
add_int32_str(dest,old_mem*2+adr_off+(int32)read_int16()); |
767 |
strcat (dest,",pc)"); |
768 |
break; |
769 |
case 3: decode_extended(false,0,old_mem); |
770 |
break; |
771 |
case 4: strcat (dest,"#"); |
772 |
switch (size) { |
773 |
case BYTE_SILENT: |
774 |
case BYTE: add_int8_str(dest,read_int8() & 0xff); |
775 |
break; |
776 |
case WORD_SILENT: |
777 |
case WORD: add_int16_str(dest,read_int16()); |
778 |
break; |
779 |
case LONG_SILENT: |
780 |
case LONG: add_int32_str(dest,read_int32()); |
781 |
break; |
782 |
case NOSIZE: add_int8_str(dest,opcode & 0xff); |
783 |
break; |
784 |
default: ; |
785 |
} |
786 |
break; |
787 |
default: error (ER_UNKNOWN_ADDRESS_MODE); |
788 |
return -1; |
789 |
} |
790 |
break; |
791 |
case AD_C: strcat (dest,con_str[aaa]); |
792 |
break; |
793 |
case AD_BRANCH: |
794 |
switch (size){ |
795 |
case BYTE_SILENT: |
796 |
case BYTE: add_int32_str(dest, (int32)(int8)aaa+old_mem*2+adr_off); |
797 |
break; |
798 |
case WORD_SILENT: |
799 |
case WORD: add_int32_str(dest, (int32)read_int16()+old_mem*2+adr_off); |
800 |
break; |
801 |
case LONG_SILENT: |
802 |
case LONG: add_int32_str(dest, read_int32()+old_mem*2+adr_off); |
803 |
break; |
804 |
} |
805 |
break; |
806 |
case AD_MULT: { |
807 |
int dir = 1; |
808 |
int off = 0; |
809 |
if (aaa != 0) { |
810 |
dir = -1; |
811 |
off = 15; |
812 |
} |
813 |
int lend = -1; |
814 |
bool first = true; |
815 |
for (int i=0;i < 16;i++) { |
816 |
if (((mask >> (off + dir * i))& 1) == 0) { |
817 |
// print reg from lend+1 to i-1 |
818 |
if ((lend+1) <= (i-1)) { |
819 |
if (!first) dest = strcat (dest,"/"); else first = false; |
820 |
if (((lend + 1) < 8) && ((i-1) > 7)) { |
821 |
print_range (lend+1,7); |
822 |
dest = strcat (dest,"/"); |
823 |
print_range (8,i-1); |
824 |
} else { |
825 |
print_range (lend+1,i-1); |
826 |
} |
827 |
} |
828 |
lend = i; |
829 |
} |
830 |
} |
831 |
if (((mask >> (off + dir * 15)) & 1) == 1) { // print last regs |
832 |
if (!first) dest = strcat (dest,"/"); |
833 |
print_range (lend+1,15); |
834 |
} |
835 |
break; |
836 |
} |
837 |
case AD_DATA_IMM: |
838 |
strcat (dest,"#"); |
839 |
switch (size) { |
840 |
case BYTE: case BYTE_SILENT: add_int8_str(dest,data_val); break; |
841 |
case WORD: case WORD_SILENT: add_int16_str(dest,data_val); break; |
842 |
case LONG: case LONG_SILENT: add_int32_str(dest,data_val); break; |
843 |
default: ; |
844 |
} |
845 |
break; |
846 |
case AD_DATA: |
847 |
switch (size) { |
848 |
case BYTE: case BYTE_SILENT: add_int8_str(dest,data_val); break; |
849 |
case WORD: case WORD_SILENT: add_int16_str(dest,data_val); break; |
850 |
case LONG: case LONG_SILENT: add_int32_str(dest,data_val); break; |
851 |
default: ; |
852 |
} |
853 |
break; |
854 |
case AD_CACHE: |
855 |
switch (aaa) { |
856 |
case 1: strcat(dest, "dc"); break; |
857 |
case 2: strcat(dest, "ic"); break; |
858 |
case 3: strcat(dest, "dc/ic"); break; |
859 |
default: strcat(dest, "?"); break; |
860 |
} |
861 |
break; |
862 |
default: |
863 |
error (ER_UNKNOWN_ADDRESS_MODE); |
864 |
return -1; |
865 |
} |
866 |
return 0; |
867 |
} |
868 |
|
869 |
static void diss (char *ndest,uint16 *nmem,int &npos,unsigned int adr) { |
870 |
dest = ndest; mem = nmem; mem_pos = npos; adr_off=adr; |
871 |
dest[0]=0; |
872 |
opcode = read_uint16 (); |
873 |
strcat(dest,"\t"); |
874 |
|
875 |
no_param("?") |
876 |
parse(); |
877 |
|
878 |
dest = strcat(dest,op_name); |
879 |
if ((dest_eee == AD_BRANCH) && (size != NOSIZE)) dest = strcat (dest,cc_str[dest_aaa]); |
880 |
switch (size) { |
881 |
case BYTE: strcat (dest,source_eee == AD_BRANCH ? ".s\t" : ".b\t"); break; |
882 |
case WORD: strcat (dest,source_eee == AD_BRANCH ? "\t" : ".w\t"); break; |
883 |
case LONG: strcat (dest,".l\t"); break; |
884 |
default: dest = strcat (dest,"\t"); break; |
885 |
} |
886 |
if (count_param > 0) { |
887 |
if (decode_address_mode(source_eee,source_aaa,size) == -1) { |
888 |
npos = mem_pos; |
889 |
return; |
890 |
} |
891 |
if (count_param > 1) { |
892 |
strcat (dest, ","); |
893 |
if (decode_address_mode(dest_eee,dest_aaa,size) == -1) { |
894 |
npos = mem_pos; |
895 |
return; |
896 |
} |
897 |
} |
898 |
} |
899 |
npos = mem_pos; |
900 |
} |
901 |
|
902 |
|
903 |
/* |
904 |
* Disassemble one instruction, return number of bytes |
905 |
*/ |
906 |
|
907 |
int disass_68k(FILE *f, uint32 adr, uint16 *m) |
908 |
{ |
909 |
char output[80]; |
910 |
int mem_pos = 0; |
911 |
diss(output, m, mem_pos,adr); |
912 |
for (int i=0;i<4;i++) if (i<mem_pos) fprintf(f,"%04x ", m[i]); else fprintf(f," "); |
913 |
fprintf(f, "%s\n", output); |
914 |
return mem_pos << 1; |
915 |
} |