xa_asm: fixed parsing of symbols used with DS directive in BSEG (pass 2&3).
[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 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #define printf(x...) fprintf(stderr,x)
26
27 #include "xa_main.h"
28
29 extern void yyrestart(FILE *new_file);
30 extern void hexout(int byte, int memory_location, int end);
31 extern int yyparse();
32
33
34 /* global variables */
35
36 FILE *fhex, *fmem, *list_fp;
37 extern FILE *yyin;
38 extern char *yytext;
39 extern char last_line_text[];
40 struct symbol *sym_list=NULL;
41 struct target *targ_list=NULL;
42 int lineno=1;
43 int p1=0, p2=0, p3=0;
44 int expr_result, expr_ok, jump_dest, inst;
45 int opcode, operand;
46 char symbol_name[1000];
47 struct area_struct area[NUM_AREAS];
48 int current_area=AREA_CSEG;
49
50
51 char *areaToString (int area) {
52   switch (area) 
53     {
54     case AREA_CSEG: return "CSEG";
55     case AREA_DSEG: return "DSEG";
56     case AREA_OSEG: return "OSEG";
57     case AREA_ISEG: return "ISEG";
58     case AREA_BSEG: return "BSEG";
59     case AREA_XSEG: return "XSEG";
60     case AREA_XISEG: return "XISEG";
61     case AREA_XINIT: return "XINIT";
62     }
63   return ("UNKNOW");
64 }
65
66 /* "mem" is replaced by area[current_area].alloc_position */
67 /* int mem=0; */   /* mem is location in memory */
68
69 /* add symbols to list when we find their definition in pass #1 */
70 /* we will evaluate their values in pass #2, and figure out if */
71 /* they are branch targets betweem passes 1 and 2.  Every symbol */
72 /* should appear exactly once in this list, since it can't be redefined */
73
74 struct symbol * build_sym_list(char *thename)
75 {
76         struct symbol *new, *p;
77
78 /*      printf("  Symbol: %s  Line: %d\n", thename, lineno); */
79         new = (struct symbol *) malloc(sizeof(struct symbol));
80         new->name = (char *) malloc(strlen(thename)+1);
81         strcpy(new->name, thename);
82         new->value = 0;
83         new->istarget = 0;
84         new->isdef = 0;
85         new->isbit = 0;
86         new->isreg = 0;
87         new->line_def = lineno - 1;
88         new->area = current_area;
89         new->next = NULL;
90         if (sym_list == NULL) return (sym_list = new);
91         p = sym_list;
92         while (p->next != NULL) p = p->next;
93         p->next = new;
94         return (new);
95 }
96
97 int assign_value(char *thename, int thevalue)
98 {
99         struct symbol *p;
100
101         p = sym_list;
102         while (p != NULL) {
103                 if (!(strcasecmp(thename, p->name))) {
104                         p->value = thevalue;
105                         p->isdef = 1;
106                         return (0);
107                 }
108                 p = p->next;
109         }
110         fprintf(stderr, "Internal Error!  Couldn't find symbol\n");
111         exit(1);
112 }
113
114 int mk_bit(char *thename)
115 {
116         struct symbol *p;
117
118         p = sym_list;
119         while (p != NULL) {
120                 if (!(strcasecmp(thename, p->name))) {
121                         p->isbit = 1;
122                         return (0);
123                 }
124                 p = p->next;
125         }
126         fprintf(stderr, "Internal Error!  Couldn't find symbol\n");
127         exit(1);
128 }
129
130
131 int mk_reg(char *thename)
132 {
133         struct symbol *p;
134
135         p = sym_list;
136         while (p != NULL) {
137                 if (!(strcasecmp(thename, p->name))) {
138                         p->isreg = 1;
139                         return (0);
140                 }
141                 p = p->next;
142         }
143         fprintf(stderr, "Internal Error!  Couldn't find symbol\n");
144         exit(1);
145 }
146
147
148
149 int get_value(char *thename)
150 {
151         struct symbol *p;
152         p = sym_list;
153         while (p != NULL) {
154                 if (!(strcasecmp(thename, p->name)))
155                         return (p->value);
156                 p = p->next;
157         }
158         fprintf(stderr, "Internal Error!  Couldn't find symbol value\n");
159         exit(1);
160 }
161                 
162
163
164 /* add every branch target to this list as we find them */
165 /* ok if multiple entries of same symbol name in this list */
166
167 struct target * build_target_list(char *thename)
168 {
169         struct target *new, *p;
170         new = (struct target *) malloc(sizeof(struct target));
171         new->name = (char *) malloc(strlen(thename)+1);
172         strcpy(new->name, thename);
173         new->next = NULL;
174         if (targ_list == NULL) return (targ_list = new);
175         p = targ_list;
176         while (p->next != NULL) p = p->next;
177         p->next = new;
178         return (new);
179 }
180
181 /* figure out which symbols are branch targets */
182
183 void flag_targets()
184 {
185         struct symbol *p_sym;
186         struct target *p_targ;
187         p_targ = targ_list;
188         while (p_targ != NULL) {
189                 p_sym = sym_list;
190                 while (p_sym != NULL) {
191                         if (!strcasecmp(p_sym->name, p_targ->name))
192                                 p_sym->istarget = 1;
193                         p_sym = p_sym->next;
194                 }
195                 p_targ = p_targ->next;
196         }
197 }
198
199 void print_symbol_table()
200 {
201   struct symbol *p;
202   p = sym_list;
203   while (p != NULL) {
204     printf("Sym in %-5s: %s\n", areaToString(p->area), p->name);
205     printf("  at: 0x%04X (%5d)", p->value, p->value);
206     printf(" Def:%s", p->isdef ? "Yes" : "No ");
207     printf(" Bit:%s", p->isbit ? "Yes" : "No ");
208     printf(" Target:%s", p->istarget ? "Yes" : "No ");
209     printf(" Line %d\n", p->line_def);
210     p = p->next;
211   }
212 }
213
214 /* check that every symbol is in the table only once */
215
216 void check_redefine()
217 {
218         struct symbol *p1, *p2;
219         p1 = sym_list;
220         while (p1 != NULL) {
221                 p2 = p1->next;
222                 while (p2 != NULL) {
223                         if (!strcasecmp(p1->name, p2->name)) {
224                                 fprintf(stderr, "Error: symbol '%s' redefined on line %d", p1->name, p2->line_def);
225                                 fprintf(stderr, ", first defined on line %d\n", p1->line_def);
226                         exit(1);
227                         }
228                         p2 = p2->next;
229                 }
230                 p1 = p1->next;
231         }
232 }
233
234 int is_target(char *thename)
235 {
236         struct symbol *p;
237         p = sym_list;
238         while (p != NULL) {
239                 if (!strcasecmp(thename, p->name)) return (p->istarget);
240                 p = p->next;
241         }
242         return (0);
243 }
244
245 int is_bit(char *thename)
246 {
247         struct symbol *p;
248         p = sym_list;
249         while (p != NULL) {
250                 if (!strcasecmp(thename, p->name)) return (p->isbit);
251                 p = p->next;
252         }
253         return (0);
254 }
255
256 int is_reg(char *thename)
257 {
258         struct symbol *p;
259         p = sym_list;
260         while (p != NULL) {
261                 if (!strcasecmp(thename, p->name)) return (p->isreg);
262                 p = p->next;
263         }
264         return (0);
265 }
266
267
268 int is_def(char *thename)
269 {
270         struct symbol *p;
271         p = sym_list;
272         while (p != NULL) {
273                 if (!strcasecmp(thename, p->name) && p->isdef) return(1);
274                 p = p->next;
275         }
276         return (0);
277 }
278
279 /* this routine is used to dump a group of bytes to the output */
280 /* it is responsible for generating the list file and sending */
281 /* the bytes one at a time to the object code generator */
282 /* this routine is also responsible for generatine the list file */
283 /* though is it expected that the lexer has placed all the actual */
284 /* original text from the line in "last_line_text" */
285
286 void out(int *byte_list, int num)
287 {
288         int i, first=1;
289
290         if (num > 0) fprintf(list_fp, "%06X: ", MEM_POS);
291         else fprintf(list_fp, "\t");
292
293         for (i=0; i<num; i++) {
294                 hexout(byte_list[i], MEM_POS + i, 0);
295                 if (!first && (i % 4) == 0) fprintf(list_fp, "\t");
296                 fprintf(list_fp, "%02X", byte_list[i]);
297                 if ((i+1) % 4 == 0) {
298                         if (first) fprintf(list_fp, "\t%s\n", last_line_text);
299                         else fprintf(list_fp, "\n");
300                         first = 0;
301                 } else {
302                         if (i<num-1) fprintf(list_fp, " ");
303                 }
304         }
305         if (first) {
306                 if (num < 3) fprintf(list_fp, "\t");
307                 fprintf(list_fp, "\t%s\n", last_line_text);
308         } else {
309                 if (num % 4) fprintf(list_fp, "\n");
310         }
311 }
312
313
314 /* add NOPs to align memory location on a valid branch target address */
315
316 void pad_with_nop()
317 {
318         static int nops[] = {NOP_OPCODE, NOP_OPCODE, NOP_OPCODE, NOP_OPCODE};
319         int num;
320
321         last_line_text[0] = '\0';
322
323         for(num=0; (MEM_POS + num) % BRANCH_SPACING; num++) ;
324         if (p3) out(nops, num);
325         MEM_POS += num;
326 }
327
328 /* print branch out of bounds error */
329
330 void boob_error()
331 {
332         fprintf(stderr, "Error: branch out of bounds");
333         fprintf(stderr, " in line %d\n", lineno);
334         exit(1);
335 }
336
337 /* output the jump either direction on carry */
338 /* jump_dest and MEM_POS must have the proper values */
339
340 /* 
341 void do_jump_on_carry()
342 {
343         if (p3) {
344                 operand = REL4(jump_dest, MEM_POS);
345                 if (operand < 0) {
346                         operand *= -1;
347                         operand -= 1;
348                         if (operand > 15) boob_error();
349                         out(0x20 + (operand & 15));
350                 } else {
351                         if (operand > 15) boob_error();
352                         out(0x30 + (operand & 15));
353                 }
354         }
355 }
356 */ 
357
358 /* turn a string like "10010110b" into an int */
359
360 int binary2int(char *str)
361 {
362         register int i, j=1, sum=0;
363         
364         for (i=strlen(str)-2; i >= 0; i--) {
365                 sum += j * (str[i] == '1');
366                 j *= 2;
367         }
368         return (sum);
369 }
370
371 void print_usage();
372
373
374 /* todo: someday this will allow the user to control where the */
375 /* various memory areas go, and it will take care of assigning */
376 /* positions to area which follow others (such as OSEG getting */
377 /* set just after DSEG on the 2nd and 3rd passes when we have */
378 /* leared the size needed for each segment */
379
380 void init_areas(void)
381 {
382         area[AREA_CSEG].alloc_position = 0;
383         area[AREA_DSEG].alloc_position = 0x30;
384         area[AREA_OSEG].alloc_position = 0x80;
385         area[AREA_ISEG].alloc_position = 0;
386         area[AREA_BSEG].alloc_position = 0;
387         area[AREA_XSEG].alloc_position = 0;
388         area[AREA_XISEG].alloc_position = 0;
389         area[AREA_GSINIT].alloc_position = 0;
390         area[AREA_GSFINAL].alloc_position = 0;
391         area[AREA_HOME].alloc_position = 0;
392 }
393
394
395 /* pass #1 (p1=1) find all symbol defs and branch target names */
396 /* pass #2 (p2=1) align branch targets, evaluate all symbols */
397 /* pass #3 (p3=1) produce object code */
398
399 int main(int argc, char **argv)
400 {
401         char infilename[200], outfilename[200], listfilename[200];
402
403         if (argc < 2) print_usage();
404         strcpy(infilename, argv[1]);
405         if(strlen(infilename) > 3) {
406                 if (strncasecmp(infilename+strlen(infilename)-3, ".xa", 3))
407                         strcat(infilename, ".xa");
408         } else strcat(infilename, ".xa");
409         strcpy(outfilename, infilename);
410         outfilename[strlen(outfilename)-3] = '\0';
411         strcpy(listfilename, outfilename);
412         strcat(outfilename, ".hex");
413         strcat(listfilename, ".lst");
414         yyin = fopen(infilename, "r");
415         if (yyin == NULL) {
416                 fprintf(stderr, "Can't open file '%s'.\n", infilename);
417                 exit(1);
418         }
419         fhex = fopen(outfilename, "w");
420         if (fhex == NULL) {
421                 fprintf(stderr, "Can't write file '%s'.\n", outfilename);
422                 exit(1);
423         }
424         list_fp = fopen(listfilename, "w");
425         if (list_fp == NULL) {
426                 fprintf(stderr, "Can't write file '%s'.\n", listfilename);
427                 exit(1);
428         }
429
430         /* todo: add a command line option to supress verbose messages */
431         printf("\nPaul's XA51 Assembler\n");
432         printf("Copyright 1997,2002 Paul Stoffregen\n\n");
433         printf("This program is free software; you can redistribute it\n");
434         printf("and/or modify it under the terms of the GNU General Public\n");
435         printf("License, Version 2, published by the Free Software Foundation\n\n");
436         printf("This program is distributed in the hope that it will be useful,\n");
437         printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
438         printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
439
440
441
442         printf("    Building Symbol Table:\n");
443         p1 = 1;
444         //mem = 0;
445         init_areas();
446         yyparse();
447         flag_targets();
448         print_symbol_table();
449         check_redefine();
450         p1 = 0;
451         p2 = 1;
452         rewind(yyin);
453         yyrestart(yyin);
454         lineno = 1;
455         printf("    Aligning Branch Targets:\n");
456         //mem = 0;
457         init_areas();
458         yyparse();
459         // print_symbol_table();
460         p2 = 0;
461         p3 = 1;
462         rewind(yyin);
463         yyrestart(yyin);
464         lineno = 1;
465         printf("    Generating Object Code:\n");
466         //mem = 0;
467         init_areas();
468         yyparse();
469         fclose(yyin);
470         hexout(0, 0, 1);  /* flush and close intel hex file output */
471         return 0;
472 }
473
474
475 void print_usage()
476 {
477         fprintf(stderr, "Usage: xa_asm file\n");
478         fprintf(stderr, "   or  xa_asm file.asm\n");
479         exit(1);
480 }
481