]> Shamusworld >> Repos - virtualjaguar/blob - src/m68000/m68kdasm.c
Fixed limits on cartridge space from 4MB to 6MB.
[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 // Prototypes
25 void HandleMovem(char * output, uint16_t data, int direction);
26
27 // Local "global" variables
28 static long int m68kpc_offset;
29
30 #if 0
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))
34 #else
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))
38 #endif
39
40
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)
43 {
44         uint16_t dp;
45         int8_t disp8;
46         int16_t disp16;
47         int r;
48         uint32_t dispreg;
49         uint32_t addr;
50         int32_t offset = 0;
51         char buffer[80];
52
53         switch (mode)
54         {
55         case Dreg:
56                 sprintf(buffer,"D%d", reg);
57                 break;
58         case Areg:
59                 sprintf(buffer,"A%d", reg);
60                 break;
61         case Aind:
62                 sprintf(buffer,"(A%d)", reg);
63                 break;
64         case Aipi:
65                 sprintf(buffer,"(A%d)+", reg);
66                 break;
67         case Apdi:
68                 sprintf(buffer,"-(A%d)", reg);
69                 break;
70         case Ad16:
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,
74                         (unsigned long)addr);
75                 break;
76         case Ad8r:
77                 dp = get_iword_1(m68kpc_offset); m68kpc_offset += 2;
78                 disp8 = dp & 0xFF;
79                 r = (dp & 0x7000) >> 12;
80                 dispreg = (dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r));
81
82                 if (!(dp & 0x800))
83                         dispreg = (int32_t)(int16_t)(dispreg);
84
85                 dispreg <<= (dp >> 9) & 3;
86
87                 if (dp & 0x100)
88                 {
89                         int32_t outer = 0, disp = 0;
90                         int32_t base = m68k_areg(regs,reg);
91                         char name[10];
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; }
97                         base += disp;
98
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; }
101
102                         if (!(dp & 4)) base += dispreg;
103                         if (dp & 3) base = m68k_read_memory_32(base);
104                         if (dp & 4) base += dispreg;
105
106                         addr = base + outer;
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);
111                 }
112                 else
113                 {
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);
118                 }
119                 break;
120         case PC16:
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);
125                 break;
126         case PC8r:
127                 addr = m68k_getpc() + m68kpc_offset;
128                 dp = get_iword_1(m68kpc_offset); m68kpc_offset += 2;
129                 disp8 = dp & 0xFF;
130                 r = (dp & 0x7000) >> 12;
131                 dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r);
132
133                 if (!(dp & 0x800))
134                         dispreg = (int32_t)(int16_t)(dispreg);
135
136                 dispreg <<= (dp >> 9) & 3;
137
138                 if (dp & 0x100)
139                 {
140                         int32_t outer = 0,disp = 0;
141                         int32_t base = addr;
142                         char name[10];
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; }
148                         base += disp;
149
150                         if ((dp & 0x3) == 0x2)
151                         {
152                                 outer = (int32_t)(int16_t)get_iword_1(m68kpc_offset);
153                                 m68kpc_offset += 2;
154                         }
155
156                         if ((dp & 0x3) == 0x3)
157                         {
158                                 outer = get_ilong_1(m68kpc_offset);
159                                 m68kpc_offset += 4;
160                         }
161
162                         if (!(dp & 4)) base += dispreg;
163                         if (dp & 3) base = m68k_read_memory_32(base);
164                         if (dp & 4) base += dispreg;
165
166                         addr = base + outer;
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);
170                 }
171                 else
172                 {
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);
177                 }
178                 break;
179         case absw:
180                 sprintf(buffer,"$%lX", (unsigned long)(int32_t)(int16_t)get_iword_1(m68kpc_offset));
181                 m68kpc_offset += 2;
182                 break;
183         case absl:
184                 sprintf(buffer,"$%lX", (unsigned long)get_ilong_1(m68kpc_offset));
185                 m68kpc_offset += 4;
186                 break;
187         case imm:
188                 switch (size)
189                 {
190                 case sz_byte:
191                         sprintf(buffer,"#$%X", (unsigned int)(get_iword_1(m68kpc_offset) & 0xFF));
192                         m68kpc_offset += 2;
193                         break;
194                 case sz_word:
195                         sprintf(buffer,"#$%X", (unsigned int)(get_iword_1(m68kpc_offset) & 0xFFFF));
196                         m68kpc_offset += 2;
197                         break;
198                 case sz_long:
199                         sprintf(buffer,"#$%lX", (unsigned long)(get_ilong_1(m68kpc_offset)));
200                         m68kpc_offset += 4;
201                         break;
202                 default:
203                         break;
204                 }
205                 break;
206         case imm0:
207                 offset = (int32_t)(int8_t)get_iword_1(m68kpc_offset);
208                 m68kpc_offset += 2;
209                 sprintf(buffer,"#$%X", (unsigned int)(offset & 0xFF));
210                 break;
211         case imm1:
212                 offset = (int32_t)(int16_t)get_iword_1(m68kpc_offset);
213                 m68kpc_offset += 2;
214
215                 if (mnemonic == i_MVMEL)
216                 {
217                         HandleMovem(buffer, offset, 0);
218                 }
219                 else if (mnemonic == i_MVMLE)
220                 {
221                         HandleMovem(buffer, offset, 1);
222                 }
223                 else
224                         sprintf(buffer,"#$%X", (unsigned int)(offset & 0xFFFF));
225
226                 break;
227         case imm2:
228                 offset = (int32_t)get_ilong_1(m68kpc_offset);
229                 m68kpc_offset += 4;
230                 sprintf(buffer,"#$%lX", (unsigned long)(offset & 0xFFFFFFFF));
231                 break;
232         case immi:
233                 offset = (int32_t)(int8_t)(reg & 0xFF);
234                 sprintf(buffer,"#$%lX", (unsigned long)(offset & 0xFFFFFFFF));
235                 break;
236         default:
237                 break;
238         }
239
240 //      if (buf == 0)
241 //              fprintf(f, "%s", buffer);
242 //      else
243         strcat(buf, buffer);
244
245         return offset;
246 }
247
248
249 void HandleMovem(char * output, uint16_t data, int direction)
250 {
251 #if 0
252 static void d68000_movem_re_32(void)
253 {
254         uint data = read_imm_16();
255         char buffer[40];
256         uint first;
257         uint run_length;
258         uint i;
259
260         buffer[0] = 0;
261
262         for(i=0; i<8; i++)
263         {
264                 if (data & (1 << i))    // (15 - i) for pre-decr
265                 {
266                         first = i;
267                         run_length = 0;
268
269                         for(i++; i<8; i++)
270                                 if (data & (1 << i))    // 15 - i
271                                         run_length++;
272
273                         if (buffer[0] != 0)
274                                 strcat(buffer, "/");
275
276                         sprintf(buffer+strlen(buffer), "D%d", first);
277
278                         if (run_length > 0)
279                                 sprintf(buffer+strlen(buffer), "-D%d", first + run_length);
280                 }
281         }
282
283         for(i=0; i<8; i++)
284         {
285                 if (data & (1 << (i + 8)))      // (7 - i) for pre-decr
286                 {
287                         first = i;
288                         run_length = 0;
289
290                         for(i++; i<8; i++)
291                                 if (data & (1 << (i + 8)))      // 7 - i
292                                         run_length++;
293
294                         if (buffer[0] != 0)
295                                 strcat(buffer, "/");
296
297                         sprintf(buffer+strlen(buffer), "A%d", first);
298
299                         if (run_length > 0)
300                                 sprintf(buffer+strlen(buffer), "-A%d", first + run_length);
301                 }
302         }
303
304         sprintf(g_dasm_str, "movem.l %s, %s", buffer, get_ea_mode_str_32(g_cpu_ir));
305 }
306 #else
307         uint16_t ascending[16] = {
308                 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
309                 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000 };
310         uint16_t descending[16] = {
311                 0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100,
312                 0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004, 0x0002, 0x0001 };
313
314         int i, j, first, runLength, firstPrint = 1;
315         char buf[16];
316         uint16_t * bitMask;
317
318         bitMask = (direction ? descending : ascending);
319         output[0] = 0;
320
321 //printf("HM: data = $%X\n", data);
322 //$42E0
323         // Handle D0-D7...
324         for(i=0; i<8; i++)
325         {
326 //printf(" D: i=%d\n", i);
327                 if (data & bitMask[i])
328                 {
329                         first = i;
330                         runLength = 0;
331
332 //                      while ((++i < 8) && (data & bitMask[i]))
333                         for(j=i+1; j<8 && (data & bitMask[j]); j++)
334                                 runLength++;
335
336                         i += runLength;
337
338                         if (firstPrint)
339                                 firstPrint = 0;
340                         else
341                                 strcat(output, "/");
342
343                         sprintf(buf, "D%d", first);
344                         strcat(output, buf);
345
346                         if (runLength > 0)
347                         {
348                                 sprintf(buf, "-D%d", first + runLength);
349                                 strcat(output, buf);
350                         }
351                 }
352         }
353
354         // Handle A0-A7...
355         for(i=0; i<8; i++)
356         {
357 //printf(" A: i=%d\n", i);
358                 if (data & bitMask[i + 8])
359                 {
360                         first = i;
361                         runLength = 0;
362
363 //                      while ((++i < 8) && (data & bitMask[i + 8]))
364                         for(j=i+1; j<8 && (data & bitMask[j+8]); j++)
365                                 runLength++;
366
367                         i += runLength;
368
369                         if (firstPrint)
370                                 firstPrint = 0;
371                         else
372                                 strcat(output, "/");
373
374                         sprintf(buf, "A%d", first);
375                         strcat(output, buf);
376
377                         if (runLength > 0)
378                         {
379                                 sprintf(buf, "-A%d", first + runLength);
380                                 strcat(output, buf);
381                         }
382                 }
383         }
384 #endif
385 }
386
387
388 unsigned int m68k_disasm(char * output, uint32_t addr, uint32_t * nextpc, int cnt)
389 {
390         char f[256], str[256];
391         static const char * const ccnames[] =
392                 { "RA","RN","HI","LS","CC","CS","NE","EQ",
393                   "VC","VS","PL","MI","GE","LT","GT","LE" };
394
395         str[0] = 0;
396         output[0] = 0;
397         uint32_t newpc = 0;
398         m68kpc_offset = addr - m68k_getpc();
399         long int pcOffsetSave = m68kpc_offset;
400         int opwords;
401
402         while (cnt-- > 0)
403         {
404                 char instrname[20], * ccpt;
405                 uint32_t opcode;
406                 const struct mnemolookup * lookup;
407                 struct instr * dp;
408
409                 opcode = get_iword_1(m68kpc_offset);
410                 m68kpc_offset += 2;
411
412                 if (cpuFunctionTable[opcode] == IllegalOpcode)
413                         opcode = 0x4AFC;
414
415                 dp = table68k + opcode;
416
417                 for(lookup=lookuptab; lookup->mnemo!=dp->mnemo; lookup++)
418                         ;
419
420                 strcpy(instrname, lookup->name);
421                 ccpt = strstr(instrname, "cc");
422
423                 if (ccpt)
424                         strncpy(ccpt, ccnames[dp->cc], 2);
425
426                 sprintf(f, "%s", instrname);
427                 strcat(str, f);
428
429                 switch (dp->size)
430                 {
431                         case sz_byte: strcat(str, ".B\t"); break;
432                         case sz_word: strcat(str, ".W\t"); break;
433                         case sz_long: strcat(str, ".L\t"); break;
434                         default: strcat(str, "\t"); break;
435                 }
436
437                 if (dp->suse)
438                 {
439                         f[0] = 0;
440                         newpc = m68k_getpc() + m68kpc_offset;
441                         newpc += ShowEA(dp->mnemo, dp->sreg, dp->smode, dp->size, f);
442
443                         // Don't display if branch or BSR or MVMLE, but DO let this go
444                         // if it's a DBRcc...
445 //This is still not right... !!! FIX !!!
446                         if (!(ccpt && dp->mnemo == i_DBcc) && !((opcode & 0xFF00) == 0x6100))
447 //                              && (ccpt && dp->mnemo == i_DBcc)
448                                 strcat(str, f);
449                 }
450
451                 if (dp->suse && dp->duse)
452                         strcat(str, ", ");
453
454                 if (dp->duse)
455                 {
456                         f[0] = 0;
457                         newpc = m68k_getpc() + m68kpc_offset;
458                         newpc += ShowEA(dp->mnemo, dp->dreg, dp->dmode, dp->size, f);
459
460                         if (!ccpt && !((opcode & 0xFF00) == 0x6100))
461                                 strcat(str, f);
462                 }
463
464                 if (ccpt)
465                 {
466                         if (cctrue(dp->cc))
467                                 sprintf(f, "$%lX (TRUE)", (long)newpc);
468                         else
469                                 sprintf(f, "$%lX (FALSE)", (long)newpc);
470
471                         strcat(str, f);
472                 }
473                 else if ((opcode & 0xFF00) == 0x6100) // BSR
474                 {
475                         sprintf(f, "$%lX", (long)newpc);
476                         strcat(str, f);
477                 }
478         }
479
480         long int numberOfBytes = m68kpc_offset - pcOffsetSave;
481
482         for(opwords=0; opwords<5; opwords++)
483         {
484                 if (((opwords + 1) * 2) <= numberOfBytes)
485                         sprintf(f, "%04X ", get_iword_1(pcOffsetSave + opwords * 2));
486                 else
487                         sprintf(f, "     ");
488
489                 strcat(output, f);
490         }
491
492         strcat(output, str);
493
494         return numberOfBytes;
495 }
496
497
498 //
499 // Disasemble one instruction at pc and store in str_buff
500 //
501 unsigned int m68k_disassemble(char * str_buff, unsigned int pc, unsigned int cpu_type)
502 {
503         return m68k_disasm(str_buff, pc, 0, 1);
504 }
505