/*)BUILD # untested */ /* * Z-80 assembler. */ #include #define NCPS 8 #define NSYM 256 #define NBIN 32 #define NTSYM 128 #define NERR 10 #define NINPUT 128 #define NCODE 128 #define NTIT 64 #define NLIST 0 #define SLIST 1 #define ALIST 2 #define CLIST 3 #define B 0 #define C 1 #define D 2 #define E 3 #define H 4 #define L 5 #define M 6 #define A 7 #define V 8 #define R 9 #define BC 0 #define DE 1 #define HL 2 #define SP 3 #define AF 4 #define IX 5 #define IY 6 #define dot (&sym[0]) typedef unsigned addr_t; struct sym { char s_name[NCPS]; char s_type; char s_flag; addr_t s_addr; }; #define S_UND 0 #define S_ABS 1 #define S_OP0 2 #define S_OP1 3 #define S_OP2 4 #define S_OP3 5 #define S_OP4 6 #define S_OP5 7 #define S_OP6 8 #define S_OP7 9 #define S_OP8 10 #define S_OP9 11 #define S_OP10 12 #define S_OP11 13 #define S_OP12 14 #define S_OP13 15 #define S_OP14 16 #define S_OP15 17 #define S_OP16 18 #define S_RPAIR 19 #define S_IC 20 #define S_IPAIR 21 #define S_LIT 22 #define S_INDEX 23 #define S_REG 24 #define S_WORD 25 #define S_ASCII 26 #define S_ASCIZ 27 #define S_BLKB 28 #define S_PAGE 29 #define S_TITLE 30 #define S_BYTE 31 #define S_HLIST 32 #define S_OLIST 33 #define S_INTEL 34 #define S_MKBUG 35 #define S_MDF 01 /* Mult. def */ #define S_ASG 02 /* Assigned def */ #define S_TWO 04 /* Two byte opcode */ #define PCHL 0351 #define JMP 0303 #define DJNZ 0020 #define INC 0004 #define INX 0003 #define DCX 0013 #define BITOP 0313 #define XTHL 0343 #define EXAF 0010 #define XCHG 0353 #define IN 0333 #define OUT 0323 #define IN_C 0100 #define OUT_C 0101 #define ADD 0200 #define ADDX 0011 #define ADC 0210 #define ADCX 0112 #define SBCX 0102 #define MVI 0006 #define MVI_M 0066 #define LXI 0001 #define STA 0062 #define STAX 0002 #define MOV_AV 0107 #define MOV_AR 0117 #define MOV 0100 #define MOV_RM 0160 #define LDA 0072 #define LDAX 0012 #define MOV_VA 0127 #define MOV_RA 0137 #define MOV_MR 0106 #define SPHL 0371 #define SHLD 0042 #define LHLD 0052 #define SRPD 0103 #define LRPD 0113 struct tsym { int t_num; addr_t t_addr; }; struct tsymp { struct tsym *t_fp; struct tsym *t_bp; }; struct addr { char a_type; char a_reg; addr_t a_addr; }; int line; int page; int lop; int pass; int nsym = 124; int ntsym; int lflag; int nflag; int eflag; addr_t laddr; int lmode; int hlist; int mkbug; char *ep; char eb[NERR]; char *ip; char ib[NINPUT]; char *cp; char cb[NCODE]; char tb[NTIT]; int bo; int ba; char bb[NBIN]; extern struct sym sym[]; char imtab[3] = { 0106, 0126, 0136 }; struct tsym tsym[NTSYM]; struct tsymp tsymp[10]; FILE *lfp; FILE *ofp; FILE *sfp; main(argc, argv) char *argv[]; { register char *p; register c, i; struct tsym *tp; char *fn; fn = NULL; for (i=1; is_type = S_ABS; dot->s_flag = S_ASG; dot->s_addr = 0; line = 0; page = 1; lop = 60; rewind(sfp); if (pass == 1) { for (i=0; i<10; ++i) { tsymp[i].t_fp = NULL; tsymp[i].t_bp = NULL; tp = tsym; while (tp < &tsym[ntsym]) { if (tp->t_num == i) { tsymp[i].t_fp = tp; break; } ++tp; } } } while (fgetss(ib, sizeof ib, sfp) != NULL) { ++line; cp = cb; ep = eb; ip = ib; eflag = 0; setexit(); if (eflag == 0) asm(); if (pass == 1) { diag(); list(); } } } if (!nflag) { bflush(); beof(); } } } afile(fn, wf) char *fn; { register FILE *fp; fp = fopen(fn, wf?"w":"r"); if (fp == NULL) { fprintf(stderr, "%s: cannot open.\n", fn); exit(1); } return (fp); } asm() { register c; register addr_t a; struct sym *sp; struct tsym *tp; int b, d, op; char *p, id[NCPS]; struct addr a1, a2; laddr = dot->s_addr; lmode = SLIST; loop: while ((c = getnb()) == ';') ; if (c == 0 || c == '/') return; if (isdigit(c)) { if (getnb() != ':') err('q'); c -= '0'; if (pass == 0) { if (ntsym >= NTSYM) error("Too many temp. symbols!\n"); tsym[ntsym].t_num = c; tsym[ntsym].t_addr = dot->s_addr; ++ntsym; } tp = tsymp[c].t_fp; tsymp[c].t_bp = tp; tsymp[c].t_fp = NULL; ++tp; while (tp < &tsymp[ntsym]) { if (tp->t_num == c) { tsymp[c].t_fp = tp; break; } ++tp; } goto loop; } if (!isidc(c)) err('q'); getid(c, id); if ((c = getnb()) == ':') { sp = lookup(id, 1); if (pass == 0) { if (sp->s_type!=S_UND && (sp->s_flag&S_ASG)==0) sp->s_flag |= S_MDF; sp->s_type = S_ABS; sp->s_addr = dot->s_addr; } else { if ((sp->s_flag&S_MDF) != 0) err('m'); if (sp->s_type!=S_ABS || sp->s_addr!=dot->s_addr) err('p'); } lmode = ALIST; goto loop; } if (c == '=') { sp = lookup(id, 1); if (sp->s_type!=S_UND && (sp->s_flag&S_ASG)==0) err('m'); expr(&a1); sp->s_addr = laddr = a1.a_addr; sp->s_flag = S_ASG; sp->s_type = a1.a_type; lmode = ALIST; goto loop; } unget(c); lmode = CLIST; if ((sp=lookup(id, 0)) == NULL) { err('o'); return; } op = sp->s_addr; switch(sp->s_type) { case S_HLIST: case S_OLIST: hlist = op; lmode = SLIST; break; case S_INTEL: case S_MKBUG: mkbug = op; lmode = SLIST; break; case S_BYTE: case S_WORD: do { expr(&a1); a = a1.a_addr; if (sp->s_type == S_BYTE) { bcheck(a, 't'); outb(a); } else outw(a); } while ((c = getnb()) == ','); unget(c); break; case S_ASCII: case S_ASCIZ: if ((d = getnb()) == 0) err('q'); while ((c = get()) != 0 && c != d) outb(c); if (c == 0) err('q'); if (sp->s_type == S_ASCIZ) outb(0); break; case S_BLKB: expr(&a1); a = a1.a_addr; if ((c = getnb()) == ',') { expr(&a1); b = a1.a_addr; } else { unget(c); b = 0; } while (a--) outb(b); lmode = ALIST; break; case S_TITLE: p = tb; if (c = getnb()) { do { if (p < &tb[NTIT-1]) *p++ = c; } while (c = get()); } *p = 0; unget(c); case S_PAGE: lop = 60; lmode = NLIST; break; case S_OP0: if ((sp->s_flag&S_TWO) != 0) outb(op>>8); outb(op); break; case S_OP1: expr(&a1); if ((a=a1.a_addr) < 3) { outb(0355); outb(imtab[a]); break; } aerr(); break; case S_OP2: expr(&a1); if ((a=a1.a_addr) < 8) { out3(op, a); break; } aerr(); break; case S_OP3: case S_OP4: case S_OP5: case S_OP15: addr(sp->s_type==S_OP5 ? &a2 : &a1); comma(); addr(sp->s_type==S_OP5 ? &a1 : &a2); if (sp->s_type == S_OP15) { mov(&a1, &a2); break; } if (sp->s_type == S_OP3) { if (a1.a_type==S_RPAIR && a2.a_type==S_RPAIR) { a = a1.a_addr; b = a2.a_addr; if ((b!=HL && b!=IX && b!=IY) || (b!=HL && op!=ADD) || (a!=BC && a!=DE && a!=SP && a!=b)) aerr(); if (a > AF) a = HL; if (op == ADD) { testx(b); op = ADDX; } else { outb(0355); op = (op == ADC) ? ADCX : SBCX; } out4(op, a); break; } } if (a2.a_type!=S_REG || a2.a_addr!=A) aerr(); if (a1.a_type == S_INDEX) { outx(a1.a_reg); outb(op|M); outb(a1.a_addr); break; } if (a1.a_type == S_LIT) { outb(op|0100|M); outb(a1.a_addr); break; } if (a1.a_type == S_REG) { outb(op|a1.a_addr); break; } aerr(); break; case S_OP6: expr(&a1); comma(); addr(&a2); if (a1.a_addr > 7) aerr(); if (a2.a_type == S_INDEX) { outx(a2.a_reg); outb(BITOP); outb(a2.a_addr); out3(op|M, a1.a_addr); break; } if (a2.a_type == S_REG) { outb(BITOP); out3(op|a2.a_addr, a1.a_addr); break; } aerr(); break; case S_OP8: addr(&a1); if (op == JMP) { if (a1.a_type==S_REG && a1.a_addr==M) { outb(PCHL); break; } if (a1.a_type==S_INDEX && a1.a_addr==0) { outx(a1.a_reg); outb(PCHL); break; } } if (a1.a_type == S_ABS) { outb(op); outw(a1.a_addr); break; } aerr(); break; case S_OP9: if (op == DJNZ) { addr(&a1); if (a1.a_type!=S_REG || a1.a_addr!=B) aerr(); comma(); } expr(&a1); a = a1.a_addr - dot->s_addr - 2; bcheck(a, 'a'); outb(op); outb(a); break; case S_OP10: case S_OP11: case S_OP12: addr(&a1); if (sp->s_type == S_OP10) { if (a1.a_type==S_RPAIR && (a=a1.a_addr)!=AF) { out4((op==INC)?INX:DCX, testx(a)); break; } } if (sp->s_type == S_OP11) { if (a1.a_type==S_REG && a1.a_addr==A) { outb(op|A); break; } } if (a1.a_type == S_INDEX) { outx(a1.a_reg); if ((sp->s_flag&S_TWO) != 0) outb(op>>8); else out3(op, M); outb(a1.a_addr); if ((sp->s_flag&S_TWO) != 0) outb(op|M); break; } if (a1.a_type == S_REG) { if ((sp->s_flag&S_TWO) != 0) { outb(op>>8); outb(op|a1.a_addr); } else out3(op, a1.a_addr); break; } aerr(); break; case S_OP13: addr(&a1); if (a1.a_type==S_RPAIR && (a=a1.a_addr)!=SP) { if ((a = testx(a)) == AF) a = SP; out4(op, a); break; } aerr(); break; case S_OP14: addr(op==IN ? &a1 : &a2); comma(); addr(op==IN ? &a2 : &a1); if (a2.a_type == S_REG) { if (a2.a_addr==A && a1.a_type==S_ABS) { a = a1.a_addr; bcheck(a, 't'); outb(op); outb(a); break; } if (a1.a_type == S_IC) { outb(0355); out3((op == IN) ? IN_C : OUT_C, a2.a_addr); break; } } aerr(); break; case S_OP16: addr(&a1); comma(); addr(&a2); if (a2.a_type == S_RPAIR) { if (a1.a_type==S_IPAIR && a1.a_addr==SP) { if (testx(a2.a_addr) == HL) { outb(XTHL); break; } } else if (a1.a_type == S_RPAIR) { a = a1.a_addr; if (a==AF && a2.a_addr==AF) { outb(EXAF); break; } if (a==DE && a2.a_addr==HL) { outb(XCHG); break; } } } aerr(); break; default: err('o'); } goto loop; } mov(s, d) register struct addr *s, *d; { addr_t as, ad; as = s->a_addr; ad = d->a_addr; /* * Literal source. */ if (s->a_type == S_LIT) { if (d->a_type==S_REG && ad<=A) { out3(MVI, ad); outb(as); } else if (d->a_type == S_INDEX) { outx(d->a_reg); outb(MVI_M); outb(ad); outb(as); } else if (d->a_type==S_RPAIR && ad!=AF) { out4(LXI, testx(ad)); outw(as); } else aerr(); return; } /* * 8 bit. */ if (isr8(s)) { if (as == A) { if (d->a_type == S_ABS) { outb(STA); outw(ad); return; } if (d->a_type==S_IPAIR && ad<=DE) { out4(STAX, ad); return; } if (d->a_type==S_REG && ad>A) { outb(0355); outb((ad == V) ? MOV_AV : MOV_AR); return; } } if (isr8(d)) { out3(MOV|as, ad); return; } if (d->a_type == S_INDEX) { outx(d->a_reg); outb(MOV_RM|as); outb(d->a_addr); return; } aerr(); return; } if (isr8(d)) { if (ad == A) { if (s->a_type == S_ABS) { outb(LDA); outw(as); return; } if (s->a_type==S_IPAIR && as<=DE) { out4(LDAX, as); return; } if (s->a_type==S_REG && as>A) { outb(0355); outb((as == V) ? MOV_VA : MOV_RA); return; } } if (s->a_type == S_INDEX) { outx(s->a_reg); out3(MOV_MR, ad); outb(s->a_addr); return; } aerr(); return; } /* * 16 bit. */ if (s->a_type == S_RPAIR) { if (d->a_type==S_RPAIR && ad==SP) { if ((as = testx(as)) == HL) outb(SPHL); else aerr(); return; } if (d->a_type == S_ABS) { if ((as = testx(as)) == HL) { outb(SHLD); outw(ad); } else if (as != AF) { outb(0355); out4(SRPD, as); outw(ad); } else aerr(); return; } aerr(); return; } if (d->a_type == S_RPAIR) { if (s->a_type == S_ABS) { if ((ad = testx(ad)) == HL) { outb(LHLD); outw(as); } else if (ad != AF) { outb(0355); out4(LRPD, ad); outw(as); } else aerr(); return; } } aerr(); } isr8(ap) register struct addr *ap; { return (ap->a_type==S_REG && ap->a_addr<=A); } testx(r) register r; { if (r > AF) { outx(r); r = HL; } return (r); } addr(ap) register struct addr *ap; { register c; register addr_t a; struct sym *sp; if ((c=getnb()) == '$') { expr(ap); ap->a_type = S_LIT; return; } if (c == '(') { sp = addr1(); if (sp->s_type == S_REG) { if (sp->s_addr != C) err('q'); ap->a_type = S_IC; return; } if (sp->s_type==S_RPAIR && (a=sp->s_addr)!=AF) { if (a == HL) { ap->a_type = S_REG; ap->a_addr = M; return; } if (a==IX || a==IY) { ap->a_type = S_INDEX; ap->a_reg = a; ap->a_addr = 0; return; } ap->a_type = S_IPAIR; ap->a_addr = a; return; } err('q'); } unget(c); expr(ap); if (ap->a_type != S_ABS) return; if ((c=getnb()) != '(') { unget(c); return; } sp = addr1(); if (sp->s_type==S_RPAIR && (a=sp->s_addr)!=AF) { if (a!=IX && a!=IY) { if (ap->a_addr != 0) err('q'); if (a == HL) { ap->a_type = S_REG; ap->a_addr = M; return; } ap->a_type = S_IPAIR; ap->a_addr = a; return; } bcheck(ap->a_addr, 'a'); ap->a_type = S_INDEX; ap->a_reg = a; } } addr1() { register c; register struct sym *sp; char id[NCPS]; if (isidc(c = getnb())) { getid(c, id); if (getnb()==')' && (sp=lookup(id, 0))!=NULL) return (sp); } err('q'); } expr(ap) register struct addr *ap; { register c; struct addr right; term(ap); if (ap->a_type != S_ABS) return; for (;;) { c = getnb(); if ((c=='<' || c=='>') && c!=getnb()) err('q'); if (!any(c, "+-*%&|><")) { unget(c); break; } term(&right); if (right.a_type != S_ABS) err('r'); switch(c) { case '+': ap->a_addr += right.a_addr; break; case '-': ap->a_addr -= right.a_addr; break; case '*': ap->a_addr *= right.a_addr; break; case '%': ap->a_addr /= right.a_addr; break; case '&': ap->a_addr &= right.a_addr; break; case '|': ap->a_addr |= right.a_addr; break; case '>': ap->a_addr >>= right.a_addr; break; case '<': ap->a_addr <<= right.a_addr; } } } term(ap) register struct addr *ap; { register c; addr_t dec, oct; char id[NCPS]; struct sym *sp; struct tsym *tp; int n, r, v; c = getnb(); if (c == '[') { expr(ap); if (getnb() != ']') err('q'); return; } if (c == '-' || c == '!') { expr(ap); if (ap->a_type != S_ABS) { err('r'); ap->a_type = S_ABS; } if (c == '-') ap->a_addr = -ap->a_addr; else ap->a_addr = ~ap->a_addr; return; } if (isdigit(c)) { ap->a_type = S_ABS; r = 10; if (c == '0') { r = 8; if ((c = get()) == 'x') { r = 16; c = get(); } } n = 0; while ((v = digit(c, r)) >= 0) { n = r*n + v; c = get(); } if (c=='f' || c=='b') { if (n < 10) { if (c == 'f') tp = tsymp[n].t_fp; else tp = tsymp[n].t_bp; if (tp != NULL) { ap->a_addr = tp->t_addr; return; } } err('u'); ap->a_addr = 0; return; } unget(c); ap->a_addr = n; return; } if (isidc(c)) { getid(c, id); if ((sp = lookup(id, 0)) != NULL) { ap->a_type = sp->s_type; ap->a_addr = sp->s_addr; return; } err('u'); ap->a_type = S_ABS; ap->a_addr = 0; return; } err('q'); } digit(c, r) register c, r; { if (r == 16) { if (c >= 'A' && c <= 'F') return (c - 'A' + 10); if (c >= 'a' && c <= 'f') return (c - 'a' + 10); } if (c >= '0' && c <= '9') return (c - '0'); return (-1); } any(c, s) register c; register char *s; { register b; while (b = *s++) if (b == c) return (1); return (0); } list() { register char *wp; register nb; if (lfp==NULL || lmode==NLIST) return; slew(); while (ep < &eb[NERR]) *ep++ = ' '; fprintf(lfp, "%.10s", eb); if (lmode == SLIST) { fprintf(lfp, "%24s%5d %s\n", "", line, ib); return; } fprintf(lfp, hlist?" %04x":" %06o", laddr); if (lmode == ALIST) { fprintf(lfp, "%17s%5d %s\n", "", line, ib); return; } wp = cb; nb = cp - cb; list1(wp, nb, 1); fprintf(lfp, " %5d %s\n", line, ib); while ((nb -= 4) > 0) { wp += 4; slew(); fprintf(lfp, "%17s", ""); list1(wp, nb, 0); putc('\n', lfp); } } list1(wp, nb, f) register char *wp; register nb; { register i; if (nb > 4) nb = 4; for (i=0; i= 60) { fprintf(lfp, "\fZ-80 Assembler, page %d\n", page++); fprintf(lfp, "%s\n\n", tb); lop = 4; } } bcheck(n, f) register n; { if ((n&0200) != 0) n |= ~0377; if (n<-128 || n>127) err(f); } comma() { if (getnb() != ',') err('q'); } getid(c, id) register c; char *id; { register char *p; p = id; do { if (p < &id[NCPS]) *p++ = c; } while (isidc(c=get()) || c=='\'' || (c>='0' && c<='9')); unget(c); while (p < &id[NCPS]) *p++ = 0; } getnb() { register c; while ((c=get())==' ' || c=='\t') ; return (c); } get() { register c; if ((c = *ip) != '\0') ++ip; return (c); } unget(c) { if (c != '\0') --ip; } isdigit(c) register c; { return (c>='0' && c<='9'); } isidc(c) register c; { if (c == '_') return (1); if (c == '.') return (1); if (c>='a' && c<='z') return (1); if (c>='A' && c<='Z') return (1); return (0); } lookup(id, f) char *id; { register struct sym *sp; register char *p1, *p2; sp = sym; while (sp < &sym[nsym]) { p1 = id; p2 = sp->s_name; while (p1 < &id[NCPS]) { if (*p1 != *p2++) break; ++p1; } if (p1 == &id[NCPS]) return (sp); ++sp; } if (f == 0) return (NULL); if (nsym++ >= NSYM) error("Too many symbols!\n"); p1 = id; p2 = sp->s_name; while (p1 < &id[NCPS]) *p2++ = *p1++; sp->s_type = S_UND; sp->s_flag = 0; sp->s_addr = 0; return (sp); } aerr() { err('a'); } err(c) register c; { register char *p; p = eb; while (p < ep) if (c == *p++) return; if (p < &eb[NERR]) { *p++ = c; ep = p; } if (c == 'q') { ++eflag; unwind(); } } diag() { register char *p; p = eb; while (p < ep) printf("%c %04d\n", *p++, line); } outx(x) { outb(x==IX ? 0335 : 0375); } outw(w) register w; { outb(w); outb(w>>8); } outb(b) register b; { if (pass != 0) { if (cp >= &cb[NCODE]) err('z'); else *cp++ = b; if (!nflag) { if (bo>=NBIN || ba+bo!=dot->s_addr) { bflush(); ba = dot->s_addr; bo = 0; } bb[bo++] = b; } } ++dot->s_addr; } bflush() { register b, c, i; if (bo == 0) return; fprintf(ofp, ":%02X%04X00", bo, ba); c = bo + ba + (ba>>8); for (i=0; i