2 // m68kdasm.c: 68000 instruction disassembly
4 // Originally part of the UAE 68000 cpu core
7 // Adapted to Virtual Jaguar by James Hammons
9 // This file is distributed under the GNU Public License, version 3 or at your
10 // option any later version. Read the file GPLv3 for details.
20 // Stuff from m68kinterface.c
21 extern unsigned long IllegalOpcode(uint32_t opcode
);
22 extern cpuop_func
* cpuFunctionTable
[65536];
25 void HandleMovem(char * output
, uint16_t data
, int direction
);
27 // Local "global" variables
28 static long int m68kpc_offset
;
31 #define get_ibyte_1(o) get_byte(regs.pc + (regs.pc_p - regs.pc_oldp) + (o) + 1)
32 #define get_iword_1(o) get_word(regs.pc + (regs.pc_p - regs.pc_oldp) + (o))
33 #define get_ilong_1(o) get_long(regs.pc + (regs.pc_p - regs.pc_oldp) + (o))
35 #define get_ibyte_1(o) m68k_read_memory_8(regs.pc + (o) + 1)
36 #define get_iword_1(o) m68k_read_memory_16(regs.pc + (o))
37 #define get_ilong_1(o) m68k_read_memory_32(regs.pc + (o))
41 //int32_t ShowEA(FILE * f, int reg, amodes mode, wordsizes size, char * buf)
42 int32_t ShowEA(int mnemonic
, int reg
, amodes mode
, wordsizes size
, char * buf
)
56 sprintf(buffer
,"D%d", reg
);
59 sprintf(buffer
,"A%d", reg
);
62 sprintf(buffer
,"(A%d)", reg
);
65 sprintf(buffer
,"(A%d)+", reg
);
68 sprintf(buffer
,"-(A%d)", reg
);
71 disp16
= get_iword_1(m68kpc_offset
); m68kpc_offset
+= 2;
72 addr
= m68k_areg(regs
,reg
) + (int16_t)disp16
;
73 sprintf(buffer
,"(A%d,$%X) == $%lX", reg
, disp16
& 0xFFFF,
77 dp
= get_iword_1(m68kpc_offset
); m68kpc_offset
+= 2;
79 r
= (dp
& 0x7000) >> 12;
80 dispreg
= (dp
& 0x8000 ? m68k_areg(regs
,r
) : m68k_dreg(regs
,r
));
83 dispreg
= (int32_t)(int16_t)(dispreg
);
85 dispreg
<<= (dp
>> 9) & 3;
89 int32_t outer
= 0, disp
= 0;
90 int32_t base
= m68k_areg(regs
,reg
);
92 sprintf (name
,"A%d, ",reg
);
93 if (dp
& 0x80) { base
= 0; name
[0] = 0; }
94 if (dp
& 0x40) dispreg
= 0;
95 if ((dp
& 0x30) == 0x20) { disp
= (int32_t)(int16_t)get_iword_1(m68kpc_offset
); m68kpc_offset
+= 2; }
96 if ((dp
& 0x30) == 0x30) { disp
= get_ilong_1(m68kpc_offset
); m68kpc_offset
+= 4; }
99 if ((dp
& 0x3) == 0x2) { outer
= (int32_t)(int16_t)get_iword_1(m68kpc_offset
); m68kpc_offset
+= 2; }
100 if ((dp
& 0x3) == 0x3) { outer
= get_ilong_1(m68kpc_offset
); m68kpc_offset
+= 4; }
102 if (!(dp
& 4)) base
+= dispreg
;
103 if (dp
& 3) base
= m68k_read_memory_32(base
);
104 if (dp
& 4) base
+= dispreg
;
107 sprintf(buffer
,"(%s%c%d.%c*%d+%ld)+%ld == $%lX", name
,
108 dp
& 0x8000 ? 'A' : 'D', (int)r
, dp
& 0x800 ? 'L' : 'W',
109 1 << ((dp
>> 9) & 3),
110 (long)disp
, (long)outer
, (unsigned long)addr
);
114 addr
= m68k_areg(regs
,reg
) + (int32_t)((int8_t)disp8
) + dispreg
;
115 sprintf (buffer
,"(A%d, %c%d.%c*%d, $%X) == $%lX", reg
,
116 dp
& 0x8000 ? 'A' : 'D', (int)r
, dp
& 0x800 ? 'L' : 'W',
117 1 << ((dp
>> 9) & 3), disp8
, (unsigned long)addr
);
121 addr
= m68k_getpc() + m68kpc_offset
;
122 disp16
= get_iword_1(m68kpc_offset
); m68kpc_offset
+= 2;
123 addr
+= (int16_t)disp16
;
124 sprintf(buffer
,"(PC, $%X) == $%lX", disp16
& 0xFFFF, (unsigned long)addr
);
127 addr
= m68k_getpc() + m68kpc_offset
;
128 dp
= get_iword_1(m68kpc_offset
); m68kpc_offset
+= 2;
130 r
= (dp
& 0x7000) >> 12;
131 dispreg
= dp
& 0x8000 ? m68k_areg(regs
,r
) : m68k_dreg(regs
,r
);
134 dispreg
= (int32_t)(int16_t)(dispreg
);
136 dispreg
<<= (dp
>> 9) & 3;
140 int32_t outer
= 0,disp
= 0;
143 sprintf (name
,"PC, ");
144 if (dp
& 0x80) { base
= 0; name
[0] = 0; }
145 if (dp
& 0x40) dispreg
= 0;
146 if ((dp
& 0x30) == 0x20) { disp
= (int32_t)(int16_t)get_iword_1(m68kpc_offset
); m68kpc_offset
+= 2; }
147 if ((dp
& 0x30) == 0x30) { disp
= get_ilong_1(m68kpc_offset
); m68kpc_offset
+= 4; }
150 if ((dp
& 0x3) == 0x2)
152 outer
= (int32_t)(int16_t)get_iword_1(m68kpc_offset
);
156 if ((dp
& 0x3) == 0x3)
158 outer
= get_ilong_1(m68kpc_offset
);
162 if (!(dp
& 4)) base
+= dispreg
;
163 if (dp
& 3) base
= m68k_read_memory_32(base
);
164 if (dp
& 4) base
+= dispreg
;
167 sprintf(buffer
,"(%s%c%d.%c*%d+%ld)+%ld == $%lX", name
,
168 dp
& 0x8000 ? 'A' : 'D', (int)r
, dp
& 0x800 ? 'L' : 'W',
169 1 << ((dp
>> 9) & 3), (long)disp
, (long)outer
, (unsigned long)addr
);
173 addr
+= (int32_t)((int8_t)disp8
) + dispreg
;
174 sprintf(buffer
,"(PC, %c%d.%c*%d, $%X) == $%lX", dp
& 0x8000 ? 'A' : 'D',
175 (int)r
, dp
& 0x800 ? 'L' : 'W', 1 << ((dp
>> 9) & 3),
176 disp8
, (unsigned long)addr
);
180 sprintf(buffer
,"$%lX", (unsigned long)(int32_t)(int16_t)get_iword_1(m68kpc_offset
));
184 sprintf(buffer
,"$%lX", (unsigned long)get_ilong_1(m68kpc_offset
));
191 sprintf(buffer
,"#$%X", (unsigned int)(get_iword_1(m68kpc_offset
) & 0xFF));
195 sprintf(buffer
,"#$%X", (unsigned int)(get_iword_1(m68kpc_offset
) & 0xFFFF));
199 sprintf(buffer
,"#$%lX", (unsigned long)(get_ilong_1(m68kpc_offset
)));
207 offset
= (int32_t)(int8_t)get_iword_1(m68kpc_offset
);
209 sprintf(buffer
,"#$%X", (unsigned int)(offset
& 0xFF));
212 offset
= (int32_t)(int16_t)get_iword_1(m68kpc_offset
);
215 if (mnemonic
== i_MVMEL
)
216 HandleMovem(buffer
, offset
, 0);
217 else if (mnemonic
== i_MVMLE
)
218 HandleMovem(buffer
, offset
, 1);
220 sprintf(buffer
,"#$%X", (unsigned int)(offset
& 0xFFFF));
224 offset
= (int32_t)get_ilong_1(m68kpc_offset
);
226 sprintf(buffer
,"#$%lX", (unsigned long)(offset
& 0xFFFFFFFF));
229 offset
= (int32_t)(int8_t)(reg
& 0xFF);
230 sprintf(buffer
,"#$%lX", (unsigned long)(offset
& 0xFFFFFFFF));
237 // fprintf(f, "%s", buffer);
245 void HandleMovem(char * output
, uint16_t data
, int direction
)
247 uint16_t ascending
[16] = {
248 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
249 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000 };
250 uint16_t descending
[16] = {
251 0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100,
252 0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004, 0x0002, 0x0001 };
254 int i
, j
, first
, runLength
, firstPrint
= 1;
258 bitMask
= (direction
? descending
: ascending
);
264 if (data
& bitMask
[i
])
269 for(j
=i
+1; j
<8 && (data
& bitMask
[j
]); j
++)
279 sprintf(buf
, "D%d", first
);
284 sprintf(buf
, "-D%d", first
+ runLength
);
293 if (data
& bitMask
[i
+ 8])
298 for(j
=i
+1; j
<8 && (data
& bitMask
[j
+8]); j
++)
308 sprintf(buf
, "A%d", first
);
313 sprintf(buf
, "-A%d", first
+ runLength
);
321 // Disassemble the M68K line based on the address
322 // Append, or not, the line with the ouput pointer and return the number of bytes
323 unsigned int M68KDisassemble(char * output
, uint32_t addr
, unsigned int OpCodes
)
325 char f
[256], str
[256];
326 char src
[256], dst
[256];
327 static const char * const ccnames
[] =
328 { "RA","RN","HI","LS","CC","CS","NE","EQ",
329 "VC","VS","PL","MI","GE","LT","GT","LE" };
334 m68kpc_offset
= addr
- m68k_getpc();
335 long int pcOffsetSave
= m68kpc_offset
;
338 const struct mnemolookup
* lookup
;
341 uint32_t opcode
= get_iword_1(m68kpc_offset
);
344 // replace an illegal opcode by the illegal opcode
345 if (cpuFunctionTable
[opcode
] == IllegalOpcode
)
348 // point on the opcode information
349 struct instr
* dp
= table68k
+ opcode
;
351 // get the instruction name from the opcode
352 for(lookup
=lookuptab
; lookup
->mnemo
!=dp
->mnemo
; lookup
++);
353 strcpy(instrname
, lookup
->name
);
355 // look for a branching instruction
356 char * ccpt
= strstr(instrname
, "cc");
358 // correct branch naming
360 strncpy(ccpt
, ccnames
[dp
->cc
], 2);
362 // keep the instruction name
363 sprintf(f
, "%s", instrname
);
366 // set instruction size
369 case sz_byte
: strcat(str
, ".B\t"); break;
370 case sz_word
: strcat(str
, ".W\t"); break;
371 case sz_long
: strcat(str
, ".L\t"); break;
372 default: strcat(str
, "\t"); break;
376 src
[0] = dst
[0] = f
[0] = 0;
378 // get source operand in src
380 newpc
= m68k_getpc() + m68kpc_offset
+ ShowEA(dp
->mnemo
, dp
->sreg
, dp
->smode
, dp
->size
, src
);
382 // get destination operand in dst
384 newpc
= m68k_getpc() + m68kpc_offset
+ ShowEA(dp
->mnemo
, dp
->dreg
, dp
->dmode
, dp
->size
, dst
);
386 // Handle execptions to the standard rules
387 if (dp
->mnemo
== i_BSR
|| dp
->mnemo
== i_Bcc
)
388 sprintf(f
, "$%lX", (long)newpc
);
389 else if (dp
->mnemo
== i_DBcc
)
390 sprintf(f
, "%s, $%lX", src
, (long)newpc
);
391 else if (dp
->mnemo
== i_MVMEL
)
392 sprintf(f
, "%s, %s", dst
, src
);
394 sprintf(f
, "%s%s%s", src
, (dp
->suse
&& dp
->duse
? ", " : ""), dst
);
400 sprintf(f
, " (%s)", (cctrue(dp
->cc
) ? "true" : "false"));
404 // Add byte(s) display to front of disassembly
405 long int numberOfBytes
= m68kpc_offset
- pcOffsetSave
;
407 for(opwords
=0; opwords
<5; opwords
++)
409 if (((opwords
+ 1) * 2) <= numberOfBytes
)
410 sprintf(f
, "%04X ", get_iword_1(pcOffsetSave
+ opwords
* 2));
417 // add the line to the output
418 OpCodes
? strcat(output
, str
) : strcpy(output
, str
);
420 return numberOfBytes
;
425 // Disassemble one instruction at pc and store in str_buff
427 unsigned int m68k_disassemble(char * str_buff
, unsigned int pc
, unsigned int cpu_type
, unsigned int OpCodes
)
429 return M68KDisassemble(str_buff
, pc
, OpCodes
);