]> git.sur5r.net Git - cc65/blob - src/da65/main.c
Renamed the config file to info file and changed the handling when the
[cc65] / src / da65 / main.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                  main.c                                   */
4 /*                                                                           */
5 /*                  Main program for the da65 disassembler                   */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2003 Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 52                                             */
11 /*               D-70794 Filderstadt                                         */
12 /* EMail:        uz@cc65.org                                                 */
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 "cpu.h"
46 #include "fname.h"
47 #include "print.h"
48 #include "version.h"
49
50 /* da65 */
51 #include "attrtab.h"
52 #include "code.h"
53 #include "data.h"
54 #include "error.h"
55 #include "global.h"
56 #include "infofile.h"
57 #include "opctable.h"
58 #include "output.h"
59 #include "scanner.h"
60
61
62
63 /*****************************************************************************/
64 /*                                   Code                                    */
65 /*****************************************************************************/
66
67
68
69 static void Usage (void)
70 /* Print usage information and exit */
71 {
72     fprintf (stderr,
73              "Usage: %s [options] file\n"
74              "Short options:\n"
75              "  -g\t\t\tAdd debug info to object file\n"
76              "  -h\t\t\tHelp (this text)\n"
77              "  -i name\t\tSpecify an info file\n"
78              "  -o name\t\tName the output file\n"
79              "  -v\t\t\tIncrease verbosity\n"
80              "  -F\t\t\tAdd formfeeds to the output\n"
81              "  -S addr\t\tSet the start/load address\n"
82              "  -V\t\t\tPrint the disassembler version\n"
83              "\n"
84              "Long options:\n"
85              "  --cpu type\t\tSet cpu type\n"
86              "  --debug-info\t\tAdd debug info to object file\n"
87              "  --formfeeds\t\tAdd formfeeds to the output\n"
88              "  --help\t\tHelp (this text)\n"
89              "  --info name\t\tSpecify an info file\n"
90              "  --pagelength n\tSet the page length for the listing\n"
91              "  --start-addr addr\tSet the start/load address\n"
92              "  --verbose\t\tIncrease verbosity\n"
93              "  --version\t\tPrint the disassembler version\n",
94              ProgName);
95 }
96
97
98
99 static unsigned long CvtNumber (const char* Arg, const char* Number)
100 /* Convert a number from a string. Allow '$' and '0x' prefixes for hex
101  * numbers.
102  */
103 {
104     unsigned long Val;
105     int           Converted;
106
107     /* Convert */
108     if (*Number == '$') {
109         ++Number;
110         Converted = sscanf (Number, "%lx", &Val);
111     } else {
112         Converted = sscanf (Number, "%li", (long*)&Val);
113     }
114
115     /* Check if we do really have a number */
116     if (Converted != 1) {
117         Error ("Invalid number given in argument: %s\n", Arg);
118     }
119
120     /* Return the result */
121     return Val;
122 }
123
124
125
126 static void OptCPU (const char* Opt attribute ((unused)), const char* Arg)
127 /* Handle the --cpu option */
128 {
129     /* Find the CPU from the given name */
130     CPU = FindCPU (Arg);
131     SetOpcTable (CPU);
132 }
133
134
135
136 static void OptDebugInfo (const char* Opt attribute ((unused)),
137                           const char* Arg attribute ((unused)))
138 /* Add debug info to the object file */
139 {
140     DebugInfo = 1;
141 }
142
143
144
145 static void OptFormFeeds (const char* Opt attribute ((unused)),
146                           const char* Arg attribute ((unused)))
147 /* Add form feeds to the output */
148 {
149     FormFeeds = 1;
150 }
151
152
153
154 static void OptHelp (const char* Opt attribute ((unused)),
155                      const char* Arg attribute ((unused)))
156 /* Print usage information and exit */
157 {
158     Usage ();
159     exit (EXIT_SUCCESS);
160 }
161
162
163
164 static void OptInfo (const char* Opt attribute ((unused)), const char* Arg)
165 /* Handle the --info option */
166 {
167     InfoSetName (Arg);
168 }
169
170
171
172 static void OptPageLength (const char* Opt attribute ((unused)), const char* Arg)
173 /* Handle the --pagelength option */
174 {
175     int Len = atoi (Arg);
176     if (Len != 0 && (Len < MIN_PAGE_LEN || Len > MAX_PAGE_LEN)) {
177         AbEnd ("Invalid page length: %d", Len);
178     }
179     PageLength = Len;
180 }
181
182
183
184 static void OptStartAddr (const char* Opt, const char* Arg)
185 /* Set the default start address */
186 {
187     StartAddr = CvtNumber (Opt, Arg);
188 }
189
190
191
192 static void OptVerbose (const char* Opt attribute ((unused)),
193                         const char* Arg attribute ((unused)))
194 /* Increase verbosity */
195 {
196     ++Verbosity;
197 }
198
199
200
201 static void OptVersion (const char* Opt attribute ((unused)),
202                         const char* Arg attribute ((unused)))
203 /* Print the disassembler version */
204 {
205     fprintf (stderr,
206              "da65 V%u.%u.%u - (C) Copyright 2000 Ullrich von Bassewitz\n",
207              VER_MAJOR, VER_MINOR, VER_PATCH);
208 }
209
210
211
212 static void OneOpcode (unsigned RemainingBytes)
213 /* Disassemble one opcode */
214 {
215     /* Get the opcode from the current address */
216     unsigned char OPC = GetCodeByte (PC);
217
218     /* Get the opcode description for the opcode byte */
219     const OpcDesc* D = &OpcTable[OPC];
220
221     /* If we have a label at this address, output the label */
222     if (MustDefLabel (PC)) {
223         DefLabel (GetLabel (PC));
224     }
225
226     /* Check...
227      *   - ...if we have enough bytes remaining for the code at this address.
228      *   - ...if the current instruction is valid for the given CPU.
229      *   - ...if there is no label somewhere between the instruction bytes.
230      * If any of these conditions is true, switch to data mode.
231      */
232     if (GetStyleAttr (PC) == atDefault) {
233         if (D->Size > RemainingBytes) {
234             MarkAddr (PC, atIllegal);
235         } else if (D->Flags & flIllegal) {
236             MarkAddr (PC, atIllegal);
237         } else {
238             unsigned I;
239             for (I = 1; I < D->Size; ++I) {
240                 if (HaveLabel (PC+I)) {
241                     MarkAddr (PC, atIllegal);
242                     break;
243                 }
244             }
245         }
246     }
247
248     /* Disassemble the line */
249     switch (GetStyleAttr (PC)) {
250
251         case atDefault:
252         case atCode:
253             D->Handler (D);
254             PC += D->Size;
255             break;
256
257         case atByteTab:
258             ByteTable ();
259             break;
260
261         case atWordTab:
262             WordTable ();
263             break;
264
265         case atDWordTab:
266             DWordTable ();
267             break;
268
269         case atAddrTab:
270             AddrTable ();
271             break;
272
273         case atRtsTab:
274             RtsTable ();
275             break;
276
277         case atTextTab:
278             TextTable ();
279             break;
280
281         default:
282             DataByteLine (1);
283             ++PC;
284             break;
285
286     }
287 }
288
289
290
291 static void OnePass (void)
292 /* Make one pass through the code */
293 {
294     unsigned Count;
295
296     /* Disassemble until nothing left */
297     while ((Count = GetRemainingBytes()) > 0) {
298         OneOpcode (Count);
299     }
300 }
301
302
303
304 static void Disassemble (void)
305 /* Disassemble the code */
306 {
307     /* Pass 1 */
308     Pass = 1;
309     OnePass ();
310
311     Output ("---------------------------");
312     LineFeed ();
313
314     /* Pass 2 */
315     Pass = 2;
316     ResetCode ();
317     OutputSettings ();
318     DefOutOfRangeLabels ();
319     OnePass ();
320 }
321
322
323
324 int main (int argc, char* argv [])
325 /* Assembler main program */
326 {
327     /* Program long options */
328     static const LongOpt OptTab[] = {
329         { "--cpu",              1,      OptCPU                  },
330         { "--debug-info",       0,      OptDebugInfo            },
331         { "--formfeeds",        0,      OptFormFeeds            },
332         { "--help",             0,      OptHelp                 },
333         { "--info",             1,      OptInfo                 },
334         { "--pagelength",       1,      OptPageLength           },
335         { "--start-addr",       1,      OptStartAddr            },
336         { "--verbose",          0,      OptVerbose              },
337         { "--version",          0,      OptVersion              },
338     };
339
340     unsigned I;
341
342     /* Initialize the cmdline module */
343     InitCmdLine (&argc, &argv, "da65");
344
345     /* Check the parameters */
346     I = 1;
347     while (I < ArgCount) {
348
349         /* Get the argument */
350         const char* Arg = ArgVec[I];
351
352         /* Check for an option */
353         if (Arg [0] == '-') {
354             switch (Arg [1]) {
355
356                 case '-':
357                     LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
358                     break;
359
360                 case 'g':
361                     OptDebugInfo (Arg, 0);
362                     break;
363
364                 case 'h':
365                     OptHelp (Arg, 0);
366                     break;
367
368                 case 'i':
369                     OptInfo (Arg, GetArg (&I, 2));
370                     break;
371
372                 case 'o':
373                     OutFile = GetArg (&I, 2);
374                     break;
375
376                 case 'v':
377                     OptVerbose (Arg, 0);
378                     break;
379
380                 case 'S':
381                     OptStartAddr (Arg, GetArg (&I, 2));
382                     break;
383
384                 case 'V':
385                     OptVersion (Arg, 0);
386                     break;
387
388                 default:
389                     UnknownOption (Arg);
390                     break;
391
392             }
393         } else {
394             /* Filename. Check if we already had one */
395             if (InFile) {
396                 fprintf (stderr, "%s: Don't know what to do with `%s'\n",
397                          ProgName, Arg);
398                 exit (EXIT_FAILURE);
399             } else {
400                 InFile = Arg;
401             }
402         }
403
404         /* Next argument */
405         ++I;
406     }
407
408     /* Must have an input file */
409     if (InFile == 0) {
410         AbEnd ("No input file");
411     }
412
413     /* Try to read the configuration file */
414     ReadInfoFile ();
415
416     /* Make the output file name from the input file name if none was given */
417     if (OutFile == 0) {
418         OutFile = MakeFilename (InFile, OutExt);
419     }
420
421     /* If no CPU given, use the default CPU */
422     if (CPU == CPU_UNKNOWN) {
423         CPU = CPU_6502;
424     }
425
426     /* Load the input file */
427     LoadCode (InFile, StartAddr);
428
429     /* Open the output file */
430     OpenOutput (OutFile);
431
432     /* Disassemble the code */
433     Disassemble ();
434
435     /* Close the output file */
436     CloseOutput ();
437
438     /* Done */
439     return EXIT_SUCCESS;
440 }
441
442
443