asz80: finish conversion
authorAlan Cox <alan@linux.intel.com>
Sat, 28 Oct 2017 15:57:35 +0000 (16:57 +0100)
committerAlan Cox <alan@linux.intel.com>
Sat, 28 Oct 2017 15:57:35 +0000 (16:57 +0100)
This now behaves rather more like we need. It lacks includes and some other
nice to have bits but is also small enough to run on a Z80 box sanely. Trimming
out stdio and soem other slack could be done if needed but is a fair bit of
work.

Also add an nm mostly at this point to check the output is valid.

Now all we need is to tweak the smallc output syntax to match, and a linker...

12 files changed:
Applications/MWC/cmd/asz80/Makefile.68000
Applications/MWC/cmd/asz80/Makefile.6809
Applications/MWC/cmd/asz80/Makefile.z80
Applications/MWC/cmd/asz80/as.h
Applications/MWC/cmd/asz80/as0.c
Applications/MWC/cmd/asz80/as1.c
Applications/MWC/cmd/asz80/as2.c
Applications/MWC/cmd/asz80/as3.c
Applications/MWC/cmd/asz80/as4.c
Applications/MWC/cmd/asz80/as5.c [deleted file]
Applications/MWC/cmd/asz80/nm.c [new file with mode: 0644]
Applications/MWC/cmd/asz80/obj.h [new file with mode: 0644]

index 07b360b..ee348e6 100644 (file)
@@ -14,13 +14,13 @@ CRT0NS = ../../../../Library/libs/crt0nostdio_68000.o
 ELF2FUZIX = elf2flt
 .SUFFIXES: .c .o
 
-SRCS  = as0.c as1.c as2.c as3.c as4.c as5.c as6.c
+SRCS  = as0.c as1.c as2.c as3.c as4.c as6.c
 
-INCS  = as.h
+INCS  = as.h obj.h
 
 OBJS = $(SRCS:.c=.o)
 
-all: as
+all: as nm
 
 $(OBJS): $(INCS)
 
@@ -33,6 +33,12 @@ as: $(CRT0) $(OBJS)
        $(LINKER) $^ -o $@.bin $(LINKER_OPT)
        $(ELF2FUZIX) -o $@ $@.bin
 
+nm: $(CRT0) nm.o
+       $(LINKER) $^ -o $@.bin $(LINKER_OPT)
+       $(ELF2FUZIX) -o $@ $@.bin
+
+nm.c: obj.h
+       
 size.report: $(APPS)
        ls -l $^ > $@
 
index 2379f78..2bec36e 100644 (file)
@@ -17,13 +17,13 @@ CRT0 = ../../../../Library/libs/crt0_6809.o
 .SUFFIXES: .c .o
 
 
-SRCS  = as0.c as1.c as2.c as3.c as4.c as5.c as6.c
+SRCS  = as0.c as1.c as2.c as3.c as4.c as6.c
 
-INCS  = as.h
+INCS  = as.h obj.h
 
 OBJS = $(SRCS:.c=.o)
 
-all: as
+all: as nm
 
 $(OBJS): $(INCS)
 
@@ -33,6 +33,11 @@ $(OBJS): %.o : %.c
 as: $(OBJS) $(CRT0)
        $(LINKER) -o $@ $(LINKER_OPT) $^
 
+nm.c: obj.h
+
+nm: nm.o $(CRT0)
+       $(LINKER) -o $@ $(LINKER_OPT) $^
+
 clean:
        rm -f $(OBJS) as $(SRCS:.c=) core *~
 
index d420648..f583c6f 100644 (file)
@@ -5,19 +5,24 @@ PLATFORM =
 
 .SUFFIXES: .c .rel
 
-SRCS  = as0.c as1.c as2.c as3.c as4.c as5.c as6.c
+SRCS  = as0.c as1.c as2.c as3.c as4.c as6.c
 
-INCS  = as.h
+INCS  = as.h obj.h
 
 OBJS = $(SRCS:.c=.rel)
 
 LIBS = ../../../../Library/libs/syslib.lib
 
-all: as
+all: as nm
 
 as: $(OBJS)
        $(FCC) $(PLATFORM) $(OBJS) -o $@
 
+nm.c: obj.h
+
+nm: nm.rel
+       $(FCC) $(PLATFORM) nm.rel -o $@
+
 $(OBJS): $(INCS)
 
 .c.rel:
index a025eb5..b36cb4a 100644 (file)
 #define        GOOD    0
 #define        BAD     1
 
