as: incomplete 6809 code
authorAlan Cox <alan@linux.intel.com>
Thu, 2 Nov 2017 18:17:11 +0000 (18:17 +0000)
committerAlan Cox <alan@linux.intel.com>
Thu, 2 Nov 2017 18:17:11 +0000 (18:17 +0000)
Doesn't build yet but I figure we might as well make all of our platforms
able to use the same object file format, linker, library tools for self hosting
work.

Applications/MWC/cmd/asz80/as.h
Applications/MWC/cmd/asz80/as1-6809.c [new file with mode: 0644]
Applications/MWC/cmd/asz80/as6-6809.c [new file with mode: 0644]

index e562ed8..1d37c48 100644 (file)
@@ -345,6 +345,109 @@ typedef   uint32_t        VALUE;          /* For symbol values */
 #define BAD_PCREL      BRA_RANGE
 #define        SEGMENT_CLASH   31
 
+#elif TARGET_6809
+
+typedef        uint16_t        VALUE;          /* For symbol values */
+
+#define NSEGMENT 4                     /* # of segments */
+
+#define ARCH OA_6809
+#define ARCH_FLAGS 0
+
+#define TARGET_BIGENDIAN
+#define TARGET_USES_SQUARE
+
+/*
+ * 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   0x007F                  /* Register code */
+#define        TMMDF   0x0001                  /* Multidef */
+#define        TMASG   0x0002                  /* Defined by "=" */
+#define        TMMODE  0xFF00                  /* Mode */
+#define        TMINDIR 0x8000                  /* Indirect flag in mode */
+#define TPUBLIC        0x0080                  /* Exported symbol */
+
+#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 TSEGMENT 0x0D00                        /* segments by number */
+#define TEXPORT 0x0E00                 /* symbol export */
+/* CPU specific codes */
+#define THI    0x1100                  /* all modes opcodes 0x80+ */
+#define THIW   0x1200                  /* ditto word mode */
+#define THINOIMM 0x1300                        /* ditto byte no immediate */
+#define THIWNOIMM 0x1400               /* ditto word no immediate */
+#define TIMM8  0x1500                  /* 8bit immediate only */
+#define TEXG   0x1600                  /* registers as 8bit immediate */
+#define TPUSH  0x1700                  /* register mask as 8bit immediate */
+#define TIMP   0x1800                  /* implied by instruction */
+#define TLO    0x1900                  /* low instructions with some modes */
+#define TLEA   0x1A00                  /* lea */
+#define TBR    0x1B00                  /* branch */
+#define TLBR   0x1C00                  /* long branch */
+
+#define TAIMM  0x0000                  /* #x :immediate mode 8bit */
+#define TADIR  0x0010                  /* dp:x */
+#define TAIND  0x0020                  /* Indexed postbyte forms */
+#define TAEXT  0x0030                  /* xx : extended addressing */
+
+/*
+ * Registers.
+ */
+#define        A       0               /* re-arrange to match bit patterns */
+#define        B       1
+#define        DP      2
+#define        CC      3
+#define        D       4
+#define        U       5
+#define        X       6
+#define        Y       7
+#define        S       8
+#define PCR    9
+
+/*
+ *     Error message numbers: FIXME - sort general first
+ */
+
+#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 BRA_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 CONSTANT_RANGE  24
+#define DATA_IN_BSS     25
+#define SEGMENT_OVERFLOW 26
+#define DATA_IN_ZP     27
+#define REQUIRE_Z180   28
+#define        SEGMENT_CLASH   29
+
 #else
 #error "Unknown target"
 #endif
