comparison jagdis.c @ 1093:4987fddd42a0

Initial stab at jaguar disassemler
author Michael Pavone <pavone@retrodev.com>
date Sun, 30 Oct 2016 19:42:48 -0700
parents
children
comparison
equal deleted inserted replaced
1092:f338c950fcef 1093:4987fddd42a0
1 /*
2 Copyright 2013 Michael Pavone
3 This file is part of BlastEm.
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
5 */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <stdarg.h>
10 #include <ctype.h>
11 #include "tern.h"
12 #include "util.h"
13 #include "jagcpu.h"
14
15 uint8_t visited[(16*1024*1024)/16];
16 uint16_t label[(16*1024*1024)/8];
17
18 void fatal_error(char *format, ...)
19 {
20 va_list args;
21 va_start(args, format);
22 vfprintf(stderr, format, args);
23 va_end(args);
24 exit(1);
25 }
26
27
28 void visit(uint32_t address)
29 {
30 address &= 0xFFFFFF;
31 visited[address/16] |= 1 << ((address / 2) % 8);
32 }
33
34 void reference(uint32_t address)
35 {
36 address &= 0xFFFFFF;
37 //printf("referenced: %X\n", address);
38 label[address/16] |= 1 << (address % 16);
39 }
40
41 uint8_t is_visited(uint32_t address)
42 {
43 address &= 0xFFFFFF;
44 return visited[address/16] & (1 << ((address / 2) % 8));
45 }
46
47 uint16_t is_label(uint32_t address)
48 {
49 address &= 0xFFFFFF;
50 return label[address/16] & (1 << (address % 16));
51 }
52
53 typedef struct {
54 uint32_t num_labels;
55 uint32_t storage;
56 char *labels[];
57 } label_names;
58
59 tern_node * add_label(tern_node * head, char * name, uint32_t address)
60 {
61 char key[MAX_INT_KEY_SIZE];
62 address &= 0xFFFFFF;
63 reference(address);
64 tern_int_key(address, key);
65 label_names * names = tern_find_ptr(head, key);
66 if (names)
67 {
68 if (names->num_labels == names->storage)
69 {
70 names->storage = names->storage + (names->storage >> 1);
71 names = realloc(names, sizeof(label_names) + names->storage * sizeof(char *));
72 }
73 } else {
74 names = malloc(sizeof(label_names) + 4 * sizeof(char *));
75 names->num_labels = 0;
76 names->storage = 4;
77 head = tern_insert_ptr(head, key, names);
78 }
79 names->labels[names->num_labels++] = strdup(name);
80 return head;
81 }
82
83 typedef struct deferred {
84 uint32_t address;
85 struct deferred *next;
86 } deferred;
87
88 deferred * defer(uint32_t address, deferred * next)
89 {
90 if (is_visited(address) || address & 1) {
91 return next;
92 }
93 //printf("deferring %X\n", address);
94 deferred * d = malloc(sizeof(deferred));
95 d->address = address;
96 d->next = next;
97 return d;
98 }
99
100 void check_reference(uint16_t inst, uint32_t address, uint8_t is_gpu)
101 {
102 if (jag_opcode(inst, is_gpu) == JAG_JR) {
103 reference(jag_jr_dest(inst, address));
104 }
105 }
106
107 char * strip_ws(char * text)
108 {
109 while (*text && (!isprint(*text) || isblank(*text)))
110 {
111 text++;
112 }
113 char * ret = text;
114 text = ret + strlen(ret) - 1;
115 while (text > ret && (!isprint(*text) || isblank(*text)))
116 {
117 *text = 0;
118 text--;
119 }
120 return ret;
121 }
122
123 int main(int argc, char ** argv)
124 {
125 long filesize;
126 unsigned short *filebuf;
127 char disbuf[1024];
128 unsigned short * cur;
129 deferred *def = NULL, *tmpd;
130 uint32_t start = 0xFFFFFFFF;
131
132 uint8_t labels = 0, addr = 0, only = 0, vos = 0, reset = 0;
133 tern_node * named_labels = NULL;
134
135 uint32_t address_off = 0xFFFFFFFF, address_end;
136 uint8_t is_gpu = 1;
137 for(uint8_t opt = 2; opt < argc; ++opt) {
138 if (argv[opt][0] == '-') {
139 FILE * address_log;
140 switch (argv[opt][1])
141 {
142 case 'l':
143 labels = 1;
144 break;
145 case 'a':
146 addr = 1;
147 break;
148 case 'o':
149 only = 1;
150 break;
151 case 'r':
152 reset = 1;
153 break;
154 case 's':
155 opt++;
156 if (opt >= argc) {
157 fputs("-s must be followed by an offset\n", stderr);
158 exit(1);
159 }
160 address_off = strtol(argv[opt], NULL, 0);
161 break;
162 case 'p':
163 opt++;
164 if (opt >= argc) {
165 fputs("-p must be followed by a starting PC value\n", stderr);
166 exit(1);
167 }
168 start = strtol(argv[opt], NULL, 0);
169 break;
170 case 'd':
171 is_gpu = 0;
172 break;
173 case 'f':
174 opt++;
175 if (opt >= argc) {
176 fputs("-f must be followed by a filename\n", stderr);
177 exit(1);
178 }
179 address_log = fopen(argv[opt], "r");
180 if (!address_log) {
181 fprintf(stderr, "Failed to open %s for reading\n", argv[opt]);
182 exit(1);
183 }
184 while (fgets(disbuf, sizeof(disbuf), address_log)) {
185 if (disbuf[0]) {
186 char *end;
187 uint32_t address = strtol(disbuf, &end, 16);
188 if (address) {
189 def = defer(address, def);
190 reference(address);
191 if (*end == '=') {
192 named_labels = add_label(named_labels, strip_ws(end+1), address);
193 }
194 }
195 }
196 }
197 }
198 } else {
199 char *end;
200 uint32_t address = strtol(argv[opt], &end, 16);
201 def = defer(address, def);
202 reference(address);
203 if (*end == '=') {
204 named_labels = add_label(named_labels, end+1, address);
205 }
206 }
207 }
208 if (address_off == 0xFFFFFFFF) {
209 address_off = is_gpu ? 0xF03000 : 0xF1B000;
210 }
211 if (start == 0xFFFFFFFF) {
212 start = address_off;
213 }
214 FILE * f = fopen(argv[1], "rb");
215 fseek(f, 0, SEEK_END);
216 filesize = ftell(f);
217 fseek(f, 0, SEEK_SET);
218
219 char int_key[MAX_INT_KEY_SIZE];
220 address_end = address_off + filesize;
221 filebuf = malloc(filesize);
222 if (fread(filebuf, 2, filesize/2, f) != filesize/2)
223 {
224 fprintf(stderr, "Failure while reading file %s\n", argv[1]);
225 }
226 fclose(f);
227 for(cur = filebuf; cur - filebuf < (filesize/2); ++cur)
228 {
229 *cur = (*cur >> 8) | (*cur << 8);
230 }
231 named_labels = add_label(named_labels, "start", start);
232 if (!def || !only) {
233 def = defer(start, def);
234 }
235
236 uint16_t *encoded, *next;
237 uint32_t size, tmp_addr;
238 uint32_t address;
239 while(def) {
240 do {
241 encoded = NULL;
242 address = def->address;
243 if (!is_visited(address)) {
244 encoded = filebuf + (address - address_off)/2;
245 }
246 tmpd = def;
247 def = def->next;
248 free(tmpd);
249 } while(def && encoded == NULL);
250 if (!encoded) {
251 break;
252 }
253 for(;;) {
254 if (address > address_end || address < address_off) {
255 break;
256 }
257 visit(address);
258 uint16_t inst = *encoded;
259 uint32_t inst_address = address;
260 check_reference(inst, address, is_gpu);
261 uint16_t opcode = jag_opcode(inst, is_gpu);
262 if (opcode == JAG_MOVEI) {
263 address += 6;
264 encoded += 3;
265 } else {
266 address += 2;
267 encoded++;
268 }
269
270
271 if (opcode == JAG_JR || opcode == JAG_JUMP) {
272 if (!(jag_reg2(inst) & 0xF)) {
273 //unconditional jump
274 if (opcode == JAG_JR) {
275 address = jag_jr_dest(inst, inst_address);
276 reference(address);
277 if (is_visited(address)) {
278 break;
279 }
280 } else {
281 break;
282 }
283 } else if (opcode == JAG_JR) {
284 uint32_t dest = jag_jr_dest(inst, inst_address);
285 reference(dest);
286 def = defer(dest, def);
287 }
288 }
289 }
290 }
291 if (labels) {
292 for (address = 0; address < address_off; address++) {
293 if (is_label(address)) {
294 printf("ADR_%X equ $%X\n", address, address);
295 }
296 }
297 for (address = filesize; address < (16*1024*1024); address++) {
298 char key[MAX_INT_KEY_SIZE];
299 tern_int_key(address, key);
300 label_names *names = tern_find_ptr(named_labels, key);
301 if (names) {
302 for (int i = 0; i < names->num_labels; i++)
303 {
304 printf("%s equ $%X\n", names->labels[i], address);
305 }
306 } else if (is_label(address)) {
307 printf("ADR_%X equ $%X\n", address, address);
308 }
309 }
310 puts("");
311 }
312 for (address = address_off; address < address_end; address+=2) {
313 if (is_visited(address)) {
314 encoded = filebuf + (address-address_off)/2;
315 jag_cpu_disasm(&encoded, address, disbuf, is_gpu, labels);
316 if (labels) {
317 char keybuf[MAX_INT_KEY_SIZE];
318 label_names * names = tern_find_ptr(named_labels, tern_int_key(address, keybuf));
319 if (names)
320 {
321 for (int i = 0; i < names->num_labels; i++)
322 {
323 printf("%s:\n", names->labels[i]);
324 }
325 } else if (is_label(address)) {
326 printf("ADR_%X:\n", address);
327 }
328 if (addr) {
329 printf("\t%s\t;%X\n", disbuf, address);
330 } else {
331 printf("\t%s\n", disbuf);
332 }
333 } else {
334 printf("%X: %s\n", address, disbuf);
335 }
336 }
337 }
338 return 0;
339 }