Move source into src directory
[a56.git] / src / main.c
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..2d6b759
--- /dev/null
@@ -0,0 +1,487 @@
+/*******************************************************
+ *
+ *  a56 - a DSP56001 assembler
+ *
+ *  Written by Quinn C. Jensen
+ *  July 1990
+ *
+ *******************************************************\
+
+/*
+ * Copyright (C) 2008 Robert Millan <rmh@aybabtu.com>
+ * Copyright (C) 2012 Thorsten Alteholz <debian@alteholz.de>
+ * Copyright (C) 2014 Arthur Marble <arthur@info9.net>
+ *
+ * This file 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 of the License,
+ * 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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (C) 1990-1994 Quinn C. Jensen
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.  The author makes no representations
+ * about the suitability of this software for any purpose.  It is
+ * provided "as is" without express or implied warranty.
+ *
+ */
+static char *Copyright = "Copyright (C) 1990-1994 Quinn C. Jensen";
+
+/*
+ *  main.c - The "main" code for the assembler.
+ *
+ */
+
+#include "a56.h"
+
+#define MAX 1024
+
+int pass;
+int error, warning;
+extern unsigned int pc;
+extern int seg;
+BOOL binary_listing = FALSE;
+BOOL list_includes = FALSE;
+FILE *obj = NULL;
+extern BOOL list_on;
+BOOL list_on_next = TRUE;
+
+main(argc,argv)
+int argc;
+char *argv[];
+{
+       int i;
+       extern char *optarg;
+       extern int optind;
+       int c;
+       char *output_file = "a56.out";
+       char *input_file;
+       char *usage = "usage: a56  [-b]  [-l]  [-d]  [-o output-file]  input-file\n";
+
+       while((c = getopt(argc, argv, "bldo:")) != EOF) switch (c) {
+               case 'b':
+                       binary_listing++;
+                       break;
+               case 'l':
+                       list_includes++;
+                       break;
+               case 'd':
+                       ldebug++;
+                       break;
+               case 'o':
+                       output_file = optarg;
+                       break;
+               case '?':
+               default:
+                       fatal(usage);
+       }
+       input_file = argv[optind++];
+       if(input_file == NULL) fatal(usage);
+       obj = open_write(output_file);
+
+       pc = 0;
+       seg = 0;
+       pass = 1;
+       reset_psects();
+       include(input_file);
+
+       pc = 0;
+       seg = 0;
+       pass = 2;
+       reset_psects();
+       include(input_file);
+
+       psect_summary();
+       dump_symtab();
+       fclose(obj);
+       printf("errors=%d\n", error);
+       printf("warnings=%d\n", warning);
+       return error ? 1 : 0;
+}
+
+struct inc inc[MAX_NEST];
+int inc_p = 0;
+FILE *yyin;
+
+include(file)
+char *file;
+{
+       FILE *fp = open_read(file);
+
+       inc_p++;
+       if(inc_p >= MAX_NEST)
+               fatal("%s: include nesting too deep\n", file);
+
+       inc[inc_p].file = file;
+       inc[inc_p].fp = fp;
+       inc[inc_p].line = 1;
+
+       list_on_next = TRUE;
+       if(inc_p > 1 && NOT list_includes)
+               list_on_next = FALSE;
+
+       yyin = inc[inc_p].fp;
+       if(inc_p == 1)
+#ifdef FLEX
+       {
+               static int started = 0;
+               if(started)
+                       yyrestart(yyin);
+               else
+                       started = 1;
+               yyparse();
+       }
+#else
+               yyparse();
+#endif
+}
+
+yywrap()
+{
+       fclose(inc[inc_p].fp);
+       inc_p--;
+       list_on = list_on_next = TRUE;
+       if(inc_p > 1)
+               list_on = list_on_next = FALSE;
+       if(inc_p) {
+               yyin = inc[inc_p].fp;
+               return 0;
+       } else {
+               return 1;
+       }
+}
+
+struct n
+sym_ref(sym)           /* return symbol value or UNDEF if not defined yet */
+char *sym;
+{
+       struct sym *sp, *find_sym();
+       struct n result;
+
+       result.type = UNDEF;
+
+       sp = find_sym(sym);
+       if(NOT sp) {
+               if(pass == 2) {
+                       yyerror("%s: undefined symbol", sym);
+               }                  
+               return result;
+       }
+
+       return sp->n;
+}
+
+#define HASHSIZE 128
+
+#define HASH(sym) (((sym)[0] ^ sym[1]) % HASHSIZE)
+
+struct sym *symtab[HASHSIZE];
+
+sym_def(sym, type, seg, i, f)
+char *sym;
+int type;
+int seg;
+int i;
+double f;
+{
+       struct sym *sp, **stop, *find_sym();
+
+       if(pass == 1) {
+               if(find_sym(sym)) {
+                       pass = 2;                               /* what a kludge */
+                       yyerror("%s: multiply defined symbol", sym);
+                       pass = 1;
+                       return 1;
+               }
+               stop = &symtab[HASH(sym)];
+               sp = NEW(struct sym);
+               sp->next = *stop;
+               *stop = sp;
+               sp->name = strsave(sym);
+               sp->n.type = type;
+               sp->n.seg = seg;
+               if(type == INT)
+                       sp->n.val.i = i & 0xFFFFFF;
+               else
+                       sp->n.val.f = f;
+       } else {
+               sp = find_sym(sym);
+               if(NOT sp)
+                       fatal("internal error 304\n");
+               if(sp->n.type != type ||
+                       type == INT && sp->n.val.i != (i & 0xFFFFFF) ||
+                       type == FLT && sp->n.val.f != f)
+                       yyerror("%s: assembler phase error", sym);
+       }               
+}
+
+struct sym *find_sym(sym)
+char *sym;
+{
+       struct sym *sp, **stop;
+
+       stop = &symtab[HASH(sym)];
+       for(sp = *stop; sp; sp = sp->next)
+               if(strcmp(sp->name, sym) == 0)
+                       return sp;
+               
+       return NULL;
+}
+
+extern char segs[];
+dump_symtab()
+{
+       struct sym *sp, **stop;
+       int i;
+
+       printf("\n\
+Symbol Table\n\
+-------------------------------------\n");
+/*
+SSSSSSSSSSSSSSSS S XXXXXX
+SSSSSSSSSSSSSSSS S DDDDDDDDD.DDDDDDDDDD
+*/
+
+       for(i = 0, stop = symtab; i < HASHSIZE; i++, stop++) {
+               for(sp = *stop; sp; sp = sp->next) {
+                       if(sp->n.type == INT) {
+                               printf("%16s %c %06X\n", sp->name, segs[sp->n.seg], sp->n.val.i);
+                               fprintf(obj, "I %06X %s\n", sp->n.val.i, sp->name);
+                       } else {
+                               printf("%16s %c %.10f\n", sp->name, segs[sp->n.seg], sp->n.val.f);
+                               fprintf(obj, "F %.10f %s\n", sp->n.val.f, sp->name);
+                       }
+               }
+       }   
+}
+
+char *printcode(word)
+int word;
+{
+       static char list[MAX], *lp;
+       int i;
+
+       word &= 0xFFFFFF;
+
+       if(binary_listing) {
+               sprintf(list, "%06X<", word);
+               for(i = 0, lp = &list[7]; i < 24; i++, lp++) {
+                       *lp = word & 1 << 23 - i ? '1' : '0';
+                       if(i && i % 4 == 3)
+                               *++lp = i % 8 == 7 ? ' ' : ',';
+               }
+               lp[-1] = '>';
+               lp[0] = '\0';
+       } else {
+               sprintf(list, "%06X", word);
+       }
+       return list;
+}
+
+char *spacespace[2] = {
+/*P:XXXX_XXXXXX_*/
+ "              ",
+/*P:XXXX_XXXXXX(XXXX_XXXX_XXXX_XXXX_XXXX_XXXX)_*/
+ "                                             "};
+char *spaces(n)
+int n;
+{
+       return spacespace[binary_listing ? 1 : 0] + n;
+}
+
+extern char segs[];
+
+gencode(seg, pc, word)
+int seg, pc, word;
+{
+       fprintf(obj, "%c %04X %06X\n", segs[seg], pc, word & 0xFFFFFF);
+}
+
+char fixbuf[1024];
+
+char *fixstring(s)
+char *s;
+{
+       char *bp = fixbuf;
+       int ival;
+
+       while(*s) {
+               switch (*s) {
+                       case '\'':
+                       case '\"':
+                               s++;
+                               break;
+                       case '\\':
+                               switch (*++s) {
+                                       case 'b': *bp++ = '\b'; break;
+                                       case 'r': *bp++ = '\r'; break;
+                                       case 'f': *bp++ = '\f'; break;
+                                       case 'n': *bp++ = '\n'; break;
+                                       case 't': *bp++ = '\t'; break;
+                                       case '\\': *bp++ = '\\'; break;
+                                       case '0':
+                                               ival = 0;
+                                               while(*s >= '0' && *s <= '9') {
+                                                       ival <<= 3;
+                                                       ival += *s++ - '0';
+                                               }
+                                               *bp++ = ival;
+                                               break;
+                               }
+                               break;
+                       default:
+                               *bp++ = *s++;
+                               break;
+               }
+       }
+       *bp = '\0';
+       return fixbuf;
+}
+
+#define ONE 0x4000000
+
+makefrac(s)
+char *s;
+{
+       int frac = 0, div = 1;
+       int scale = 1;
+
+       while(*s) {
+               switch(*s) {
+                       case '-':
+                               scale = -1;
+                               break;
+                       case '.':
+                               div = 10;
+                               break;
+                       default:
+                               frac += (*s - '0') * scale * ONE / div;
+                               div *= 10;
+                               break;
+               }
+               s++;
+       }
+
+       return frac + scale * 4 >> 3 & 0xFFFFFF;
+}
+
+/***************** psect stuff ************************/
+
+struct psect *ptop = NULL, *cur_psect = NULL;
+
+reset_psects()
+{
+       struct psect *pp;
+
+       for(pp = ptop; pp; pp = pp->next) {
+               pp->pc = pp->bottom;
+       }
+
+       set_psect(NULL);
+}
+
+psect_summary()
+{
+       printf("\nSummary of psect usage\n\n");
+
+       printf("\
+                 section seg base last top      used       avail    total\n\
+-------------------------------------------------------------------------\n");
+/*
+SSSSSSSSSSSSSSSSSSSSSSSS  X  FFFF FFFF FFFF 99999 100%  99999 100%  99999
+*/
+
+       summarize(ptop);        /* do it recursively to place back in order */
+       printf("\n");
+}
+
+summarize(pp)
+struct psect *pp;
+{
+       int used, avail, of;
+
+       if(pp == NULL)
+               return 1;
+
+       used = pp->pc - pp->bottom;
+       avail = pp->top - pp->pc;
+       of = pp->top - pp->bottom;
+
+       summarize(pp->next);
+
+       printf("%24.24s  %c  %04X %04X %04X %5d %3d%%  %5d %3d%%  %5d\n",
+               pp->name, segs[pp->seg], pp->bottom, pp->pc, pp->top,
+               used, of ? used * 100 / of : 0, avail, of ? avail * 100 / of : 0,
+               of);
+}
+
+struct psect *find_psect(name)
+char *name;
+{
+       struct psect *pp;
+
+       for(pp = ptop; pp; pp = pp->next)
+               if(strcmp(pp->name, name) == 0)
+                       return pp;
+
+       return NULL;
+}
+
+set_psect(pp)
+struct psect *pp;
+{
+       cur_psect = pp;
+}
+
+check_psect(seg, pc)
+int seg;
+unsigned int pc;
+{
+       if(cur_psect) {
+               if(seg == cur_psect->seg && pc >= cur_psect->bottom && 
+                       pc <= cur_psect->top) {
+                       cur_psect->pc = pc;
+                       return TRUE;
+               } else {
+                       return FALSE;
+               }
+       } else {
+               return TRUE;
+       }
+}
+
+struct psect *new_psect(name, seg, bottom, top)
+char *name;
+int seg;
+unsigned int bottom, top;
+{
+       struct psect *pp = find_psect(name);
+
+       if(NOT pp) {
+               pp = (struct psect *)alloc(sizeof *pp);
+               pp->next = ptop;
+               ptop = pp;
+               pp->name = strsave(name);
+               pp->seg = seg;
+               pp->pc = bottom;
+       }
+       pp->bottom = bottom;
+       pp->top = top;
+
+       return pp;
+}