]> git.sur5r.net Git - cc65/blob - src/da65/main.c
Working
[cc65] / src / da65 / main.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  main.c                                   */
4 /*                                                                           */
5 /*                  Main program for the da65 disassembler                   */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2000 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <time.h>
41
42 /* common */
43 #include "abend.h"
44 #include "cmdline.h"
45 #include "fname.h"
46 #include "version.h"
47
48 /* da65 */
49 #include "attrtab.h"
50 #include "code.h"
51 #include "config.h"
52 #include "cpu.h"
53 #include "error.h"
54 #include "global.h"
55 #include "opctable.h"
56 #include "output.h"
57 #include "scanner.h"
58
59
60
61 /*****************************************************************************/
62 /*                                   Code                                    */
63 /*****************************************************************************/
64
65
66
67 static void Usage (void)
68 /* Print usage information and exit */
69 {
70     fprintf (stderr,
71              "Usage: %s [options] file\n"
72              "Short options:\n"
73              "  -g\t\t\tAdd debug info to object file\n"
74              "  -h\t\t\tHelp (this text)\n"
75              "  -i\t\t\tIgnore case of symbols\n"
76              "  -l\t\t\tCreate a listing if assembly was ok\n"
77              "  -o name\t\tName the output file\n"
78              "  -s\t\t\tEnable smart mode\n"
79              "  -t sys\t\tSet the target system\n"
80              "  -v\t\t\tIncrease verbosity\n"
81              "  -D name[=value]\tDefine a symbol\n"
82              "  -I dir\t\tSet an include directory search path\n"
83              "  -U\t\t\tMark unresolved symbols as import\n"
84              "  -V\t\t\tPrint the assembler version\n"
85              "  -W n\t\t\tSet warning level n\n"
86              "\n"
87              "Long options:\n"
88              "  --auto-import\t\tMark unresolved symbols as import\n"
89              "  --cpu type\t\tSet cpu type\n"
90              "  --debug-info\t\tAdd debug info to object file\n"
91              "  --feature name\tSet an emulation feature\n"
92              "  --help\t\tHelp (this text)\n"
93              "  --ignore-case\t\tIgnore case of symbols\n"
94              "  --include-dir dir\tSet an include directory search path\n"
95              "  --listing\t\tCreate a listing if assembly was ok\n"
96              "  --pagelength n\tSet the page length for the listing\n"
97              "  --smart\t\tEnable smart mode\n"
98              "  --target sys\t\tSet the target system\n"
99              "  --verbose\t\tIncrease verbosity\n"
100              "  --version\t\tPrint the assembler version\n",
101              ProgName);
102 }
103
104
105
106 static void OptCPU (const char* Opt, const char* Arg)
107 /* Handle the --cpu option */
108 {
109     if (Arg == 0) {
110         NeedArg (Opt);
111     }
112     if (strcmp (Arg, "6502") == 0) {
113         SetCPU (CPU_6502);
114     } else if (strcmp (Arg, "65C02") == 0) {
115         SetCPU (CPU_65C02);
116     } else if (strcmp (Arg, "65816") == 0) {
117         SetCPU (CPU_65816);
118 #ifdef SUNPLUS
119     } else if (strcmp (Arg, "sunplus") == 0) {
120         SetCPU (CPU_SUNPLUS);
121 #endif
122     } else {
123         AbEnd ("Invalid CPU: `%s'", Arg);
124     }
125 }
126
127
128
129 static void OptHelp (const char* Opt, const char* Arg)
130 /* Print usage information and exit */
131 {
132     Usage ();
133     exit (EXIT_SUCCESS);
134 }
135
136
137
138 static void OptPageLength (const char* Opt, const char* Arg)
139 /* Handle the --pagelength option */
140 {
141     int Len;
142     if (Arg == 0) {
143         NeedArg (Opt);
144     }
145     Len = atoi (Arg);
146     if (Len != -1 && (Len < MIN_PAGE_LEN || Len > MAX_PAGE_LEN)) {
147         AbEnd ("Invalid page length: %d", Len);
148     }
149     PageLength = Len;
150 }
151
152
153
154 static void OptVerbose (const char* Opt, const char* Arg)
155 /* Increase verbosity */
156 {
157     ++Verbosity;
158 }
159
160
161
162 static void OptVersion (const char* Opt, const char* Arg)
163 /* Print the disassembler version */
164 {
165     fprintf (stderr,
166              "da65 V%u.%u.%u - (C) Copyright 2000 Ullrich von Bassewitz\n",
167              VER_MAJOR, VER_MINOR, VER_PATCH);
168 }
169
170
171
172 static void ByteTable (unsigned RemainingBytes)
173 /* Output a table of bytes */
174 {
175     /* Count how many bytes may be output. This number is limited by the
176      * number of remaining bytes, a label, or the end of the ByteTable
177      * attribute.
178      */
179     unsigned Count = 1;
180     while (Count < RemainingBytes) {
181         if (HaveLabel(PC+Count) || GetStyle (PC+Count) != atByteTab) {
182             break;
183         }
184         ++Count;
185     }
186     RemainingBytes -= Count;
187
188     /* Output as many data bytes lines as needed */
189     while (Count > 0) {
190
191         /* Calculate the number of bytes for the next line */
192         unsigned Chunk = (Count > BytesPerLine)? BytesPerLine : Count;
193
194         /* Output a line with these bytes */
195         DataByteLine (Chunk);
196
197         /* Next line */
198         Count -= Chunk;
199         PC    += Chunk;
200     }
201
202     /* If the next line is not a byte table line, add a separator */
203     if (RemainingBytes > 0 && GetStyle (PC) != atByteTab) {
204         SeparatorLine ();
205     }
206 }
207
208
209
210 static void WordTable (unsigned RemainingBytes)
211 /* Output a table of words */
212 {
213     /* Count how many bytes may be output. This number is limited by the
214      * number of remaining bytes, a label, or the end of the WordTable
215      * attribute.
216      */
217     unsigned Count = 1;
218     while (Count < RemainingBytes) {
219         if (HaveLabel(PC+Count) || GetStyle (PC+Count) != atWordTab) {
220             break;
221         }
222         ++Count;
223     }
224     RemainingBytes -= Count;
225
226     /* Make the given number even */
227     Count &= ~1U;
228
229     /* Output as many data word lines as needed */
230     while (Count > 0) {
231
232         /* Calculate the number of bytes for the next line */
233         unsigned Chunk = (Count > BytesPerLine)? BytesPerLine : Count;
234
235         /* Output a line with these bytes */
236         DataWordLine (Chunk);
237
238         /* Next line */
239         PC    += Chunk;
240         Count -= Chunk;
241     }
242
243     /* If the next line is not a byte table line, add a separator */
244     if (RemainingBytes > 0 && GetStyle (PC) != atWordTab) {
245         SeparatorLine ();
246     }
247 }
248
249
250
251 static void AddrTable (unsigned RemainingBytes)
252 /* Output a table of addresses */
253 {
254     /* Count how many bytes may be output. This number is limited by the
255      * number of remaining bytes, a label, or the end of the WordTable
256      * attribute.
257      */
258     unsigned Count = 1;
259     while (Count < RemainingBytes) {
260         if (HaveLabel(PC+Count) || GetStyle (PC+Count) != atAddrTab) {
261             break;
262         }
263         ++Count;
264     }
265     RemainingBytes -= Count;
266
267     /* Make the given number even */
268     Count &= ~1U;
269
270     /* Output as many data bytes lines as needed. For addresses, each line
271      * will hold just one address.
272      */
273     while (Count > 0) {
274
275         /* Get the address */
276         unsigned Addr = GetCodeWord (PC);
277
278         /* In pass 1, define a label, in pass 2 output the line */
279         if (Pass == 1) {
280             if (!HaveLabel (Addr)) {
281                 AddLabel (Addr, MakeLabelName (Addr));
282             }
283         } else {
284             const char* Label = GetLabel (Addr);
285             if (Label == 0) {
286                 /* OOPS! Should not happen */
287                 Internal ("OOPS - Label for address %04X disappeard!", Addr);
288             }
289             Indent (MIndent);
290             Output (".word");
291             Indent (AIndent);
292             Output ("%s", Label);
293             LineComment (PC, 2);
294             LineFeed ();
295         }
296
297         /* Next line */
298         PC    += 2;
299         Count -= 2;
300     }
301
302     /* If the next line is not a byte table line, add a separator */
303     if (RemainingBytes > 0 && GetStyle (PC) != atAddrTab) {
304         SeparatorLine ();
305     }
306 }
307
308
309
310 static void OneOpcode (unsigned RemainingBytes)
311 /* Disassemble one opcode */
312 {
313     /* Get the opcode from the current address */
314     unsigned char OPC = GetCodeByte (PC);
315
316     /* Get the opcode description for the opcode byte */
317     const OpcDesc* D = &OpcTable[OPC];
318
319     /* If we have a label at this address, output the label */
320     const char* Label = GetLabel (PC);
321     if (Label) {
322         DefLabel (Label);
323     }
324
325     /* Check...
326      *   - ...if we have enough bytes remaining for the code at this address.
327      *   - ...if the current instruction is valid for the given CPU.
328      *   - ...if there is no label somewhere between the instruction bytes.
329      * If any of these conditions is true, switch to data mode.
330      */
331     if (GetStyle (PC) == atDefault) {
332         if (D->Size > RemainingBytes) {
333             MarkAddr (PC, atIllegal);
334         } else if ((D->CPU & CPU) != CPU) {
335             MarkAddr (PC, atIllegal);
336         } else {
337             unsigned I;
338             for (I = 1; I < D->Size; ++I) {
339                 if (HaveLabel (PC+I)) {
340                     MarkAddr (PC, atIllegal);
341                     break;
342                 }
343             }
344         }
345     }
346
347     /* Disassemble the line */
348     switch (GetStyle (PC)) {
349
350         case atDefault:
351         case atCode:
352             D->Handler (D);
353             PC += D->Size;
354             break;
355
356         case atByteTab:
357             ByteTable (RemainingBytes);
358             break;
359
360         case atWordTab:
361             WordTable (RemainingBytes);
362             break;
363
364         case atAddrTab:
365             AddrTable (RemainingBytes);
366             break;
367
368         default:
369             DataByteLine (1);
370             ++PC;
371             break;
372
373     }
374 }
375
376
377
378 static void OnePass (void)
379 /* Make one pass through the code */
380 {
381     unsigned Count;
382
383     /* Disassemble until nothing left */
384     while ((Count = GetRemainingBytes()) > 0) {
385         OneOpcode (Count);
386     }
387 }
388
389
390
391 static void Disassemble (void)
392 /* Disassemble the code */
393 {
394     /* Pass 1 */
395     Pass = 1;
396     OnePass ();
397
398     Output ("---------------------------");
399     LineFeed ();
400
401     /* Pass 2 */
402     Pass = 2;              
403     ResetCode ();
404     DefOutOfRangeLabels ();
405     OnePass ();
406 }
407
408
409
410 int main (int argc, char* argv [])
411 /* Assembler main program */
412 {
413     /* Program long options */
414     static const LongOpt OptTab[] = {
415         { "--cpu",              1,      OptCPU                  },
416         { "--help",             0,      OptHelp                 },
417         { "--pagelength",       1,      OptPageLength           },
418         { "--verbose",          0,      OptVerbose              },
419         { "--version",          0,      OptVersion              },
420     };
421
422     int I;
423
424     /* Initialize the cmdline module */
425     InitCmdLine (argc, argv, "da65");
426
427     /* Check the parameters */
428     I = 1;
429     while (I < argc) {
430
431         /* Get the argument */
432         const char* Arg = argv [I];
433
434         /* Check for an option */
435         if (Arg [0] == '-') {
436             switch (Arg [1]) {
437
438                 case '-':
439                     LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
440                     break;
441
442                 case 'h':
443                     OptHelp (Arg, 0);
444                     break;
445
446                 case 'o':
447                     OutFile = GetArg (&I, 2);
448                     break;
449
450                 case 'v':
451                     OptVerbose (Arg, 0);
452                     break;
453
454                 case 'V':
455                     OptVersion (Arg, 0);
456                     break;
457
458                 default:
459                     UnknownOption (Arg);
460                     break;
461
462             }
463         } else {
464             /* Filename. Check if we already had one */
465             if (InFile) {
466                 fprintf (stderr, "%s: Don't know what to do with `%s'\n",
467                          ProgName, Arg);
468                 exit (EXIT_FAILURE);
469             } else {
470                 InFile = Arg;
471             }
472         }
473
474         /* Next argument */
475         ++I;
476     }
477
478     /* Must have an input file */
479     if (InFile == 0) {
480         AbEnd ("No input file");
481     }
482
483     /* Make the config file name from the input file if none was given */
484     if (!CfgAvail ()) {
485         CfgSetName (MakeFilename (InFile, CfgExt));
486     }
487
488     /* Try to read the configuration file */
489     CfgRead ();
490
491     /* Make the output file name from the input file name if none was given */
492     if (OutFile == 0) {
493         OutFile = MakeFilename (InFile, OutExt);
494     }
495
496     /* Load the input file */
497     LoadCode (InFile, 0xE000);  /* ### */
498
499     /* Open the output file */
500     OpenOutput (OutFile);
501
502     /* Disassemble the code */
503     Disassemble ();
504
505     /* Close the output file */
506     CloseOutput ();
507
508     /* Done */
509     return EXIT_SUCCESS;
510 }
511
512
513