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