From 960aaff113e07506c1a0284c683b7ad3b07ce15f Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sat, 28 Oct 2017 16:57:35 +0100 Subject: [PATCH] asz80: finish conversion 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... --- Applications/MWC/cmd/asz80/Makefile.68000 | 12 ++- Applications/MWC/cmd/asz80/Makefile.6809 | 11 +- Applications/MWC/cmd/asz80/Makefile.z80 | 11 +- Applications/MWC/cmd/asz80/as.h | 49 ++++++--- Applications/MWC/cmd/asz80/as0.c | 23 +--- Applications/MWC/cmd/asz80/as1.c | 87 +++++++-------- Applications/MWC/cmd/asz80/as2.c | 90 ++++++++-------- Applications/MWC/cmd/asz80/as3.c | 26 ++--- Applications/MWC/cmd/asz80/as4.c | 71 +++++++----- Applications/MWC/cmd/asz80/as5.c | 75 ------------- Applications/MWC/cmd/asz80/nm.c | 125 ++++++++++++++++++++++ Applications/MWC/cmd/asz80/obj.h | 53 +++++++++ 12 files changed, 381 insertions(+), 252 deletions(-) delete mode 100644 Applications/MWC/cmd/asz80/as5.c create mode 100644 Applications/MWC/cmd/asz80/nm.c create mode 100644 Applications/MWC/cmd/asz80/obj.h diff --git a/Applications/MWC/cmd/asz80/Makefile.68000 b/Applications/MWC/cmd/asz80/Makefile.68000 index 07b360bd..ee348e63 100644 --- a/Applications/MWC/cmd/asz80/Makefile.68000 +++ b/Applications/MWC/cmd/asz80/Makefile.68000 @@ -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 $^ > $@ diff --git a/Applications/MWC/cmd/asz80/Makefile.6809 b/Applications/MWC/cmd/asz80/Makefile.6809 index 2379f785..2bec36e3 100644 --- a/Applications/MWC/cmd/asz80/Makefile.6809 +++ b/Applications/MWC/cmd/asz80/Makefile.6809 @@ -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 *~ diff --git a/Applications/MWC/cmd/asz80/Makefile.z80 b/Applications/MWC/cmd/asz80/Makefile.z80 index d420648e..f583c6f5 100644 --- a/Applications/MWC/cmd/asz80/Makefile.z80 +++ b/Applications/MWC/cmd/asz80/Makefile.z80 @@ -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: diff --git a/Applications/MWC/cmd/asz80/as.h b/Applications/MWC/cmd/asz80/as.h index a025eb5d..b36cb4a3 100644 --- a/Applications/MWC/cmd/asz80/as.h +++ b/Applications/MWC/cmd/asz80/as.h @@ -30,15 +30,6 @@ #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 @@ -130,6 +121,33 @@ #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); diff --git a/Applications/MWC/cmd/asz80/as0.c b/Applications/MWC/cmd/asz80/as0.c index 355350cc..f3bbaca6 100644 --- a/Applications/MWC/cmd/asz80/as0.c +++ b/Applications/MWC/cmd/asz80/as0.c @@ -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(); diff --git a/Applications/MWC/cmd/asz80/as1.c b/Applications/MWC/cmd/asz80/as1.c index a9f54d23..50df3e0f 100644 --- a/Applications/MWC/cmd/asz80/as1.c +++ b/Applications/MWC/cmd/asz80/as1.c @@ -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); } /* diff --git a/Applications/MWC/cmd/asz80/as2.c b/Applications/MWC/cmd/asz80/as2.c index c3607e81..a03d8e7c 100644 --- a/Applications/MWC/cmd/asz80/as2.c +++ b/Applications/MWC/cmd/asz80/as2.c @@ -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); diff --git a/Applications/MWC/cmd/asz80/as3.c b/Applications/MWC/cmd/asz80/as3.c index e572bab4..cedc59a1 100644 --- a/Applications/MWC/cmd/asz80/as3.c +++ b/Applications/MWC/cmd/asz80/as3.c @@ -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); } diff --git a/Applications/MWC/cmd/asz80/as4.c b/Applications/MWC/cmd/asz80/as4.c index 0144429d..e3496be5 100644 --- a/Applications/MWC/cmd/asz80/as4.c +++ b/Applications/MWC/cmd/asz80/as4.c @@ -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 index 8e78f624..00000000 --- a/Applications/MWC/cmd/asz80/as5.c +++ /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 +#include +#include +#include +#include +#include + +#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 index 00000000..c441e009 --- /dev/null +++ b/Applications/MWC/cmd/asz80/obj.h @@ -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 */ + + + -- 2.34.1