* asranlib/asranlib.c, link/lkar.h, link/lkar.c:
[fw/sdcc] / as / xa51 / xa_main.c
1 /* xa_main.c - Paul's XA51 Assembler
2
3    Copyright 1997,2002 Paul Stoffregen (paul at pjrc dot com)
4
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 3, or (at your option) any
8 later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
17
18 /* adapted from the osu8asm project, 1995 */
19 /* http://www.pjrc.com/tech/osu8/index.html */
20
21 /* 
22    made "relocatable" by johan.knol@iduna.nl for sdcc
23    
24    This isn't a standalone assembler anymore. It's only purpose is to
25    create relocatable modules (that has to be processed with xa_link) 
26    out of sdcc-generated .xa files
27 */
28
29 #define D(x) x
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <limits.h>
35
36 #define printf(x...) fprintf(stderr,x)
37
38 #include "xa_main.h"
39 #include "xa_version.h"
40 extern void yyrestart(FILE *new_file);
41 extern int yyparse();
42
43
44 char modulename[PATH_MAX];
45 char infilename[PATH_MAX];
46 char outfilename[PATH_MAX];
47 char listfilename[PATH_MAX];
48 char symfilename[PATH_MAX];
49
50 /* global variables */
51
52 FILE *frel, *fmem, *list_fp, *sym_fp;
53 extern FILE *yyin;
54 extern char *yytext;
55 extern char last_line_text[];
56 struct symbol *sym_list=NULL;
57 struct target *targ_list=NULL;
58 int lineno=1;
59 int p1=0, p2=0, p3=0;
60 int expr_result, expr_ok, jump_dest, inst;
61 int opcode;
62 char symbol_name[1000];
63 struct area_struct area[NUM_AREAS];
64 int current_area=0;
65
66 char rel_line[2][132];
67
68 char *areaToString (int area) {
69   switch (area) 
70     {
71     case AREA_CSEG: return "CSEG";
72     case AREA_DSEG: return "DSEG";
73       //case AREA_OSEG: return "OSEG";
74       //case AREA_ISEG: return "ISEG";
75     case AREA_BSEG: return "BSEG";
76     case AREA_XSEG: return "XSEG";
77     case AREA_XISEG: return "XISEG";
78     case AREA_XINIT: return "XINIT";
79     case AREA_GSINIT: return "GSINIT";
80       //case AREA_GSFINAL: return "GSFINAL";
81       //case AREA_HOME: return "HOME";
82       //case AREA_SSEG: return "SSEG";
83     }
84   return ("UNKNOW");
85 }
86
87 /* "mem" is replaced by area[current_area].alloc_position */
88 /* int mem=0; */   /* mem is location in memory */
89
90 /* add symbols to list when we find their definition in pass #1 */
91 /* we will evaluate their values in pass #2, and figure out if */
92 /* they are branch targets betweem passes 1 and 2.  Every symbol */
93 /* should appear exactly once in this list, since it can't be redefined */
94
95 struct symbol * build_sym_list(char *thename)
96 {
97         struct symbol *new, *p;
98
99         if ((p=findSymbol(thename))) {
100           if (p->isdef) {
101             fprintf (stderr, "error: symbol %s already defined\n", thename);
102             exit (1);
103           } else {
104             return p;
105           }
106         }
107
108         //printf("  Symbol: %s  Line: %d\n", thename, lineno);
109         new = (struct symbol *) malloc(sizeof(struct symbol));
110         new->name = (char *) malloc(strlen(thename)+1);
111         strcpy(new->name, thename);
112         new->value = 0;
113         new->istarget = 0;
114         new->isdef = 0;
115         new->isbit = 0;
116         new->isreg = 0;
117         new->line_def = lineno - 1;
118         new->area = current_area;
119         new->mode = 'X'; // start with an external
120         new->next = NULL;
121         if (sym_list == NULL) return (sym_list = new);
122         p = sym_list;
123         while (p->next != NULL) p = p->next;
124         p->next = new;
125         return (new);
126 }
127
128 struct symbol *findSymbol (char *thename) {
129   struct symbol *p;
130   for (p=sym_list; p; p=p->next) {
131     if (strcasecmp(thename, p->name)==0) {
132       return p;
133     }
134   }
135   return NULL;
136 }
137
138 int assign_value(char *thename, int thevalue, char mode) {
139   struct symbol *p;
140   
141   p = sym_list;
142   while (p != NULL) {
143     if (!(strcasecmp(thename, p->name))) {
144       p->area=current_area;
145       p->value = thevalue;
146       p->isdef = 1;
147       p->mode = mode;
148       return (0);
149     }
150     p = p->next;
151   }
152   fprintf(stderr, "Internal Error!  Couldn't find symbol\n");
153   exit(1);
154 }
155
156 int mk_bit(char *thename, int area)
157 {
158         struct symbol *p;
159
160         p = sym_list;
161         while (p != NULL) {
162                 if (!(strcasecmp(thename, p->name))) {
163                         p->isbit = 1;
164                         p->area = area;
165                         return (0);
166                 }
167                 p = p->next;
168         }
169         fprintf(stderr, "Internal Error!  Couldn't find symbol\n");
170         exit(1);
171 }
172
173 int mk_sfr(char *thename)
174 {
175         struct symbol *p;
176
177         p = sym_list;
178         while (p != NULL) {
179                 if (!(strcasecmp(thename, p->name))) {
180                         p->issfr = 1;
181                         p->area = 0;
182                         return (0);
183                 }
184                 p = p->next;
185         }
186         fprintf(stderr, "Internal Error!  Couldn't find symbol\n");
187         exit(1);
188 }
189
190
191 int mk_reg(char *thename)
192 {
193         struct symbol *p;
194
195         p = sym_list;
196         while (p != NULL) {
197                 if (!(strcasecmp(thename, p->name))) {
198                         p->isreg = 1;
199                         return (0);
200                 }
201                 p = p->next;
202         }
203         fprintf(stderr, "Internal Error!  Couldn't find symbol\n");
204         exit(1);
205 }
206
207 int mk_global(char *thename)
208 {
209   struct symbol *p;
210   
211   p = sym_list;
212   while (p != NULL) {
213     if (!(strcasecmp(thename, p->name))) {
214       p->global = 1;
215       return (0);
216     }
217     p = p->next;
218   }
219   fprintf(stderr, "Internal Error!  Couldn't find symbol\n");
220   exit(1);
221 }
222
223 int get_value(char *thename)
224 {
225   struct symbol *p;
226   p = sym_list;
227   while (p != NULL) {
228     if (!(strcasecmp(thename, p->name))) {
229       if (p->mode=='=')
230         ;//return 0;
231       return (p->value);
232     }
233     p = p->next;
234   }
235   fprintf(stderr, "Internal Error!  Couldn't find symbol value\n");
236   exit(1);
237 }
238                 
239
240
241 /* add every branch target to this list as we find them */
242 /* ok if multiple entries of same symbol name in this list */
243
244 struct target * build_target_list(char *thename)
245 {
246         struct target *new, *p;
247         new = (struct target *) malloc(sizeof(struct target));
248         new->name = (char *) malloc(strlen(thename)+1);
249         strcpy(new->name, thename);
250         new->next = NULL;
251         if (targ_list == NULL) return (targ_list = new);
252         p = targ_list;
253         while (p->next != NULL) p = p->next;
254         p->next = new;
255         return (new);
256 }
257
258 /* figure out which symbols are branch targets */
259
260 void flag_targets()
261 {
262         struct symbol *p_sym;
263         struct target *p_targ;
264         p_targ = targ_list;
265         while (p_targ != NULL) {
266                 p_sym = sym_list;
267                 while (p_sym != NULL) {
268                         if (!strcasecmp(p_sym->name, p_targ->name))
269                                 p_sym->istarget = 1;
270                         p_sym = p_sym->next;
271                 }
272                 p_targ = p_targ->next;
273         }
274 }
275
276 void print_symbol_table()
277 {
278   struct symbol *p;
279   p = sym_list;
280   while (p != NULL) {
281 #if 0
282     fprintf(sym_fp, "Sym in %-5s: %s\n", areaToString(p->area), p->name);
283     fprintf(sym_fp, "  at: 0x%04X (%5d)", p->value, p->value);
284     fprintf(sym_fp, " Def:%s", p->isdef ? "Yes" : "No ");
285     fprintf(sym_fp, " Bit:%s", p->isbit ? "Yes" : "No ");
286     fprintf(sym_fp, " Target:%s", p->istarget ? "Yes" : "No ");
287     fprintf(sym_fp, " Line %d\n", p->line_def);
288 #else
289     if (p->issfr) {
290       fprintf (sym_fp, "%-7s", "SFR");
291     } else if (p->isbit && !p->area) {
292       fprintf (sym_fp, "%-7s", "SBIT");
293     } else if (p->mode=='=') {
294       fprintf (sym_fp,"ABS    ");
295     } else if (!p->isdef) {
296       fprintf (sym_fp,"EXTRN  ");
297     } else {
298       fprintf (sym_fp, "%-7s", areaToString(p->area));
299     }
300     fprintf (sym_fp, " 0x%04x (%5d)", p->value, p->value);
301     fprintf (sym_fp, " %s", p->isdef ? "D" : "-");
302     fprintf (sym_fp, "%s", p->isbit ? "B" : "-");
303     fprintf (sym_fp, "%s", p->istarget ? "T" : "-");
304     fprintf (sym_fp, " %s\n", p->name);
305 #endif
306     p = p->next;
307   }
308 }
309
310 /* check that every symbol is in the table only once */
311
312 void check_redefine()
313 {
314   struct symbol *p1, *p2;
315   p1 = sym_list;
316   while (p1 != NULL) {
317     p2 = p1->next;
318     while (p2 != NULL) {
319       if (!strcasecmp(p1->name, p2->name)) {
320         fprintf(stderr, "Error: symbol '%s' redefined on line %d", 
321                 p1->name, p2->line_def);
322         fprintf(stderr, ", first defined on line %d\n", p1->line_def);
323         exit(1);
324       }
325       p2 = p2->next;
326     }
327     p1 = p1->next;
328   }
329 }
330
331 int is_target(char *thename)
332 {
333         struct symbol *p;
334         p = sym_list;
335         while (p != NULL) {
336                 if (!strcasecmp(thename, p->name)) return (p->istarget);
337                 p = p->next;
338         }
339         return (0);
340 }
341
342 int is_bit(char *thename)
343 {
344         struct symbol *p;
345         p = sym_list;
346         while (p != NULL) {
347                 if (!strcasecmp(thename, p->name)) return (p->isbit);
348                 p = p->next;
349         }
350         return (0);
351 }
352
353 int is_reg(char *thename)
354 {
355         struct symbol *p;
356         p = sym_list;
357         while (p != NULL) {
358                 if (!strcasecmp(thename, p->name)) return (p->isreg);
359                 p = p->next;
360         }
361         return (0);
362 }
363
364
365 struct symbol *is_def(char *thename)
366 {
367   struct symbol *p;
368   p = sym_list;
369   while (p != NULL) {
370     if (!strcasecmp(thename, p->name) && p->isdef) 
371       return p;
372     p = p->next;
373   }
374   return NULL;
375 }
376
377 struct symbol *is_ref(char *thename) {
378   struct symbol *p;
379   p = sym_list;
380   while (p != NULL) {
381     if (strcasecmp(thename, p->name)==0) 
382       return p;
383     p = p->next;
384   }
385   return NULL;
386 }
387
388 int is_abs(char *thename) {
389   struct symbol *p;
390   p = sym_list;
391   while (p != NULL) {
392     if (strcasecmp(thename, p->name)==0) 
393       return p->mode == '=';
394     p = p->next;
395   }
396   return 0;
397 }
398
399 /* this routine is used to dump a group of bytes to the output */
400 /* it is responsible for generating the list file and sending */
401 /* the bytes one at a time to the object code generator */
402 /* this routine is also responsible for generatine the list file */
403 /* though is it expected that the lexer has placed all the actual */
404 /* original text from the line in "last_line_text" */
405
406 static short last_area=-1;
407
408 int debug=0;
409
410 void out(int *byte_list, int num) {
411   struct symbol *p;
412   int i, first=1;
413   
414   if (num > 0) fprintf(list_fp, "%06X: ", MEM_POS);
415   else fprintf(list_fp, "\t");
416   
417   if (last_area!=current_area) {
418     // emit area information
419     if (area[current_area].size) {
420       fprintf (frel, "A %s size %d flags 0\n", 
421                areaToString(current_area),
422                area[current_area].size);
423       if  (!area[current_area].defsEmitted) {
424         for (p=sym_list; p; p=p->next) {
425           if (p->global && p->isdef && p->area==current_area) {
426             // skip temp labels
427             if (p->name[strlen(p->name)-1]!='$') {
428               if (p->mode=='=') {
429                 fprintf (frel, "S %s Abs%04x\n", p->name, p->value);
430               } else {
431                 fprintf (frel, "S %s Def%04x\n", p->name, p->value);
432               }
433             }
434           }
435         }
436         area[current_area].defsEmitted=1;
437       }
438     }
439     last_area=current_area;
440   }
441   if (current_area==AREA_CSEG ||
442       current_area==AREA_GSINIT ||
443       current_area==AREA_XINIT) {
444     if (num) {
445       for (i=0; i<num; i++) {
446         if ((i%16)==0) {
447           fprintf (frel, "%sT %04x", i ? "\n" : "", MEM_POS+i);
448         }
449         fprintf (frel, " %02x", byte_list[i]);
450       }
451       fprintf (frel, "\n");
452       if (rel_line[0][0]) {
453         fprintf (frel, "%s\n", rel_line[0]);
454         if (rel_line[1][0]) {
455           fprintf (frel, "%s\n", rel_line[1]);
456         }
457       }
458     }
459     for (i=0; i<num; i++) {
460       if (!first && (i % 4) == 0) fprintf(list_fp, "\t");
461       fprintf(list_fp, "%02X", byte_list[i]);
462       if ((i+1) % 4 == 0) {
463         if (first) fprintf(list_fp, "\t%s\n", last_line_text);
464         else fprintf(list_fp, "\n");
465         first = 0;
466       } else {
467         if (i<num-1) fprintf(list_fp, " ");
468       }
469     }
470   }
471   if (first) {
472     if (num < 3) fprintf(list_fp, "\t");
473     fprintf(list_fp, "\t%s\n", last_line_text);
474   } else {
475     if (num % 4) fprintf(list_fp, "\n");
476   }
477   operand[0][0]='\0';
478   operand[1][0]='\0';
479   rel_line[0][0]='\0';
480   rel_line[1][0]='\0';
481 }
482
483
484 /* add NOPs to align memory location on a valid branch target address */
485
486 void pad_with_nop()
487 {
488   static int nops[] = {NOP_OPCODE, NOP_OPCODE, NOP_OPCODE, NOP_OPCODE};
489   int num;
490   
491   last_line_text[0] = '\0';
492   
493   for(num=0; (MEM_POS + num) % BRANCH_SPACING; num++) {
494     sprintf (last_line_text, "\tnop\t; word allignment");
495   }
496   if (p3) out(nops, num);
497   MEM_POS += num;
498 }
499
500 /* print branch out of bounds error */
501
502 void boob_error()
503 {
504         fprintf(stderr, "Error: branch out of bounds");
505         fprintf(stderr, " in line %d\n", lineno);
506         exit(1);
507 }
508
509 /* turn a string like "10010110b" into an int */
510
511 int binary2int(char *str)
512 {
513         register int i, j=1, sum=0;
514         
515         for (i=strlen(str)-2; i >= 0; i--) {
516                 sum += j * (str[i] == '1');
517                 j *= 2;
518         }
519         return (sum);
520 }
521
522 void print_usage(int);
523
524 void init_areas(void)
525 {
526   area[AREA_CSEG].start=area[AREA_CSEG].alloc_position = 0;
527   area[AREA_DSEG].start=area[AREA_DSEG].alloc_position = 0;
528   area[AREA_BSEG].start=area[AREA_BSEG].alloc_position = 0;
529   area[AREA_XSEG].start=area[AREA_XSEG].alloc_position = 0;
530   area[AREA_XISEG].start=area[AREA_XISEG].alloc_position = 0;
531   area[AREA_XINIT].start=area[AREA_XINIT].alloc_position = 0;
532   area[AREA_GSINIT].start=area[AREA_GSINIT].alloc_position = 0;
533   area[AREA_GSFINAL].start=area[AREA_GSFINAL].alloc_position = 0;
534   area[AREA_HOME].start=area[AREA_HOME].alloc_position = 0;
535 }
536
537 void relPrelude() {
538   //char buffer[132];
539   int i, areas=0, globals=0;
540   struct symbol *p;
541
542   fprintf (frel, "SDCCXA rel, version %1.1f\n", version);
543   for (i=1; i<NUM_AREAS; i++) {
544     if ((area[i].size=area[i].alloc_position-area[i].start)) {
545       areas++;
546     }
547   }
548   for (p=sym_list; p; p=p->next) {
549     if (p->isdef) {
550       // skip temp labels
551       if (p->name[strlen(p->name)-1]!='$') {
552         globals++;
553       }
554     }
555   }
556   fprintf (frel, "H %d areas %d global symbols\n", areas, globals);
557   fprintf (frel, "M %s\n", modulename);
558   for (p=sym_list; p; p=p->next) {
559     if (!p->isdef) {
560       fprintf (frel, "S %s Ref0000\n", p->name);
561     }
562   }
563 }
564
565 void printVersion() {
566   printf("\nPaul's XA51 Assembler\n");
567   printf("Copyright 1997,2002 Paul Stoffregen\n\n");
568   printf("This program is free software; you can redistribute it\n");
569   printf("and/or modify it under the terms of the GNU General Public\n");
570   printf("License, Version 2, published by the Free Software Foundation\n\n");
571   printf("This program is distributed in the hope that it will be useful,\n");
572   printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
573   printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
574 }
575
576 int verbose=0, createSymbolFile=0;
577
578 void process_args(int argc, char **argv) 
579 {
580   int i=0;
581
582   if (argc < 2) print_usage(1);
583   
584   while (++i<argc && *argv[i]=='-') {
585     if (strcmp(argv[i], "--version")==0) {
586       printVersion();
587       exit (0);
588     }
589     if (strcmp(argv[i], "--help")==0) {
590       print_usage(0);
591     }
592     if (strcmp(argv[i], "-v")==0) {
593       verbose++;
594       continue;
595     }
596     if (strcmp(argv[i], "-s")==0) {
597       createSymbolFile++;
598       continue;
599     }
600     print_usage(1);
601   }
602
603   if (i!=argc-1) {
604     // only 1 source file for now
605     print_usage(1);
606   }
607
608   strcpy(infilename, argv[i]);
609
610   if (strncasecmp(infilename+strlen(infilename)-4, ".asm", 3)) {
611     fprintf (stderr, "unrecognized input file: \"%s\"\n", argv[i]);
612     print_usage(1);
613   }
614
615   strcpy(modulename, infilename);
616   modulename[strlen(modulename)-4] = '\0';
617   sprintf (outfilename, "%s.rel", modulename);
618   sprintf (listfilename, "%s.lst", modulename);
619   if (createSymbolFile) {
620     sprintf (symfilename, "%s.sym", modulename);
621   }
622 }
623
624 /* pass #1 (p1=1) find all symbol defs and branch target names */
625 /* pass #2 (p2=1) align branch targets, evaluate all symbols */
626 /* pass #3 (p3=1) produce object code */
627
628 int main(int argc, char **argv)
629 {
630         process_args (argc, argv);
631
632         yyin = fopen(infilename, "r");
633         if (yyin == NULL) {
634                 fprintf(stderr, "Can't open file '%s'.\n", infilename);
635                 exit(1);
636         }
637         frel = fopen(outfilename, "w");
638         if (frel == NULL) {
639                 fprintf(stderr, "Can't write file '%s'.\n", outfilename);
640                 exit(1);
641         }
642         list_fp = fopen(listfilename, "w");
643         if (list_fp == NULL) {
644                 fprintf(stderr, "Can't write file '%s'.\n", listfilename);
645                 exit(1);
646         }
647         if (createSymbolFile) {
648           sym_fp = fopen(symfilename, "w");
649           if (sym_fp == NULL) {
650             fprintf(stderr, "Can't write file '%s'.\n", symfilename);
651             exit(1);
652           }
653         }
654
655         if (verbose) printf("Pass 1: Building Symbol Table:\n");
656         p1 = 1;
657         init_areas();
658         yyparse();
659         flag_targets();
660         check_redefine();
661
662         if (verbose) printf("Pass 2: Aligning Branch Targets:\n");
663         p1 = 0;
664         p2 = 1;
665         rewind(yyin);
666         yyrestart(yyin);
667         lineno = 1;
668         init_areas();
669         yyparse();
670
671         relPrelude();
672         if (createSymbolFile) print_symbol_table();
673
674         if (verbose) printf("Pass 3: Generating Object Code:\n");
675         p2 = 0;
676         p3 = 1;
677         rewind(yyin);
678         yyrestart(yyin);
679         lineno = 1;
680         init_areas();
681         yyparse();
682
683         fclose(yyin);
684         return 0;
685 }
686
687
688 void print_usage(int fatal)
689 {
690   FILE *out = fatal ? stderr : stdout;
691
692   fprintf (out, "Usage: xa_asm [-s] [-v] file.xa\n");
693   fprintf (out, "  -v            verbose: show progress\n");
694   fprintf (out, "  -s            create symbol file\n");
695   fprintf (out, "  --version     show version/copyright info and exit\n");
696   fprintf (out, "  --help        show this and exit\n");
697 #if 0
698   // some usefull options I can think of.
699   fprintf (out, "  -m            create map file\n");
700   fprintf (out, "  -ss           create symbol file sorted by symbol\n");
701   fprintf (out, "  -sa           create symbol file sorted by segment/address\n");
702   fprintf (out, "  --no-temps    supress temp symbols in map and sym file\n");
703   fprintf (out, "  --code-loc=#  sets the start address of the code\n");
704   fprintf (out, "  --xdata-loc=# sets the start address of the external data\n");
705   fprintf (out, "  --stack-loc=# sets the start address of the stack\n");
706 #endif
707   exit(fatal);
708 }
709