diff --git a/Applications/MWC/cmd/asz80/as1-6809.c b/Applications/MWC/cmd/asz80/as1-6809.c
new file mode 100644 (file)
index 0000000..7e08882
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ * Z-80 assembler.
+ * Assemble one line of input.
+ * Knows all the dirt.
+ */
+#include       "as.h"
+
+
+/*
+ * Deal with the syntactic mess 6809 assembler has
+ *
+ * In some cases (JSR JMP and definitions - eg .word)
+ * $ABCD means a constant everywhere else that is #ABCD
+ */
+
+static void constify(ADDR *ap)
+{
+       if ((ap->a_type & TMMODE) == (TUSER|TMINDIR))
+               ap->a_type = TUSER;
+}
+
+static void constant_to_dp(ADDR *ap)
+{
+       if (ap->a_segment != ABSOLUTE || ap->a_sym)
+               return;
+       /* FIMXE: need to support .setdp */
+       if (ap->a_value > 255)
+               return;
+       ap->a_segment = ZP;
+       return;
+}
+
+/*
+ * 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.
+ */
+uint8_t getaddr(ADDR *ap, uint8_t *extbyte, uint8_t size)
+{
+       int c;
+       ADDR tmp;
+       ADDR off;
+
+       ap->a_type = 0;
+       ap->a_flags = 0;
+       ap->a_sym = NULL;
+       
+       c = getnb();
+
+       /* Immediate */
+       if (c == '#') {
+               c = getnb();
+               if (c == '<')
+                       ap->a_flags |= A_LOW;
+               else if (c == '>')
+                       ap->a_flags |= A_HIGH;
+               else
+                       unget(c);
+               expr1(ap, LOPRI, 0);
+               istuser(ap);
+               return size;
+       }
+       
+       /* [xx] */
+       if (c == '[') {
+               getaddr_sub(ap, extbyte, size);
+               c = getnb();
+               if (c != ']')
+                       err('s', SQUARE_EXPECTED);
+               if ((ap->ap_type & TADDR) == TAEXT) {
+                       if (!(*extbyte & 0x80)) {
+                               /* Convert from 5bit to 8bit */
+                               size = 1;
+                               *extbyte &= 0x60;
+                               *extbyte |= 0x88;       /* 8 bit offset */
+                       }
+                       c = (*extbyte & 0x9F);
+                       /* Not allowed to indirect a - / + just -- and ++ */
+                       if (c == 0x80 || c == 0x82)
+                               err('a', INVALID_INDIR);
+                       *extbyte |= 0x10;
+                       ap->a_type |= TAEXT|TMINDIR;
+                       return size;
+               }
+               return;
+       }
+       unget(c);
+       getaddr_sub(ap, extbyte, size, &off);
+}
+
+/*
+ *     Perform the main work of decoding modes that can be direct or
+ *     indrected
+ */
+uint8_t getaddr_sub(ADDR *ap, uint8_t *extbyte, ADDR *off)
+{
+       int reg;
+       int c;
+       ADDR tmp;
+       ADDR off;
+       int index = 0;
+
+       /* ,foo is the same as 0,foo */ 
+       off.a_type = TUSER;
+       off.a_value = 0;
+
+       /* We need to decode
+       
+               reg, reg
+               offset,reg
+               address
+               dp:address
+               autodec(2) reg
+               reg autoinc(2)
+               offset,pc
+        */
+       c =  getnb();
+       if (c != ',') {
+               /* The left of the comma can be a constant or A/B/D register */
+               unget(c);
+               expr1(&off, LOPRI, 0);
+               ireg = reg_expr(ap);
+               if (reg != -1) {
+                       if (ireg != A || ireg != B || ireg != D)
+                               error(INVALID_REGISTER);
+                       index = 2;
+                       /* We are doing reg,index */
+               } else { /* Must be a constant */
+                       istuser(&off);
+                       if (ap->a_value != 0)
+                               index = 1;
+                       c = get();
+                       if (c != ',') {
+                               /* Extended or DP addressing - lda foo */
+                               unget(c);
+                               /* FIXME figure out extbyte etc  */
+                               ap->a_type = TUSER;
+                               ap->a_value = off.a_value;
+                               ap->a_sym = off.a_sym;
+                               ap->a_segment = off.a_segment;
+                               return;
+                       }
+                       unget(c);
+               }
+               comma();
+       }
+
+       /* Afer the comma should be a register but it may have a - -- prefix */ 
+       c = getnb();
+       if (c == '-') {
+               if (index)
+                       aerr(BAD_MODE);
+               extop = 0x82;
+               c = get();
+               if (c == '-')
+                       extop = 0x83;
+               else
+                       unget(c);
+       } else
+               unget(c);
+
+       /* Compute the expression that follows. Should be a register  */
+       expr1(ap, LOPRI, 1);
+
+       reg = reg_expr(ap);
+       if (reg == -1)
+               aerr(BAD_MODE);
+       c = get();
+       if (c == '+') {
+               if (extop || index)     
+                       aerr(BAD_MODE);
+               c = get();
+               extop = 0x81;
+               if (c == '+')
+                       extop = 0x80;
+               else
+                       unget(c);
+       } else
+               unget(c);
+
+       if (index == 2) {
+               /* encode a/b/d, reg */
+               switch(ireg)
+               {
+                       case A:
+                               *extbyte = 0x86;
+                               break;
+                       case B:
+                               *extbyte = 0x85;
+                               break;
+                       case D:
+                               *extbyte = 0x8B;
+                               break;
+                       default:
+                               qerr(SYNTAX_ERROR);
+               }
+               *extbyte |= toindex(reg);
+               return 0;
+       }
+       if (extop) {
+               /* No offset with increment/decrement */        
+               if (index)
+                       aerr(BAD_MDOE);
+               /* --/-/+/++ */
+               *extbyte = extop | toindex(reg);
+               return 0;
+       }
+       /* Simple offset. Only it's not so simple because it might be a
+          symbol that is external. In which case we must assume the worst
+          FIXME: check this logic works for TNEW */
+
+       if (ap->a_segment != ABSOLUTE)
+               off = ap->a_value - dot[segment];
+
+       /* Is this a relocation that we can compute te value of ? */
+       if (ap->a_sym == NULL || (ap->a_type & TMMODE) == TUSER) {
+               /* Is it within our segment or absolute */
+               if (ap->a_segment == segment || ap->a_segment == ABSOLUTE) {
+                       /* In which case we can actually use the short forms */
+                       if (reg != PCR && offset5bit(off)) {
+                               *extbyte = offset5bit(off)|toindex(reg);
+                               return 0;
+                       }
+                       if (offset8bit(off)) {
+                               if (reg == PCR)
+                                       *extbyte = 0x8C;
+                               else
+                                       *extbyte = 0x88 | toindex(reg);
+                               return 1;
+                       }
+               }
+       }
+       /* Otherwise we use the long form to be safe for linking */
+       if (reg == PCR)
+               *extbyte = 0x8D;
+       else
+               *extbyte = 0x89;
+       return 2;
+}
+
+/*
+ * Assemble one line.
+ * The line in in "ib", the "ip"
+ * scans along it. The code is written
+ * right out.
+ */
+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;
+       int user;
+
+loop:
+       if ((c=getnb())=='\n' || c==';')
+               return;
+       if (isalpha(c) == 0 && c != '_' && c != '.')
+               qerr(UNEXPECTED_CHR);
+       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[segment];
+                       sp->s_segment = segment;
+               } else {
+                       if ((sp->s_type&TMMDF) != 0)
+                               err('m', MULTIPLE_DEFS);
+                       if (sp->s_value != dot[segment])
+                               err('p', PHASE_ERROR);
+               }
+               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', SYNTAX_ERROR);
+                       return;
+               }
+               getaddr(&a1);
+               constify(&a1);
+               istuser(&a1);
+               sp = lookup(id, uhash, 1);
+               if ((sp->s_type&TMMODE) != TNEW
+               &&  (sp->s_type&TMASG) == 0)
+                       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 */
+               goto loop;
+       }
+       unget(c);
+       opcode = sp->s_value;
+       switch (sp->s_type&TMMODE) {
+       case TORG:
+               getaddr(&a1);
+               constify(&a1);
+               istuser(&a1);
+               if (a1.a_segment != ABSOLUTE)
+                       qerr(MUST_BE_ABSOLUTE);
+               segment = ABSOLUTE;
+               dot[segment] = a1.a_value;
+               /* Tell the binary generator we've got a new absolute
+                  segment. */
+               outabsolute(a1.a_value);
+               break;
+
+       case TEXPORT:
+               getid(id, getnb());
+               sp = lookup(id, uhash, 1);
+               sp->s_type |= TPUBLIC;
+               break;
+               /* .code etc */
+
+       case TSEGMENT:
+               segment = sp->s_value;
+               /* Tell the binary generator about a segment switch to a non
+                  absolute segnent */
+               outsegment(segment);
+               break;
+
+       case TDEFB:
+               do {
+                       getaddr(&a1);
+                       constify(&a1);
+                       istuser(&a1);
+                       outrab(&a1);
+               } while ((c=getnb()) == ',');
+               unget(c);
+               break;
+
+       case TDEFW:
+               do {
+                       getaddr(&a1);
+                       constify(&a1);
+                       istuser(&a1);
+                       outraw(&a1);
+               } while ((c=getnb()) == ',');
+               unget(c);
+               break;
+
+       case TDEFM:
+               if ((delim=getnb()) == '\n')
+                       qerr(MISSING_DELIMITER);
+               while ((c=get()) != delim) {
+                       if (c == '\n')
+                               qerr(MISSING_DELIMITER);
+                       outab(c);
+               }
+               break;
+
+       case TDEFS:
+               getaddr(&a1);
+               constify(&a1);
+               istuser(&a1);
+               /* Write out the bytes. The BSS will deal with the rest */
+               for (value = 0 ; value < a1.a_value; value++)
+                       outab(0);
+               break;
+
+       case TBRA:
+               /* FIXME: sort out symbols here and on 6502 */
+               getaddr(&a1);
+               disp = a1.a_value-dot[segment]-2;
+               if (disp<-128 || disp>127 || a1.a_segment != segment)
+                       aerr(BRA_RANGE);
+               outab(opcode);
+               outab(disp);
+               break;
+
+       case TLBRA:
+               /* FIXME: support this with symbols */
+               getaddr(&a1);
+               disp = a1.a_value-dot[segment]-2;
+               if (disp<-32768 || disp> 32767 || a1.a_segment != segment)
+                       aerr(LBRA_RANGE);
+               outab(opcode);
+               outab(disp);
+               break;
+
+       case TIMPL:
+               if (opcode >> 8)
+                       outab(opcode >> 8);
+               outab(opcode);
+               break;
+
+       case TLO:
+               size = getaddr(&a1, &ext);
+
+               if (opcode >> 8)
+                       outab(opcode >> 8);
+               switch(a1.a_type & TMADDR) {
+                       case 0:
+                               aerr(NO_IMMEDIATE);
+                               break;
+                       case TEXT:
+                               outab(opcode + 0x70);
+                               outraw(&a1);
+                               break;
+                       case TDP:
+                               outab(opcode);
+                               outrab(&a1);
+                               break;
+                       case TIND:
+                               outab(opcode + 0x60);
+                               outrab(ext);
+                               if (size == 1)
+                                       outrab(&a1);
+                               else if (size == 2)
+                                       outraw(&a1);
+               }
+               break;                          
+       case TLEA:
+               size = getaddr(&a1, &ext);
+               if ((a1.a1_type & TMADDR) != TEXT)
+                       aerr(MUST_BE_INDEXED);
+               outab(opcode);
+               outab(ext);
+               if (size == 1)
+                       outrabs(a1);
+               else if (size == 2)
+                       outraws(a1);
+               break;
+       case THI:
+       case THIW:
+       case THINOIMM:
+       case THIWNOIMM:
+               size = getaddr(&a1, &ext);
+               mode = a1.a1_type & TMADDR;
+
+               if (opcode >> 8)
+                       outab(opcode >> 8);
+
+               switch(mode) {
+                       case 0:
+                               outab(opcode);
+                               switch(sp->s_type & TMMODE) {
+                               case THIW:
+                                       outraw(&a1);
+                                       break;
+                               case THI:
+                                       outrab(&a1);
+                                       break;
+                               default:
+                                       aerr(NO_IMMEDIATE);
+                               }
+                               break;
+                       case TEXT:
+                               outab(opcode + 0x30);
+                               outraw(&a1);
+                               break;
+                       case TDP:
+                               outab(opcode + 0x10);
+                               outrab(&a1);
+                               break;
+                       case TIND:
+                               outab(opcode + 0x20);
+                               outrab(ext);
+                               if (size == 1)
+                                       outrabs(&a1);
+                               else if (size == 2)
+                                       outraws(&a1);
+               }
+               break;
+
+       case TIMM8:
+               getaddr(&a1);
+               istuser(&a1);
+               if (a1.a_value > 255)
+                       aerr(CONSTANT_TOO_LARGE);
+               if (opcode >> 8)
+                       outab(opcode >> 8);
+               outab(opcode);
+               outrab(a1);
+               break;
+
+       case TEXG:
+               r1 = get_register();
+               comma();
+               r2 = get_register();
+               opcode |= ????
+               outab(opcode);
+               break;
+       
+       case TPUSH:
+               mask |= 1 << get_register_mask();
+               while((c = getnb()) == ',') {
+                       mask |= 1 << get_register_mask();
+               unget(c);
+               outab(opcde);
+               outab(mask);
+               break;
+       
+       default:
+               aerr(SYNTAX_ERROR);
+       }
+       goto loop;
+}
diff --git a/Applications/MWC/cmd/asz80/as6-6809.c b/Applications/MWC/cmd/asz80/as6-6809.c
new file mode 100644 (file)
index 0000000..ab3e0d1
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * 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,      "a",            TBR,            A       },
+       {       0,      "b",            TBR,            B       },
+       {       0,      "dp",           TBR,            DP      },
+       {       0,      "cc",           TBR,            CC      },
+       {       0,      "d",            TWR,            D       },
+       {       0,      "u",            TWR,            U       },
+       {       0,      "x",            TWR,            X       },
+       {       0,      "y",            TWR,            Y       },
+       {       0,      "s",            TWR,            S       },
+       {       0,      "pc",           TWR,            PCR     },
+       {       0,      "pcr",          TWR,            PCR     },
+       {       0,      "defw",         TDEFW,          XXXX    },
+       {       0,      "defs",         TDEFS,          XXXX    },
+       {       0,      "defm",         TDEFM,          XXXX    },
+       {       0,      "org",          TORG,           XXXX    },
+       {       0,      "equ",          TEQU,           XXXX    },
+       {       0,      "export",       TEXPORT,        XXXX    },
+       {       0,      ".byte",        TDEFB,          XXXX    },
+       {       0,      ".word",        TDEFW,          XXXX    },
+       {       0,      ".blkb",        TDEFS,          XXXX    },
+       {       0,      ".ascii",       TDEFM,          XXXX    },
+       {       0,      ".org",         TORG,           XXXX    },
+       {       0,      ".equ",         TEQU,           XXXX    },
+       {       0,      ".export",      TEXPORT,        XXXX    },
+       {       0,      "cond",         TCOND,          XXXX    },
+       {       0,      "endc",         TENDC,          XXXX    },
+       {       0,      "code",         TSEGMENT,       CODE    },
+       {       0,      "data",         TSEGMENT,       DATA    },
+       {       0,      "bss",          TSEGMENT,       BSS     },
+       {       0,      ".code",        TSEGMENT,       CODE    },
+       {       0,      ".data",        TSEGMENT,       DATA    },
+       {       0,      ".bss",         TSEGMENT,       BSS     },
+       {       0,      ".dp",          TSEGMENT,       ZP      },
+       {       0,      "adca",         THI,            0x89    },
+       {       0,      "adcb",         THI,            0xC9    },
+       {       0,      "adda",         THI,            0x8B    },
+       {       0,      "addb",         THI,            0xCB    },
+       {       0,      "addd",         THIW,           0xC3    },
+       {       0,      "anda",         THI,            0x84    },
+       {       0,      "andb",         THI,            0xC4    },
+       {       0,      "adcc",         TIMM8,          0x1C    },
+       {       0,      "asla",         TIMP,           0x48    },
+       {       0,      "aslb",         TIMP,           0x58    },
+       {       0,      "asl",          TLO,            0x08    },
+       {       0,      "asra",         TIMP,           0x47    },
+       {       0,      "asrb",         TIMP,           0x57    },
+       {       0,      "asr",          TLO,            0x07    },
+       /* TODO Bxx */
+       {       0,      "bita",         THI,            0x85    },
+       {       0,      "bitb",         THI,            0xC5    },
+       {       0,      "clra",         TIMP,           0x4F    },
+       {       0,      "clrb",         TIMP,           0x5F    },
+       {       0,      "clr",          TLO,            0x0F    },
+       {       0,      "cmpa",         THI,            0x81    },
+       {       0,      "cmpb",         THI,            0xC1    },
+       {       0,      "cmpd",         THIW,           0x1083  },
+       {       0,      "cmps",         THIW,           0x118C  },
+       {       0,      "cmpu",         THIW,           0x1183  },
+       {       0,      "cmpx",         THIW,           0x8C    },
+       {       0,      "cmpy",         THIW,           0x108C  },
+       {       0,      "coma",         TIMP,           0x43    },
+       {       0,      "comb",         TIMP,           0x53    },
+       {       0,      "com",          TLO,            0x03    },
+       {       0,      "cwai",         TIMM8,          0x3C    },
+       {       0,      "daa",          TIMP,           0x19    },
+       {       0,      "deca",         TIMP,           0x4A    },
+       {       0,      "decb",         TIMP,           0x5A    },
+       {       0,      "dec",          TLO,            0x08    },
+       {       0,      "eora",         THI,            0x88    },
+       {       0,      "eorb",         THI,            0xC8    },
+       {       0,      "exg",          TEXG,           0x1E    },
+       {       0,      "inca",         TIMP,           0x4C    },
+       {       0,      "incb",         TIMP,           0x5C    },
+       {       0,      "inc",          TLO,            0x0C    },
+       {       0,      "jmp",          TLO,            0x0E    },
+       {       0,      "jsr",          TLO,            0x9D    },
+       /* TODO: lbxx */
+       {       0,      "lda",          THI,            0x86    },
+       {       0,      "ldb",          THI,            0xC6    },
+       {       0,      "ldd",          THIW,           0xCC    },
+       {       0,      "lds",          THIW,           0x10CE  },
+       {       0,      "ldu",          THIW,           0xCE    },
+       {       0,      "ldx",          THIW,           0x8E    },
+       {       0,      "ldy",          THIW,           0x108E  },
+       {       0,      "leas",         TLEA,           0x32    },
+       {       0,      "leau",         TLEA,           0x33    },
+       {       0,      "leax",         TLEA,           0x30    },
+       {       0,      "leay",         TLEA,           0x31    },
+       {       0,      "lsla",         TIMP,           0x48    },
+       {       0,      "lslb",         TIMP,           0x49    },
+       {       0       "lsl",          TLO,            0x08    },
+       {       0,      "lsra",         TIMP,           0x44    },
+       {       0,      "lsrb",         TIMP,           0x54    },
+       {       0,      "lsr",          TLO,            0x04    },
+       {       0,      "mul",          TIMP,           0x3D    },
+       {       0,      "nega",         TIMP,           0x40    },
+       {       0,      "negb",         TIMP,           0x50    },
+       {       0,      "neg",          TLO,            0x00    },
+       {       0,      "nop",          TIMP,           0x12    },
+       {       0,      "ora",          THI,            0x8A    },
+       {       0,      "orb",          THI,            0xCA    },
+       {       0,      "orcc",         TIMM8,          0x1A    },
+       {       0,      "pshs",         TPUSH,          0x34    },
+       {       0,      "pshu",         TPUSH,          0x36    },
+       {       0,      "puls",         TPUSH,          0x35    },
+       {       0,      "pulu",         TPUSH,          0x37    },
+       {       0,      "rola",         TIMP,           0x49    },
+       {       0,      "rolb",         TIMP,           0x59    },
+       {       0,      "rol",          TLO,            0x09    },
+       {       0,      "rora",         TIMP,           0x46    },
+       {       0,      "rorb",         TIMP,           0x56    },
+       {       0,      "ror",          TLO,            0x06    },
+       {       0,      "rti",          TIMP,           0x3B    },
+       {       0,      "rts",          TIMP,           0x39    },
+       {       0,      "sbca",         THI,            0x82    },
+       {       0,      "sbcb",         THI,            0xC2    },
+       {       0,      "sex",          TIMP,           0x1D    },
+       {       0,      "sta",          THINOIMM,       0x87    },
+       {       0,      "stb",          THINOIMM,       0xC7    },
+       {       0,      "std",          THIWNOIMM,      0xCD    },
+       {       0,      "sts",          THIWNOIMM,      0x10CF  },
+       {       0,      "stu",          THIWNOIMM,      0xCF    },
+       {       0,      "stx",          THIWNOIMM,      0x8F    },
+       {       0,      "sty",          THIWNOIMM,      0x108F  },
+       {       0,      "suba",         THI,            0x80    },
+       {       0,      "subb",         THI,            0xC0    },
+       {       0,      "subd",         THIW,           0x83    },
+       {       0,      "swi",          TIMP,           0x3F    },
+       {       0,      "swi2",         TIMP,           0x103F  },
+       {       0,      "swi3",         TIMP,           0x113F  },
+       {       0,      "sync",         TIMP,           0x13    },
+       {       0,      "tfr",          TEXG,/*check*/  0x1F    },
+       {       0,      "tsta",         TIMP,           0x4D    },
+       {       0,      "tstb",         TIMP,           0x5D    },
+       {       0       "tst",          TLO,            0x0D    },
+};
+
+/*
+ * 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;
+       }
+}
+
+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",
+       "constant out of range",
+       "data in BSS",
+       "segment overflow",
+       "Z180 instruction",
+       "segment conflict"
+};
+
+/*
+ * 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(ADDR_REQUIRED);
+}