/* xa_main.c - Paul's XA51 Assembler Copyright 1997,2002 Paul Stoffregen (paul at pjrc dot com) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* adapted from the osu8asm project, 1995 */ /* http://www.pjrc.com/tech/osu8/index.html */ /* made "relocatable" by johan.knol@iduna.nl for sdcc This isn't a standalone assembler anymore. It's only purpose is to create relocatable modules (that has to be processed with xa_link) out of sdcc-generated .xa files */ #define D(x) x #include #include #include #include #define printf(x...) fprintf(stderr,x) #include "xa_main.h" #include "xa_version.h" extern void yyrestart(FILE *new_file); extern int yyparse(); char modulename[PATH_MAX]; char infilename[PATH_MAX]; char outfilename[PATH_MAX]; char listfilename[PATH_MAX]; char symfilename[PATH_MAX]; /* global variables */ FILE *frel, *fmem, *list_fp, *sym_fp; extern FILE *yyin; extern char *yytext; extern char last_line_text[]; struct symbol *sym_list=NULL; struct target *targ_list=NULL; int lineno=1; int p1=0, p2=0, p3=0; int expr_result, expr_ok, jump_dest, inst; int opcode; char symbol_name[1000]; struct area_struct area[NUM_AREAS]; int current_area=0; char rel_line[2][132]; char *areaToString (int area) { switch (area) { case AREA_CSEG: return "CSEG"; case AREA_DSEG: return "DSEG"; //case AREA_OSEG: return "OSEG"; //case AREA_ISEG: return "ISEG"; case AREA_BSEG: return "BSEG"; case AREA_XSEG: return "XSEG"; case AREA_XISEG: return "XISEG"; case AREA_XINIT: return "XINIT"; case AREA_GSINIT: return "GSINIT"; //case AREA_GSFINAL: return "GSFINAL"; //case AREA_HOME: return "HOME"; //case AREA_SSEG: return "SSEG"; } return ("UNKNOW"); } /* "mem" is replaced by area[current_area].alloc_position */ /* int mem=0; */ /* mem is location in memory */ /* add symbols to list when we find their definition in pass #1 */ /* we will evaluate their values in pass #2, and figure out if */ /* they are branch targets betweem passes 1 and 2. Every symbol */ /* should appear exactly once in this list, since it can't be redefined */ struct symbol * build_sym_list(char *thename) { struct symbol *new, *p; if ((p=findSymbol(thename))) { if (p->isdef) { fprintf (stderr, "error: symbol %s already defined\n", thename); exit (1); } else { return p; } } //printf(" Symbol: %s Line: %d\n", thename, lineno); new = (struct symbol *) malloc(sizeof(struct symbol)); new->name = (char *) malloc(strlen(thename)+1); strcpy(new->name, thename); new->value = 0; new->istarget = 0; new->isdef = 0; new->isbit = 0; new->isreg = 0; new->line_def = lineno - 1; new->area = current_area; new->mode = 'X'; // start with an external new->next = NULL; if (sym_list == NULL) return (sym_list = new); p = sym_list; while (p->next != NULL) p = p->next; p->next = new; return (new); } struct symbol *findSymbol (char *thename) { struct symbol *p; for (p=sym_list; p; p=p->next) { if (strcasecmp(thename, p->name)==0) { return p; } } return NULL; } int assign_value(char *thename, int thevalue, char mode) { struct symbol *p; p = sym_list; while (p != NULL) { if (!(strcasecmp(thename, p->name))) { p->area=current_area; p->value = thevalue; p->isdef = 1; p->mode = mode; return (0); } p = p->next; } fprintf(stderr, "Internal Error! Couldn't find symbol\n"); exit(1); } int mk_bit(char *thename, int area) { struct symbol *p; p = sym_list; while (p != NULL) { if (!(strcasecmp(thename, p->name))) { p->isbit = 1; p->area = area; return (0); } p = p->next; } fprintf(stderr, "Internal Error! Couldn't find symbol\n"); exit(1); } int mk_sfr(char *thename) { struct symbol *p; p = sym_list; while (p != NULL) { if (!(strcasecmp(thename, p->name))) { p->issfr = 1; p->area = 0; return (0); } p = p->next; } fprintf(stderr, "Internal Error! Couldn't find symbol\n"); exit(1); } int mk_reg(char *thename) { struct symbol *p; p = sym_list; while (p != NULL) { if (!(strcasecmp(thename, p->name))) { p->isreg = 1; return (0); } p = p->next; } fprintf(stderr, "Internal Error! Couldn't find symbol\n"); exit(1); } int mk_global(char *thename) { struct symbol *p; p = sym_list; while (p != NULL) { if (!(strcasecmp(thename, p->name))) { p->global = 1; return (0); } p = p->next; } fprintf(stderr, "Internal Error! Couldn't find symbol\n"); exit(1); } int get_value(char *thename) { struct symbol *p; p = sym_list; while (p != NULL) { if (!(strcasecmp(thename, p->name))) { if (p->mode=='=') ;//return 0; return (p->value); } p = p->next; } fprintf(stderr, "Internal Error! Couldn't find symbol value\n"); exit(1); } /* add every branch target to this list as we find them */ /* ok if multiple entries of same symbol name in this list */ struct target * build_target_list(char *thename) { struct target *new, *p; new = (struct target *) malloc(sizeof(struct target)); new->name = (char *) malloc(strlen(thename)+1); strcpy(new->name, thename); new->next = NULL; if (targ_list == NULL) return (targ_list = new); p = targ_list; while (p->next != NULL) p = p->next; p->next = new; return (new); } /* figure out which symbols are branch targets */ void flag_targets() { struct symbol *p_sym; struct target *p_targ; p_targ = targ_list; while (p_targ != NULL) { p_sym = sym_list; while (p_sym != NULL) { if (!strcasecmp(p_sym->name, p_targ->name)) p_sym->istarget = 1; p_sym = p_sym->next; } p_targ = p_targ->next; } } void print_symbol_table() { struct symbol *p; p = sym_list; while (p != NULL) { #if 0 fprintf(sym_fp, "Sym in %-5s: %s\n", areaToString(p->area), p->name); fprintf(sym_fp, " at: 0x%04X (%5d)", p->value, p->value); fprintf(sym_fp, " Def:%s", p->isdef ? "Yes" : "No "); fprintf(sym_fp, " Bit:%s", p->isbit ? "Yes" : "No "); fprintf(sym_fp, " Target:%s", p->istarget ? "Yes" : "No "); fprintf(sym_fp, " Line %d\n", p->line_def); #else if (p->issfr) { fprintf (sym_fp, "%-7s", "SFR"); } else if (p->isbit && !p->area) { fprintf (sym_fp, "%-7s", "SBIT"); } else if (p->mode=='=') { fprintf (sym_fp,"ABS "); } else if (!p->isdef) { fprintf (sym_fp,"EXTRN "); } else { fprintf (sym_fp, "%-7s", areaToString(p->area)); } fprintf (sym_fp, " 0x%04x (%5d)", p->value, p->value); fprintf (sym_fp, " %s", p->isdef ? "D" : "-"); fprintf (sym_fp, "%s", p->isbit ? "B" : "-"); fprintf (sym_fp, "%s", p->istarget ? "T" : "-"); fprintf (sym_fp, " %s\n", p->name); #endif p = p->next; } } /* check that every symbol is in the table only once */ void check_redefine() { struct symbol *p1, *p2; p1 = sym_list; while (p1 != NULL) { p2 = p1->next; while (p2 != NULL) { if (!strcasecmp(p1->name, p2->name)) { fprintf(stderr, "Error: symbol '%s' redefined on line %d", p1->name, p2->line_def); fprintf(stderr, ", first defined on line %d\n", p1->line_def); exit(1); } p2 = p2->next; } p1 = p1->next; } } int is_target(char *thename) { struct symbol *p; p = sym_list; while (p != NULL) { if (!strcasecmp(thename, p->name)) return (p->istarget); p = p->next; } return (0); } int is_bit(char *thename) { struct symbol *p; p = sym_list; while (p != NULL) { if (!strcasecmp(thename, p->name)) return (p->isbit); p = p->next; } return (0); } int is_reg(char *thename) { struct symbol *p; p = sym_list; while (p != NULL) { if (!strcasecmp(thename, p->name)) return (p->isreg); p = p->next; } return (0); } struct symbol *is_def(char *thename) { struct symbol *p; p = sym_list; while (p != NULL) { if (!strcasecmp(thename, p->name) && p->isdef) return p; p = p->next; } return NULL; } struct symbol *is_ref(char *thename) { struct symbol *p; p = sym_list; while (p != NULL) { if (strcasecmp(thename, p->name)==0) return p; p = p->next; } return NULL; } int is_abs(char *thename) { struct symbol *p; p = sym_list; while (p != NULL) { if (strcasecmp(thename, p->name)==0) return p->mode == '='; p = p->next; } return 0; } /* this routine is used to dump a group of bytes to the output */ /* it is responsible for generating the list file and sending */ /* the bytes one at a time to the object code generator */ /* this routine is also responsible for generatine the list file */ /* though is it expected that the lexer has placed all the actual */ /* original text from the line in "last_line_text" */ static short last_area=-1; int debug=0; void out(int *byte_list, int num) { struct symbol *p; int i, first=1; if (num > 0) fprintf(list_fp, "%06X: ", MEM_POS); else fprintf(list_fp, "\t"); if (last_area!=current_area) { // emit area information if (area[current_area].size) { fprintf (frel, "A %s size %d flags 0\n", areaToString(current_area), area[current_area].size); if (!area[current_area].defsEmitted) { for (p=sym_list; p; p=p->next) { if (p->global && p->isdef && p->area==current_area) { // skip temp labels if (p->name[strlen(p->name)-1]!='$') { if (p->mode=='=') { fprintf (frel, "S %s Abs%04x\n", p->name, p->value); } else { fprintf (frel, "S %s Def%04x\n", p->name, p->value); } } } } area[current_area].defsEmitted=1; } } last_area=current_area; } if (current_area==AREA_CSEG || current_area==AREA_GSINIT || current_area==AREA_XINIT) { if (num) { for (i=0; i= 0; i--) { sum += j * (str[i] == '1'); j *= 2; } return (sum); } void print_usage(int); void init_areas(void) { area[AREA_CSEG].start=area[AREA_CSEG].alloc_position = 0; area[AREA_DSEG].start=area[AREA_DSEG].alloc_position = 0; area[AREA_BSEG].start=area[AREA_BSEG].alloc_position = 0; area[AREA_XSEG].start=area[AREA_XSEG].alloc_position = 0; area[AREA_XISEG].start=area[AREA_XISEG].alloc_position = 0; area[AREA_XINIT].start=area[AREA_XINIT].alloc_position = 0; area[AREA_GSINIT].start=area[AREA_GSINIT].alloc_position = 0; area[AREA_GSFINAL].start=area[AREA_GSFINAL].alloc_position = 0; area[AREA_HOME].start=area[AREA_HOME].alloc_position = 0; } void relPrelude() { //char buffer[132]; int i, areas=0, globals=0; struct symbol *p; fprintf (frel, "SDCCXA rel, version %1.1f\n", version); for (i=1; inext) { if (p->isdef) { // skip temp labels if (p->name[strlen(p->name)-1]!='$') { globals++; } } } fprintf (frel, "H %d areas %d global symbols\n", areas, globals); fprintf (frel, "M %s\n", modulename); for (p=sym_list; p; p=p->next) { if (!p->isdef) { fprintf (frel, "S %s Ref0000\n", p->name); } } } void printVersion() { printf("\nPaul's XA51 Assembler\n"); printf("Copyright 1997,2002 Paul Stoffregen\n\n"); printf("This program is free software; you can redistribute it\n"); printf("and/or modify it under the terms of the GNU General Public\n"); printf("License, Version 2, published by the Free Software Foundation\n\n"); printf("This program is distributed in the hope that it will be useful,\n"); printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); } int verbose=0, createSymbolFile=0; void process_args(int argc, char **argv) { int i=0; if (argc < 2) print_usage(1); while (++i