2717
|
1 #include <stdio.h>
|
|
2 #include <stdlib.h>
|
|
3 #include <string.h>
|
|
4 #include <stdarg.h>
|
|
5 #include "upd78k2_dis.h"
|
|
6 #include "util.h"
|
|
7
|
|
8 int headless;
|
|
9 void render_errorbox(char *title, char *message) {}
|
|
10 void render_warnbox(char *title, char *message) {}
|
|
11 void render_infobox(char *title, char *message) {}
|
|
12
|
|
13 typedef struct {
|
|
14 uint16_t address_off;
|
|
15 uint16_t address_end;
|
|
16 uint8_t *buffer;
|
|
17 } rom_def;
|
|
18
|
|
19 uint8_t fetch(uint16_t address, void *data)
|
|
20 {
|
|
21 rom_def *rom = data;
|
|
22 if (address >= rom->address_off && address < rom->address_end) {
|
|
23 return rom->buffer[(address - rom->address_off)];
|
|
24 }
|
|
25 return 0;
|
|
26 }
|
|
27
|
|
28 void print_label_def(char *key, tern_val val, uint8_t valtype, void *data)
|
|
29 {
|
|
30 rom_def *rom = data;
|
|
31 label_def *label = val.ptrval;
|
|
32 uint32_t address = label->full_address & 0xFFFF;
|
|
33 if (address >= rom->address_off && address < rom->address_end) {
|
|
34 return;
|
|
35 }
|
|
36 if (!label->referenced) {
|
|
37 return;
|
|
38 }
|
|
39 if (label->num_labels) {
|
|
40 for (int i = 0; i < label->num_labels; i++)
|
|
41 {
|
|
42 printf("%s equ 0%XH\n", label->labels[i], label->full_address);
|
|
43 }
|
|
44 } else {
|
|
45 printf("ADR_%X equ 0%XH\n", label->full_address, label->full_address);
|
|
46 }
|
|
47 }
|
|
48
|
|
49 void format_data(disasm_context *context, rom_def *rom, uint8_t labels, uint16_t start_address, uint16_t end_address)
|
|
50 {
|
|
51 char label_buf[256];
|
|
52 for (uint16_t address = start_address; address < end_address;)
|
|
53 {
|
|
54 if (labels) {
|
|
55 uint16_t end = address + 8;
|
|
56 if (end > end_address) {
|
|
57 end = end_address;
|
|
58 }
|
|
59 uint16_t start = address;
|
|
60 if (!(address & 1) && address < 0x80) {
|
|
61 for (; address < end; address += 2) {
|
|
62 uint16_t value = fetch(address, rom);
|
|
63 value |= fetch(address + 1, rom) << 8;
|
|
64 format_label(label_buf, value, context);
|
|
65 if (address == start) {
|
|
66 printf("\tdw %s", label_buf);
|
|
67 } else {
|
|
68 printf(", %s", label_buf);
|
|
69 }
|
|
70 }
|
|
71 } else {
|
|
72 if (address < 0x80) {
|
|
73 end = address + 1;
|
|
74 }
|
|
75 for (; address < end; address++) {
|
|
76 uint8_t value = fetch(address, rom);
|
|
77 if (address == start) {
|
|
78 printf("\tdb 0%02XH", value);
|
|
79 } else {
|
|
80 printf(", 0%02XH", value);
|
|
81 }
|
|
82 }
|
|
83 }
|
|
84 address = end;
|
|
85 puts("");
|
|
86 } else {
|
|
87 uint8_t value = fetch(address, rom);
|
|
88 printf("%X: %X\n", address, value);
|
|
89 address++;
|
|
90 }
|
|
91 }
|
|
92 }
|
|
93
|
|
94 int main(int argc, char ** argv)
|
|
95 {
|
|
96 long filesize;
|
|
97 uint8_t *filebuf = NULL;
|
|
98 char disbuf[1024];
|
|
99
|
|
100 uint8_t labels = 0, addr = 0, only = 0, reset = 0;
|
|
101 disasm_context *context = create_upd78k2_disasm();
|
|
102
|
|
103 uint32_t address_off = 0, address_end;
|
|
104 for(uint8_t opt = 2; opt < argc; ++opt) {
|
|
105 if (argv[opt][0] == '-') {
|
|
106 FILE * address_log;
|
|
107 switch (argv[opt][1])
|
|
108 {
|
|
109 case 'l':
|
|
110 labels = 1;
|
|
111 break;
|
|
112 case 'a':
|
|
113 addr = 1;
|
|
114 break;
|
|
115 case 'o':
|
|
116 only = 1;
|
|
117 break;
|
|
118 case 'r':
|
|
119 reset = 1;
|
|
120 break;
|
|
121 case 's':
|
|
122 opt++;
|
|
123 if (opt >= argc) {
|
|
124 fputs("-s must be followed by an offset\n", stderr);
|
|
125 exit(1);
|
|
126 }
|
|
127 address_off = strtol(argv[opt], NULL, 0);
|
|
128 break;
|
|
129 case 'f':
|
|
130 opt++;
|
|
131 if (opt >= argc) {
|
|
132 fputs("-f must be followed by a filename\n", stderr);
|
|
133 exit(1);
|
|
134 }
|
|
135 address_log = fopen(argv[opt], "r");
|
|
136 if (!address_log) {
|
|
137 fprintf(stderr, "Failed to open %s for reading\n", argv[opt]);
|
|
138 exit(1);
|
|
139 }
|
|
140 while (fgets(disbuf, sizeof(disbuf), address_log)) {
|
|
141 if (disbuf[0]) {
|
|
142 char *end;
|
|
143 uint32_t address = strtol(disbuf, &end, 16);
|
|
144 if (address) {
|
|
145 defer_disasm(context, address);
|
|
146 if (*end == '=') {
|
|
147 add_label(context, strip_ws(end+1), address);
|
|
148 } else {
|
|
149 reference(context, address);
|
|
150 }
|
|
151 }
|
|
152 }
|
|
153 }
|
|
154 fclose(address_log);
|
|
155 }
|
|
156 } else {
|
|
157 char *end;
|
|
158 uint32_t address = strtol(argv[opt], &end, 16);
|
|
159 defer_disasm(context, address);
|
|
160 if (*end == '=') {
|
|
161 add_label(context, end+1, address);
|
|
162 } else {
|
|
163 reference(context, address);
|
|
164 }
|
|
165 }
|
|
166 }
|
|
167 if (labels) {
|
|
168 add_upd7823x_labels(context);
|
|
169 }
|
|
170 FILE * f = fopen(argv[1], "rb");
|
|
171 fseek(f, 0, SEEK_END);
|
|
172 filesize = ftell(f);
|
|
173 fseek(f, 0, SEEK_SET);
|
|
174
|
|
175 char int_key[MAX_INT_KEY_SIZE];
|
|
176 uint8_t has_manual_defs = !!context->deferred;
|
|
177 filebuf = malloc(filesize);
|
|
178 if (fread(filebuf, 1, filesize, f) != filesize)
|
|
179 {
|
|
180 fprintf(stderr, "Failure while reading file %s\n", argv[1]);
|
|
181 }
|
|
182 address_end = address_off + filesize;
|
|
183 if (address_end > 0xFB00) {
|
|
184 //correct for uPD78237 and some other members of the uPD78K/II family
|
|
185 //but others allow external ROM up to higher addresses
|
|
186 address_end = 0xFB00;
|
|
187 }
|
|
188 if (!address_off && filesize >= 0x40) {
|
|
189 char *vector_names[] = {
|
|
190 "reset",
|
|
191 "nmi",
|
|
192 NULL,
|
|
193 "intp0",
|
|
194 "intp1",
|
|
195 "intp2",
|
|
196 "intp3",
|
|
197 "intp4_intc30",
|
|
198 "intp5_intad",
|
|
199 "intc20_intp6",
|
|
200 "intc00",
|
|
201 "intc01",
|
|
202 "intc10",
|
|
203 "intc11",
|
|
204 "intc21",
|
|
205 NULL,
|
|
206 "intser",
|
|
207 "intsr",
|
|
208 "intst",
|
|
209 "intcsi",
|
|
210 [0x3E/2] = "brkex"
|
|
211 };
|
|
212 for (int i = 0; i < sizeof(vector_names)/sizeof(*vector_names); i++)
|
|
213 {
|
|
214 if (vector_names[i]) {
|
|
215 uint16_t address = filebuf[i * 2] | (filebuf[i * 2 + 1] << 8);
|
|
216 if (address < address_end) {
|
|
217 defer_disasm(context, address);
|
|
218 add_label(context, vector_names[i], address);
|
|
219 }
|
|
220 }
|
|
221 }
|
|
222 }
|
|
223 rom_def rom = {
|
|
224 .address_off = address_off,
|
|
225 .address_end = address_end,
|
|
226 .buffer = filebuf
|
|
227 };
|
|
228 uint16_t address, tmp_addr;
|
|
229 uint8_t valid_address;
|
|
230 while(context->deferred) {
|
|
231 do {
|
|
232 valid_address = 0;
|
|
233 address = context->deferred->address;
|
|
234 if (!is_visited(context, address)) {
|
|
235 address &= context->address_mask;
|
|
236 if (address < address_end && address >= address_off) {
|
|
237 valid_address = 1;
|
|
238 address = context->deferred->address;
|
|
239 }
|
|
240 }
|
|
241 deferred_addr *tmpd = context->deferred;
|
|
242 context->deferred = context->deferred->next;
|
|
243 free(tmpd);
|
|
244 } while(context->deferred && !valid_address);
|
|
245 if (!valid_address) {
|
|
246 break;
|
|
247 }
|
|
248 for(;;) {
|
|
249 if ((address & context->address_mask) > address_end || address < address_off) {
|
|
250 break;
|
|
251 }
|
|
252 visit(context, address);
|
|
253 upd_address_ref ref;
|
|
254 address = upd78k2_disasm(disbuf, &ref, address, fetch, &rom, NULL);
|
|
255 if (!strcmp(disbuf, "invalid") || startswith(disbuf, "ret")) {
|
|
256 break;
|
|
257 }
|
|
258 switch(ref.ref_type)
|
|
259 {
|
|
260 case UPD_REF_NONE:
|
|
261 if (startswith(disbuf, "br ")) {
|
|
262 //unconditional branch to register
|
|
263 goto loop_end;
|
|
264 }
|
|
265 break;
|
|
266 case UPD_REF_OP:
|
|
267 reference(context, ref.address);
|
|
268 break;
|
|
269 case UPD_REF_2OP:
|
|
270 reference(context, ref.address);
|
|
271 reference(context, ref.address2);
|
|
272 break;
|
|
273 case UPD_REF_BRANCH:
|
|
274 reference(context, ref.address);
|
|
275 if (ref.address <= address) {
|
|
276 defer_disasm(context, ref.address);
|
|
277 goto loop_end;
|
|
278 } else {
|
|
279 address = ref.address;
|
|
280 }
|
|
281 break;
|
|
282 case UPD_REF_COND_BRANCH:
|
|
283 case UPD_REF_CALL:
|
|
284 reference(context, ref.address);
|
|
285 defer_disasm(context, ref.address);
|
|
286 break;
|
|
287 case UPD_REF_OP_BRANCH:
|
|
288 reference(context, ref.address);
|
|
289 reference(context, ref.address2);
|
|
290 defer_disasm(context, ref.address2);
|
|
291 break;
|
|
292 case UPD_REF_CALL_TABLE:
|
|
293 reference(context, ref.address);
|
|
294 if (ref.address >= address_off && ref.address < address_end - 1) {
|
|
295 uint16_t table_address = ref.address;
|
|
296 ref.address = fetch(table_address, &rom);
|
|
297 ref.address |= fetch(table_address + 1, &rom) << 8;
|
|
298 reference(context, ref.address);
|
|
299 defer_disasm(context, ref.address);
|
|
300 }
|
|
301 break;
|
|
302 }
|
|
303 }
|
|
304 loop_end:
|
|
305 }
|
|
306 if (labels) {
|
|
307 tern_foreach(context->labels, print_label_def, &rom);
|
|
308 puts("");
|
|
309 }
|
|
310 uint16_t data_start = 0xFFFF;
|
|
311 for (address = address_off; address < address_end;) {
|
|
312 if (labels) {
|
|
313 label_def *label = find_label(context, address);
|
|
314 if (label) {
|
|
315 if (data_start < address) {
|
|
316 format_data(context, &rom, labels, data_start, address);
|
|
317 data_start = 0xFFFF;
|
|
318 }
|
|
319 if (label->num_labels) {
|
|
320 for (int i = 0; i < label->num_labels; i++)
|
|
321 {
|
|
322 printf("%s:\n", label->labels[i]);
|
|
323 }
|
|
324 } else {
|
|
325 printf("ADR_%X:\n", label->full_address);
|
|
326 }
|
|
327 }
|
|
328 }
|
|
329 if (is_visited(context, address)) {
|
|
330 if (data_start < address) {
|
|
331 format_data(context, &rom, labels, data_start, address);
|
|
332 data_start = 0xFFFF;
|
|
333 }
|
|
334 uint16_t next = upd78k2_disasm(disbuf, NULL, address, fetch, &rom, labels ? context : NULL);
|
|
335 if (labels) {
|
|
336 if (addr) {
|
|
337 printf("\t%s\t;%X\n", disbuf, address);
|
|
338 } else {
|
|
339 printf("\t%s\n", disbuf);
|
|
340 }
|
|
341 } else {
|
|
342 printf("%X: %s\n", address, disbuf);
|
|
343 }
|
|
344 address = next;
|
|
345 } else {
|
|
346 if (data_start > address) {
|
|
347 data_start = address;
|
|
348 }
|
|
349 address++;
|
|
350 }
|
|
351 }
|
|
352 if (data_start < address) {
|
|
353 format_data(context, &rom, labels, data_start, address);
|
|
354 }
|
|
355 return 0;
|
|
356 } |