-/*
- * Listing modes.
- */
-#define        NLIST   0                       /* No list */
-#define        ALIST   1                       /* Address only */
-#define        BLIST   2                       /* Byte format */
-#define        WLIST   3                       /* Word format */
-#define        SLIST   4                       /* Source text only */
-
 /*
  * Types. These are used
  * in both symbols and in address
 #define DATA           2
 #define BSS            3
 
+/*
+ *     Error message numbers
+ */
+
+#define BRACKET_EXPECTED 1
+#define MISSING_COMMA  2
+#define SQUARE_EXPECTED 3
+#define PERCENT_EXPECTED 4
+#define UNEXPECTED_CHR 10
+#define PHASE_ERROR    11
+#define MULTIPLE_DEFS  12
+#define SYNTAX_ERROR   13
+#define MUST_BE_ABSOLUTE       14
+#define MISSING_DELIMITER 15
+#define INVALID_CONST  16
+#define JR_RANGE       17
+#define CONDCODE_ONLY  18
+#define INVALID_REG    19
+#define ADDR_REQUIRED  20
+#define INVALID_ID     21
+#define REG_MUST_BE_C  22
+#define DIVIDE_BY_ZERO 23
+#define INVALID_CONSTANT 24
+#define DATA_IN_BSS     25
+#define SEGMENT_OVERFLOW 26
+
+
 typedef        uint16_t        VALUE;          /* For symbol values */
 
 /*
@@ -159,10 +177,7 @@ typedef    struct  SYM     {
  * External variables.
  */
 extern char    *cp;
-extern char    *ep;
 extern char    *ip;
-extern char    cb[];
-extern char    eb[];
 extern char    ib[];
 extern FILE    *ifp;
 extern FILE    *ofp;
@@ -179,6 +194,8 @@ extern      jmp_buf env;
 extern VALUE   dot[NSEGMENT];
 extern  int    segment;
 extern int     debug_write;
+extern char    *fname;
+extern int     noobj;
 
 extern void asmline(void);
 extern void asmld(void);
@@ -188,10 +205,10 @@ extern void comma(void);
 extern void istuser(ADDR *);
 extern int ccfetch(ADDR *);
 extern int symhash(char *);
-extern void err(char);
+extern void err(char, uint8_t);
 extern void uerr(char *);
-extern void aerr(void);
-extern void qerr(void);
+extern void aerr(uint8_t);
+extern void qerr(uint8_t);
 extern void storerror(int);
 extern void getid(char *, int);
 extern SYM *lookup(char *, SYM *[], int);
@@ -215,6 +232,4 @@ extern void outrab(ADDR *);
 extern void outeof(void);
 extern void outbyte(uint8_t);
 extern void outflush(void);
-extern void list(void);
-extern void list1(char *, int, int);
 extern void syminit(void);
index 355350c..f3bbaca 100644 (file)
@@ -8,15 +8,12 @@
 FILE   *ifp;
 FILE   *ofp;
 FILE   *lfp;
-char   cb[NCODE];
 char   eb[NERR];
 char   ib[NINPUT];
 char   *cp;
 char   *ep;
 char   *ip;
-int    lflag;
-VALUE  laddr;
-int    lmode;
+char   *fname;
 VALUE  dot[NSEGMENT];
 int    segment = CODE;
 SYM    *phash[NHASH];
@@ -25,6 +22,7 @@ int   pass;
 int    line;
 jmp_buf        env;
 int    debug_write = 1 ;
+int    noobj;
 
 
 /*
@@ -67,10 +65,6 @@ int main(int argc, char *argv[])
                if (*p == '-') {
                        while ((c = *++p) != 0) {
                                switch (c) {
-                               case 'l':
-                                       ++lflag;
-                                       break;
-
                                default:
                                        fprintf(stderr, "Bad option %c\n", c);
                                        exit(BAD);
@@ -87,6 +81,9 @@ int main(int argc, char *argv[])
                fprintf(stderr, "No source file\n");
                exit(BAD);
        }
+
+       fname = ifn;
+
        if ((ifp=fopen(ifn, "r")) == NULL) {
                fprintf(stderr, "%s: cannot open\n", ifn);
                exit(BAD);
@@ -96,13 +93,6 @@ int main(int argc, char *argv[])
                fprintf(stderr, "%s: cannot create\n", fn);
                exit(BAD);
        }
-       if (lflag != 0) {
-               mkname(fn, ifn, "lis");
-               if ((lfp=fopen(fn, "w")) == NULL) {
-                       fprintf(stderr, "%s: cannot create\n", fn);
-                       exit(BAD);
-               }
-       }
        syminit();
        for (pass=0; pass<2; ++pass) {
                outpass();
@@ -111,13 +101,10 @@ int main(int argc, char *argv[])
                fseek(ifp, 0L, 0);
                while (fgets(ib, NINPUT, ifp) != NULL) {
                        ++line;
-                       cp = &cb[0];
                        ep = &eb[0];
                        ip = &ib[0];
                        if (setjmp(env) == 0)
                                asmline();
-                       if (pass != 0)
-                               list();
                }
        }
        outeof();
index a9f54d2..50df3e0 100644 (file)
@@ -32,8 +32,7 @@
  * Assemble one line.
  * The line in in "ib", the "ip"
  * scans along it. The code is written
- * right out, and also stashed in the
- * "cb" for the listing.
+ * right out.
  */
 void asmline(void)
 {
@@ -52,13 +51,11 @@ void asmline(void)
        ADDR a1;
        ADDR a2;
 
-       laddr = dot[segment];
-       lmode = SLIST;
 loop:
        if ((c=getnb())=='\n' || c==';')
                return;
        if (isalpha(c) == 0 && c != '_' && c != '.')
-               qerr();
+               qerr(UNEXPECTED_CHR);
        getid(id, c);
        if ((c=getnb()) == ':') {
                sp = lookup(id, uhash, 1);
@@ -72,11 +69,10 @@ loop:
                        sp->s_segment = segment;
                } else {
                        if ((sp->s_type&TMMDF) != 0)
-                               err('m');
+                               err('m', MULTIPLE_DEFS);
                        if (sp->s_value != dot[segment])
-                               err('p');
+                               err('p', PHASE_ERROR);
                }
-               lmode = ALIST;
                goto loop;
        }
        /*
@@ -89,7 +85,7 @@ loop:
                getid(id1, c);
                if ((sp1=lookup(id1, phash, 0)) == NULL
                ||  (sp1->s_type&TMMODE) != TEQU) {
-                       err('o');
+                       err('o', SYNTAX_ERROR);
                        return;
                }
                getaddr(&a1);
@@ -97,32 +93,28 @@ loop:
                sp = lookup(id, uhash, 1);
                if ((sp->s_type&TMMODE) != TNEW
                &&  (sp->s_type&TMASG) == 0)
-                       err('m');
+                       err('m', MULTIPLE_DEFS);
                sp->s_type &= ~(TMMODE|TPUBLIC);
                sp->s_type |= TUSER|TMASG;
                sp->s_value = a1.a_value;
                sp->s_segment = a1.a_segment;
                /* FIXME: review .equ to an external symbol/offset and
                   what should happen */
