as further work
authorAlan Cox <alan@linux.intel.com>
Tue, 31 Oct 2017 20:48:32 +0000 (20:48 +0000)
committerAlan Cox <alan@linux.intel.com>
Tue, 31 Oct 2017 20:48:32 +0000 (20:48 +0000)
- Initial core support for word addressed machines
- Sketch out a compilable DG Nova PoC for this
- PC relative addressing

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

index ad053e4..cb8c766 100644 (file)
@@ -152,6 +152,7 @@ typedef     uint16_t        VALUE;          /* For symbol values */
 #define SEGMENT_OVERFLOW 26
 #define DATA_IN_ZP     27
 #define REQUIRE_Z180   28
+#define        SEGMENT_CLASH   29
 
 
 
@@ -251,7 +252,98 @@ typedef    uint16_t        VALUE;          /* For symbol values */
 #define DATA_IN_BSS     25
 #define SEGMENT_OVERFLOW 26
 #define DATA_IN_ZP     27
+#define        SEGMENT_CLASH   28
 
+#elif TARGET_DGNOVA
+
+#define TARGET_WORD_MACHINE
+
+/* 16 bit machine but we need to track in 32bits to allow for the fact we
+   can be dealing with 2^16 words */
+typedef        uint32_t        VALUE;          /* For symbol values */
+
+#define SEGMENT_LIMIT  0x10000         /* bytes */
+
+#define NSEGMENT 5                     /* # of segments */
+
+#define ARCH OA_DGNOVA
+#define ARCH_FLAGS 0
+
+
+/*
+ * 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   0x000F                  /* 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 */
+#define TCC    0x0F00
+/* CPU specific codes */
+#define TCPUOPT        0x1100
+#define TMEMORY        0x1200
+#define TALU   0x1300
+#define TIO    0x1400
+#define TDEV   0x1500
+#define TAC    0x1600
+#define TIMPL  0x1700
+#define TBYTE  0x1800
+#define TTRAP  0x1900
+
+#define TPCREL 0x0010
+
+/*
+ *     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 BRA_RANGE      17
+#define CONDCODE_ONLY  18
+#define INVALID_REG    19
+#define ADDR_REQUIRED  20
+#define INVALID_ID     21
+#define BADMODE                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 BAD_ACCUMULATOR        28
+#define NEED_ZPABS     29
+#define BADDEVICE      30
+#define BAD_PCREL      BRA_RANGE
+#define        SEGMENT_CLASH   31
 
 #else
 #error "Unknown target"
@@ -275,6 +367,10 @@ typedef    uint16_t        VALUE;          /* For symbol values */
 #define        MULPRI  2
 #define        HIPRI   3
 
+#ifndef SEGMENT_LIMIT
+#define SEGMENT_LIMIT  0
+#endif
+
 /*
  * Address description.
  */
