]> Shamusworld >> Repos - virtualjaguar/blob - src/m68000/m68kdasm.c
2.0.2 release.
[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         // Sanity checking...
238 //      if (addr > 0xFFFFFF)
239 //              addr = 0;
240
241         char f[256], str[256];
242         static const char * const ccnames[] =
243                 { "T ","F ","HI","LS","CC","CS","NE","EQ",
244                   "VC","VS","PL","MI","GE","LT","GT","LE" };
245
246         str[0] = 0;
247         output[0] = 0;
248         uint32_t newpc = 0;
249         m68kpc_offset = addr - m68k_getpc();
250         long int pcOffsetSave = m68kpc_offset;
251         int opwords;
252
253         while (cnt-- > 0)
254         {
255                 char instrname[20], * ccpt;
256                 uint32_t opcode;
257                 const struct mnemolookup * lookup;
258                 struct instr * dp;
259 //              sprintf(f, "%06lX: ", m68k_getpc() + m68kpc_offset);
260 //              strcat(str, f);
261
262 #if 0
263                 for(opwords=0; opwords<5; opwords++)
264                 {
265                         sprintf(f, "%04X ", get_iword_1(m68kpc_offset + opwords * 2));
266                         strcat(str, f);
267                 }
268 #endif
269
270                 opcode = get_iword_1(m68kpc_offset);
271                 m68kpc_offset += 2;
272
273                 if (cpuFunctionTable[opcode] == IllegalOpcode)
274                 {
275                         opcode = 0x4AFC;
276                 }
277
278                 dp = table68k + opcode;
279
280                 for(lookup=lookuptab; lookup->mnemo!=dp->mnemo; lookup++)
281                         ;
282
283                 strcpy(instrname, lookup->name);
284                 ccpt = strstr(instrname, "cc");
285
286                 if (ccpt != 0)
287                 {
288                         strncpy(ccpt, ccnames[dp->cc], 2);
289                 }
290
291                 sprintf(f, "%s", instrname);
292                 strcat(str, f);
293
294 #if 0
295                 switch (dp->size)
296                 {
297                         case sz_byte: sprintf(f, ".B "); break;
298                         case sz_word: sprintf(f, ".W "); break;
299                         case sz_long: sprintf(f, ".L "); break;
300                         default: sprintf(f, "   "); break;
301                 }
302                 strcat(str, f);
303 #else
304                 switch (dp->size)
305                 {
306                         case sz_byte: strcat(str, ".B "); break;
307                         case sz_word: strcat(str, ".W "); break;
308                         case sz_long: strcat(str, ".L "); break;
309                         default: strcat(str, "   "); break;
310                 }
311 #endif
312
313                 if (dp->suse)
314                 {
315                         f[0] = 0;
316                         newpc = m68k_getpc() + m68kpc_offset;
317                         newpc += ShowEA(0, dp->sreg, dp->smode, dp->size, f);
318                         strcat(str, f);
319                 }
320
321 #if 1
322                 if (dp->suse && dp->duse)
323                 {
324 //                      sprintf(f, ",");
325 //                      strcat(str, f);
326                         strcat(str, ",");
327                 }
328 #endif
329
330                 if (dp->duse)
331                 {
332                         f[0] = 0;
333                         newpc = m68k_getpc() + m68kpc_offset;
334                         newpc += ShowEA(0, dp->dreg, dp->dmode, dp->size, f);
335                         strcat(str, f);
336                 }
337
338                 if (ccpt != 0)
339                 {
340                         if (cctrue(dp->cc))
341                                 sprintf(f, " == %08lX (TRUE)", (long)newpc);
342                         else
343                                 sprintf(f, " == %08lX (FALSE)", (long)newpc);
344
345                         strcat(str, f);
346                 }
347                 else if ((opcode & 0xFF00) == 0x6100) // BSR
348                 {
349                         sprintf(f, " == %08lX", (long)newpc);
350                         strcat(str, f);
351                 }
352
353 //              fprintf(f, "\n");
354         }
355
356 //      if (nextpc)
357 //              *nextpc = m68k_getpc() + m68kpc_offset;
358
359         long int numberOfBytes = m68kpc_offset - pcOffsetSave;
360
361         for(opwords=0; opwords<5; opwords++)
362         {
363                 if (((opwords + 1) * 2) <= numberOfBytes)
364                         sprintf(f, "%04X ", get_iword_1(pcOffsetSave + opwords * 2));
365                 else
366                         sprintf(f, "     ");
367
368                 strcat(output, f);
369         }
370
371         strcat(output, str);
372
373         return numberOfBytes;
374 }
375
376 //
377 // Disasemble one instruction at pc and store in str_buff
378 //
379 unsigned int m68k_disassemble(char * str_buff, unsigned int pc, unsigned int cpu_type)
380 {
381         return m68k_disasm(str_buff, pc, 0, 1);
382 }