-               laddr = a1.a_value;
-               lmode = ALIST;
                goto loop;
        }
        unget(c);
-       lmode = BLIST;
        opcode = sp->s_value;
        switch (sp->s_type&TMMODE) {
        case TORG:
                getaddr(&a1);
                istuser(&a1);
                if (a1.a_segment != ABSOLUTE)
-                       qerr();
-               lmode = ALIST;
+                       qerr(MUST_BE_ABSOLUTE);
                segment = 0;
-               laddr = dot[segment] = a1.a_value;
+               dot[segment] = a1.a_value;
                /* Tell the binary generator we've got a new absolute
                   segment. */
-               outabsolute(laddr);
+               outabsolute(a1.a_value);
                break;
 
        case TEXPORT:
@@ -148,7 +140,6 @@ loop:
                break;
 
        case TDEFW:
-               lmode = WLIST;
                do {
                        getaddr(&a1);
                        istuser(&a1);
@@ -159,17 +150,15 @@ loop:
 
        case TDEFM:
                if ((delim=getnb()) == '\n')
-                       qerr();
+                       qerr(MISSING_DELIMITER);
                while ((c=get()) != delim) {
                        if (c == '\n')
-                               qerr();
+                               qerr(MISSING_DELIMITER);
                        outab(c);
                }
                break;
 
        case TDEFS:
-               laddr = dot[segment];
-               lmode = ALIST;
                getaddr(&a1);
                istuser(&a1);
                /* Write out the bytes. The BSS will deal with the rest */
@@ -191,22 +180,22 @@ loop:
                        outab(OPRST|(a1.a_value<<3));
                        break;  
                }
-               aerr();
+               aerr(INVALID_CONST);
                break;
 
        case TREL:
                getaddr(&a1);
                if ((cc=ccfetch(&a1)) >= 0) {
                        if (opcode==OPDJNZ || cc>=CPO)
-                               aerr();
+                               aerr(SYNTAX_ERROR);
                        opcode = OPJR | (cc<<3);
                        comma();
                        getaddr(&a1);
                }
                istuser(&a1);
                disp = a1.a_value-dot[segment]-2;
-               if (disp<-128 || disp>127)
-                       aerr();
+               if (disp<-128 || disp>127 || a1.a_segment != segment)
+                       aerr(JR_RANGE);
                outab(opcode);
                outab(disp);
                break;
@@ -216,7 +205,7 @@ loop:
                if (c!='\n' && c!=';') {
                        getaddr(&a1);
                        if ((cc=ccfetch(&a1)) < 0)
-                               aerr();
+                               aerr(CONDCODE_ONLY);
                        opcode = OPRET | (cc<<3);
                }
                outab(opcode);
@@ -233,7 +222,7 @@ loop:
                        reg = a1.a_type&TMREG;
                        if (reg==M || reg==IX || reg==IY) {
                                if (opcode != OPJP)
-                                       aerr();
+                                       aerr(INVALID_REG);
                                outop(OPPCHL, &a1);
                                break;
                        }
@@ -261,19 +250,19 @@ loop:
                                break;
                        case SP:
                        case AFPRIME:
-                               aerr();
+                               aerr(INVALID_REG);
                        }
                        outab(opcode|(reg<<4));
                        break;
                }
-               aerr();
+               aerr(INVALID_REG);
                break;
 
        case TIM:
                getaddr(&a1);
                istuser(&a1);
                if ((value=a1.a_value) > 2)