@@ -294,8 +390,9 @@ typedef     struct  SYM     {
        char    s_id[NCPS];             /* Name */
        int     s_type;                 /* Type */
        VALUE   s_value;                /* Value */
+       uint16_t s_number;              /* Symbol number 1..n, also usable for
+                                          tokens as extra data */
        int     s_segment;              /* Segment this symbol is relative to */
-       uint16_t s_number;              /* Symbol number 1..n */
 }      SYM;
 
 /*
@@ -352,6 +449,7 @@ extern void outab(uint8_t);
 extern void outabchk(uint16_t);
 extern void outraw(ADDR *);
 extern void outrab(ADDR *);
+extern void outrabrel(ADDR *);
 extern void outeof(void);
 extern void outbyte(uint8_t);
 extern void outflush(void);
diff --git a/Applications/MWC/cmd/asz80/as1-nova.c b/Applications/MWC/cmd/asz80/as1-nova.c
new file mode 100644 (file)
index 0000000..8db6909
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * DG Nova assembler.
+ * Assemble one line of input.
+ * Knows all the dirt.
+ */
+#include       "as.h"
+
+/*
+ * 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;
+
+       /* We only have one addressing format we ever use.. an address.
+          Quite how we encode it is another saga because our memory ops
+          use register relative or pc relative */
+       c = getnb();
+       if (c != '#')
+               unget(c);
+       expr1(ap, LOPRI, 1);
+       switch (ap->a_type&TMMODE) {
+       case TUSER:
+               break;
+       default:
+               qerr(SYNTAX_ERROR);
+       }
+       if (c == '@')   /* Indirect */
+               ap->a_value |= 0x8000;
+}
+
+static int accumulator(void)
+{
+       int c = getnb();
+       if (c < '0' || c > '3') {
+               aerr(BAD_ACCUMULATOR);
+               unget(c);
+               return 0;
+       }
+       return c - '0';
+}
+
+static int carryop(char c)
+{
+       c = toupper(c);
+       if (c == 'Z')
+               return 1;
+       if (c == 'O')
+               return 2;
+       if (c == 'C')
+               return 3;
+       return 0;
+}
+
+static int postop(char c)
+{
+       c = toupper(c);
+       if (c == 'L')
+               return 1;
+       if (c == 'R')
+               return 2;
+       if (c == 'S')
+               return 3;
+       return 0;
+}
+/*
+ * 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 acs, acd;
+       int opcode;
+       int disp;
+       int reg;
+       int srcreg;
+       int cc;
+       VALUE value;
+       int delim;
+       SYM *sp1;
+       char id[NCPS];
+       char id1[NCPS];
+       char iid[4];
+       ADDR a1;
+       ADDR a2;
+
+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;
+                       /* Word machine so half the byte count */
+                       sp->s_value = dot[segment] >> 1;
+                       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;
+       }
+       /* We have to do ugly things here because the Nova instruction set
+          merges the opcode and flags */
+       memcpy(iid, id, 4);
+       iid[3] = 0;
+       
+       /*
+        * 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 &&
+               (sp = lookup(iid, 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);
+               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);
+               istuser(&a1);
+               if (a1.a_segment != ABSOLUTE)
+                       qerr(MUST_BE_ABSOLUTE);
+               segment = 0;
+               dot[segment] = a1.a_value * 2;  /* dot is in bytes */
+               /* Tell the binary generator we've got a new absolute
+                  segment. */
+               outabsolute(dot[segment]);
+               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 TDEFW:
+               do {
+                       getaddr(&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);
+               }
+               /* Word machine - pad the end */
+               if (dot[segment] & 1)
+                       dot[segment]++;
+               break;
+
+       case TDEFS:
+               getaddr(&a1);
+               istuser(&a1);
+               /* Write out the words. The BSS will deal with the rest */
+               for (value = 0 ; value < a1.a_value; value++)
+                       outaw(0);
+               break;
+
+       case TCPUOPT:
+               cpu_flags |= sp->s_value;
+               break;
+
+       case TMEMORY:
+       {
+               int indirect = 0;
+               /*
+                *      Memory operations are either
+                *      0,disp          Word 0-255 (zero page)
+                *      1,signed disp   PC relative
+                *      2.disp          ac2 + offset
+                *      3,disp          ac3 + offset
+                *
+                *      We don't enforce any rules on ac2/ac3 but encode
+                *      them on the basis the user knows what they are doing
+                *
+                *      0,disp is encoded is an 8 bit relocation for ZP
+                *      1,disp FIXME needs to be encoded as an 8bit PCREL
+                *
+                *      There is *no* immediate load nor is there anyway
+                *      to load arbitrary addresses.
+                *
+                *      FIXME: we need some Nova specific meta ops as a
+                *      result
+                *
+                *      .nomodify       - don't sneak in data words
+                *      .modify         - allowed to sneak in data words
+                *      .local          - local data word
+                *      .flushlocal     - write locals out here
+                *
+                *      local data words are placed in a queue with their
+                *      relocation address. During pass 0 we try to place them
+                *      by adding ,skp to TALU instructions and putting one
+                *      after it. If we reach the point it won't fit we add a
+                *      JMP around the data and load with data. Likewise we
+                *      can fill after a jump.
+                *
+                *      This has its own fun... a jump is itself pcrel or
+                *      constrained. Fortunately however we can encode an
+                *      arbitrary jump as JMP #.+1 and a word. We can't do
+                *      this ourself with JSR but compilers can jmp 3,1
+                *      and do it.
+                *
+                *      For A2/A3 the same way to write stuff is likely to be
+                *
+                *      ; a2 is loaded with foo
+                *
+                *      LDA 1,bar-foo,2
+                *
+                *      and the assembler with turn bar-foo into an ABSOLUTE
+                */
+               acd = accumulator();
+               comma();
+               c = get();
+               if (c == '@')
+                       indirect = 1;
+               else {
+                       unget(c);
+                       indirect = 0;
+               }
+               getaddr(&a1);
+               c = get();
+               disp = 0;
+               if (c == ',')
+                       acs = accumulator();
+               else
+                       unget(c);
+               /* ,0 means zero page */
+               if (acs == 0) {
+                       if (a1.a_segment == UNKNOWN)
+                               a1.a_segment = ZP;
+                       if (a1.a_segment != ZP && a1.a_segment != ABSOLUTE)
+                               aerr(NEED_ZPABS);
+               }
+               /* ,2 + are indexes so we can't really police them for sanity */
+               /* ,1 is PC relative so must be in this segment */
+               if (acs == 1) {
+                       if (a1.a_segment == UNKNOWN)
+                               a1.a_segment = segment;
+                       else if (a1.a_segment != ABSOLUTE && a1.a_segment != segment)
+                               aerr(BAD_PCREL);
+                       if (a1.a_segment != ABSOLUTE)
+                               a1.a_type |= TPCREL;
+               }
+               /* Insert the accumulators */
+               opcode |= (acd << 13);
+               opcode |= (acs << 8);
+               if (indirect)
+                       opcode |= 0x0400;
+               if (acs)
+                       outrabrel(&a1); /* Signed */
+               else if (acs == 0)
+                       outrab(&a1);    /* Unsigned */
+               outab(opcode >> 8);
+               break;
+       }
+
+       case TALU:
+       {
+               char *p = id + 3;
+               SYM *skp = NULL;
+               int drop;
+               int cf;
+               int sh;
+
+               cf = carryop(*p);
+               if (cf)
+                       p++;
+               sh = postop(*p);
+               if (sh)
+                       p++;
+               c = get();
+               if (c == '#')
+                       drop = 1;
+               else {
+                       unget(c);
+                       drop = 0;
+               }
+               acs = accumulator();
+               comma();
+               acd = accumulator();
+               c = getnb();
+               if (c == ',') {
+                       getid(id1,getnb());
+                       skp = lookup(id1, phash, 0);
+                       if (skp == NULL || skp->s_type != TCC)
+                               err('s',SYNTAX_ERROR);
+               } else
+                       unget(c);
+               opcode |= (acs << 13);
+               opcode |= (acd << 11);
+               opcode |= (sh << 6);
+               opcode |= (cf << 4);
+               opcode |= (drop << 3);
+               if (skp)
+                       opcode |= skp->s_value;
+               outaw(opcode);
+               break;
+       }
+
+       case TIO:
+               acs = accumulator();
+               comma();
+               getaddr(&a1);
+               istuser(&a1);
+               if (a1.a_value > 63)
+                       err('d', BADDEVICE);
+               opcode |= (acs << 1);
+               opcode |= a1.a_value;
+               outaw(opcode);
+               break;
+
+       case TDEV:
+               getaddr(&a1);
+               istuser(&a1);
+               if (a1.a_value > 63)
+                       err('d', BADDEVICE);
+               opcode |= a1.a_value;
+               outaw(opcode);
+               break;
+
+       case TAC:
+               acs = accumulator();
+               opcode |= (acs << 11);
+               outaw(opcode);
+               break;
+
+       case TIMPL:
+               outaw(opcode);
+               break;
+
+       case TBYTE:
+               acs = accumulator();
+               comma();
+               acd = accumulator();
+               opcode |= (acd << 11);
+               opcode |= (acs << 6);
+               outaw(opcode);
+               break;
+
+       case TTRAP:
+               acs = accumulator();
+               comma();                
+               acd = accumulator();
+               comma();
+               getaddr(&a1);
+               /* We can't relocate these yet FIXME */
+               istuser(&a1);
+               opcode |= (acs << 15);
+               opcode |= (acd << 13);
+               opcode |= (a1.a_value << 4);
+               outaw(opcode);
+               break;
+       default:
+               aerr(SYNTAX_ERROR);
+       }
+       goto loop;
+}
+
index e455059..a2164c7 100644 (file)
@@ -1,7 +1,12 @@
 /*
- * Z-80 assembler.
- * Output Intel compatable
- * hex files.
+ * Output FUZIX object files for 8/16bit machines.
+ *
+ * Currently we understand little endian 8 and 16bit formats along with
+ * PC relative.
+ *
+ * FIXME: We need to manage dot[segment] properly for word addressed machines
+ * so that we track and write in words not bytes. Right now word addressing
+ * is broken
  */
 
 #include       "as.h"
