Mercurial > hg > forks > dxa
annotate main.c @ 4:0990d9322fc8
Implement address-ranged labels. Breaks compatibility of label files.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Wed, 25 Feb 2015 04:15:07 +0200 |
parents | ec2f8f6f1dc9 |
children | b91c47026822 |
rev | line source |
---|---|
0 | 1 /*\ |
2 * dxa v0.1.3 -- symbolic 65xx disassembler | |
3 * | |
4 * Based on d65 Copyright (C) 1993, 1994 Marko M\"akel\"a | |
5 * Changes for dxa (C) 2005, 2006 Cameron Kaiser | |
6 * | |
7 * This program is free software; you can redistribute it and/or modify | |
8 * it under the terms of the GNU General Public License as published by | |
9 * the Free Software Foundation; either version 2 of the License, or | |
10 * (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 * GNU General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU General Public License | |
18 * along with this program; if not, write to the Free Software | |
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 * | |
21 * Marko does not maintain dxa, so questions specific to dxa should be | |
22 * sent to me at ckaiser@floodgap.com . Otherwise, | |
23 * | |
24 * Contacting the author: | |
25 * | |
26 * Via Internet E-mail: | |
27 * <Marko.Makela@FTP.FUNET.FI> | |
28 * | |
29 * Via Snail Mail: | |
30 * Marko M\"akel\"a | |
31 * Sillitie 10 A | |
32 * FIN-01480 VANTAA | |
33 * Finland | |
34 \*/ | |
35 | |
36 #define _MAIN_C_ | |
37 #include <stdio.h> | |
38 #include <stdlib.h> | |
39 #include <string.h> | |
40 #ifdef __GNUC__ | |
41 #include <unistd.h> | |
42 #endif | |
43 #ifdef LONG_OPTIONS | |
44 #include <getopt.h> | |
45 #endif /* __GNUC__ */ | |
46 #include "proto.h" | |
47 #include "options.h" | |
48 #include "opcodes.h" | |
49 | |
2
ec2f8f6f1dc9
Cleanup pass #1: Get rid of some ancient K&R-isms.
Matti Hamalainen <ccr@tnsp.org>
parents:
0
diff
changeset
|
50 |
0 | 51 int main (int argc, char **argv) |
52 { | |
53 FILE *file; | |
54 unsigned address1, address2; | |
55 #ifdef LONG_OPTIONS | |
56 int option_index; | |
57 #endif | |
58 int fFinished = FALSE, fType; | |
59 char labelname[MAXLINE], strig[MAXLINE], *scanner; | |
60 | |
61 extern char *optarg; | |
62 extern int optind; | |
63 | |
64 #ifdef LONG_OPTIONS | |
65 static struct option cmd_options [] = { | |
66 { "datablock", 1, 0, 'b' }, /* an address range to be marked | |
67 as a data block */ | |
68 { "datablocks", 1, 0, 'B' },/* a file containing the address ranges | |
69 to be marked as data blocks */ | |
70 { "labels", 1, 0, 'l' }, /* a file containing labels to be translated | |
71 in the output phase */ | |
72 { "routine", 1, 0, 'r' }, /* an address of a routine */ | |
73 { "routines", 1, 0, 'R' }, /* a file containing the addresses */ | |
74 | |
75 { "listing-width", 1, 0, 'L' }, | |
76 /* maximum number of dumped bytes per line */ | |
77 { "addresses", 1, 0, 'a' }, /* dumping addresses in the output phase */ | |
78 { "datablock-detection", 1, 0, 'd' }, | |
79 /* data block detection options */ | |
80 { "processor", 1, 0, 'p' }, /* instruction set */ | |
81 { "no-colon-newline", 0, 0, 'n' }, | |
82 { "colon-newline", 0, 0, 'N' }, | |
83 { "no-external-labels", 0, 0, 'e' }, | |
84 { "external-labels", 0, 0, 'E' }, | |
85 { "address-tables", 0, 0, 't' }, | |
86 { "no-address-statements", 0, 0, 's' }, | |
87 { "address-statements", 0, 0, 'S' }, | |
88 { "suspect-jsr", 0, 0, 'J' }, | |
89 { "no-suspect-jsr", 0, 0, 'j' }, | |
90 { "one-byte-routines", 0, 0, 'O' }, | |
91 { "no-one-byte-routines", 0, 0, 'o' }, | |
92 { "stupid-jumps", 0, 0, 'M' }, | |
93 { "no-stupid-jumps", 0, 0, 'm' }, | |
94 { "allow-brk", 0, 0, 'W' }, | |
95 { "no-allow-brk", 0, 0, 'w' }, | |
96 { "suspect-branches", 0, 0, 'C' }, | |
97 { "no-suspect-branches", 0, 0, 'c' }, | |
98 { "cross-reference", 0, 0, 'X' }, | |
99 { "no-cross-reference", 0, 0, 'x' }, | |
100 { "verbose", 0, 0, 'v' }, | |
101 { "help", 0, 0, '?' }, | |
102 { "word-sa", 0, 0, 'Q' }, | |
103 { "no-word-sa", 0, 0, 'q' }, | |
104 { "get-sa", 0, 0, 'G' }, | |
105 { "no-get-sa", 0, 0, 'g' }, | |
106 { NULL, 0, 0, 0 } | |
107 }; | |
108 #endif /* LONG_OPTIONS */ | |
109 | |
110 opset = standard_nmos6502; | |
111 | |
112 StartAddress = 0; | |
113 Options = O_ADR_ADR_DMP | B_LBL_ALWAYS | O_TBL_NOEXT | | |
114 B_STM_DETECT | B_STK_BALANCE | B_RSC_STRICT | O_DBL_STRICT | | |
115 B_JMP_STRICT | B_BRK_REJECT; | |
116 | |
117 /* dxa defaults */ | |
118 Options = (Options & ~M_ADDRESSES) | O_ADR_NOTHING; | |
119 Options = (Options & ~M_DATA_BLOCKS) | O_DBL_IGNORE; | |
120 Options &= ~B_LBL_ALWAYS; | |
121 Options &= ~B_LABCOL; | |
122 Options |= B_SA_WORD; | |
123 Options |= B_GET_SA; | |
124 | |
125 for (address1 = sizeof MemType / sizeof *MemType; address1--; | |
126 MemType[address1] = 0); | |
127 | |
128 for (address1 = sizeof MemFlag / sizeof *MemFlag; address1--; | |
129 MemFlag[address1] = MemLabel[address1] = 0); | |
130 | |
131 for (address1 = sizeof LowByte / sizeof *LowByte; address1--; | |
132 HighByte[address1] = LowByte[address1] = 0); | |
133 | |
134 for (prog = *argv; *prog; prog++); | |
135 for (;prog > *argv; prog--) | |
136 if (*prog == '/') { | |
137 prog++; | |
138 break; | |
139 } | |
140 | |
141 while (!fFinished) | |
142 #ifdef LONG_OPTIONS | |
143 switch (getopt_long (argc, argv, | |
144 "?b:B:L:r:R:h:l:a:d:p:g:t:eEnNsSjJoOcCmMvVwWxXqQG", | |
145 cmd_options, &option_index)) { | |
146 #else | |
147 switch (getopt (argc, argv, | |
148 "?b:B:L:r:R:h:l:a:d:p:g:t:eEnNsSjJoOcCmMvVwWxXqQG")){ | |
149 #endif /* LONG_OPTIONS */ | |
150 case -1: | |
151 case ':': | |
152 fFinished = TRUE; | |
153 break; | |
154 | |
155 case '?': | |
156 case 'V': | |
157 goto Usage; | |
158 | |
159 case 'b': | |
160 if (*optarg == '!') { | |
161 fType = MEM_PARAMETER; | |
162 optarg++; | |
163 } | |
164 else if (*optarg == '?') { | |
165 fType = MEM_UNPROCESSED; | |
166 optarg++; | |
167 } | |
168 else | |
169 fType = MEM_DATA; | |
170 | |
171 if (!sscanf (optarg, "%X-%X", &address1, &address2) || | |
172 address1 > 65535 || address2 > 65535) { | |
173 fprintf (stderr, "%s: Error in data block address range `%s'.\n\n", | |
174 prog, optarg); | |
175 goto Usage; | |
176 } | |
177 | |
178 for (; (ADDR_T)address1 != address2; address1++) { | |
179 SetMemType (address1, fType); | |
180 SetMemFlag (address1); | |
181 } | |
182 | |
183 SetMemType (address1, fType); | |
184 SetMemFlag (address1); | |
185 | |
186 break; | |
187 | |
188 case 'B': | |
189 if (!((file = fopen (optarg, "rt")))) { | |
190 fprintf (stderr, "%s: Could not open %s.\n", prog, optarg); | |
191 return 2; | |
192 } | |
193 | |
194 while (!feof (file)) { | |
195 if ('!' == (fType = fgetc (file))) | |
196 fType = MEM_PARAMETER; | |
197 else if ('?' == fType) | |
198 fType = MEM_UNPROCESSED; | |
199 else { | |
200 ungetc (fType, file); | |
201 fType = MEM_DATA; | |
202 } | |
203 | |
204 if (!fscanf (file, "%X-%X\n", &address1, &address2) || | |
205 address1 > 65535 || address2 > 65535) { | |
206 fprintf (stderr, "%s: Error in data block address file %s.\n", | |
207 prog, optarg); | |
208 | |
209 fclose (file); | |
210 return 3; | |
211 } | |
212 | |
213 for (; (ADDR_T)address1 != address2; address1++) { | |
214 SetMemType (address1, fType); | |
215 SetMemFlag (address1); | |
216 } | |
217 | |
218 SetMemType (address1, fType); | |
219 SetMemFlag (address1); | |
220 } | |
221 | |
222 fclose (file); | |
223 break; | |
224 | |
225 case 'r': | |
226 if (!sscanf (optarg, "%X", &address1) || address1 > 65535) { | |
227 fprintf (stderr, "%s: Error in routine address `%s'.\n\n", | |
228 prog, optarg); | |
229 goto Usage; | |
230 } | |
231 | |
232 AddEntry (address1, address1, RTN_SURE); | |
233 break; | |
234 | |
235 case 'R': | |
236 if (!((file = fopen (optarg, "rt")))) { | |
237 fprintf (stderr, "%s: Could not open %s.\n", prog, optarg); | |
238 return 2; | |
239 } | |
240 | |
241 while (!feof (file)) { | |
242 if (!fscanf (file, "%X\n", &address1) || address1 > 65535) { | |
243 fprintf (stderr, "%s: Error in data block address file `%s'.\n", | |
244 prog, optarg); | |
245 | |
246 fclose (file); | |
247 return 3; | |
248 } | |
249 | |
250 AddEntry (address1, address1, RTN_SURE); | |
251 } | |
252 | |
253 fclose (file); | |
254 break; | |
255 | |
256 case 'L': | |
257 if (0 > (listwidth = atoi (optarg))) { | |
258 fprintf (stderr, "%s: Illegal listing width specified.\n\n", prog); | |
259 goto Usage; | |
260 } | |
261 | |
262 break; | |
263 | |
264 case 'a': | |
265 if (!strcmp (optarg, "disabled")) | |
266 Options = (Options & ~M_ADDRESSES) | O_ADR_NOTHING; | |
267 else if (!strcmp (optarg, "enabled")) | |
268 Options = (Options & ~M_ADDRESSES) | O_ADR_ADRPFIX; | |
269 else if (!strcmp (optarg, "dump")) | |
270 Options = (Options & ~M_ADDRESSES) | O_ADR_ADR_DMP; | |
271 else { | |
272 fprintf (stderr, "%s: Unrecognized option for dumping addresses.\n\n", | |
273 prog); | |
274 goto Usage; | |
275 } | |
276 break; | |
277 | |
278 case 'd': | |
279 if (!strcmp (optarg, "poor")) | |
280 Options = (Options & ~M_DATA_BLOCKS) | O_DBL_IGNORE; | |
281 else if (!strcmp (optarg, "extended")) | |
282 Options = (Options & ~M_DATA_BLOCKS) | O_DBL_DETECT; | |
283 else if (!strcmp (optarg, "skip-scanning")) | |
284 Options = (Options & ~M_DATA_BLOCKS) | O_DBL_NOSCAN; | |
285 else if (!strcmp (optarg, "strict")) | |
286 Options = (Options & ~M_DATA_BLOCKS) | O_DBL_STRICT; | |
287 else { | |
288 fprintf (stderr, | |
289 "%s: Unrecognized option for detecting data blocks.\n\n", | |
290 prog); | |
291 goto Usage; | |
292 } | |
293 break; | |
294 | |
295 case 'p': | |
296 if (!strcmp (optarg, "all-nmos6502")) | |
297 opset = all_nmos6502; | |
298 else if (!strcmp (optarg, "rational-nmos6502")) | |
299 opset = rational_nmos6502; | |
300 else if (!strcmp (optarg, "useful-nmos6502")) | |
301 opset = useful_nmos6502; | |
302 else if (!strcmp (optarg, "traditional-nmos6502")) | |
303 opset = traditional_nmos6502; | |
304 else if (!strcmp (optarg, "r65c02")) | |
305 opset = r65c02; | |
306 else if (!strcmp (optarg, "standard-nmos6502")) | |
307 opset = standard_nmos6502; | |
308 else { | |
309 fprintf (stderr, "%s: Unsupported instruction set `%s'.\n\n", | |
310 prog, optarg); | |
311 goto Usage; | |
312 } | |
313 break; | |
314 | |
315 case 'e': | |
316 Options &= ~B_LBL_ALWAYS; | |
317 break; | |
318 case 'E': | |
319 Options |= B_LBL_ALWAYS; | |
320 break; | |
321 | |
322 case 't': | |
323 if (!strcmp (optarg, "ignore")) | |
324 Options = (Options & ~M_ADR_TABLES) | O_TBL_IGNORE; | |
325 else if (!strcmp (optarg, "detect-all")) | |
326 Options = (Options & ~M_ADR_TABLES) | O_TBL_DETECT; | |
327 else if (!strcmp (optarg, "detect-internal")) | |
328 Options = (Options & ~M_ADR_TABLES) | O_TBL_NOEXT; | |
329 else { | |
330 fprintf (stderr, | |
331 "%s: Unknown address table detection option `%s'.\n\n", | |
332 prog, optarg); | |
333 goto Usage; | |
334 } | |
335 break; | |
336 | |
337 case 's': | |
338 Options &= ~B_STM_DETECT; | |
339 break; | |
340 case 'S': | |
341 Options |= B_STM_DETECT; | |
342 break; | |
343 | |
344 case 'J': | |
345 Options &= ~B_STK_BALANCE; | |
346 break; | |
347 case 'j': | |
348 Options |= B_STK_BALANCE; | |
349 break; | |
350 | |
351 case 'o': | |
352 Options &= ~B_RSC_STRICT; | |
353 break; | |
354 case 'O': | |
355 Options |= B_RSC_STRICT; | |
356 break; | |
357 | |
358 case 'c': | |
359 Options &= ~B_SCEPTIC; | |
360 break; | |
361 case 'C': | |
362 Options |= B_SCEPTIC; | |
363 break; | |
364 | |
365 case 'M': | |
366 Options &= ~B_JMP_STRICT; | |
367 break; | |
368 case 'm': | |
369 Options |= B_JMP_STRICT; | |
370 break; | |
371 | |
372 case 'v': | |
373 fVerbose = TRUE; | |
374 break; | |
375 | |
376 case 'W': | |
377 Options &= ~B_BRK_REJECT; | |
378 break; | |
379 case 'w': | |
380 Options |= B_BRK_REJECT; | |
381 break; | |
382 | |
383 case 'x': | |
384 Options &= ~B_CROSSREF; | |
385 break; | |
386 case 'X': | |
387 Options |= B_CROSSREF; | |
388 break; | |
389 | |
390 /* new or altered dxa options */ | |
391 case 'n': | |
392 Options &= ~B_LABCOL; | |
393 break; | |
394 case 'N': | |
395 Options |= B_LABCOL; | |
396 break; | |
397 case 'q': | |
398 Options &= ~B_SA_WORD; | |
399 break; | |
400 case 'Q': | |
401 Options |= B_SA_WORD; | |
402 break; | |
403 case 'G': | |
404 Options |= B_GET_SA; | |
405 break; | |
406 case 'g': | |
407 Options &= ~B_GET_SA; | |
408 if (!sscanf (optarg, "%X", &address1) || address1 > 65535) { | |
409 fprintf (stderr, "%s: Error specifying starting address `%s'.\n\n", | |
410 prog, optarg); | |
411 goto Usage; | |
412 } | |
413 StartAddress = address1; | |
414 break; | |
415 case 'l': | |
416 if (!((file = fopen (optarg, "rt")))) { | |
417 fprintf (stderr, | |
418 "%s: Label file %s could not be opened for reading.\n\n", | |
419 prog, optarg); | |
420 | |
421 goto Usage; | |
422 } | |
423 | |
424 while (!feof (file)) { | |
4
0990d9322fc8
Implement address-ranged labels. Breaks compatibility of label files.
Matti Hamalainen <ccr@tnsp.org>
parents:
2
diff
changeset
|
425 int tmp; |
0 | 426 fType = fgetc (file); |
427 | |
428 if (feof (file)) | |
429 break; | |
430 | |
431 ungetc (fType, file); | |
432 | |
433 /* This is the xa-compatible label scanner. */ | |
4
0990d9322fc8
Implement address-ranged labels. Breaks compatibility of label files.
Matti Hamalainen <ccr@tnsp.org>
parents:
2
diff
changeset
|
434 if (!fscanf(file, "%s%i,%i,%i", labelname, &address1, &tmp, &address2) || |
0990d9322fc8
Implement address-ranged labels. Breaks compatibility of label files.
Matti Hamalainen <ccr@tnsp.org>
parents:
2
diff
changeset
|
435 address1 > 65535 || |
0990d9322fc8
Implement address-ranged labels. Breaks compatibility of label files.
Matti Hamalainen <ccr@tnsp.org>
parents:
2
diff
changeset
|
436 !fgets(strig, sizeof strig, file)) { |
0990d9322fc8
Implement address-ranged labels. Breaks compatibility of label files.
Matti Hamalainen <ccr@tnsp.org>
parents:
2
diff
changeset
|
437 |
0 | 438 LabelError: |
439 fprintf (stderr, "%s: Error in label file %s.\n", prog, optarg); | |
440 fprintf (stderr, "Address(?): 0x%x ... Label(?): \"%s\"\n\n", | |
441 address1, labelname); | |
442 fclose (file); | |
443 return 3; | |
444 } | |
445 | |
446 for (scanner = labelname; *scanner; scanner++); | |
447 | |
448 #if(0) | |
449 if (scanner[-1] != '\n') goto LabelError; /* line too long */ | |
450 #endif | |
451 | |
452 while (--scanner > labelname && ( | |
453 *(unsigned char *)scanner < 32 || | |
454 *(unsigned char *)scanner == 44)) /* and commas */ | |
455 *scanner = 0; /* remove trailing control characters */ | |
456 | |
457 for (scanner = labelname; *(unsigned char *)scanner < 32; scanner++) | |
458 if (!*scanner) goto LabelError; /* label name missing */ | |
459 | |
4
0990d9322fc8
Implement address-ranged labels. Breaks compatibility of label files.
Matti Hamalainen <ccr@tnsp.org>
parents:
2
diff
changeset
|
460 AddLabel (address1, scanner, address2 != 0, address2); |
0 | 461 } |
462 | |
463 fclose (file); | |
464 } | |
465 | |
466 if (argc - optind > 1) { | |
467 Usage: | |
468 fprintf (stderr, "%s v0.1.3 -- symbolic 65xx disassembler\n", prog); | |
469 fprintf (stderr, "Based on d65 copyright (C) 1993-4 Marko M\"akel\"a\n"); | |
470 fprintf (stderr, "Changes for dxa copyright (c) 2006-7 Cameron Kaiser\n\n"); | |
471 fprintf (stderr, "Usage: %s [options] [filename]\n", prog); | |
472 return 1; | |
473 } | |
474 | |
475 /* Fix, Need "rb" (binary mode) on Windows to avoid termintating on $1A */ | |
476 if (!(file = (argc - optind) ? fopen (argv[argc - 1], "rb") : stdin)) { | |
477 fprintf (stderr, "%s: Couldn't open input file.\n", prog); | |
478 return 2; | |
479 } | |
480 | |
481 if (Options & B_GET_SA) { | |
482 StartAddress = (unsigned)fgetc (file); | |
483 StartAddress |= (unsigned)fgetc (file) << 8; | |
484 } | |
485 | |
486 | |
487 if (feof (file)) { | |
488 fprintf (stderr, "%s: Error reading the file.\n", prog); | |
489 return 3; | |
490 } | |
491 | |
492 /* this doesn't work so well */ | |
493 /* AddEntry (StartAddress, StartAddress, RTN_SURE); */ | |
494 EndAddress = StartAddress + fread (&Memory[StartAddress], sizeof (char), | |
495 65536 - StartAddress, file); | |
496 | |
497 if (!feof (file)) { | |
498 if ((EndAddress = fread (Memory, sizeof (char), StartAddress, file))) | |
499 fprintf (stderr, "%s: Warning: Input file caused an address overflow.\n", | |
500 prog); | |
501 | |
502 if (!feof (file)) { | |
503 fprintf (stderr, "%s: Error: Input file is longer than 64 kilobytes.\n", | |
504 prog); | |
505 fclose (file); | |
506 return 3; | |
507 } | |
508 } | |
509 | |
510 fclose (file); | |
511 | |
512 if (fVerbose) | |
513 fprintf (stderr, "%s: disassembling %X-%X\n", prog, | |
514 StartAddress, EndAddress); | |
515 | |
516 if (ScanSpecified ()) { | |
517 fprintf (stderr, "\n%s: Invalid routine address(es) specified. Stop.\n", | |
518 prog); | |
519 | |
520 return 4; | |
521 } | |
522 | |
523 ScanPotentials (); | |
524 ScanTheRest (); | |
525 Collect (); | |
526 SearchVectors (); | |
527 Dump (); | |
528 | |
529 return 0; | |
530 } |