-                       aerr();
+                       aerr(INVALID_CONST);
                else if (value != 0)
                        ++value;
                outab(0xED);
@@ -292,7 +281,7 @@ loop:
                if ((a1.a_type&TMMODE)==TBR && a2.a_type==(TBR|TMINDIR|C)) {
                        reg = a1.a_type&TMREG;
                        if (reg==M || reg==IX || reg==IY)
-                               aerr();
+                               aerr(INVALID_REG);
                        outab(0xED);
                        if (opcode == OPIN)
                                opcode = OPIIN; else
@@ -300,7 +289,7 @@ loop:
                        outab(opcode|(reg<<3));
                        break;
                }
-               aerr();
+               aerr(INVALID_REG);
                break;
 
        case TBIT:
@@ -315,7 +304,7 @@ loop:
                        outop(opcode|(a1.a_value<<3)|reg, &a2);
                        break;
                }
-               aerr();
+               aerr(INVALID_REG);
                break;
 
        case TSHR:
@@ -326,7 +315,7 @@ loop:
                        outop(opcode|reg, &a1);
                        break;
                }
-               aerr();
+               aerr(INVALID_REG);
 
        case TINC:
                getaddr(&a1);
@@ -343,7 +332,7 @@ loop:
                                break;
                        case AF:
                        case AFPRIME:
-                               aerr();
+                               aerr(INVALID_REG);
                        }
                        if (opcode == OPINC)
                                opcode = OPINCRP; else
@@ -357,7 +346,7 @@ loop:
                        outop(opcode|(reg<<3), &a1);
                        break;
                }
-               aerr();
+               aerr(INVALID_REG);
                break;
 
        case TEX:
@@ -373,7 +362,7 @@ loop:
                else if (a1.a_type == (TWR|TMINDIR|SP))
                        opcode = OPXTHL;
                else
-                       aerr();
+                       aerr(INVALID_REG);
                if (a2.a_type == (TWR|HL))
                        outab(opcode);
                else if (a2.a_type == (TWR|IX)) {
@@ -383,7 +372,7 @@ loop:
                        outab(0xFD);
                        outab(opcode);
                } else
-                       aerr();
+                       aerr(INVALID_REG);
                break;
 
        case TSUB:
@@ -399,7 +388,7 @@ loop:
                        outop(opcode|reg, &a1);
                        break;
                }
-               aerr();
+               aerr(INVALID_REG);
                break;
 
        case TADD:
@@ -423,14 +412,14 @@ loop:
                        switch(reg = a1.a_type&TMREG) {
                        case IX:
                                if (opcode != OPADD)
-                                       aerr();
+                                       aerr(INVALID_REG);
                                outab(0xDD);
                                opcode = OPDAD;
                                srcreg = IX;
                                break;
                        case IY:
                                if (opcode != OPADD)
-                                       aerr();
+                                       aerr(INVALID_REG);
                                outab(0xFD);
                                opcode = OPDAD;
                                srcreg = IY;
@@ -448,7 +437,7 @@ loop:
                                srcreg = HL;
                                break;
                        default:
-                               aerr();
+                               aerr(INVALID_REG);
                        }
                        if ((a2.a_type&TMMODE) == TWR) {
                                reg = a2.a_type&TMREG;
@@ -462,7 +451,7 @@ loop:
                                }
                        }
                }
-               aerr();
+               aerr(INVALID_REG);
                break;
 
        case TLD:
@@ -470,7 +459,7 @@ loop:
                break;
 
        default:
-               err('o');
+               aerr(SYNTAX_ERROR);
        }
        goto loop;
 }
@@ -579,7 +568,7 @@ void asmld(void)
                        outrab(indexap);
                return;
        }
-       aerr();
+       aerr(INVALID_REG);
 }
 
 /*
@@ -624,7 +613,7 @@ ADDR        *getldaddr(ADDR *ap, int *modep, int *regp, ADDR *iap)
 
        case TWR|AF:
        case TWR|AFPRIME:
-               aerr();
+               aerr(INVALID_REG);
                reg = HL;
        }
        *modep = mode;
@@ -671,7 +660,7 @@ void outop(int op, ADDR *ap)
 void comma(void)
 {
        if (getnb() != ',')
-               qerr();
+               qerr(MISSING_COMMA);
 }
 
 /*
@@ -682,7 +671,7 @@ void comma(void)
 void istuser(ADDR *ap)
 {
        if ((ap->a_type&TMMODE) != TUSER)
-               aerr();
+               aerr(ADDR_REQUIRED);
 }
 
 /*
index c3607e8..a03d8e7 100644 (file)
@@ -25,76 +25,79 @@ int symhash(char *id)
        return (hash&HMASK);
 }
 
+/* We may want to move this out into a a helper app at the end to dump
+   errors without using assembler space */
+
+static char *etext[] = {
+       "unexpected character",
+       "phase error",
+       "multiple definitions",
+       "syntax error",
+       "must be absolute",
+       "missing delimiter",
+       "invalid constant",
+       "JR out of range",
+       "condition required",
+       "invalid register for operation",
+       "address required",
+       "invalid id",
+       "must be C",
+       "divide by 0",
+       "invalid constant",
+       "data in BSS",
+       "segment overflow"
+};
+
+static void errstr(uint8_t code)
+{
+       if (code < 10) {
+               printf("%c expected.\n", "),]%"[code-1]);
+               return;
+       }
+       printf("%s.\n", etext[code - 10]);
+}
+       
 /*
  * Handle an error.
  * If no listing file, write out
  * the error directly. Otherwise save
  * the error in the error buffer.
+ *
+ * Will need tweaking once we support .include as we must show the file
+ * name then. TODO
  */