@@ -18,6 +23,7 @@ void outpass(void)
 {
        off_t base = sizeof(obh);
        int i;
+
        if (pass == 1) {
                /* Lay the file out */
                for (i = 1; i < NSEGMENT; i++) {
@@ -36,15 +42,6 @@ void outpass(void)
                obh.o_dbgbase = 0;      /* for now */
                /* Number the symbols for output */
                numbersymbols();
-               outsegment(1);
-#ifdef TARGET_WORDMACHINE
-               outbyte(REL_WORDMACHINE);
-               outbyte(BYTES_PER_ADDRESS);
-#elif TARGET_BIGENDIAN
-               outbyte(REL_BIGENDIAN);
-#else
-               outbyte(REL_LITTLEENDIAN);
-#endif
        }
 }
 
@@ -74,8 +71,13 @@ void outsegment(int seg)
  */
 void outaw(uint16_t w)
 {
+#ifdef TARGET_BE
+       outab(w >> 8);
+       outab(w);
+#else
        outab(w);
        outab(w >> 8);
+#endif
 }
 
 static void check_store_allowed(uint8_t segment, uint16_t value)
@@ -86,6 +88,10 @@ static void check_store_allowed(uint8_t segment, uint16_t value)
                err('z', DATA_IN_ZP);
 }
 
