Mercurial > hg-old > index.cgi
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 } |