]> Shamusworld >> Repos - virtualjaguar/blob - src/m68000/m68kdasm.c
007f9d696ddcbd2fa3b28925d149662e2f21f0ca
[virtualjaguar] / src / m68000 / m68kdasm.c
1 //
2 // m68kdasm.c: 68000 instruction disassembly
3 //
4 // Originally part of the UAE 68000 cpu core
5 // by Bernd Schmidt
6 //
7 // Adapted to Virtual Jaguar by James Hammons
8 //
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.
11 //
12
13 #include <string.h>
14 #include "cpudefs.h"
15 #include "cpuextra.h"
16 #include "inlines.h"
17 #include "readcpu.h"
18
19
20 // Stuff from m68kinterface.c
21 extern unsigned long IllegalOpcode(uint32_t opcode);
22 extern cpuop_func * cpuFunctionTable[65536];
23
24 // Local "global" variables
25 static long int m68kpc_offset;
26
27 #if 0
28 #define get_ibyte_1(o) get_byte(regs.pc + (regs.pc_p - regs.pc_oldp) + (o) + 1)
29 #define get_iword_1(o) get_word(regs.pc + (regs.pc_p - regs.pc_oldp) + (o))
30 #define get_ilong_1(o) get_long(regs.pc + (regs.pc_p - regs.pc_oldp) + (o))
31 #else
32 #define get_ibyte_1(o) m68k_read_memory_8(regs.pc + (o) + 1)
33 #define get_iword_1(o) m68k_read_memory_16(regs.pc + (o))
34 #define get_ilong_1(o) m68k_read_memory_32(regs.pc + (o))
35 #endif
36
37
38 int32_t ShowEA(FILE * f, int reg, amodes mode, wordsizes size, char * buf)
39 {
40         uint16_t dp;
41         int8_t disp8;
42         int16_t disp16;
43         int r;
44         uint32_t dispreg;
45         uint32_t addr;
46         int32_t offset = 0;
47         char buffer[80];
48
49         switch (mode)
50         {
51         case Dreg:
52                 sprintf(buffer,"D%d", reg);
53                 break;
54         case Areg:
55                 sprintf(buffer,"A%d", reg);
56                 break;
57         case Aind:
58                 sprintf(buffer,"(A%d)", reg);
59                 break;
60         case Aipi:
61                 sprintf(buffer,"(A%d)+", reg);
62                 break;
63         case Apdi:
64                 sprintf(buffer,"-(A%d)", reg);
65                 break;
66         case Ad16:
67                 disp16 = get_iword_1(m68kpc_offset); m68kpc_offset += 2;
68                 addr = m68k_areg(regs,reg) + (int16_t)disp16;
69                 sprintf(buffer,"(A%d,$%04X) == $%08lX", reg, disp16 & 0xFFFF,
70                         (unsigned long)addr);
71                 break;
72         case Ad8r:
73                 dp = get_iword_1(m68kpc_offset); m68kpc_offset += 2;
74                 disp8 = dp & 0xFF;
75                 r = (dp & 0x7000) >> 12;
76                 dispreg = (dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r));
77
78                 if (!(dp & 0x800))
79                         dispreg = (int32_t)(int16_t)(dispreg);
80
81                 dispreg <<= (dp >> 9) & 3;
82
83                 if (dp & 0x100)
84                 {
85                         int32_t outer = 0, disp = 0;
86                         int32_t base = m68k_areg(regs,reg);
87                         char name[10];
88                         sprintf (name,"A%d, ",reg);
89                         if (dp & 0x80) { base = 0; name[0] = 0; }
90                         if (dp & 0x40) dispreg = 0;
91                         if ((dp & 0x30) == 0x20) { disp = (int32_t)(int16_t)get_iword_1(m68kpc_offset); m68kpc_offset += 2; }
92                         if ((dp & 0x30) == 0x30) { disp = get_ilong_1(m68kpc_offset); m68kpc_offset += 4; }
93                         base += disp;
94
95                         if ((dp & 0x3) == 0x2) { outer = (int32_t)(int16_t)get_iword_1(m68kpc_offset); m68kpc_offset += 2; }
96                         if ((dp & 0x3) == 0x3) { outer = get_ilong_1(m68kpc_offset); m68kpc_offset += 4; }
97
98                         if (!(dp & 4)) base += dispreg;
99                         if (dp & 3) base = m68k_read_memory_32(base);
100                         if (dp & 4) base += dispreg;
101
102                         addr = base + outer;
103                         sprintf(buffer,"(%s%c%d.%c*%d+%ld)+%ld == $%08lX", name,
104                                 dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
105                                 1 << ((dp >> 9) & 3),
106                                 (long)disp, (long)outer, (unsigned long)addr);
107                 }
108                 else
109                 {
110                         addr = m68k_areg(regs,reg) + (int32_t)((int8_t)disp8) + dispreg;
111                         sprintf (buffer,"(A%d, %c%d.%c*%d, $%02X) == $%08lX", reg,
112                                 dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
113                                 1 << ((dp >> 9) & 3), disp8, (unsigned long)addr);
114                 }
115                 break;
116         case PC16:
117                 addr = m68k_getpc() + m68kpc_offset;
118                 disp16 = get_iword_1(m68kpc_offset); m68kpc_offset += 2;
119                 addr += (int16_t)disp16;
120                 sprintf(buffer,"(PC,$%04X) == $%08lX", disp16 & 0xffff,(unsigned long)addr);
121                 break;
122         case PC8r:
123                 addr = m68k_getpc() + m68kpc_offset;
124                 dp = get_iword_1(m68kpc_offset); m68kpc_offset += 2;
125                 disp8 = dp & 0xFF;
126                 r = (dp & 0x7000) >> 12;
127                 dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r);
128
129                 if (!(dp & 0x800))
130                         dispreg = (int32_t)(int16_t)(dispreg);
131
132                 dispreg <<= (dp >> 9) & 3;
133
134                 if (dp & 0x100)
135                 {
136                         int32_t outer = 0,disp = 0;
137                         int32_t base = addr;
138                         char name[10];
139                         sprintf (name,"PC, ");
140                         if (dp & 0x80) { base = 0; name[0] = 0; }
141                         if (dp & 0x40) dispreg = 0;
142                         if ((dp & 0x30) == 0x20) { disp = (int32_t)(int16_t)get_iword_1(m68kpc_offset); m68kpc_offset += 2; }
143                         if ((dp & 0x30) == 0x30) { disp = get_ilong_1(m68kpc_offset); m68kpc_offset += 4; }
144                         base += disp;
145
146                         if ((dp & 0x3) == 0x2)
147                         {
148                                 outer = (int32_t)(int16_t)get_iword_1(m68kpc_offset);
149                                 m68kpc_offset += 2;
150                         }
151
152                         if ((dp & 0x3) == 0x3)
153                         {
154                                 outer = get_ilong_1(m68kpc_offset);
155                                 m68kpc_offset += 4;
156                         }
157
158                         if (!(dp & 4)) base += dispreg;
159                         if (dp & 3) base = m68k_read_memory_32(base);
160                         if (dp & 4) base += dispreg;
161
162                         addr = base + outer;
163                         sprintf(buffer,"(%s%c%d.%c*%d+%ld)+%ld == $%08lX", name,
164                                 dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
165                                 1 << ((dp >> 9) & 3), (long)disp, (long)outer, (unsigned long)addr);
166                 }
167                 else
168                 {
169                         addr += (int32_t)((int8_t)disp8) + dispreg;
170                         sprintf(buffer,"(PC, %c%d.%c*%d, $%02X) == $%08lX", dp & 0x8000 ? 'A' : 'D',
171                                 (int)r, dp & 0x800 ? 'L' : 'W',  1 << ((dp >> 9) & 3),
172                                 disp8, (unsigned long)addr);
173                 }
174                 break;
175         case absw:
176                 sprintf(buffer,"$%08lX", (unsigned long)(int32_t)(int16_t)get_iword_1(m68kpc_offset));
177                 m68kpc_offset += 2;
178                 break;
179         case absl:
180                 sprintf(buffer,"$%08lX", (unsigned long)get_ilong_1(m68kpc_offset));
181                 m68kpc_offset += 4;
182                 break;
183         case imm:
184                 switch (size)
185                 {
186                 case sz_byte:
187                         sprintf(buffer,"#$%02X", (unsigned int)(get_iword_1(m68kpc_offset) & 0xFF));
188                         m68kpc_offset += 2;
189                         break;
190                 case sz_word:
191                         sprintf(buffer,"#$%04X", (unsigned int)(get_iword_1(m68kpc_offset) & 0xFFFF));
192                         m68kpc_offset += 2;
193                         break;
194                 case sz_long:
195                         sprintf(buffer,"#$%08lX", (unsigned long)(get_ilong_1(m68kpc_offset)));
196                         m68kpc_offset += 4;
197                         break;
198                 default:
199                         break;
200                 }
201                 break;
202         case imm0:
203                 offset = (int32_t)(int8_t)get_iword_1(m68kpc_offset);
204                 m68kpc_offset += 2;
205                 sprintf (buffer,"#$%02X", (unsigned int)(offset & 0xFF));
206                 break;
207         case imm1:
208                 offset = (int32_t)(int16_t)get_iword_1(m68kpc_offset);
209                 m68kpc_offset += 2;
210                 sprintf (buffer,"#$%04X", (unsigned int)(offset & 0xFFFF));
211                 break;
212         case imm2:
213                 offset = (int32_t)get_ilong_1(m68kpc_offset);
214                 m68kpc_offset += 4;
215                 sprintf(buffer,"#$%08lX", (unsigned long)offset);
216                 break;
217         case immi:
218                 offset = (int32_t)(int8_t)(reg & 0xFF);
219                 sprintf(buffer,"#$%08lX", (unsigned long)offset);
220                 break;
221         default:
222                 break;
223         }
224
225         if (buf == 0)
226                 fprintf(f, "%s", buffer);
227         else
228                 strcat(buf, buffer);
229
230         return offset;
231 }
232
233
234 //void m68k_disasm(FILE * f, uint32_t addr, uint32_t * nextpc, int cnt)
235 unsigned int m68k_disasm(char * output, uint32_t addr, uint32_t * nextpc, int cnt)
236 {
237         char f[256], str[256];
238         static const char * const ccnames[] =
239                 { "RA","RN","HI","LS","CC","CS","NE","EQ",
240                   "VC","VS","PL","MI","GE","LT","GT","LE" };
241
242         str[0] = 0;
243         output[0] = 0;
244         uint32_t newpc = 0;
245         m68kpc_offset = addr - m68k_getpc();
246         long int pcOffsetSave = m68kpc_offset;
247         int opwords;
248
249         while (cnt-- > 0)
250         {
251                 char instrname[20], * ccpt;
252                 uint32_t opcode;
253                 const struct mnemolookup * lookup;
254                 struct instr * dp;
255 //              sprintf(f, "%06lX: ", m68k_getpc() + m68kpc_offset);
256 //              strcat(str, f);
257
258 #if 0
259                 for(opwords=0; opwords<5; opwords++)
260                 {
261                         sprintf(f, "%04X ", get_iword_1(m68kpc_offset + opwords * 2));
262                         strcat(str, f);
263                 }
264 #endif
265
266                 opcode = get_iword_1(m68kpc_offset);
267                 m68kpc_offset += 2;
268
269                 if (cpuFunctionTable[opcode] == IllegalOpcode)
270                 {
271                         opcode = 0x4AFC;
272                 }
273
274                 dp = table68k + opcode;
275
276                 for(lookup=lookuptab; lookup->mnemo!=dp->mnemo; lookup++)
277                         ;
278
279                 strcpy(instrname, lookup->name);
280                 ccpt = strstr(instrname, "cc");
281
282                 if (ccpt != 0)
283                 {
284                         strncpy(ccpt, ccnames[dp->cc], 2);
285                 }
286
287                 sprintf(f, "%s", instrname);
288                 strcat(str, f);
289
290 #if 0
291                 switch (dp->size)
292                 {
293                         case sz_byte: sprintf(f, ".B "); break;
294                         case sz_word: sprintf(f, ".W "); break;
295                         case sz_long: sprintf(f, ".L "); break;
296                         default: sprintf(f, "   "); break;
297                 }
298                 strcat(str, f);
299 #else
300                 switch (dp->size)
301                 {
302                         case sz_byte: strcat(str, ".B\t"); break;
303                         case sz_word: strcat(str, ".W\t"); break;
304                         case sz_long: strcat(str, ".L\t"); break;
305                         default: strcat(str, "\t"); break;
306                 }
307 #endif
308
309                 if (dp->suse)
310                 {
311                         f[0] = 0;
312                         newpc = m68k_getpc() + m68kpc_offset;
313                         newpc += ShowEA(0, dp->sreg, dp->smode, dp->size, f);
314                         strcat(str, f);
315                 }
316
317 #if 1
318                 if (dp->suse && dp->duse)
319                 {
320 //                      sprintf(f, ",");
321 //                      strcat(str, f);
322                         strcat(str, ", ");
323                 }
324 #endif
325
326                 if (dp->duse)
327                 {
328                         f[0] = 0;
329                         newpc = m68k_getpc() + m68kpc_offset;
330                         newpc += ShowEA(0, dp->dreg, dp->dmode, dp->size, f);
331                         strcat(str, f);
332                 }
333
334                 if (ccpt != 0)
335                 {
336                         if (cctrue(dp->cc))
337                                 sprintf(f, " == %08lX (TRUE)", (long)newpc);
338                         else
339                                 sprintf(f, " == %08lX (FALSE)", (long)newpc);
340
341                         strcat(str, f);
342                 }
343                 else if ((opcode & 0xFF00) == 0x6100) // BSR
344                 {
345                         sprintf(f, " == %08lX", (long)newpc);
346                         strcat(str, f);
347                 }
348
349 //              fprintf(f, "\n");
350         }
351
352 //      if (nextpc)
353 //              *nextpc = m68k_getpc() + m68kpc_offset;
354
355         long int numberOfBytes = m68kpc_offset - pcOffsetSave;
356
357         for(opwords=0; opwords<5; opwords++)
358         {
359                 if (((opwords + 1) * 2) <= numberOfBytes)
360                         sprintf(f, "%04X ", get_iword_1(pcOffsetSave + opwords * 2));
361                 else
362                         sprintf(f, "     ");
363
364                 strcat(output, f);
365         }
366
367         strcat(output, str);
368
369         return numberOfBytes;
370 }
371
372 //
373 // Disasemble one instruction at pc and store in str_buff
374 //
375 unsigned int m68k_disassemble(char * str_buff, unsigned int pc, unsigned int cpu_type)
376 {
377         return m68k_disasm(str_buff, pc, 0, 1);
378 }