--- /dev/null
+PLATFORM = 68000
+CC = m68k-uclinux-gcc
+ASM = m68k-uclinux-as
+AR = m68k-uclinux-ar
+LINKER = m68k-uclinux-ld
+CFLAGS = -Os -fno-strict-aliasing -fomit-frame-pointer -fno-builtin -Wall -m68000 -I../../../../Library/include -I../../../../Library/include/68000
+LINKER_OPT = -L../../../../Library/libs -lc68000
+LIBGCCDIR = $(dir $(shell $(CC) -print-libgcc-file-name))
+LINKER_OPT += --emit-relocs -L$(LIBGCCDIR) -lgcc -T ../../../../Library/elf2flt.ld
+CRT0 = ../../../../Library/libs/crt0_68000.o
+CRT0NS = ../../../../Library/libs/crt0nostdio_68000.o
+# For now while we get going. Really we want to use some kind of elf2zmagic
+# with relocs.
+ELF2FUZIX = elf2flt
+.SUFFIXES: .c .o
+
+SRCS = as0.c as1.c as2.c as3.c as4.c as5.c as6.c
+
+INCS = as.h
+
+OBJS = $(SRCS:.c=.o)
+
+all: as
+
+$(OBJS): $(INCS)
+
+OBJS = $(SRCS:.c=.o)
+
+$(OBJS): %.o : %.c
+ $(CC) -c $(CFLAGS) $(COPT) $<
+
+as: $(CRT0) $(OBJS)
+ $(LINKER) $^ -o $@.bin $(LINKER_OPT)
+ $(ELF2FUZIX) -o $@ $@.bin
+
+size.report: $(APPS)
+ ls -l $^ > $@
+
+clean:
+ rm -f $(OBJS) $(APPS) $(SRCS:.c=) core *~ *.asm *.lst *.sym *.map *.noi *.lk *.ihx *.tmp *.bin size.report *.o
+
+rmbak:
+ rm -f *~ core
+
--- /dev/null
+PLATFORM = 6809
+CC = m6809-unknown-gcc
+ASM = m6809-unknown-as
+AR = m6809-unknown-ar
+LINKER = m6809-unknown-ld
+CFLAGS = -I../../../../Library/include -I../../../../Library/include/6809 -Wall -pedantic -fno-strict-aliasing
+# Workaround for gcc6809 bug - register copy propagation issue
+CFLAGS += -fno-cprop-registers
+COPT = -Os
+LINKER_OPT = --oformat=raw -L../../../../Library/libs -lc6809
+LIBGCCDIR = $(dir $(shell $(CC) -print-libgcc-file-name))
+LINKER_OPT += -L$(LIBGCCDIR) -lgcc -Map=sh.map
+LINKER_OPT += --script=../../../util/$(TARGET).link
+ASM_OPT = -o
+CRT0 = ../../../../Library/libs/crt0_6809.o
+
+.SUFFIXES: .c .o
+
+
+SRCS = as0.c as1.c as2.c as3.c as4.c as5.c as6.c
+
+INCS = as.h
+
+OBJS = $(SRCS:.c=.o)
+
+all: as
+
+$(OBJS): $(INCS)
+
+$(OBJS): %.o : %.c
+ $(CC) -c $(CFLAGS) $(COPT) $<
+
+as: $(OBJS) $(CRT0)
+ $(LINKER) -o $@ $(LINKER_OPT) $^
+
+clean:
+ rm -f $(OBJS) as $(SRCS:.c=) core *~
+
+rmbak:
+ rm -f *~ core
--- /dev/null
+LINKER = sdcc
+FCC = ../../../../Library/tools/fcc -O2
+PLATFORM =
+#PLATFORM = -tzx128
+
+.SUFFIXES: .c .rel
+
+SRCS = as0.c as1.c as2.c as3.c as4.c as5.c as6.c
+
+INCS = as.h
+
+OBJS = $(SRCS:.c=.rel)
+
+LIBS = ../../../../Library/libs/syslib.lib
+
+all: as
+
+as: $(OBJS)
+ $(FCC) $(PLATFORM) $(OBJS) -o $@
+
+$(OBJS): $(INCS)
+
+.c.rel:
+ $(FCC) $(PLATFORM) -c $<
+
+%: %.rel
+ $(FCC) $(PLATFORM) $< -o $@
+
+clean:
+ rm -f $(OBJS) as $(SRCS:.c=) core *~ *.asm *.lst *.sym *.map *.noi *.lk *.ihx *.tmp *.bin
+
+rmbak:
+ rm -f *~ core
+
--- /dev/null
+Add outraw outrab and use them so that we can generate relocations
+
+Change the output format to some kind of binary folow
+
+Header
+Code
+Data
+BSS
+Symbols
+DebugSymbols (optional copy of local only symbols)
+
+Code/Data is packed as follows (BSS is 0 anyway but you can have a sym in
+BSS)
+
+0 END
+1-223 copy this many bytes
+
+224-239 reserved
+241 relocate next byte low
+242 relocate next byte high
+243 relocate next word (native order)
+ followed by symnum.w
+ followed by data byte/word
+
+Special symnums for versus our own base (for simple relocs) or a different
+byte code (eg 240-247 / 248-255 where latter don't give sym ?)
+
+Future
+
+244 relocate ZP ref (6502)
+245 24bit
+246 32bit
+
+etc
+
+Symbol Table
+type.b seg.b {addr} sym\0
+
+type
+
+bits 0-2 -> size of addr 1-4
+bits 3-6 -> free
+bit 7
+ 0x00 import
+ 0x80 export
+
+
+Write a matching nlist(3) and nm to test the basics
+
--- /dev/null
+/*
+ * Z-80 assembler.
+ * Header file, used by all
+ * parts of the assembler.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <setjmp.h>
+
+/*
+ * Table sizes, etc.
+ */
+#define NCPS 8 /* # of characters in symbol */
+#define NHASH 64 /* # of hash buckets */
+#define HMASK 077 /* Mask for above */
+#define NFNAME 32 /* # of characters in filename */
+#define NERR 10 /* Size of error buffer */
+#define NCODE 128 /* # of characters in code buffer */
+#define NINPUT 128 /* # of characters in input line */
+#define NLPP 60 /* # of lines on a page */
+#define XXXX 0 /* Unused value */
+
+/*
+ * Exit codes.
+ */
+#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
+ * descriptions. Observe the way the
+ * symbol flags hide in the register
+ * field of the address.
+ */
+#define TMREG 0x00FF /* Register code */
+#define TMMDF 0x0001 /* Multidef */
+#define TMASG 0x0002 /* Defined by "=" */
+#define TMMODE 0xFF00 /* Mode */
+#define TMINDIR 0x8000 /* Indirect flag in mode */
+
+#define TNEW 0x0000 /* Virgin */
+#define TUSER 0x0100 /* User name */
+#define TBR 0x0200 /* Byte register */
+#define TWR 0x0300 /* Word register */
+#define TSR 0x0400 /* Special register (I, R) */
+#define TDEFB 0x0500 /* defb */
+#define TDEFW 0x0600 /* defw */
+#define TDEFS 0x0700 /* defs */
+#define TDEFM 0x0800 /* defm */
+#define TORG 0x0900 /* org */
+#define TEQU 0x0A00 /* equ */
+#define TCOND 0x0B00 /* conditional */
+#define TENDC 0x0C00 /* end conditional */
+#define TNOP 0x0F00 /* nop */
+#define TRST 0x1000 /* restarts */
+#define TREL 0x1100 /* djnz, jr */
+#define TRET 0x1200 /* ret */
+#define TJMP 0x1300 /* call, jp */
+#define TPUSH 0x1400 /* push, pop */
+#define TIM 0x1500 /* im */
+#define TIO 0x1600 /* in, out */
+#define TBIT 0x1700 /* set, res, bit */
+#define TSHR 0x1800 /* sl, sr et al */
+#define TINC 0x1900 /* inc, dec */
+#define TEX 0x1A00 /* ex */
+#define TADD 0x1B00 /* add, adc, sbc */
+#define TLD 0x1C00 /* ld */
+#define TCC 0x1D00 /* condition code */
+#define TSUB 0x1E00 /* sub et al */
+
+/*
+ * Registers.
+ */
+#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 IX 8
+#define IY 9
+
+#define BC 0
+#define DE 1
+#define HL 2
+#define SP 3
+#define AF 4
+#define AFPRIME 5
+
+#define I 0
+#define R 1
+
+/*
+ * Condition codes.
+ */
+#define CNZ 0
+#define CZ 1
+#define CNC 2
+#define CC 3
+#define CPO 4
+#define CPE 5
+#define CP 6
+#define CM 7
+
+typedef unsigned int VALUE; /* For symbol values */
+
+/*
+ * Address description.
+ */
+typedef struct ADDR {
+ int a_type; /* Type */
+ VALUE a_value; /* Index offset, etc */
+} ADDR;
+
+/*
+ * Symbol.
+ */
+typedef struct SYM {
+ struct SYM *s_fp; /* Link in hash */
+ char s_id[NCPS]; /* Name */
+ int s_type; /* Type */
+ VALUE s_value; /* Value */
+} 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;
+extern FILE *lfp;
+extern int line;
+extern int lmode;
+extern VALUE laddr;
+extern SYM sym[];
+extern int pass;
+extern SYM *phash[];
+extern SYM *uhash[];
+extern int lflag;
+extern jmp_buf env;
+extern VALUE dot;
+
+extern void asmline(void);
+extern void asmld(void);
+extern ADDR *getldaddr(ADDR *, int *, int *, ADDR *);
+extern void outop(int, ADDR *);
+extern void comma(void);
+extern void istuser(ADDR *);
+extern int ccfetch(ADDR *);
+extern int symhash(char *);
+extern void err(char);
+extern void uerr(char *);
+extern void aerr(void);
+extern void qerr(void);
+extern void storerror(int);
+extern void getid(char *, int);
+extern SYM *lookup(char *, SYM *[], int);
+extern int symeq(char *, char *);
+extern void symcopy(char *, char *);
+extern int get(void);
+extern int getnb(void);
+extern void unget(int);
+extern void getaddr(ADDR *);
+extern void expr1(ADDR *, int, int);
+extern void expr2(ADDR *);
+extern void expr3(ADDR *, int);
+extern void isokaors(ADDR *, int);
+extern void outaw(int);
+extern void outab(int);
+extern void outeof(void);
+extern void outbyte(int);
+extern void outflush(void);
+extern void outhex(int);
+extern void list(void);
+extern void list1(char *, int, int);
+extern void syminit(void);
--- /dev/null
+/*
+ * Z-80 assembler.
+ * Command line processing
+ * and main driver.
+ */
+#include "as.h"
+
+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;
+VALUE dot;
+SYM *phash[NHASH];
+SYM *uhash[NHASH];
+int pass;
+int line;
+jmp_buf env;
+
+
+/*
+ * Make up a file name.
+ * The "sfn" is the source file
+ * name and "dft" is the desired file
+ * type. The finished name is copied
+ * into the "dfn" buffer.
+ */
+void mkname(char *dfn, char *sfn, char *dft)
+{
+ char *p1;
+ char *p2;
+ int c;
+
+ p1 = sfn;
+ while (*p1 != 0)
+ ++p1;
+ while (p1!=sfn && p1[-1]!='/')
+ --p1;
+ p2 = dfn;
+ while ((c = *p1++)!=0 && c!='.')
+ *p2++ = c;
+ *p2++ = '.';
+ p1 = dft;
+ while ((*p2++ = *p1++) != 0);
+}
+
+int main(int argc, char *argv[])
+{
+ char *ifn;
+ char *p;
+ int i;
+ int c;
+ char fn[NFNAME];
+
+ ifn = NULL;
+ for (i=1; i<argc; ++i) {
+ p = argv[i];
+ if (*p == '-') {
+ while ((c = *++p) != 0) {
+ switch (c) {
+ case 'l':
+ ++lflag;
+ break;
+
+ default:
+ fprintf(stderr, "Bad option %c\n", c);
+ exit(BAD);
+ }
+ }
+ } else if (ifn == NULL)
+ ifn = p;
+ else {
+ fprintf(stderr, "Too many source files\n");
+ exit(BAD);
+ }
+ }
+ if (ifn == NULL) {
+ fprintf(stderr, "No source file\n");
+ exit(BAD);
+ }
+ if ((ifp=fopen(ifn, "r")) == NULL) {
+ fprintf(stderr, "%s: cannot open\n", ifn);
+ exit(BAD);
+ }
+ mkname(fn, ifn, "hex");
+ if ((ofp=fopen(fn, "w")) == NULL) {
+ 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) {
+ line = 0;
+ dot = 0;
+ 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();
+ exit(GOOD);
+}
+
--- /dev/null
+/*
+ * Z-80 assembler.
+ * Assemble one line of input.
+ * Knows all the dirt.
+ */
+#include "as.h"
+
+#define OPDJNZ 0x10 /* Opcode: djnz */
+#define OPADD 0x80 /* Opcode: add */
+#define OPDAD 0x09 /* Opcode: dad */
+#define OPADC 0x88 /* Opcode: adc */
+#define OPADCW 0x4A /* Opcode: adc hl */
+#define OPSBCW 0x42 /* Opcode: sbc hl */
+#define OPSUBI 0xC6 /* Opcode: make immediate */
+#define OPXCHG 0xEB /* Opcode: xchg */
+#define OPXTHL 0xE3 /* Opcode: xthl */
+#define OPEXAF 0x08 /* Opcode: ex af,af' */
+#define OPRST 0xC7 /* Opcode: rst 0 */
+#define OPINCRP 0x03 /* Opcode: inc rp */
+#define OPDECRP 0x0B /* Opcode: dec rp */
+#define OPINC 0x04 /* Opcode: inc */
+#define OPIIN 0x40 /* Opcode: indirect in */
+#define OPIOUT 0x41 /* Opcode: indirect out */
+#define OPIN 0xDB /* Opcode: in */
+#define OPIM 0x46 /* Opcode: im */
+#define OPPCHL 0xE9 /* Opcode: jp (hl) */
+#define OPJP 0xC3 /* Opcode: jp cc base */
+#define OPJR 0x20 /* Opcode: jr cc base */
+#define OPRET 0xC0 /* Opcode: ret cc base */
+
+/*
+ * 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.
+ */
+void asmline(void)
+{
+ SYM *sp;
+ int c;
+ int opcode;
+ int disp;
+ int reg;
+ int srcreg;
+ int cc;
+ VALUE value;
+ int delim;
+ SYM *sp1;
+ char id[NCPS];
+ char id1[NCPS];
+ ADDR a1;
+ ADDR a2;
+
+ laddr = dot;
+ lmode = SLIST;
+loop:
+ if ((c=getnb())=='\n' || c==';')
+ return;
+ if (isalpha(c) == 0)
+ qerr();
+ getid(id, c);
+ if ((c=getnb()) == ':') {
+ sp = lookup(id, uhash, 1);
+ if (pass == 0) {
+ if ((sp->s_type&TMMODE) != TNEW
+ && (sp->s_type&TMASG) == 0)
+ sp->s_type |= TMMDF;
+ sp->s_type &= ~TMMODE;
+ sp->s_type |= TUSER;
+ sp->s_value = dot;
+ } else {
+ if ((sp->s_type&TMMDF) != 0)
+ err('m');
+ if (sp->s_value != dot)
+ err('p');
+ }
+ lmode = ALIST;
+ goto loop;
+ }
+ /*
+ * If the first token is an
+ * id and not an operation code,
+ * assume that it is the name in front
+ * of an "equ" assembler directive.
+ */
+ if ((sp=lookup(id, phash, 0)) == NULL) {
+ getid(id1, c);
+ if ((sp1=lookup(id1, phash, 0)) == NULL
+ || (sp1->s_type&TMMODE) != TEQU) {
+ err('o');
+ return;
+ }
+ getaddr(&a1);
+ istuser(&a1);
+ sp = lookup(id, uhash, 1);
+ if ((sp->s_type&TMMODE) != TNEW
+ && (sp->s_type&TMASG) == 0)
+ err('m');
+ sp->s_type &= ~TMMODE;
+ sp->s_type |= TUSER|TMASG;
+ sp->s_value = a1.a_value;
+ 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);
+ lmode = ALIST;
+ laddr = dot = a1.a_value;
+ break;
+
+ case TDEFB:
+ do {
+ getaddr(&a1);
+ istuser(&a1);
+ outab(a1.a_value);
+ } while ((c=getnb()) == ',');
+ unget(c);
+ break;
+
+ case TDEFW:
+ lmode = WLIST;
+ do {
+ getaddr(&a1);
+ istuser(&a1);
+ outaw(a1.a_value);
+ } while ((c=getnb()) == ',');
+ unget(c);
+ break;
+
+ case TDEFM:
+ if ((delim=getnb()) == '\n')
+ qerr();
+ while ((c=get()) != delim) {
+ if (c == '\n')
+ qerr();
+ outab(c);
+ }
+ break;
+
+ case TDEFS:
+ laddr = dot;
+ lmode = ALIST;
+ getaddr(&a1);
+ istuser(&a1);
+ dot += a1.a_value;
+ break;
+
+ case TNOP:
+ if ((opcode&0xFF00) != 0)
+ outab(opcode >> 8);
+ outab(opcode);
+ break;
+
+ case TRST:
+ getaddr(&a1);
+ istuser(&a1);
+ if (a1.a_value < 8) {
+ outab(OPRST|(a1.a_value<<3));
+ break;
+ }
+ aerr();
+ break;
+
+ case TREL:
+ getaddr(&a1);
+ if ((cc=ccfetch(&a1)) >= 0) {
+ if (opcode==OPDJNZ || cc>=CPO)
+ aerr();
+ opcode = OPJR | (cc<<3);
+ comma();
+ getaddr(&a1);
+ }
+ istuser(&a1);
+ disp = a1.a_value-dot-2;
+ if (disp<-128 || disp>127)
+ aerr();
+ outab(opcode);
+ outab(disp);
+ break;
+
+ case TRET:
+ unget(c = getnb());
+ if (c!='\n' && c!=';') {
+ getaddr(&a1);
+ if ((cc=ccfetch(&a1)) < 0)
+ aerr();
+ opcode = OPRET | (cc<<3);
+ }
+ outab(opcode);
+ break;
+
+ case TJMP:
+ getaddr(&a1);
+ if ((cc=ccfetch(&a1)) >= 0) {
+ opcode = (opcode&0x00C6) | (cc<<3);
+ comma();
+ getaddr(&a1);
+ }
+ if ((a1.a_type&TMMODE) == TBR) {
+ reg = a1.a_type&TMREG;
+ if (reg==M || reg==IX || reg==IY) {
+ if (opcode != OPJP)
+ aerr();
+ outop(OPPCHL, &a1);
+ break;
+ }
+ }
+ istuser(&a1);
+ outab(opcode);
+ outaw(a1.a_value);
+ break;
+
+ case TPUSH:
+ getaddr(&a1);
+ if ((a1.a_type&TMMODE) == TWR) {
+ reg = a1.a_type&TMREG;
+ switch (reg) {
+ case IX:
+ outab(0xDD);
+ reg = HL;
+ break;
+ case IY:
+ outab(0xFD);
+ reg = HL;
+ break;
+ case AF:
+ reg = SP;
+ break;
+ case SP:
+ case AFPRIME:
+ aerr();
+ }
+ outab(opcode|(reg<<4));
+ break;
+ }
+ aerr();
+ break;
+
+ case TIM:
+ getaddr(&a1);
+ istuser(&a1);
+ if ((value=a1.a_value) > 2)
+ aerr();
+ else if (value != 0)
+ ++value;
+ outab(0xED);
+ outab(OPIM|(value<<3));
+ break;
+
+ case TIO:
+ getaddr(opcode==OPIN ? &a1 : &a2);
+ comma();
+ getaddr(opcode==OPIN ? &a2 : &a1);
+ if (a1.a_type==(TBR|A) && a2.a_type==(TUSER|TMINDIR)) {
+ outab(opcode);
+ outab(a2.a_value);
+ break;
+ }
+ 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();
+ outab(0xED);
+ if (opcode == OPIN)
+ opcode = OPIIN; else
+ opcode = OPIOUT;
+ outab(opcode|(reg<<3));
+ break;
+ }
+ aerr();
+ break;
+
+ case TBIT:
+ getaddr(&a1);
+ comma();
+ getaddr(&a2);
+ if ((a1.a_type&TMMODE) == TUSER
+ && a1.a_value < 8
+ && (a2.a_type&TMMODE) == TBR) {
+ if ((reg=a2.a_type&TMREG)==IX || reg==IY)
+ reg = M;
+ outop(opcode|(a1.a_value<<3)|reg, &a2);
+ break;
+ }
+ aerr();
+ break;
+
+ case TSHR:
+ getaddr(&a1);
+ if ((a1.a_type&TMMODE) == TBR) {
+ if ((reg=a1.a_type&TMREG)==IX || reg==IY)
+ reg = M;
+ outop(opcode|reg, &a1);
+ break;
+ }
+ aerr();
+
+ case TINC:
+ getaddr(&a1);
+ if ((a1.a_type&TMMODE) == TWR) {
+ reg = a1.a_type&TMREG;
+ switch (reg) {
+ case IX:
+ outab(0xDD);
+ reg = HL;
+ break;
+ case IY:
+ outab(0xFD);
+ reg = HL;
+ break;
+ case AF:
+ case AFPRIME:
+ aerr();
+ }
+ if (opcode == OPINC)
+ opcode = OPINCRP; else
+ opcode = OPDECRP;
+ outab(opcode|(reg<<4));
+ break;
+ }
+ if ((a1.a_type&TMMODE) == TBR) {
+ if ((reg=a1.a_type&TMREG)==IX || reg==IY)
+ reg = M;
+ outop(opcode|(reg<<3), &a1);
+ break;
+ }
+ aerr();
+ break;
+
+ case TEX:
+ getaddr(&a1);
+ comma();
+ getaddr(&a2);
+ if (a1.a_type==(TWR|AF) && a2.a_type==(TWR|AFPRIME)) {
+ outab(OPEXAF);
+ break;
+ }
+ if (a1.a_type == (TWR|DE))
+ opcode = OPXCHG;
+ else if (a1.a_type == (TWR|TMINDIR|SP))
+ opcode = OPXTHL;
+ else
+ aerr();
+ if (a2.a_type == (TWR|HL))
+ outab(opcode);
+ else if (a2.a_type == (TWR|IX)) {
+ outab(0xDD);
+ outab(opcode);
+ } else if (a2.a_type == (TWR|IY)) {
+ outab(0xFD);
+ outab(opcode);
+ } else
+ aerr();
+ break;
+
+ case TSUB:
+ getaddr(&a1);
+ if (a1.a_type == TUSER) {
+ outab(opcode | OPSUBI);
+ outab(a1.a_value);
+ break;
+ }
+ if ((a1.a_type&TMMODE) == TBR) {
+ if ((reg=a1.a_type&TMREG)==IX || reg==IY)
+ reg = M;
+ outop(opcode|reg, &a1);
+ break;
+ }
+ aerr();
+ break;
+
+ case TADD:
+ getaddr(&a1);
+ comma();
+ getaddr(&a2);
+ if (a1.a_type == (TBR|A)) {
+ if (a2.a_type == TUSER) {
+ outab(opcode | OPSUBI);
+ outab(a2.a_value);
+ break;
+ }
+ if ((a2.a_type&TMMODE) == TBR) {
+ if ((reg=a2.a_type&TMREG)==IX || reg==IY)
+ reg = M;
+ outop(opcode|reg, &a1);
+ break;
+ }
+ }
+ if ((a1.a_type&TMMODE) == TWR) {
+ switch(reg = a1.a_type&TMREG) {
+ case IX:
+ if (opcode != OPADD)
+ aerr();
+ outab(0xDD);
+ opcode = OPDAD;
+ srcreg = IX;
+ break;
+ case IY:
+ if (opcode != OPADD)
+ aerr();
+ outab(0xFD);
+ opcode = OPDAD;
+ srcreg = IY;
+ break;
+ case HL:
+ if (opcode == OPADD)
+ opcode = OPDAD;
+ else {
+ outab(0xED);
+ if (opcode == OPADC)
+ opcode = OPADCW;
+ else
+ opcode = OPSBCW;
+ }
+ srcreg = HL;
+ break;
+ default:
+ aerr();
+ }
+ if ((a2.a_type&TMMODE) == TWR) {
+ reg = a2.a_type&TMREG;
+ if (reg==BC || reg==DE || reg==SP) {
+ outab(opcode|(reg<<4));
+ break;
+ }
+ if (reg == srcreg) {
+ outab(opcode|(HL<<4));
+ break;
+ }
+ }
+ }
+ aerr();
+ break;
+
+ case TLD:
+ asmld();
+ break;
+
+ default:
+ err('o');
+ }
+ goto loop;
+}
+
+/*
+ * Handle the dreaded "ld" instruction,
+ * with its dozens of forms, formats and special
+ * encodings. The "getldaddr" routine performs most
+ * of the special stuff for index registers and for
+ * indexing. This layer just screens out the many
+ * cases, and emits the correct bytes.
+ */
+void asmld(void)
+{
+ int mdst;
+ int rdst;
+ int msrc;
+ int rsrc;
+ ADDR *indexap;
+ ADDR dst;
+ ADDR src;
+
+ indexap = NULL;
+ indexap = getldaddr(&dst, &mdst, &rdst, indexap);
+ comma();
+ indexap = getldaddr(&src, &msrc, &rsrc, indexap);
+ if (dst.a_type == (TBR|A)) {
+ if (msrc == TSR) {
+ if (rsrc == I)
+ outaw(0x57ED); /* ld a,i */
+ else
+ outaw(0x5FED); /* ld a,r */
+ return;
+ }
+ if (msrc == (TMINDIR|TUSER)) {
+ outab(0x3A); /* lda */
+ outaw(src.a_value);
+ return;
+ }
+ if (msrc == (TMINDIR|TWR)) {
+ if (rsrc==BC || rsrc==DE) {
+ outab(0x0A|(rsrc<<4)); /* ldax */
+ return;
+ }
+ }
+ }
+ if (src.a_type == (TBR|A)) {
+ if (mdst == TSR) {
+ if (rdst == I)
+ outaw(0x47ED); /* ld i,a */
+ else
+ outaw(0x4FED); /* ld r,a */
+ return;
+ }
+ if (mdst == (TMINDIR|TUSER)) {
+ outab(0x32); /* sta */
+ outaw(dst.a_value);
+ return;
+ }
+ if (mdst == (TMINDIR|TWR)) {
+ if (rdst==BC || rdst==DE) {
+ outab(0x02|(rdst<<4)); /* stax */
+ return;
+ }
+ }
+ }
+ if (dst.a_type==(TWR|SP) && msrc==TWR) {
+ if (rsrc == HL) {
+ outab(0xF9); /* sphl */
+ return;
+ }
+ }
+ if (msrc == TUSER) {
+ if (mdst == TBR) {
+ outab(0x06|(rdst<<3)); /* mvi */
+ if (indexap != NULL)
+ outab(indexap->a_value);
+ outab(src.a_value);
+ return;
+ }
+ if (mdst == TWR) {
+ outab(0x01|(rdst<<4)); /* lxi */
+ outaw(src.a_value);
+ return;
+ }
+ }
+ if (mdst==TWR && msrc==(TMINDIR|TUSER)) {
+ if (rdst == HL)
+ outab(0x2A); /* lhld */
+ else
+ outaw(0x4BED|(rdst<<12)); /* ld rp,(ppqq) */
+ outaw(src.a_value);
+ return;
+ }
+ if (mdst==(TMINDIR|TUSER) && msrc==TWR) {
+ if (rsrc == HL)
+ outab(0x22); /* shld */
+ else
+ outaw(0x43ED|(rsrc<<12)); /* ld (ppqq),rp */
+ outaw(dst.a_value);
+ return;
+ }
+ if (mdst==TBR && msrc==TBR && (rdst!=M || rsrc!=M)) {
+ outab(0x40|(rdst<<3)|rsrc);
+ if (indexap != NULL)
+ outab(indexap->a_value);
+ return;
+ }
+ aerr();
+}
+
+/*
+ * Read in addresses for "ld"
+ * instructions. Split off the mode
+ * and the register name. Adjust the register
+ * name to correctly deal with the index registers
+ * and for indexed addressing modes. Return the address
+ * pointer "ap" if indexing is required, otherwise just
+ * pass the "iap" through.
+ */
+ADDR *getldaddr(ADDR *ap, int *modep, int *regp, ADDR *iap)
+{
+ int mode;
+ int reg;
+
+ getaddr(ap);
+ mode = ap->a_type&TMMODE;
+ reg = ap->a_type&TMREG;
+ switch (ap->a_type) {
+ case TBR|IX:
+ outab(0xDD);
+ reg = M;
+ iap = ap;
+ break;
+
+ case TBR|IY:
+ outab(0xFD);
+ reg = M;
+ iap = ap;
+ break;
+
+ case TWR|IX:
+ outab(0xDD);
+ reg = HL;
+ break;
+
+ case TWR|IY:
+ outab(0xFD);
+ reg = HL;
+ break;
+
+ case TWR|AF:
+ case TWR|AFPRIME:
+ aerr();
+ reg = HL;
+ }
+ *modep = mode;
+ *regp = reg;
+ return (iap);
+}
+
+/*
+ * Output an opcode, surrounded
+ * by the index prefix bytes and the
+ * index displacement byte. Look at
+ * the address mode to see if the bytes
+ * are needed.
+ */
+void outop(int op, ADDR *ap)
+{
+ int needisp;
+
+ needisp = 0;
+ if (ap->a_type == (TBR|IX)) {
+ outab(0xDD);
+ needisp = 1;
+ } else if (ap->a_type == (TBR|IY)) {
+ outab(0xFD);
+ needisp = 1;
+ }
+ if ((op&0xFF00) != 0) {
+ outab(op>>8);
+ if (needisp != 0) {
+ outab(ap->a_value);
+ needisp = 0;
+ }
+ }
+ outab(op);
+ if (needisp != 0)
+ outab(ap->a_value);
+}
+
+/*
+ * The next character
+ * in the input must be a comma
+ * or it is a fatal error.
+ */
+void comma(void)
+{
+ if (getnb() != ',')
+ qerr();
+}
+
+/*
+ * Check if the mode of
+ * an ADDR is TUSER. If not, give
+ * an error.
+ */
+void istuser(ADDR *ap)
+{
+ if ((ap->a_type&TMMODE) != TUSER)
+ aerr();
+}
+
+/*
+ * Try to interpret an "ADDR"
+ * as a condition code name. Return
+ * the condition, or "-1" if it cannot
+ * be interpreted as a condition. The
+ * "c" condition is a pain.
+ */
+int ccfetch(ADDR *ap)
+{
+ if (ap->a_type == (TBR|C))
+ return (CC);
+ if ((ap->a_type&TMMODE) == TCC)
+ return (ap->a_type&TMREG);
+ return (-1);
+}
--- /dev/null
+/*
+ * Z-80 assembler.
+ * Symbol table routines
+ * and error handling.
+ */
+#include "as.h"
+
+/*
+ * Given a pointer to a
+ * sumbol, compute the hash bucket
+ * number. The "add all the characters
+ * and take the result modulo the table
+ * size" algorithm is used.
+ */
+int symhash(char *id)
+{
+ int hash;
+ int n;
+
+ hash = 0;
+ n = NCPS;
+ do {
+ hash += *id++;
+ } while (--n);
+ return (hash&HMASK);
+}
+
+/*
+ * Handle an error.
+ * If no listing file, write out
+ * the error directly. Otherwise save
+ * the error in the error buffer.
+ */
+void err(char c)
+{
+ if (pass != 0) {
+ if (lflag != 0)
+ storerror(c);
+ else
+ printf("%04d %c\n", line, c);
+ }
+ 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.
+ */
+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)
+{
+ err('a');
+}
+
+/*
+ * 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)
+{
+ char *p;
+
+ p = &eb[0];
+ while (p < ep)
+ if (*p++ == c)
+ return;
+ if (p < &eb[NERR]) {
+ *p++ = c;
+ ep = p;
+ }
+}
+
+/*
+ * Read identifier.
+ * The character "c" is the first
+ * character of the name.
+ */
+void getid(char *id, int c)
+{
+ char *p;
+
+ if (c < 0) {
+ c = getnb();
+ if (isalpha(c) == 0)
+ qerr();
+ }
+ p = &id[0];
+ do {
+ if (p < &id[NCPS]) {
+ if (isupper(c))
+ c = tolower(c);
+ *p++ = c;
+ }
+ if ((c = *ip) != '\n')
+ ++ip;
+ } while (c=='\'' || isalnum(c)!=0);
+ if (c != '\n')
+ --ip;
+ while (p < &id[NCPS])
+ *p++ = 0;
+}
+
+/*
+ * Lookup symbol in
+ * hash table "htable".
+ * If not there, and "cf" is
+ * true, create it.
+ */
+SYM *lookup(char *id, SYM *htable[], int cf)
+{
+ SYM *sp;
+ int hash;
+
+ hash = symhash(id);
+ sp = htable[hash];
+ while (sp != NULL) {
+ if (symeq(id, sp->s_id))
+ return (sp);
+ sp = sp->s_fp;
+ }
+ if (cf != 0) {
+ if ((sp=(SYM *)malloc(sizeof(SYM))) == NULL) {
+ fprintf(stderr, "No memory\n");
+ exit(BAD);
+ }
+ sp->s_fp = htable[hash];
+ htable[hash] = sp;
+ sp->s_type = TNEW;
+ sp->s_value = 0;
+ symcopy(sp->s_id, id);
+ }
+ return (sp);
+}
+
+/*
+ * Compare two names.
+ * Each are blocks of "NCPS"
+ * bytes. True return if the names
+ * are exactly equal.
+ */
+int symeq(char *p1, char *p2)
+{
+ int n;
+
+ n = NCPS;
+ do {
+ if (*p1++ != *p2++)
+ return (0);
+ } while (--n);
+ return (1);
+}
+
+/*
+ * Copy the characters
+ * that make up the name of a
+ * symbol.
+ */
+void symcopy(char *p1, char *p2)
+{
+ int n;
+
+ n = NCPS;
+ do {
+ *p1++ = *p2++;
+ } while (--n);
+}
+
+/*
+ * Get the next character
+ * from the input buffer. Do not
+ * step past the newline.
+ */
+int get(void)
+{
+ int c;
+
+ if ((c = *ip) != '\n')
+ ++ip;
+ return (c);
+}
+
+/*
+ * Get the next non
+ * whitespace character from
+ * the input buffer. Do not step
+ * past the newline.
+ */
+int getnb(void)
+{
+ int c;
+
+ while ((c = *ip)==' ' || c=='\t')
+ ++ip;
+ if (c != '\n')
+ ++ip;
+ return (c);
+}
+
+/*
+ * Put a character back.
+ */
+void unget(int c)
+{
+ if (c != '\n')
+ --ip;
+}
--- /dev/null
+/*
+ * Z-80 assembler.
+ * Read in expressions in
+ * address fields.
+ */
+#include "as.h"
+
+#define LOPRI 0
+#define ADDPRI 1
+#define MULPRI 2
+#define HIPRI 3
+
+/*
+ * Read in an address
+ * descriptor, and fill in
+ * the supplied "ADDR" structure
+ * with the mode and value.
+ * Exits directly to "qerr" if
+ * there is no address field or
+ * if the syntax is bad.
+ */
+void getaddr(ADDR *ap)
+{
+ int reg;
+ int c;
+
+ if ((c=getnb()) != '(') {
+ unget(c);
+ expr1(ap, LOPRI, 0);
+ return;
+ }
+ expr1(ap, LOPRI, 1);
+ if (getnb() != ')')
+ qerr();
+ reg = ap->a_type&TMREG;
+ switch (ap->a_type&TMMODE) {
+ case TBR:
+ if (reg != C)
+ aerr();
+ ap->a_type |= TMINDIR;
+ break;
+ case TSR:
+ case TCC:
+ aerr();
+ break;
+ case TUSER:
+ ap->a_type |= TMINDIR;
+ break;
+ case TWR:
+ if (reg == HL)
+ ap->a_type = TBR|M;
+ else if (reg==IX || reg==IY)
+ ap->a_type = TBR|reg;
+ else if (reg==AF || reg==AFPRIME)
+ aerr();
+ else
+ ap->a_type |= TMINDIR;
+ }
+}
+
+/*
+ * Expression reader,
+ * real work, part I. Read
+ * operators and resolve types.
+ * The "lpri" is the firewall operator
+ * priority, which stops the scan.
+ * The "paren" argument is true if
+ * the expression is in parentheses.
+ */
+void expr1(ADDR *ap, int lpri, int paren)
+{
+ int c;
+ int opri;
+ ADDR right;
+
+ expr2(ap);
+ while ((c=getnb())=='+' || c=='-' || c=='*' || c=='/') {
+ opri = ADDPRI;
+ if (c=='*' || c=='/')
+ opri = MULPRI;
+ if (opri <= lpri)
+ break;
+ expr1(&right, opri, paren);
+ switch (c) {
+ case '+':
+ if ((ap->a_type&TMMODE) != TUSER)
+ istuser(&right);
+ else
+ ap->a_type = right.a_type;
+ isokaors(ap, paren);
+ ap->a_value += right.a_value;
+ break;
+ case '-':
+ istuser(&right);
+ isokaors(ap, paren);
+ ap->a_value -= right.a_value;
+ break;
+ case '*':
+ istuser(ap);
+ istuser(&right);
+ ap->a_value *= right.a_value;
+ break;
+ case '/':
+ istuser(ap);
+ istuser(&right);
+ ap->a_value /= right.a_value;
+ }
+ }
+ unget(c);
+}
+
+/*
+ * Expression reader,
+ * real work, part II. Read
+ * in terminals.
+ */
+void expr2(ADDR *ap)
+{
+ int c;
+ SYM *sp;
+ int mode;
+ char id[NCPS];
+
+ c = getnb();
+ if (c == '[') {
+ expr1(ap, LOPRI, 0);
+ if (getnb() != ']')
+ qerr();
+ return;
+ }
+ if (c == '-') {
+ expr1(ap, HIPRI, 0);
+ istuser(ap);
+ ap->a_value = -ap->a_value;
+ return;
+ }
+ if (c == '~') {
+ expr1(ap, HIPRI, 0);
+ istuser(ap);
+ ap->a_value = ~ap->a_value;
+ return;
+ }
+ if (c == '\'') {
+ ap->a_type = TUSER;
+ ap->a_value = get();
+ while ((c=get()) != '\'') {
+ if (c == '\n')
+ qerr();
+ ap->a_value = (ap->a_value<<8) + c;
+ }
+ return;
+ }
+ if (c>='0' && c<='9') {
+ expr3(ap, c);
+ return;
+ }
+ if (isalpha(c)) {
+ getid(id, c);
+ if ((sp=lookup(id, uhash, 0)) == NULL
+ && (sp=lookup(id, phash, 0)) == NULL)
+ sp = lookup(id, uhash, 1);
+ mode = sp->s_type&TMMODE;
+ if (mode==TBR || mode==TWR || mode==TSR || mode==TCC) {
+ ap->a_type = mode|sp->s_value;
+ ap->a_value = 0;
+ return;
+ }
+ if (mode == TNEW)
+ uerr(id);
+ ap->a_type = TUSER;
+ ap->a_value = sp->s_value;
+ return;
+ }
+ qerr();
+}
+
+/*
+ * Read in a constant. The argument
+ * "c" is the first character of the constant,
+ * and has already been validated. The number is
+ * gathered up (stopping on non alphanumeric).
+ * The radix is determined, and the number is
+ * converted to binary.
+ */
+void expr3(ADDR *ap, int c)
+{
+ char *np1;
+ char *np2;
+ int radix;
+ VALUE value;
+ char num[40];
+
+ np1 = &num[0];
+ do {
+ if (isupper(c))
+ c = tolower(c);
+ *np1++ = c;
+ c = *ip++;
+ } while (isalnum(c));
+ --ip;
+ switch (*--np1) {
+ case 'h':
+ radix = 16;
+ break;
+ case 'o':
+ case 'q':
+ radix = 8;
+ break;
+ case 'b':
+ radix = 2;
+ break;
+ default:
+ radix = 10;
+ ++np1;
+ }
+ np2 = &num[0];
+ value = 0;
+ while (np2 < np1) {
+ if ((c = *np2++)>='0' && c<='9')
+ c -= '0';
+ else if (c>='a' && c<='f')
+ c -= 'a'-10;
+ else
+ err('n');
+ if (c >= radix)
+ err('n');
+ value = radix*value + c;
+ }
+ ap->a_type = TUSER;
+ ap->a_value = value;
+}
+
+/*
+ * Make sure that the
+ * mode and register fields of
+ * the type of the "ADDR" pointed to
+ * by "ap" can participate in an addition
+ * or a subtraction.
+ */
+void isokaors(ADDR *ap, int paren)
+{
+ int mode;
+ int reg;
+
+ mode = ap->a_type&TMMODE;
+ if (mode == TUSER)
+ return;
+ if (mode==TWR && paren!=0) {
+ reg = ap->a_type&TMREG;
+ if (reg==IX || reg==IY)
+ return;
+ }
+ aerr();
+}
--- /dev/null
+/*
+ * Z-80 assembler.
+ * Output Intel compatable
+ * hex files.
+ */
+#include "as.h"
+
+#define NHEX 32 /* Longest record */
+
+VALUE hexla;
+VALUE hexpc;
+char hexb[NHEX];
+char *hexp = &hexb[0];
+
+/*
+ * Output a word. Use the
+ * standard Z-80 ordering (low
+ * byte then high byte).
+ */
+void outaw(int w)
+{
+ outab(w);
+ outab(w >> 8);
+}
+
+/*
+ * Output an absolute
+ * byte to the code and listing
+ * streams.
+ */
+void outab(int b)
+{
+ if (pass != 0) {
+ if (cp < &cb[NCODE])
+ *cp++ = b;
+ outbyte(b);
+ }
+ ++dot;
+}
+
+/*
+ * Put out the end of file
+ * hex item at the very end of
+ * the object file.
+ */
+void outeof(void)
+{
+ outflush();
+ fprintf(ofp, ":00000001FF\n");
+}
+
+/*
+ * Output a hex byte. Flush
+ * the buffer if no room. Store the
+ * byte in the buffer, for future
+ * checksumming. Remember the load
+ * address for flushing.
+ */
+void outbyte(int b)
+{
+ if (hexp>=&hexb[NHEX] || hexpc!=dot) {
+ outflush();
+ hexp = &hexb[0];
+ }
+ if (hexp == &hexb[0]) {
+ hexla = dot;
+ hexpc = dot;
+ }
+ *hexp++ = b;
+ ++hexpc;
+}
+
+/*
+ * Flush out a block of
+ * code to the hex file. Figure
+ * out the length word and the
+ * checksum byte.
+ */
+void outflush(void)
+{
+ char *p;
+ int b;
+ int c;
+
+ if ((b = hexp-&hexb[0]) != 0) {
+ putc(':', ofp);
+ outhex(b);
+ outhex(hexla >> 8);
+ outhex(hexla);
+ outhex(0);
+ c = b + (hexla>>8) + hexla;
+ p = &hexb[0];
+ while (p < hexp) {
+ b = *p++;
+ outhex(b);
+ c += b;
+ }
+ outhex(-c);
+ putc('\n', ofp);
+ }
+}
+
+/*
+ * Put out "b", as a
+ * two character hex value.
+ * We cannot use printf because
+ * of case problems on VMS.
+ * Upper case ascii.
+ */
+void outhex(int b)
+{
+ static const char hex[] = {
+ '0', '1', '2', '3',
+ '4', '5', '6', '7',
+ '8', '9', 'A', 'B',
+ 'C', 'D', 'E', 'F'
+ };
+
+ putc(hex[(b>>4)&0x0F], ofp);
+ putc(hex[b&0x0F], ofp);
+}
--- /dev/null
+/*
+ * 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;
+ }
+ }
+}
--- /dev/null
+/*
+ * Z-80 assembler.
+ * Basic symbol tables.
+ * Contain all of the instructions
+ * and register names.
+ */
+#include "as.h"
+
+/*
+ * This array of symbol nodes
+ * make up the basic symbol table.
+ * The "syminit" routine links these
+ * nodes into the builtin symbol hash
+ * table at start-up time.
+ */
+SYM sym[] = {
+ { 0, "b", TBR, B },
+ { 0, "c", TBR, C },
+ { 0, "d", TBR, D },
+ { 0, "e", TBR, E },
+ { 0, "h", TBR, H },
+ { 0, "l", TBR, L },
+ { 0, "a", TBR, A },
+ { 0, "bc", TWR, BC },
+ { 0, "de", TWR, DE },
+ { 0, "hl", TWR, HL },
+ { 0, "sp", TWR, SP },
+ { 0, "af", TWR, AF },
+ { 0, "af'", TWR, AFPRIME },
+ { 0, "ix", TWR, IX },
+ { 0, "iy", TWR, IY },
+ { 0, "i", TSR, I },
+ { 0, "r", TSR, R },
+ { 0, "nz", TCC, CNZ },
+ { 0, "z", TCC, CZ },
+ { 0, "nc", TCC, CNC },
+ { 0, "po", TCC, CPO },
+ { 0, "pe", TCC, CPE },
+ { 0, "p", TCC, CP },
+ { 0, "m", TCC, CM },
+ { 0, "defb", TDEFB, XXXX },
+ { 0, "defw", TDEFW, XXXX },
+ { 0, "defs", TDEFS, XXXX },
+ { 0, "defm", TDEFM, XXXX },
+ { 0, "org", TORG, XXXX },
+ { 0, "equ", TEQU, XXXX },
+ { 0, "cond", TCOND, XXXX },
+ { 0, "endc", TENDC, XXXX },
+ { 0, "nop", TNOP, 0x0000 },
+ { 0, "rlca", TNOP, 0x0007 },
+ { 0, "rrca", TNOP, 0x000F },
+ { 0, "rla", TNOP, 0x0017 },
+ { 0, "rra", TNOP, 0x001F },
+ { 0, "daa", TNOP, 0x0027 },
+ { 0, "cpl", TNOP, 0x002F },
+ { 0, "scf", TNOP, 0x0037 },
+ { 0, "ccf", TNOP, 0x003F },
+ { 0, "halt", TNOP, 0x0076 },
+ { 0, "exx", TNOP, 0x00D9 },
+ { 0, "di", TNOP, 0x00F3 },
+ { 0, "ei", TNOP, 0x00FB },
+ { 0, "neg", TNOP, 0xED44 },
+ { 0, "retn", TNOP, 0xED45 },
+ { 0, "reti", TNOP, 0xED4D },
+ { 0, "rrd", TNOP, 0xED67 },
+ { 0, "rld", TNOP, 0xED6F },
+ { 0, "ldi", TNOP, 0xEDA0 },
+ { 0, "cpi", TNOP, 0xEDA1 },
+ { 0, "ini", TNOP, 0xEDA2 },
+ { 0, "outi", TNOP, 0xEDA3 },
+ { 0, "ldd", TNOP, 0xEDA8 },
+ { 0, "cpd", TNOP, 0xEDA9 },
+ { 0, "ind", TNOP, 0xEDAA },
+ { 0, "outd", TNOP, 0xEDAB },
+ { 0, "ldir", TNOP, 0xEDB0 },
+ { 0, "cpir", TNOP, 0xEDB1 },
+ { 0, "inir", TNOP, 0xEDB2 },
+ { 0, "otir", TNOP, 0xEDB3 },
+ { 0, "lddr", TNOP, 0xEDB8 },
+ { 0, "cpdr", TNOP, 0xEDB9 },
+ { 0, "indr", TNOP, 0xEDBA },
+ { 0, "otdr", TNOP, 0xEDBB },
+ { 0, "rst", TRST, XXXX },
+ { 0, "djnz", TREL, 0x0010 },
+ { 0, "jr", TREL, 0x0018 },
+ { 0, "ret", TRET, 0x00C9 },
+ { 0, "call", TJMP, 0x00CD },
+ { 0, "jp", TJMP, 0x00C3 },
+ { 0, "push", TPUSH, 0x00C5 },
+ { 0, "pop", TPUSH, 0x00C1 },
+ { 0, "im", TIM, XXXX },
+ { 0, "in", TIO, 0x00DB },
+ { 0, "out", TIO, 0x00D3 },
+ { 0, "bit", TBIT, 0xCB40 },
+ { 0, "res", TBIT, 0xCB80 },
+ { 0, "set", TBIT, 0xCBC0 },
+ { 0, "rlc", TSHR, 0xCB00 },
+ { 0, "rrc", TSHR, 0xCB08 },
+ { 0, "rl", TSHR, 0xCB10 },
+ { 0, "rr", TSHR, 0xCB18 },
+ { 0, "sla", TSHR, 0xCB20 },
+ { 0, "sra", TSHR, 0xCB28 },
+ { 0, "srl", TSHR, 0xCB38 },
+ { 0, "inc", TINC, 0x0004 },
+ { 0, "dec", TINC, 0x0005 },
+ { 0, "ex", TEX, XXXX },
+ { 0, "add", TADD, 0x0080 },
+ { 0, "adc", TADD, 0x0088 },
+ { 0, "sbc", TADD, 0x0098 },
+ { 0, "sub", TSUB, 0x0090 },
+ { 0, "and", TSUB, 0x00A0 },
+ { 0, "xor", TSUB, 0x00A8 },
+ { 0, "or", TSUB, 0x00B0 },
+ { 0, "cp", TSUB, 0x00B8 },
+ { 0, "ld", TLD, XXXX }
+};
+
+/*
+ * Set up the symbol table.
+ * Sweep through the initializations
+ * of the "phash", and link them into the
+ * buckets. Because it is here, a
+ * "sizeof" works.
+ */
+void syminit(void)
+{
+ SYM *sp;
+ int hash;
+
+ sp = &sym[0];
+ while (sp < &sym[sizeof(sym)/sizeof(SYM)]) {
+ hash = symhash(sp->s_id);
+ sp->s_fp = phash[hash];
+ phash[hash] = sp;
+ ++sp;
+ }
+}