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