+/*
+ *     Symbol numbers and relocatios are always written little endian
+ *     for simplicity.
+ */
 void outraw(ADDR *a)
 {
        if (a->a_segment != ABSOLUTE) {
@@ -120,7 +126,7 @@ void outab(uint8_t b)
                outbyte(REL_REL);
        ++dot[segment];
        ++truesize[segment];
-       if (truesize[segment] == 0 || dot[segment] == 0)
+       if (truesize[segment] == SEGMENT_LIMIT || dot[segment] == SEGMENT_LIMIT)
                err('o', SEGMENT_OVERFLOW);
 }
 
@@ -137,10 +143,12 @@ void outrabrel(ADDR *a)
                check_store_allowed(segment, a->a_value);
                if (a->a_sym) {
                        outbyte(REL_ESC);
-                       outbyte((0 << 4 ) | PCREL);
+                       outbyte((0 << 4 ) | REL_PCREL);
                        outbyte(a->a_sym->s_number & 0xFF);
                        outbyte(a->a_sym->s_number >> 8);
-                       outaw(a->a_value);
+                       outbyte(a->a_value);
+                       outab(a->a_value >> 8);
+                       return;
                }
                /* relatives without a symbol don't need relocation */
        }
diff --git a/Applications/MWC/cmd/asz80/as6-nova.c b/Applications/MWC/cmd/asz80/as6-nova.c
new file mode 100644 (file)
index 0000000..5745eba
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * DG Nova assembler.
+ *
+ * Tables
+ */
+
+#include       "as.h"
+
+SYM    sym[] = {
+       {       0,      "skp",          TCC,            1       },
+       {       0,      "szc",          TCC,            2       },
+       {       0,      "snc",          TCC,            3       },
+       {       0,      "szr",          TCC,            4       },
+       {       0,      "snr",          TCC,            5       },
+       {       0,      "sez",          TCC,            6       },
+       {       0,      "sbn",          TCC,            7       },
+
+       {       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,      ".word",        TDEFW,          XXXX    },
+       {       0,      ".blkw",        TDEFS,          XXXX    },
+       {       0,      ".ascii",       TDEFM,          XXXX    },
+       {       0,      ".org",         TORG,           XXXX    },
+       {       0,      ".equ",         TEQU,           XXXX    },
+       {       0,      ".export",      TEXPORT,        XXXX    },
+       {       0,      "code",         TSEGMENT,       CODE    },
+       {       0,      "data",         TSEGMENT,       DATA    },
+       {       0,      "bss",          TSEGMENT,       BSS     },
+       {       0,      "zp",           TSEGMENT,       ZP      },
+       {       0,      ".code",        TSEGMENT,       CODE    },
+       {       0,      ".data",        TSEGMENT,       DATA    },
+       {       0,      ".bss",         TSEGMENT,       BSS     },
+       {       0,      ".zp",          TSEGMENT,       ZP      },
+       
+       {       0,      "jmp",          TMEMORY,        0x0000  },
+       {       0,      "jsr",          TMEMORY,        0x0800  },
+       {       0,      "isz",          TMEMORY,        0x1000  },
+       {       0,      "dsz",          TMEMORY,        0x1800  },
+       {       0,      "lda",          TMEMORY,        0x2000  },
+       {       0,      "inc",          TMEMORY,        0x3000  },
+       {       0,      "sta",          TMEMORY,        0x4000  },
+
+       {       0,      "com",          TALU,           0x8000  },
+       {       0,      "neg",          TALU,           0x8100  },
+       {       0,      "mov",          TALU,           0x8200  },
+       {       0,      "adc",          TALU,           0x8400  },
+       {       0,      "sub",          TALU,           0x8500  },
+       {       0,      "add",          TALU,           0x8600  },
+       {       0,      "and",          TALU,           0x8700  },
+       
+       {       0,      "dia",          TIO,            0x6100  },
+       {       0,      "doa",          TIO,            0x6200  },
+       {       0,      "dib",          TIO,            0x6300  },
+       {       0,      "dob",          TIO,            0x6400  },
+       {       0,      "dic",          TIO,            0x6500  },
+       {       0,      "doc",          TIO,            0x6600  },
+       {       0,      "skip",         TDEV,           0x6700  },
+       
+       
+       /* Then the post NOVA 1 operations that are less elegant being
+          device ops */
+       {       0,      "mtfp",         TAC,            0x6001  },
+       {       0,      "mffp",         TAC,            0x6081  },
+       {       0,      "mtsp",         TAC,            0x6201  },
+       {       0,      "mfsp",         TAC,            0x6281  },
+       {       0,      "psha",         TAC,            0x6301  },
+       {       0,      "popa",         TAC,            0x6381  },
+       {       0,      "sav",          TIMPL,          0x6501  },
+       {       0,      "ret",          TIMPL,          0x6581  },
+       /* Undocumented SAV n ? */
+       
+       {       0,      "trap",         TTRAP,          0x8008  },
+       {       0,      "ldb",          TBYTE,          0x6101  },
+       {       0,      "stb",          TBYTE,          0x6401  },
+       
+       {       0,      "div",          TIMPL,          0x7641  },
+       {       0,      "mul",          TIMPL,          0x76C1  },
+       {       0,      "divs",         TIMPL,          0x7E01  },
+       {       0,      "muls",         TIMPL,          0x7E81  },      
+};
+        
+/*
+ * 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",
+       "relative out of range",
+       "skip condition required",
+       "invalid register for operation",
+       "address required",
+       "invalid id",
+       "bad addressing mode",
+       "divide by 0",
+       "constant out of range",
+       "data in BSS",
+       "segment overflow",
+       "data in zero page",
+       "bad accumulator",
+       "must be zero page or absolute",
+       "bad device",
+       "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;
+       aerr(ADDR_REQUIRED);
+}
index acb4dcb..33372c5 100644 (file)
@@ -180,7 +180,8 @@ char *etext[] = {
        "constant out of range",
        "data in BSS",
        "segment overflow",
-       "Z180 instruction"
+       "Z180 instruction",
+       "segment conflict"
 };
 
 /*