]> Shamusworld >> Repos - rmac/blob - rmac.c
17715f7ad6c86e8f9f0c6cffced6920e7b76ae00
[rmac] / rmac.c
1 //
2 // RMAC - Renamed Macro Assembler for all Atari computers
3 // RMAC.C - Main Application Code
4 // Copyright (C) 199x Landon Dyer, 2011-2022 Reboot and Friends
5 // RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
6 // Source utilised with the kind permission of Landon Dyer
7 //
8
9 #include "rmac.h"
10 #include "6502.h"
11 #include "debug.h"
12 #include "direct.h"
13 #include "dsp56k.h"
14 #include "error.h"
15 #include "expr.h"
16 #include "listing.h"
17 #include "mark.h"
18 #include "macro.h"
19 #include "object.h"
20 #include "procln.h"
21 #include "riscasm.h"
22 #include "sect.h"
23 #include "symbol.h"
24 #include "token.h"
25 #include "version.h"
26
27 int perm_verb_flag;                             // Permanently verbose, interactive mode
28 int list_flag;                                  // "-l" listing flag on command line
29 int list_pag = 1;                               // Enable listing pagination by default
30 int verb_flag;                                  // Be verbose about what's going on
31 int m6502;                                              // 1, assembling 6502 code
32 int glob_flag;                                  // Assume undefined symbols are global
33 int lsym_flag;                                  // Include local symbols in object file (ALWAYS true)
34 int dsym_flag;                                  // Gen debug syms (Requires obj_format = BSD)
35 int optim_warn_flag;                    // Warn about possible short branches
36 int prg_flag;                                   // !=0, produce .PRG executable (2=symbols)
37 int prg_extend;                                 // !=0, output extended .PRG symbols
38 int legacy_flag;                                // Do stuff like insert code in RISC assembler
39 int obj_format;                                 // Object format flag
40 int debug;                                              // [1..9] Enable debugging levels
41 int err_flag;                                   // '-e' specified
42 int err_fd;                                             // File to write error messages to
43 int rgpu, rdsp;                                 // Assembling Jaguar GPU or DSP code
44 int robjproc;                                   // Assembling Jaguar Object Processor code
45 int dsp56001;                                   // Assembling DSP 56001 code
46 int list_fd;                                    // File to write listing to
47 int segpadsize;                                 // Segment padding size
48 int endian;                                             // Host processor endianess (0 = LE, 1 = BE)
49 int *regbase;                                   // Points to current DFA register table (base)
50 int *regtab;                                    // Points to current DFA register table (tab)
51 int *regcheck;                                  // Points to current DFA register table (check)
52 int *regaccept;                                 // Points to current DFA register table (accept)
53 char * objfname;                                // Object filename pointer
54 char * firstfname;                              // First source filename
55 char * cmdlnexec;                               // Executable name, pointer to ARGV[0]
56 char searchpatha[512] = { 0 };  // Buffer to hold searchpath when specified
57 char * searchpath = NULL;               // Search path for include files
58 char defname[] = "noname.o";    // Default output filename
59 int optim_flags[OPT_COUNT_ALL] = { 0 }; // Specific optimisations on/off matrix
60 int activecpu = CPU_68000;              // Active 68k CPU (68000 by default)
61 int activefpu = FPU_NONE;               // Active FPU (none by default)
62 int org68k_active = 0;                  // .org switch for 68k (only with RAW output format)
63 uint32_t org68k_address;                // .org for 68k
64 int correctMathRules;                   // 1, use C operator precedence in expressions
65 uint32_t used_architectures;    // Bitmask that records exactly which architectures were used during assembly
66
67 //
68 // Convert a string to uppercase
69 //
70 void strtoupper(char * s)
71 {
72         while (*s)
73                 *s++ &= 0xDF;
74 }
75
76 //
77 // Manipulate file extension.
78 //
79 // 'name' must be large enough to hold any possible filename. If 'stripp' is
80 // nonzero, any old extension is removed. If the file does not already have an
81 // extension, 'extension' is appended to the filename.
82 //
83 char * fext(char * name, char * extension, int stripp)
84 {
85         char * s;
86
87         // Find beginning of "real" name (strip off path)
88         char * beg = strrchr(name, SLASHCHAR);
89
90         if (beg == NULL)
91                 beg = name;
92
93         // Clobber any old extension, if requested
94         if (stripp)
95         {
96                 for(s=beg; *s && *s!='.'; ++s)
97                         ;
98
99                 *s = '\0';
100         }
101
102         if (strrchr(beg, '.') == NULL)
103                 strcat(beg, extension);
104
105         return name;
106 }
107
108 static int is_sep(char c)
109 {
110     const char *seps = PATH_SEPS;
111
112     for (seps = PATH_SEPS; *seps; seps++) {
113         if (*seps == c)
114             return 1;
115     }
116
117     return 0;
118 }
119
120 //
121 // Return 'item'nth element of semicolon-seperated pathnames specified in the
122 // enviroment string 's'. Copy the pathname to 'buf'.  Return 0 if the 'item'
123 // nth path doesn't exist.
124 //
125 // ['item' ranges from 0 to N-1, where N = #elements in search path]
126 //
127 int nthpath(char * env_var, int itemno, char * buf)
128 {
129         char * s = searchpath;
130
131         if (s == NULL)
132                 s = getenv(env_var);
133
134         if (s == NULL)
135                 return 0;
136
137         while (itemno--)
138                 while (*s != EOS && !is_sep(*s++))
139                         ;
140
141         if (*s == EOS)
142                 return 0;
143
144         while (*s != EOS && !is_sep(*s))
145                 *buf++ = *s++;
146
147         *buf++ = EOS;
148
149         return 1;
150 }
151
152 //
153 // Display command line help
154 //
155 void DisplayHelp(void)
156 {
157         printf("Usage:\n"
158                 "    %s [options] srcfile\n"
159                 "\n"
160                 "Options:\n"
161                 "  -? or -h          Display usage information\n"
162                 "  -dsymbol[=value]  Define symbol (with optional value, default=0)\n"
163                 "  -e[errorfile]     Send error messages to file, not stdout\n"
164                 "  -f[format]        Output object file format\n"
165                 "                    a: ALCYON\n"
166                 "                    b: BSD (use this for Jaguar)\n"
167                 "                    c: PRG (C64)\n"
168                 "                    e: ELF\n"
169                 "                    p: P56 (use this for DSP56001 only)\n"
170                 "                    l: LOD (use this for DSP56001 only)\n"
171                 "                    x: com/exe/xex (Atari 800)\n"
172                 "                    r: absolute address\n"
173                 "  -g                Output source level debug information (BSD object only)\n"
174                 "  -i[path]          Directory to search for include files\n"
175                 "  -l[filename]      Create an output listing file\n"
176                 "  -l*[filename]     Create an output listing file without pagination\n"
177                 "  -m[cpu]           Select default CPU. Available options:\n"
178                 "                    68000, 68020, 68030, 68040, 68060, 6502, tom, jerry, 56001\n"
179                 "  -n                Don't do things behind your back in RISC assembler\n"
180                 "  -o file           Output file name\n"
181                 "  +o[value]         Turn a specific optimisation on\n"
182                 "                    Available optimisation switches:\n"
183                 "                    o0: Absolute long addresses to word\n"
184                 "                    o1: move.l #x,dn/an to moveq\n"
185                 "                    o2: Word branches to short\n"
186                 "                    o3: Outer displacement 0(an) to (an)\n"
187                 "                    o4: lea size(An),An to addq #size,An\n"
188                 "                    o5: 68020+ Absolute long base/outer disp. to word\n"
189                 "                    o6: Null branches to NOP\n"
190                 "                    o7: clr.l Dx to moveq #0,Dx\n"
191                 "                    o8: adda.w/l #x,Dy to addq.w/l #x,Dy\n"
192                 "                    o9: adda.w/l #x,Ay to lea x(Dy),Ay\n"
193                 "                    o10: 56001 Use short format for immediate values if possible\n"
194                 "                    o11: 56001 Auto convert short addressing mode to long (default: on)\n"
195                 "                    o30: Enforce PC relative (alternative name: op)\n"
196                 "  ~o[value]         Turn a specific optimisation off\n"
197                 "  +oall             Turn all optimisations on\n"
198                 "  ~oall             Turn all optimisations off\n"
199                 "  -p                Create an ST .prg (without symbols). Forces -fa\n"
200                 "  -ps               Create an ST .prg (with symbols). Forces -fa\n"
201                 "  -px               Create an ST .prg (with exsymbols). Forces -fa\n"
202                 "  -r[size]          Pad segments to boundary size specified\n"
203                 "                    w: word (2 bytes, default alignment)\n"
204                 "                    l: long (4 bytes)\n"
205                 "                    p: phrase (8 bytes)\n"
206                 "                    d: double phrase (16 bytes)\n"
207                 "                    q: quad phrase (32 bytes)\n"
208                 "  -s                Warn about possible short branches\n"
209                 "                    and applied optimisations\n"
210                 "  -u                Force referenced and undefined symbols global\n"
211                 "  -v                Set verbose mode\n"
212                 "  -x                Turn on debugging mode\n"
213                 "  -y[pagelen]       Set page line length (default: 61)\n"
214                 "  -4                Use C style operator precedence\n"
215                 "\n", cmdlnexec);
216 }
217
218
219 //
220 // Display version information
221 //
222 void DisplayVersion(void)
223 {
224         printf("\n"
225                 " _ __ _ __ ___   __ _  ___ \n"
226                 "| '__| '_ ` _ \\ / _` |/ __|\n"
227                 "| |  | | | | | | (_| | (__ \n"
228                 "|_|  |_| |_| |_|\\__,_|\\___|\n"
229                 "\nRenamed Macro Assembler\n"
230                 "Copyright (C) 199x Landon Dyer, 2011-2022 Reboot and Friends\n"
231                 "V%01i.%01i.%01i %s (%s)\n\n", MAJOR, MINOR, PATCH, __DATE__, PLATFORM);
232 }
233
234 //
235 // Parse optimisation options
236 //
237 int ParseOptimization(char * optstring)
238 {
239         int onoff = 0;
240
241         while (*optstring)
242         {
243                 if (*optstring == '+')
244                         onoff = 1;
245                 else if (*optstring != '~')
246                         return ERROR;
247
248         if (optstring[2] == 0)
249             return error(".opt called with zero arguments");
250
251                 if ((optstring[2] == 'a' || optstring[2] == 'A')
252                         && (optstring[3] == 'l' || optstring[3] == 'L')
253                         && (optstring[4] == 'l' || optstring[4] == 'L'))
254                 {
255                         memset(optim_flags, onoff, OPT_COUNT * sizeof(int));
256                         optstring += 5;
257                 }
258                 else if (optstring[1] == 'o' || optstring[1] == 'O') // Turn on specific optimisation
259                 {
260                         if (optstring[2] == 'p' || optstring[2] == 'P')
261                         {
262                                 optim_flags[OPT_PC_RELATIVE] = onoff;
263                                 optstring += 3;
264                         }
265                         else
266                         {
267                                 int opt_no = atoi(&optstring[2]);
268
269                                 if ((opt_no >= 0) && (opt_no < OPT_COUNT))
270                                 {
271                                         optim_flags[opt_no] = onoff;
272                                         optstring += 3;
273
274                                         // If opt_no is 2 digits then consume an extra character.
275                                         // Sounds a bit sleazy but we know we're not going to hit
276                                         // more than 100 optimisation switches so this should be
277                                         // fine. If we do hit that number then it'll probably be
278                                         // time to burn the whole codebase and start from scratch.
279                                         if (opt_no > 9)
280                                                 optstring++;
281                                 }
282                                 else
283                                         return ERROR;
284                         }
285                 }
286                 else
287                 {
288                         return ERROR;
289                 }
290
291                 if (*optstring == ',')
292                         optstring++;
293         }
294         return OK;
295 }
296
297 static void ProcessFile(int fd, char *fname)
298 {
299         char *dbgname = fname;
300
301         if (NULL == fname)
302         {
303                 fname = defname; // Kludge first filename
304                 dbgname = "(stdin)";
305         }
306
307         // First file operations:
308         if (firstfname == NULL)
309         {
310                 // Record first filename.
311                 firstfname = fname;
312
313                 // Validate option compatibility
314                 if (dsym_flag)
315                 {
316                         if (obj_format != BSD)
317                         {
318                                 printf("-g: debug information only supported with BSD object file format\n");
319                                 dsym_flag = 0;
320                                 errcnt++;
321                         }
322                         else
323                         {
324                                 GenMainFileSym(dbgname);
325                         }
326                 }
327         }
328
329         include(fd, dbgname);
330         Assemble();
331 }
332
333 extern int reg68base[53];
334 extern int reg68tab[222];
335 extern int reg68check[222];
336 extern int reg68accept[222];
337
338 //
339 // Process command line arguments and do an assembly
340 //
341 int Process(int argc, char ** argv)
342 {
343         int argno;                                              // Argument number
344         SYM * sy;                                               // Pointer to a symbol record
345         char * s;                                               // String pointer
346         int fd;                                                 // File descriptor
347         char fnbuf[FNSIZ];                              // Filename buffer
348         int i;                                                  // Iterator
349         int current_path_index = 0;             // Iterator for search paths
350
351         errcnt = 0;                                             // Initialize error count
352         listing = 0;                                    // Initialize listing level
353         list_flag = 0;                                  // Initialize listing flag
354         verb_flag = perm_verb_flag;             // Initialize verbose flag
355         glob_flag = 0;                                  // Initialize .globl flag
356         optim_warn_flag = 0;                    // Initialize short branch flag
357         debug = 0;                                              // Initialize debug flag
358         objfname = NULL;                                // Initialize object filename
359         list_fname = NULL;                              // Initialize listing filename
360         err_fname = NULL;                               // Initialize error filename
361         obj_format = BSD;                               // Initialize object format
362         firstfname = NULL;                              // Initialize first filename
363         err_fd = ERROUT;                                // Initialize error file descriptor
364         err_flag = 0;                                   // Initialize error flag
365         rgpu = 0;                                               // Initialize GPU assembly flag
366         rdsp = 0;                                               // Initialize DSP assembly flag
367         robjproc = 0;                                   // Initialize OP assembly flag
368         lsym_flag = 1;                                  // Include local symbols in object file
369         dsym_flag = 0;                                  // No debug sym generation by default
370         orgactive = 0;                                  // Not in RISC org section
371         orgwarning = 0;                                 // No ORG warning issued
372         segpadsize = 2;                                 // Initialize segment padding size
373     dsp_orgmap[0].start = 0;            // Initialize 56001 org initial address
374     dsp_orgmap[0].memtype = ORG_P;      // Initialize 56001 org start segment
375         m6502 = 0;                                              // 6502 mode off by default
376         regbase = reg68base;                    // Initialise DFA register tables
377         regtab = reg68tab;                              // Idem
378         regcheck = reg68check;                  // Idem
379         regaccept = reg68accept;                // Idem
380     correctMathRules = 0;                       // respect operator precedence
381         used_architectures = 0;                 // Initialise used architectures bitfield
382         // Initialize modules
383         InitSymbolTable();                              // Symbol table
384         InitTokenizer();                                // Tokenizer
385         InitLineProcessor();                    // Line processor
386         InitExpression();                               // Expression analyzer
387         InitSection();                                  // Section manager / code generator
388         InitMark();                                             // Mark tape-recorder
389         InitMacro();                                    // Macro processor
390         InitListing();                                  // Listing generator
391         Init6502();                                             // 6502 assembler
392
393         // Process command line arguments and assemble source files
394         for(argno=0; argno<argc; argno++)
395         {
396                 if (*argv[argno] == '-')
397                 {
398                         switch (argv[argno][1])
399                         {
400                         case '4':
401                                 correctMathRules = 1;
402                                 break;
403                         case 'd':                               // Define symbol
404                         case 'D':
405                                 for(s=argv[argno]+2; *s!=EOS;)
406                                 {
407                                         if (*s++ == '=')
408                                         {
409                                                 s[-1] = EOS;
410                                                 break;
411                                         }
412                                 }
413
414                                 if (argv[argno][2] == EOS)
415                                 {
416                                         printf("-d: empty symbol\n");
417                                         errcnt++;
418                                         return errcnt;
419                                 }
420
421                                 sy = lookup(argv[argno] + 2, 0, 0);
422
423                                 if (sy == NULL)
424                                 {
425                                         sy = NewSymbol(argv[argno] + 2, LABEL, 0);
426                                         sy->svalue = 0;
427                                 }
428
429                                 sy->sattr = DEFINED | EQUATED | ABS;
430                                 sy->svalue = (*s ? (uint64_t)atoi(s) : 0);
431                                 break;
432                         case 'e':                               // Redirect error message output
433                         case 'E':
434                                 err_fname = argv[argno] + 2;
435                                 break;
436                         case 'f':                               // -f<format>
437                         case 'F':
438                                 switch (argv[argno][2])
439                                 {
440                                 case EOS:
441                                 case 'a':                       // -fa = Alcyon [the default]
442                                 case 'A':
443                                         obj_format = ALCYON;
444                                         break;
445                                 case 'b':                       // -fb = BSD (Jaguar Recommended: 3 out 4 jaguars recommend it!)
446                                 case 'B':
447                                         obj_format = BSD;
448                                         break;
449                                 case 'c':
450                                 case 'C':
451                                         obj_format = C64PRG;
452                                         break;
453                                 case 'e':                       // -fe = ELF
454                                 case 'E':
455                                         obj_format = ELF;
456                                         break;
457                 case 'l':           // -fl = LOD
458                 case 'L':
459                     obj_format = LOD;
460                     break;
461                 case 'p':           // -fp = P56
462                 case 'P':
463                     obj_format = P56;
464                                         break;
465                                 case 'x':                       // -fx = COM/EXE/XEX
466                                 case 'X':
467                                         obj_format = XEX;
468                                         break;
469                 case 'r':           // -fr = Absolute address
470                 case 'R':
471                     obj_format = RAW;
472                     break;
473                                 default:
474                                         printf("-f: unknown object format specified\n");
475                                         errcnt++;
476                                         return errcnt;
477                                 }
478                                 break;
479                         case 'g':                               // Debugging flag
480                         case 'G':
481                                 dsym_flag = 1;
482                                 break;
483                         case 'i':                               // Set directory search path
484                         case 'I':
485                         {
486                                 strcat(searchpatha, argv[argno] + 2);
487                                 strcat(searchpatha, ";");
488                                 searchpath = searchpatha;
489
490                                 // Check to see if include paths actually exist
491                                 char current_path[256];
492
493                                 for(i=current_path_index; nthpath("RMACPATH", i, current_path)!=0; i++)
494                                 {
495                                         if (strlen(current_path) > 0)
496                                         {
497                                                 DIR * test = opendir(current_path);
498
499                                                 if (test == NULL)
500                                                 {
501                                                         printf("Invalid include path: %s\n", current_path);
502                                                         errcnt++;
503                                                         return errcnt;
504                                                 }
505
506                                                 closedir(test);
507                                         }
508                                 }
509
510                                 current_path_index = i - 1;
511                                 break;
512                         }
513                         case 'l':                               // Produce listing file
514                         case 'L':
515                                 if (*(argv[argno] + 2) == '*')
516                                 {
517                                         list_fname = argv[argno] + 3;
518                                         list_pag = 0;    // Special case - turn off pagination
519                                 }
520                                 else
521                                 {
522                                         list_fname = argv[argno] + 2;
523                                 }
524
525                                 listing = 1;
526                                 list_flag = 1;
527                                 lnsave++;
528                                 break;
529                         case 'm':
530                         case 'M':
531                                 if (strcmp(argv[argno] + 2, "68000") == 0)
532                                         d_68000();
533                                 else if (strcmp(argv[argno] + 2, "68020") == 0)
534                                         d_68020();
535                                 else if (strcmp(argv[argno] + 2, "68030") == 0)
536                                         d_68030();
537                                 else if (strcmp(argv[argno] + 2, "68040") == 0)
538                                         d_68040();
539                                 else if (strcmp(argv[argno] + 2, "68060") == 0)
540                                         d_68060();
541                                 else if (strcmp(argv[argno] + 2, "68881") == 0)
542                                         d_68881();
543                                 else if (strcmp(argv[argno] + 2, "68882") == 0)
544                                         d_68882();
545                                 else if (strcmp(argv[argno] + 2, "56001") == 0)
546                                         d_56001();
547                                 else if (strcmp(argv[argno] + 2, "6502") == 0)
548                                         d_6502();
549                                 else if (strcmp(argv[argno] + 2, "tom") == 0)
550                                         d_gpu();
551                                 else if (strcmp(argv[argno] + 2, "jerry") == 0)
552                                         d_dsp();
553                                 else
554                                 {
555                                         printf("Unrecognized CPU '%s'\n", argv[argno] + 2);
556                                         errcnt++;
557                                         return errcnt;
558                                 }
559                                 break;
560                         case 'o':                               // Direct object file output
561                         case 'O':
562                                 if (argv[argno][2] != EOS)
563                                         objfname = argv[argno] + 2;
564                                 else
565                                 {
566                                         if (++argno >= argc)
567                                         {
568                                                 printf("Missing argument to -o");
569                                                 errcnt++;
570                                                 return errcnt;
571                                         }
572
573                                         objfname = argv[argno];
574                                 }
575
576                                 break;
577                         case 'p':               /* -p: generate ".PRG" executable output */
578                         case 'P':
579                                 /*
580                                  * -p           .PRG generation w/o symbols
581                                  * -ps          .PRG generation with symbols
582                                  * -px          .PRG generation with extended symbols
583                                  */
584                                 switch (argv[argno][2])
585                                 {
586                                         case EOS:
587                                                 prg_flag = 1;
588                                                 break;
589
590                                         case 's':
591                                         case 'S':
592                                                 prg_flag = 2;
593                                                 break;
594
595                                         case 'x':
596                                         case 'X':
597                                                 prg_flag = 3;
598                                                 break;
599
600                                         default:
601                                                 printf("-p: syntax error\n");
602                                                 errcnt++;
603                                                 return errcnt;
604                                 }
605
606                                 // Enforce Alcyon object format - kind of silly
607                                 // to ask for .prg output without it!
608                                 obj_format = ALCYON;
609                                 break;
610                         case 'r':                               // Pad seg to requested boundary size
611                         case 'R':
612                                 switch(argv[argno][2])
613                                 {
614                                 case 'w': case 'W': segpadsize = 2;  break;
615                                 case 'l': case 'L': segpadsize = 4;  break;
616                                 case 'p': case 'P': segpadsize = 8;  break;
617                                 case 'd': case 'D': segpadsize = 16; break;
618                                 case 'q': case 'Q': segpadsize = 32; break;
619                                 default: segpadsize = 2; break; // Effective autoeven();
620                                 }
621                                 break;
622                         case 's':                               // Warn about possible short branches and applied optimisations
623                         case 'S':
624                                 optim_warn_flag = 1;
625                                 break;
626                         case 'u':                               // Make undefined symbols .globl
627                         case 'U':
628                                 glob_flag = 1;
629                                 break;
630                         case 'v':                               // Verbose flag
631                         case 'V':
632                                 verb_flag++;
633
634                                 if (verb_flag > 1)
635                                         DisplayVersion();
636
637                                 break;
638                         case 'x':                               // Turn on debugging
639                         case 'X':
640                                 debug = 1;
641                                 printf("~ Debugging ON\n");
642                                 break;
643                         case 'y':                               // -y<pagelen>
644                         case 'Y':
645                                 pagelen = atoi(argv[argno] + 2);
646
647                                 if (pagelen < 10)
648                                 {
649                                         printf("-y: bad page length\n");
650                                         errcnt++;
651                                         return errcnt;
652                                 }
653
654                                 break;
655                         case EOS:                               // Input is stdin
656                                 ProcessFile(0, NULL);
657                                 break;
658                         case 'h':                               // Display command line usage
659                         case 'H':
660                         case '?':
661                                 DisplayVersion();
662                                 DisplayHelp();
663                                 errcnt++;
664                                 break;
665                         case 'n':                               // Turn off legacy mode
666                         case 'N':
667                                 legacy_flag = 0;
668                                 printf("Legacy mode OFF\n");
669                                 break;
670                         default:
671                                 DisplayVersion();
672                                 printf("Unknown switch: %s\n\n", argv[argno]);
673                                 DisplayHelp();
674                                 errcnt++;
675                                 break;
676                         }
677                 }
678                 else if (*argv[argno] == '+' || *argv[argno] == '~')
679                 {
680                         if (ParseOptimization(argv[argno]) != OK)
681                         {
682                                 DisplayVersion();
683                                 printf("Unknown switch: %s\n\n", argv[argno]);
684                                 DisplayHelp();
685                                 errcnt++;
686                                 break;
687                         }
688                 }
689                 else
690                 {
691                         strcpy(fnbuf, argv[argno]);
692                         fext(fnbuf, ".s", 0);
693                         fd = open(fnbuf, 0);
694
695                         if (fd < 0)
696                         {
697                                 printf("Cannot open: %s\n", fnbuf);
698                                 errcnt++;
699                                 continue;
700                         }
701
702                         ProcessFile(fd, fnbuf);
703                 }
704         }
705
706         // Wind-up processing;
707         // o  save current section (no more code generation)
708         // o  do auto-even of all sections (or boundary alignment as requested
709         //    through '-r')
710     // o  save the last pc value for 6502 (if we used 6502 at all) and
711     //    detemine if the last section contains anything
712         // o  determine name of object file:
713         //    -  "foo.o" for linkable output;
714         //    -  "foo.prg" for GEMDOS executable (-p flag).
715         SaveSection();
716         int temp_section = cursect;
717
718         for(i=TEXT; i<=BSS; i<<=1)
719         {
720                 SwitchSection(i);
721
722                 switch(segpadsize)
723                 {
724                 case 2:  d_even();    break;
725                 case 4:  d_long();    break;
726                 case 8:  d_phrase();  break;
727                 case 16: d_dphrase(); break;
728                 case 32: d_qphrase(); break;
729                 }
730
731                 SaveSection();
732         }
733
734         SwitchSection(M6502);
735
736         if (sloc != currentorg[0])
737         {
738                 currentorg[1] = sloc;
739                 currentorg += 2;
740         }
741
742         // This looks like an awful kludge...  !!! FIX !!!
743         if (temp_section & (M56001P | M56001X | M56001Y))
744         {
745                 SwitchSection(temp_section);
746
747                 if (chptr != dsp_currentorg->start)
748                 {
749                         dsp_currentorg->end = chptr;
750                         dsp_currentorg++;
751                 }
752         }
753
754         SwitchSection(TEXT);
755
756         if (objfname == NULL)
757         {
758                 if (firstfname == NULL)
759                         firstfname = defname;
760
761                 // It's the size of fnbuf minus 5 because of the possible 4 char suffix
762                 // + trailing null (added by fext()).
763                 strncpy(fnbuf, firstfname, sizeof(fnbuf) - 5);
764                 fext(fnbuf, (prg_flag ? ".prg" : ".o"), 1);
765                 objfname = fnbuf;
766         }
767
768         // With one pass finished, go back and:
769         // (1)   run through all the fixups and resolve forward references;
770         // (1.5) ensure that remaining fixups can be handled by the linker
771         //       (`lo68' format, extended (postfix) format....)
772         // (2)   generate the output file image and symbol table;
773         // (3)   generate relocation information from left-over fixups.
774         ResolveAllFixups();                                             // Do all fixups
775         StopMark();                                                             // Stop mark tape-recorder
776
777         if (errcnt == 0)
778         {
779                 if ((fd = open(objfname, _OPEN_FLAGS, _PERM_MODE)) < 0)
780                         CantCreateFile(objfname);
781
782                 if (verb_flag)
783                 {
784                         s = (prg_flag ? "executable" : "object");
785                         printf("[Writing %s file: %s]\n", s, objfname);
786                 }
787
788                 WriteObject(fd);
789                 close(fd);
790
791                 if (errcnt != 0)
792                         unlink(objfname);
793         }
794
795         if (list_flag)
796         {
797                 if (verb_flag)
798                         printf("[Wrapping-up listing file]\n");
799
800                 listing = 1;
801                 symtable();
802                 close(list_fd);
803         }
804
805         if (err_flag)
806                 close(err_fd);
807
808         DEBUG dump_everything();
809
810         return errcnt;
811 }
812
813 //
814 // Determine processor endianess
815 //
816 int GetEndianess(void)
817 {
818         int i = 1;
819         char * p = (char *)&i;
820
821         if (p[0] == 1)
822                 return 0;
823
824         return 1;
825 }
826
827 //
828 // Application entry point
829 //
830 int main(int argc, char ** argv)
831 {
832         perm_verb_flag = 0;                             // Clobber "permanent" verbose flag
833         legacy_flag = 1;                                // Default is legacy mode on (:-P)
834         optim_flags[OPT_56K_SHORT] = 1; // This ensures compatibilty with Motorola's 56k assembler
835
836         cmdlnexec = argv[0];                    // Obtain executable name
837         endian = GetEndianess();                // Get processor endianess
838
839         // If commands were passed in, process them
840         if (argc > 1)
841                 return Process(argc - 1, argv + 1);
842
843         DisplayVersion();
844         DisplayHelp();
845
846         return 0;
847 }