comparison lwdisasm/insn.c @ 409:cba03436c720

Checkpoint disassembler
author lost@l-w.ca
date Mon, 02 Aug 2010 18:07:04 -0600
parents
children
comparison
equal deleted inserted replaced
408:2a94b2e64621 409:cba03436c720
1 /*
2 insn.c
3
4 Copyright © 2010 William Astle
5
6 This file is part of LWTOOLS.
7
8 LWTOOLS is free software: you can redistribute it and/or modify it under the
9 terms of the GNU General Public License as published by the Free Software
10 Foundation, either version 3 of the License, or (at your option) any later
11 version.
12
13 This program is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 more details.
17
18 You should have received a copy of the GNU General Public License along with
19 this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include <lw_alloc.h>
29 #include <lw_string.h>
30
31 #include "lwdisasm.h"
32
33 /*
34 this function creates a linedata_t with the disassembly of the
35 current location; returns NULL if the current disassembly point
36 is not a valid instruction or we are at the end of the input
37 */
38
39 #define fb(d) do { int ____t; ____t = fetch_byte(as); if (____t < 0) return NULL; bytes[len++] = ____t; (d) = ____t; } while (0)
40 #define fb2(d) do { int ____t; ____t = fetch_byte(as); if (____t < 0) return "?"; bytes[(*len)++] = ____t; (d) = ____t; } while (0)
41
42 char *encode_target(disasmstate_t *as, int addr, int section)
43 {
44 symbol_t *s;
45 static char buffer[256];
46
47 s = find_symbol(as, addr, section);
48 if (!s)
49 {
50 sprintf(buffer, "$%04X", addr);
51 return buffer;
52 }
53 else
54 {
55 return s -> symbol;
56 }
57 }
58
59 char *decode_indexed(disasmstate_t *as, char *bytes, int *len, int *target, int section)
60 {
61 int pb, b1, b2;
62 int rn;
63 static char *rs[] = { "x", "y", "u", "s", "pcr" };
64 static char str[40];
65 char *i1 = "", *i2 = "";
66 char *tstr;
67 *target = -1;
68
69 fb2(pb);
70
71 rn = (pb >> 5) & 3;
72
73 if (pb < 0x80)
74 {
75 // 5 bit
76 b1 = pb & 15;
77 if (pb & 16)
78 b1 = b1 - 16;
79
80 sprintf(str, "%d,%s", b1, rs[rn]);
81 return str;
82 }
83 if ((pb & 0x1F) == 0x1F)
84 {
85 // extended indirect
86 fb2(b1);
87 fb2(b2);
88 sprintf(str, "[$%04X]", (b1 << 8) | b2);
89 return str;
90 }
91
92 if (pb & 0x10)
93 {
94 i1 = "[";
95 i2 = "]";
96 }
97
98 switch (pb & 0x0F)
99 {
100 case 0: // ,r+
101 if (*i1 == '[')
102 {
103 break;
104 }
105 sprintf(str, "%s,%s+%s", i1, rs[rn], i2);
106 return str;
107
108 case 1: // ,r++
109 sprintf(str, "%s,%s++%s", i1, rs[rn], i2);
110 return str;
111
112 case 2: // ,-r
113 if (*i1 == '[')
114 {
115 break;
116 }
117 sprintf(str, "%s,-%s%s", i1, rs[rn], i2);
118 return str;
119
120 case 3: // ,--r
121 sprintf(str, "%s,--%s%s", i1, rs[rn], i2);
122 return str;
123
124 case 4: // ,r
125 sprintf(str, "%s,%s%s", i1, rs[rn], i2);
126 return str;
127
128 case 5: // B,r
129 sprintf(str, "%sb,%s%s", i1, rs[rn], i2);
130 return str;
131
132 case 6: // A,r
133 sprintf(str, "%sa,%s%s", i1, rs[rn], i2);
134 return str;
135
136 case 8: // 8 bit,r
137 fb2(b1);
138 if (b1 > 128)
139 b1 -= 256;
140 sprintf(str, "%s<$%02X,%s%s", i1, b1, rs[rn], i2);
141 return str;
142
143 case 9: // 16 bit,r
144 fb2(b1);
145 fb2(b2);
146 b1 = (b1 << 8) | b2;
147 if (b2 > 32768)
148 b2 -= 65536;
149 sprintf(str, "%s>$%04X,%s%s", i1, b1, rs[rn], i2);
150 return str;
151
152 case 11: // D,r
153 sprintf(str, "%sd,%s%s", i1, rs[rn], i2);
154 return str;
155
156 case 12: // 8 bit,PCR
157 fb2(b1);
158 if (b1 > 127)
159 b1 -= 256;
160 b1 += as -> curoff;
161 b1 &= 0xFFFF;
162 sprintf(str, "%s<%s,pcr%s", i1, encode_target(as, b1, section), i2);
163 *target = b1;
164 return str;
165
166 case 13: // 16 bit,PCR
167 fb2(b1);
168 fb2(b2);
169 b1 = (b1 << 8) | b2;
170 b1 += as -> curoff;
171 b1 &= 0xFFFF;
172 sprintf(str, "%s>%s,pcr%s", i1, encode_target(as, b1, section), i2);
173 *target = b1;
174 return str;
175 }
176
177 // if we got here, we have an illegal 6809
178 if (as -> target == TARGET_6809)
179 {
180 sprintf(str, "?");
181 return str;
182 }
183
184 // now sort out 6309 operations
185 pb &= 0x1F;
186
187 switch (pb)
188 {
189 case 0x07:
190 case 0x17:
191 // E,r
192 sprintf(str, "%se,%s%s", i1, rs[rn], i2);
193 return str;
194
195 case 0x0A:
196 case 0x1A:
197 // F,r
198 sprintf(str, "%sf,%s%s", i1, rs[rn], i2);
199 return str;
200
201 case 0x0E:
202 case 0x1E:
203 // W,r
204 sprintf(str, "%sw,%s%s", i1, rs[rn], i2);
205 return str;
206
207 case 0x0F:
208 case 0x10:
209 // W indexing
210 switch (rn)
211 {
212 case 0: // ,W
213 sprintf(str, "%s,w%s", i1, i2);
214 return str;
215
216 case 1: // 16 bit,W
217 fb2(b1);
218 fb2(b2);
219 b1 = (b1 << 8) | b2;
220 if (b1 > 32768)
221 b1 -= 65536;
222 sprintf(str, "%s>$%04X,w%s", i1, b1, i2);
223 return str;
224
225 case 2: // ,W++
226 sprintf(str, "%s,w++%s", i1, i2);
227 return str;
228
229 case 3: // ,--W
230 sprintf(str, "%s,--w%s", i1, i2);
231 return str;
232 }
233 }
234
235 sprintf(str, "?");
236 return str;
237 }
238
239 char *decode_operand(disasmstate_t *as, int addrmode, uint8_t *bytes, int *len, int *target, int section)
240 {
241 int b1, b2, b3, b4;
242 static char insnbuffer[256];
243 char *t;
244 static char *rlist3[] = { "D", "X", "Y", "U", "S", "PC", "W", "V", "A", "B", "CC", "DP", "0", "0", "E", "F" };
245 static char *rlist8[] = { "D", "X", "Y", "U", "S", "PC", "?", "?", "A", "B", "CC", "DP", "?", "?", "?", "?" };
246 char **rlist = (as -> target == TARGET_6809) ? rlist8 : rlist3;
247
248 switch (addrmode)
249 {
250 case ADDR_IMM8:
251 fb2(b1);
252 sprintf(insnbuffer, "#$%02X", b1);
253 break;
254
255 case ADDR_IMM16:
256 fb2(b1);
257 fb2(b2);
258 sprintf(insnbuffer, "#$%04X", (b1 << 8) | b2);
259 break;
260
261 case ADDR_IMM32:
262 fb2(b1);
263 fb2(b2);
264 fb2(b3);
265 fb2(b4);
266 sprintf(insnbuffer, "#$%08X", (b1 << 24) | (b2 << 16) | (b3 << 8) | b4);
267 break;
268
269 case ADDR_DIR:
270 fb2(b1);
271 sprintf(insnbuffer, "<%s", encode_target(as, (as -> dpval << 8) | b1, section));
272 *target = as -> dpval * 256 + b1;
273 break;
274
275 case ADDR_EXT:
276 fb2(b1);
277 fb2(b2);
278 sprintf(insnbuffer, ">%s", encode_target(as, (b1 << 8) | b2, section));
279 *target = (b1 << 8) | b2;
280 break;
281
282 case ADDR_INH:
283 *insnbuffer = 0;
284 break;
285
286 case ADDR_IMM8DIR:
287 fb2(b1);
288 fb2(b2);
289 sprintf(insnbuffer, "#$%02X;<%s", b1, encode_target(as, (as -> dpval << 8) | b2, section));
290 *target = (as -> dpval << 8) | b2;
291 break;
292
293 case ADDR_IMM8EXT:
294 fb2(b1);
295 fb2(b2);
296 fb2(b3);
297 sprintf(insnbuffer, "#$%02X;>%s", b1, encode_target(as, (b2 << 8) | b3, section));
298 *target = (b2 << 8) | b3;
299 break;
300
301 case ADDR_IMM8IND:
302 fb2(b1);
303 t = decode_indexed(as, bytes, len, target, section);
304 sprintf(insnbuffer, "#$%02X;%s", b1, t);
305 break;
306
307 case ADDR_IND:
308 t = decode_indexed(as, bytes, len, target, section);
309 sprintf(insnbuffer, "%s", t);
310 break;
311
312 case ADDR_RTOR:
313 fb2(b1);
314 b2 = b1 & 0x0F;
315 b1 = b1 >> 4;
316 sprintf(insnbuffer, "%s,%s", rlist[b1], rlist[b2]);
317 break;
318
319 case ADDR_BITBIT:
320 fb2(b1);
321 fb2(b2);
322 sprintf(insnbuffer, "%s,%d,%d;<%s",
323 (b1 >> 6 == 0) ? "CC" : ((b1 >> 6 == 1) ? "A" : ((b1 >> 6 == 2) ? "B" : "?")),
324 (b1 >> 3) & 7, b1 & 7, encode_target(as, (as -> dpval << 8) | b2, section));
325 *target = (as -> dpval << 8) | b2;
326 break;
327
328 case ADDR_PSHPULS:
329 insnbuffer[0] = 0;
330 fb2(b1);
331 if (b1 & 0x01)
332 {
333 strcat(insnbuffer, ",cc");
334 }
335 if (b1 & 0x02)
336 {
337 strcat(insnbuffer, ",a");
338 }
339 if (b1 & 0x04)
340 {
341 strcat(insnbuffer, ",b");
342 }
343 if (b1 & 0x08)
344 {
345 strcat(insnbuffer, ",dp");
346 }
347 if (b1 & 0x10)
348 {
349 strcat(insnbuffer, "x");
350 }
351 if (b1 & 0x20)
352 {
353 strcat(insnbuffer, "y");
354 }
355 if (b1 & 0x40)
356 {
357 strcat(insnbuffer, "u");
358 }
359 if (b1 & 0x80)
360 {
361 strcat(insnbuffer, "pc");
362 }
363 return insnbuffer + 1;
364 break;
365
366 case ADDR_PSHPULU:
367 insnbuffer[0] = 0;
368 fb2(b1);
369 if (b1 & 0x01)
370 {
371 strcat(insnbuffer, ",cc");
372 }
373 if (b1 & 0x02)
374 {
375 strcat(insnbuffer, ",a");
376 }
377 if (b1 & 0x04)
378 {
379 strcat(insnbuffer, ",b");
380 }
381 if (b1 & 0x08)
382 {
383 strcat(insnbuffer, ",dp");
384 }
385 if (b1 & 0x10)
386 {
387 strcat(insnbuffer, "x");
388 }
389 if (b1 & 0x20)
390 {
391 strcat(insnbuffer, "y");
392 }
393 if (b1 & 0x40)
394 {
395 strcat(insnbuffer, "s");
396 }
397 if (b1 & 0x80)
398 {
399 strcat(insnbuffer, "pc");
400 }
401 return insnbuffer + 1;
402
403 case ADDR_REL8:
404 fb2(b1);
405 if (b1 > 127)
406 b1 -= 256;
407 b1 += as -> curoff;
408 b1 &= 0xFFFF;
409 sprintf(insnbuffer, "%s", encode_target(as, b1, section));
410 *target = b1;
411 break;
412
413 case ADDR_REL16:
414 fb2(b1);
415 if (b1 > 32767)
416 b1 -= 65536;
417 b1 += as -> curoff;
418 b1 &= 0xFFFF;
419 sprintf(insnbuffer, "%s", encode_target(as, b1, section));
420 *target = b2;
421 break;
422
423 case ADDR_TFMPP:
424 fb2(b1);
425 b2 = b1 & 0x0F;
426 b1 >>= 4;
427 sprintf(insnbuffer, "%s+,%s+", rlist[b1], rlist[b2]);
428 break;
429
430 case ADDR_TFMMM:
431 fb2(b1);
432 b2 = b1 & 0x0F;
433 b1 >>= 4;
434 sprintf(insnbuffer, "%s-,%s-", rlist[b1], rlist[b2]);
435 break;
436
437 case ADDR_TFMPC:
438 fb2(b1);
439 b2 = b1 & 0x0F;
440 b1 >>= 4;
441 sprintf(insnbuffer, "%s+,%s", rlist[b1], rlist[b2]);
442 break;
443
444 case ADDR_TFMCP:
445 fb2(b1);
446 b2 = b1 & 0x0F;
447 b1 >>= 4;
448 sprintf(insnbuffer, "%s,%s+", rlist[b1], rlist[b2]);
449 break;
450
451 default:
452 sprintf(insnbuffer, "????");
453 break;
454 }
455
456 return insnbuffer;
457 }
458
459 linedata_t *disasm_insn(disasmstate_t *as)
460 {
461 int curbyte;
462 int b1;
463 linedata_t *l;
464 char *opcode;
465 int addrmode;
466 char insnbuffer[256];
467 char *t;
468 int addr;
469 int len = 0;
470 int8_t bytes[10];
471 int target = -1;
472
473 addr = as -> curoff;
474
475 fb(curbyte);
476 if (curbyte < 0)
477 return NULL;
478
479 opcode = as->page0[curbyte].op;
480 addrmode = as->page0[curbyte].addrmode;
481
482 if (addrmode == ADDR_PAGE1)
483 {
484 fb(b1);
485 if (b1 < 0)
486 return NULL;
487 opcode = as->page1[b1].op;
488 addrmode = as->page1[b1].addrmode;
489 curbyte = (curbyte << 8) | b1;
490 }
491 else if (addrmode == ADDR_PAGE2)
492 {
493 fb(b1);
494 if (b1 < 0)
495 return NULL;
496 opcode = as->page2[b1].op;
497 addrmode = as->page2[b1].addrmode;
498 curbyte = (curbyte << 8) | b1;
499 }
500
501 if (opcode == NULL)
502 return NULL;
503
504 t = decode_operand(as, addrmode, bytes, &len, &target, 0);
505
506 if (!t)
507 return NULL;
508
509 // now create the line structure
510 l = lw_alloc(sizeof(linedata_t));
511 l -> next = NULL;
512 l -> prev = NULL;
513 l -> address = addr;
514 l -> type = type_code;
515 l -> length = len;
516 l -> bytes = lw_alloc(len);
517 memmove(l -> bytes, bytes, len);
518 l -> isref = 0;
519 l -> symbol = NULL;
520 l -> sectionref = 0;
521 sprintf(insnbuffer, "%s %s", opcode, t);
522 l -> disasm = lw_strdup(insnbuffer);
523 l -> target = target;
524 return l;
525 }
526
527 void redisasm_insn(disasmstate_t *as, linedata_t *l)
528 {
529 char *opcode;
530 int addrmode;
531 int len = 0;
532 char bytes[15];
533 int target = -1;
534 char *t;
535 char insnbuf[256];
536 int ta;
537 int ts;
538
539 // short circuit if no target in this one
540 if (l -> target == -1)
541 return;
542
543 opcode = as -> page0[l -> bytes[0]].op;
544 addrmode = as -> page0[l -> bytes[0]].addrmode;
545
546 ta = as -> curoff;
547 as -> curoff = l -> address + 1;
548
549 if (addrmode == ADDR_PAGE1)
550 {
551 opcode = as -> page1[l -> bytes[1]].op;
552 addrmode = as -> page1[l -> bytes[1]].addrmode;
553 as -> curoff++;
554 }
555 else if (addrmode == ADDR_PAGE2)
556 {
557 opcode = as -> page2[l -> bytes[1]].op;
558 addrmode = as -> page2[l -> bytes[1]].addrmode;
559 as -> curoff++;
560 }
561
562 t = decode_operand(as, addrmode, bytes, &len, &target, l -> sectionref);
563
564 // now create the line structure
565 lw_free(l -> disasm);
566 sprintf(insnbuf, "%s %s", opcode, t);
567 l -> disasm = lw_strdup(insnbuf);
568 }