-void err(char c)
+void err(char c, uint8_t code)
 {
        if (pass != 0) {
-               if (lflag != 0)
-                       storerror(c);
-               else
-                       printf("%04d %c\n", line, c);
+               printf("%s: %d: %c: ", fname, line, toupper(c));
+               errstr(code);
+               noobj = 1;
        }
        if (c == 'q')
                longjmp(env, 1);
 }
 
 /*
- * This routine is like
- * "err", but it has the "u"
- * code screwed into it, and it
- * prints the name of the identifier
- * "id" in the message.
+ * Not really an error any more (we resolve at link time)
  */
 void uerr(char *id)
 {
-       if (pass != 0) {
-               if (lflag != 0)
-                       storerror('u');
-               else
-                       printf("%04d u %.*s\n", line, NCPS, id);
-       }
 }
 
 /*
  * The "a" error is common.
  */
-void aerr(void)
+void aerr(uint8_t code)
 {
-       err('a');
+       err('a', code);
 }
 
 /*
  * Ditto the "q" error.
  */
-void qerr(void)
-{
-       err('q');
-}
-
-/*
- * Put the error code
- * "c" into the error buffer.
- * Check that it is not already
- * there.
- */
-
-void storerror(int c)
+void qerr(uint8_t code)
 {
-       char *p;
-
-       p = &eb[0];
-       while (p < ep)
-               if (*p++ == c)
-                       return;
-       if (p < &eb[NERR]) {
-               *p++ = c;
-               ep = p;
-       }
+       err('q', code);
 }
 
 /*
@@ -109,7 +112,7 @@ void getid(char *id, int c)
        if (c < 0) {
                c = getnb();
                if (isalpha(c) == 0 && c != '_' && c != '.')
-                       qerr();
+                       qerr(INVALID_ID);
        }
        p = &id[0];
        do {
@@ -137,7 +140,6 @@ SYM *lookup(char *id, SYM *htable[], int cf)
 {
        SYM *sp;
        int hash;
-       static int symnext;
 
        hash = symhash(id);
        sp  = htable[hash];
@@ -156,7 +158,7 @@ SYM *lookup(char *id, SYM *htable[], int cf)
                sp->s_type = TNEW;
                sp->s_value = 0;
                sp->s_segment = UNKNOWN;
-               sp->s_number = ++symnext;
+               sp->s_number = -1;
                symcopy(sp->s_id, id);
        }
        return (sp);
index e572bab..cedc59a 100644 (file)
@@ -31,17 +31,17 @@ void getaddr(ADDR *ap)
        }
        expr1(ap, LOPRI, 1);
        if (getnb() != ')')
-               qerr();
+               qerr(BRACKET_EXPECTED);
        reg = ap->a_type&TMREG;
        switch (ap->a_type&TMMODE) {
        case TBR:
                if (reg != C)
-                       aerr();
+                       aerr(REG_MUST_BE_C);
                ap->a_type |= TMINDIR;
                break;
        case TSR:
        case TCC:
-               aerr();
+               aerr(ADDR_REQUIRED);
                break;
        case TUSER:
                ap->a_type |= TMINDIR;
@@ -52,7 +52,7 @@ void getaddr(ADDR *ap)
                else if (reg==IX || reg==IY)
                        ap->a_type = TBR|reg;
                else if (reg==AF || reg==AFPRIME)
-                       aerr();
+                       aerr(INVALID_REG);
                else
                        ap->a_type |= TMINDIR;
        }
@@ -64,7 +64,7 @@ static void chkabsolute(ADDR *a)
        if ((a->a_type & TMMODE) != TUSER)
                return;
        if (a->a_segment != ABSOLUTE)
-               aerr();
+               aerr(MUST_BE_ABSOLUTE);
 }
 
 static void chksegment(ADDR *left, ADDR *right, int op)
@@ -95,7 +95,7 @@ static void chksegment(ADDR *left, ADDR *right, int op)
                return;
        }
        left->a_sym = NULL;
-       aerr();
+       aerr(MUST_BE_ABSOLUTE);
 }
 
 /*
@@ -148,7 +148,7 @@ void expr1(ADDR *ap, int lpri, int paren)
                        istuser(&right);
                        chksegment(ap, &right, '/');
                        if (right.a_value == 0)
-                               err('z');
+                               err('z', DIVIDE_BY_ZERO);
                        else
                                ap->a_value /= right.a_value;
                }
@@ -172,7 +172,7 @@ void expr2(ADDR *ap)
        if (c == '[') {
                expr1(ap, LOPRI, 0);
                if (getnb() != ']')
-                       qerr();
+                       qerr(SQUARE_EXPECTED);
                return;
        }
        if (c == '-') {
@@ -195,7 +195,7 @@ void expr2(ADDR *ap)
                ap->a_segment = ABSOLUTE;
                while ((c=get()) != '\'') {
                        if (c == '\n')
-                               qerr();
+                               qerr(PERCENT_EXPECTED);
                        ap->a_value = (ap->a_value<<8) + c;
                }
                return;
@@ -228,7 +228,7 @@ void expr2(ADDR *ap)
                ap->a_segment = sp->s_segment;
                return;
        }
-       qerr();
+       qerr(SYNTAX_ERROR);
 }
 
 /*
@@ -292,9 +292,9 @@ void expr3(ADDR *ap, int c)
                else if (c>='a' && c<='f')
                        c -= 'a'-10;
                else
-                       err('n');
+                       err('n', INVALID_CONSTANT);
                if (c >= radix)
-                       err('n');
+                       err('n', INVALID_CONSTANT);
                value = radix*value + c;
        }
        ap->a_type  = TUSER;
@@ -322,5 +322,5 @@ void isokaors(ADDR *ap, int paren)
                if (reg==IX || reg==IY)
                        return;
        }
-       aerr();
+       aerr(ADDR_REQUIRED);
 }
index 0144429..e3496be 100644 (file)
@@ -7,15 +7,13 @@
 #include       "as.h"
 #include       "obj.h"
 
-#define        NHEX    8                       /* Nice format size */
-
 static uint16_t segsize[NSEGMENT];
 static uint16_t truesize[NSEGMENT];
 static off_t segbase[NSEGMENT];
 
