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