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