-struct objhdr obh;
+static struct objhdr obh;
 
-static void outc(char c);
+static void numbersymbols(void);
 
 void outpass(void)
 {
@@ -27,15 +25,19 @@ void outpass(void)
                        if (i != BSS) {
                                obh.o_segbase[i] = base;
                                segbase[i] = base;
-                               printf("BASE %d %d\n", i, base);
                                base += segsize[i];
-                               printf("SIZE %d %d\n", i, truesize[i]);
                        }
                        obh.o_size[i] = truesize[i];
                }
                obh.o_magic = 0;
+               obh.o_arch = OA_Z80;
+               obh.o_flags = 0;
+               /* Will need changing if we add .Z180 and the Z180 ops */
+               obh.o_cpuflags = 0;
                obh.o_symbase = base;
                obh.o_dbgbase = 0;      /* for now */
+               /* Number the symbols for output */
+               numbersymbols();
        }
 }
 
@@ -72,9 +74,8 @@ void outaw(uint16_t w)
 void outraw(ADDR *a)
 {
        if (a->a_segment != ABSOLUTE) {
-               /* FIXME@ handle symbols */
                if (segment == BSS)
-                       err('b');
+                       err('b', DATA_IN_BSS);
                if (a->a_sym == NULL) {
                        outbyte(REL_ESC);
                        outbyte((1 << 4) | REL_SIMPLE | a->a_segment);
@@ -97,16 +98,16 @@ void outab(uint8_t b)
 {
        /* Not allowed to put data in the BSS except zero */
        if (segment == BSS && b)
-               err('b');
+               err('b', DATA_IN_BSS);
        if (segment == ABSOLUTE)
-               err('A');
+               err('A', MUST_BE_ABSOLUTE);
        outbyte(b);
        if (b == 0xDA)  /* Quote relocation markers */
                outbyte(0x00);
        ++dot[segment];
        ++truesize[segment];
        if (truesize[segment] == 0 || dot[segment] == 0)
-               err('o');
+               err('o', SEGMENT_OVERFLOW);
 }
 
 void outrab(ADDR *a)
@@ -114,7 +115,7 @@ void outrab(ADDR *a)
        /* FIXME: handle symbols */
        if (a->a_segment != ABSOLUTE) {
                if (segment == BSS)
-                       err('b');
+                       err('b', DATA_IN_BSS);
                if (a->a_sym == NULL) {
                        outbyte(REL_ESC);
                        outbyte((0 << 4) | REL_SIMPLE | a->a_segment);
@@ -132,7 +133,6 @@ static void putsymbol(SYM *s, FILE *ofp)
 {
        int i;
        uint8_t flag = 0;
-       printf("Putsymbol %s\n", s->s_id);
        if (s->s_type == TNEW)
                flag |= S_UNKNOWN;
        else {
@@ -141,8 +141,6 @@ static void putsymbol(SYM *s, FILE *ofp)
                flag |= s->s_segment;
        }
        putc(flag, ofp);
-       putc(s->s_number, ofp);
-       putc(s->s_number >> 8, ofp);
        for (i = 0; i < 16; i++) {
                putc(s->s_id[i], ofp);
                if (!s->s_id[i])
@@ -154,10 +152,15 @@ static void putsymbol(SYM *s, FILE *ofp)
        }
 }
 
-static void writesymbols(SYM *hash[], FILE *ofp, int flag)
+static void enumerate(SYM *s, FILE *dummy)
+{
+       static int sym = 0;
+       s->s_number = sym++;
+}
+
+static void dosymbols(SYM *hash[], FILE *ofp, int flag, void (*op)(SYM *, FILE *f))
 {
        int i;
-       fseek(ofp, obh.o_symbase, SEEK_SET);
        for (i = 0; i < NHASH; i++) {
                SYM *s;
                for (s = hash[i]; s != NULL; s = s->s_fp) {
@@ -167,11 +170,26 @@ static void writesymbols(SYM *hash[], FILE *ofp, int flag)
                                continue;
                        n =  (t == TNEW) || (t == TUSER && (s->s_type & TPUBLIC));
                        if (n == flag)
-                               putsymbol(s, ofp);
+                               op(s, ofp);
                }
        }
 }
 
+static void writesymbols(SYM *hash[], FILE *ofp)
+{
+       fseek(ofp, obh.o_symbase, SEEK_SET);
+       dosymbols(hash, ofp, 1, putsymbol);
+       if (debug_write) {
+               obh.o_dbgbase = ftell(ofp);
+               dosymbols(uhash, ofp, 0, putsymbol);
+       }
+}
+
+static void numbersymbols(void)
+{
+       dosymbols(uhash, NULL, 1, enumerate);
+}
+
 /*
  * Put out the end of file
  * hex item at the very end of
@@ -179,18 +197,17 @@ static void writesymbols(SYM *hash[], FILE *ofp, int flag)
  */
 void outeof(void)
 {
-       writesymbols(phash, ofp, 1);
-       writesymbols(uhash, ofp, 1);
-       if (debug_write) {
-               obh.o_dbgbase = ftell(ofp);
-               writesymbols(phash, ofp, 0);
-               writesymbols(uhash, ofp, 0);
-       }
+       /* We don't do the final write out if there was an error. That
+          leaves the magic wrong on the object file so it can't be used */
+       if (noobj || pass == 0)
+               return;
+
+       writesymbols(uhash, ofp);
        rewind(ofp);
        obh.o_magic = MAGIC_OBJ;
        fwrite(&obh, sizeof(obh), 1, ofp);
-       printf("Code %d byyes: Data %d bytes: BSS %d bytes\n",
-               truesize[CODE], truesize[DATA], truesize[BSS]);
+/*     printf("Code %d bytes: Data %d bytes: BSS %d bytes\n",
+               truesize[CODE], truesize[DATA], truesize[BSS]); */
 }
 
 /*
diff --git a/Applications/MWC/cmd/asz80/as5.c b/Applications/MWC/cmd/asz80/as5.c
deleted file mode 100644 (file)
index 8e78f62..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Z-80 assembler.
- * Build up lines for the
- * listing file.
- */
-#include       "as.h"
-
-/*
- * Copy the data in the listing
- * code buffer to the listing file.
- * Produce no file if "lfp" is NULL.
- * Honour the listing mode stored
- * in the "lmode".
- */
-void list(void)
-{
-       char *wp;
-       int nb;
-
-       if (lfp==NULL || lmode==NLIST)
-               return;
-       while (ep < &eb[NERR])
-               *ep++ = ' ';
-       fprintf(lfp, "%.10s", eb);
-       if (lmode == SLIST) {
-               fprintf(lfp, "%31s %5d %s", "", line, ib);
-               return;
-       }
-       fprintf(lfp, "   %04x", laddr);
-       if (lmode == ALIST) {
-               fprintf(lfp, "%24s %5d %s", "", line, ib);
-               return;
-       }
-       wp = cb;
-       nb = cp - cb;
-       list1(wp, nb, 1);
-       fprintf(lfp, " %5d %s", line, ib);
-       while ((nb -= 8) > 0) {
-               wp += 8;
-               fprintf(lfp, "%17s", "");
-               list1(wp, nb, 0);
-               fprintf(lfp, "\n");
-       }
-}
-
-/*
- * Copy out a partial line
- * to the listing. Used for the first
- * and the extra lines in BLIST and
- * WLIST mode.
- */
-void list1(char *wp, int nb, int f)
-{
-       int d;
-       int i;
-
-       if (nb > 8)
-               nb = 8;
-       for (i=0; i<nb; ++i) {
-               d = (*wp++) & 0xFF;
-               if (lmode == BLIST)
-                       fprintf(lfp, " %02x", d);
-               else {
-                       d |= *wp++ << 8;
-                       fprintf(lfp, "  %04x", d);
-                       ++i;
-               }
-       }
-       if (f != 0) {
-               while (i < 8) {
-                       fprintf(lfp, "   ");
-                       ++i;
-               }
-       }
-}
diff --git a/Applications/MWC/cmd/asz80/nm.c b/Applications/MWC/cmd/asz80/nm.c
new file mode 100644 (file)
index 0000000..49d8be4
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ *     For now this only works on object files. It's mostly here so I can
+ *     check the assembler output looks valid.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <stdint.h>
+
+#include "obj.h"
+
+static char *arg0;
+static int err;
+static int show_debug = 1;
+static int show_name;
+static int show_undef;
+
+static char segname[] = "ATDB????????????";
+
+static int do_nm(FILE *fp, const char *name)
+{
+    static struct objhdr oh;
+    off_t base;
+    uint8_t type;
+    int c;
+    uint8_t i;
+    uint16_t addr;
+    char symname[17];
+
+    if (show_name)
+        printf("%s:\n", name);
+    if (fread(&oh, sizeof(oh), 1, fp) != 1 ||
+        oh.o_magic != MAGIC_OBJ) {
+            fprintf(stderr, "%s: %s: not a valid object file.\n", arg0, name);
+            return 1;
+    }
+    base = oh.o_symbase;
+    if (base == 0) {
+        fprintf(stderr, "%s: %s: no symbols.\n", arg0, name);
+        return 0;
+    }
+    if (fseek(fp, base, SEEK_SET)) {
+        fprintf(stderr, "%s: %s: truncated file ?\n", arg0, name);
+        return 1;
+    }
+    while (1) {
+        if (base >= oh.o_dbgbase && show_debug == 0)
+            break;
+        c = fgetc(fp);
+        if (c == EOF)
+            return 0;
+        type = (uint8_t)c;
+        base++;
+        for (i = 0; i < 16; i++) {
+            c = fgetc(fp);
+            base++;
+            symname[i] = (char)c;
+            if (c == 0)
+                break;
+        }
+        symname[16] = 0;
+        /* Address if defined */
+        if (!(type & S_UNKNOWN)) {
+            addr = fgetc(fp);
+            addr |= fgetc(fp) << 8;
+            base += 2;
+            c = segname[type & S_SEGMENT];
+            /* Showing undefined only */
+            if (show_undef)
+                continue;
+        } else {
+            addr = 0;
+            c = 'U';
+        }
+        printf("%04X %c %s\n", addr, c, symname);
+    }
+    return 0;
+}            
+
+int main(int argc, char *argv[])
+{
+    int opt;
+    arg0 = argv[0];
+
+    while ((opt = getopt(argc,argv,"oAug")) != -1) {
+        switch(opt) {
+            case 'o':
+            case 'A':
+                show_name = 1;
+                break;
+            case 'u':
+                show_undef = 1;
+                break;
+            case 'g':
+                show_debug = 0;
+                break;
+            default:
+                fprintf(stderr, "%s: name ...\n", argv[0]);
+                exit(1);
+        }
+    }
+
+    /* Show names if multiple arguments */
+    if (optind - argc > 1)
+        show_name = 1;
+
+    if (optind >= argc)
+        do_nm(stdin, "-");
+    else while (optind < argc) {
+        FILE *fp = fopen(argv[optind], "r");
+        if (fp == NULL) {
+            perror(argv[optind]);
+            err |= 1;
+        } else {
+            err |= do_nm(fp, argv[optind]);
+            fclose(fp);
+        }
+        optind++;
+    }
+    exit(err);
+}
+
diff --git a/Applications/MWC/cmd/asz80/obj.h b/Applications/MWC/cmd/asz80/obj.h
new file mode 100644 (file)
index 0000000..c441e00
--- /dev/null
@@ -0,0 +1,53 @@
+#define MAGIC_OBJ              0x3D1A
+#define MAGIC_OBJ_SWAPPED      0x1A3D
+
+#define OSEG   8
+
+struct objhdr
+{
+    uint16_t o_magic;
+    uint8_t o_arch;
+#define OA_Z80         1
+    uint8_t o_flags;
+    uint16_t o_cpuflags;
+#define OA_Z80_Z180    1
+#define OA_Z80_Z280    2
+#define OA_Z80_R800    4
+    uint32_t o_segbase[OSEG];
+    uint16_t o_size[OSEG];
+    uint32_t o_symbase;
+    uint32_t o_dbgbase;
+};
+
+/* This byte introduces a relocation or may be escaped */
+#define REL_ESC                0xDA
+#define REL_REL                0x00    /* DA00 means write in DA */
+
+#define REL_SIZE       0x30    /* 1-4 bytes */
+/* If REL_SIMPLE then ... */
+#define REL_SIMPLE     0x80    /* relocationto base of segment */
+#define REL_SEG                0x0F    /* segment 0-15 */      
+
+/*    followed by the bytes to relocate */
+
+/* Otherwise */
+#define REL_TYPE       0x0F
+/* 00 is reserved */
+#define REL_SYMBOL     0x01
+/* 02-0F reserved */
+/* Followed by 2 byte number of symbol in symbol table */
+
+/*     followed by the bytes to relocate */
+
+
+/* symbols and debug are in the format 
+    uint8_t flags
+    char name[1..16] (0 terminated if < 16)
+    uint16_t data      if not unknown */
+
+#define        S_UNKNOWN       0x80
+#define S_PUBLIC       0x40            /* unknown is public .. */
+#define S_SEGMENT      0x0F            /* 00 means absolute */
+
+
+