as: lots of stuff here
authorAlan Cox <alan@linux.intel.com>
Mon, 30 Oct 2017 23:44:05 +0000 (23:44 +0000)
committerAlan Cox <alan@linux.intel.com>
Mon, 30 Oct 2017 23:44:05 +0000 (23:44 +0000)
- Rework types for cpu / flags
- Add 6502 types
- Teach ld that there can be a ZP segment
- Restructure the assembler to put arch specific code in less files
- Fix various minor bugs (segment checking etc)
- Fix a bug where a_sym was not reliably set to NULL for constants
- Add initial test 6502 support to prove can re-target easily

Applications/MWC/cmd/asz80/Makefile.z80
Applications/MWC/cmd/asz80/as.h
Applications/MWC/cmd/asz80/as0.c
Applications/MWC/cmd/asz80/as1.c
Applications/MWC/cmd/asz80/as2.c
Applications/MWC/cmd/asz80/as3.c
Applications/MWC/cmd/asz80/as4.c
Applications/MWC/cmd/asz80/as6.c
Applications/MWC/cmd/asz80/ld.c
Applications/MWC/cmd/asz80/obj.h

index f583c6f..1b46e27 100644 (file)
@@ -1,5 +1,5 @@
 LINKER = sdcc
-FCC = ../../../../Library/tools/fcc -O2
+FCC = ../../../../Library/tools/fcc -O2 -DTARGET_Z80
 PLATFORM =
 #PLATFORM = -tzx128
 
index 7285af2..ad053e4 100644 (file)
@@ -21,7 +21,6 @@
 #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 NSEGMENT 4                     /* # of segments */
 #define        XXXX    0                       /* Unused value */
 
 /*
 #define        GOOD    0
 #define        BAD     1
 
+#ifdef TARGET_Z80
+
+typedef        uint16_t        VALUE;          /* For symbol values */
+
+#define NSEGMENT 4                     /* # of segments */
+
+#define ARCH OA_8080
+#define ARCH_FLAGS OA_8080_Z80
+
 /*
  * Types. These are used
  * in both symbols and in address
@@ -57,6 +65,8 @@
 #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        TNOP    0x0F00                  /* nop */
 #define        TRST    0x1000                  /* restarts */
 #define        TREL    0x1100                  /* djnz, jr */
@@ -73,8 +83,6 @@
 #define        TLD     0x1C00                  /* ld */
 #define        TCC     0x1D00                  /* condition code */
 #define        TSUB    0x1E00                  /* sub et al */
-#define TSEGMENT 0x1F00                        /* segments by number */
-#define TEXPORT 0x2000                 /* symbol export */
 #define TNOP180        0x2100                  /* Z180 immediate */
 #define TTST180        0x2200                  /* TST m/g/(hl) */
 #define TIMMED8        0x2300                  /* TSTIO m */
 #define        CM      7
 
 /*
- * Segments
+ *     Error message numbers: FIXME - sort general first
  */
-#define UNKNOWN                -1
-#define ABSOLUTE       0
-#define CODE           1
-#define DATA           2
-#define BSS            3
+
+#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
+
+
+
+#elif TARGET_6502
+
+typedef        uint16_t        VALUE;          /* For symbol values */
+
+#define NSEGMENT 5                     /* # of segments */
+
+#define ARCH OA_6502
+#define ARCH_FLAGS OA_6502_BCD /* For now until CPU type properly settable */
+
+
+/*
+ * 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 TMADDR 0x00F0                  /* Addressing mode bits */
+
+#define        TZP     0x0010                  /* 0000 is TUSER */
+#define TACCUM 0x0020
+#define TZPX   0x0030
+#define TZPY   0x0040
+#define TABSX  0x0050
+#define TABSY  0x0060
+#define TZPX_IND       0x0070
+#define TZPY_IND       0x0080
+#define TZP_IND        0x0090
+
+
+#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        TCLASS0 0x1000                  /* xxxyyy00 instructions */
+#define TCLASS1        0x1100                  /* xxxyyy01 instructions */
+#define TCLASS2        0x1200                  /* xxxyyy10 instructions */
+#define TCLASS2Y 0x1300                        /* ditto but taking Y */
+#define TJMP   0x1400                  /* JMP */
+#define TREL8  0x1500                  /* Bcc */
+#define TIMPL  0x1600                  /* Implicit */
+#define TBRK   0x1700                  /* BRK */
+#define TJSR   0x1800                  /* JSR */
+
+/*
+ * Registers.
+ */
+#define        A       0
+#define        X       1
+#define        Y       2
 
 /*
  *     Error message numbers
 #define MUST_BE_ABSOLUTE       14
 #define MISSING_DELIMITER 15
 #define INVALID_CONST  16
-#define JR_RANGE       17
+#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 BADMODE                22
 #define DIVIDE_BY_ZERO 23
 #define CONSTANT_RANGE  24
 #define DATA_IN_BSS     25
 #define SEGMENT_OVERFLOW 26
-#define REQUIRE_Z180   27
+#define DATA_IN_ZP     27
 
-typedef        uint16_t        VALUE;          /* For symbol values */
+
+#else
+#error "Unknown target"
+#endif
+
+/*
+ * Segments
+ */
+#define UNKNOWN                -1
+#define ABSOLUTE       0
+#define CODE           1
+#define DATA           2
+#define BSS            3
+
+/*
+ * Expression priority
+ */
+
+#define        LOPRI   0
+#define        ADDPRI  1
+#define        MULPRI  2
+#define        HIPRI   3
 
 /*
  * Address description.
@@ -204,12 +324,8 @@ extern     int     noobj;
 extern int     cpu_flags;
 
 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, uint8_t);
 extern void uerr(char *);
@@ -241,4 +357,6 @@ extern void outbyte(uint8_t);
 extern void outflush(void);
 extern void syminit(void);
 
+extern char *etext[];
+
 #include "obj.h"
index d229555..28ba0fd 100644 (file)
@@ -23,7 +23,7 @@ int   line;
 jmp_buf        env;
 int    debug_write = 1 ;
 int    noobj;
-int    cpu_flags = OA_8080_Z80;
+int    cpu_flags = ARCH_FLAGS;
 
 /*
  * Make up a file name.
index d764505..b2592bb 100644 (file)
 #define        OPJR    0x20                    /* Opcode: jr cc base */
 #define        OPRET   0xC0                    /* Opcode: ret cc base */
 
+static void asmld(void);
+static ADDR *getldaddr(ADDR *ap, int *modep, int *regp, ADDR *iap);
+static void outop(int op, ADDR *ap);
+static int ccfetch(ADDR *ap);
+
 static void require_z180(void)
 {
        if (!(cpu_flags & OA_8080_Z180)) {
@@ -36,6 +41,55 @@ static void require_z180(void)
        }
 }
 
+/*
+ * 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(BRACKET_EXPECTED);
+       reg = ap->a_type&TMREG;
+       switch (ap->a_type&TMMODE) {
+       case TBR:
+               if (reg != C)
+                       aerr(REG_MUST_BE_C);
+               ap->a_type |= TMINDIR;
+               break;
+       case TSR:
+       case TCC:
+               aerr(ADDR_REQUIRED);
+               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(INVALID_REG);
+               else
+                       ap->a_type |= TMINDIR;
+       }
+}
+
+
 /*
  * Assemble one line.
  * The line in in "ib", the "ip"
@@ -205,7 +259,7 @@ loop:
                istuser(&a1);
                disp = a1.a_value-dot[segment]-2;
                if (disp<-128 || disp>127 || a1.a_segment != segment)
-                       aerr(JR_RANGE);
+                       aerr(BRA_RANGE);
                outab(opcode);
                outab(disp);
                break;
@@ -525,7 +579,7 @@ loop:
  * indexing. This layer just screens out the many
  * cases, and emits the correct bytes.
  */
-void asmld(void)
+static void asmld(void)
 {
        int mdst;
        int rdst;
@@ -633,7 +687,7 @@ void asmld(void)
  * pointer "ap" if indexing is required, otherwise just
  * pass the "iap" through.
  */
-ADDR   *getldaddr(ADDR *ap, int *modep, int *regp, ADDR *iap)
+static ADDR *getldaddr(ADDR *ap, int *modep, int *regp, ADDR *iap)
 {
        int mode;
        int reg;
@@ -681,7 +735,7 @@ ADDR        *getldaddr(ADDR *ap, int *modep, int *regp, ADDR *iap)
  * the address mode to see if the bytes
  * are needed.
  */
-void outop(int op, ADDR *ap)
+static void outop(int op, ADDR *ap)
 {
        int needisp;
 
@@ -705,28 +759,6 @@ void outop(int op, ADDR *ap)
                outrab(ap);
 }
 
-/*
- * The next character
- * in the input must be a comma
- * or it is a fatal error.
- */
-void comma(void)
-{
-       if (getnb() != ',')
-               qerr(MISSING_COMMA);
-}
-
-/*
- * 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(ADDR_REQUIRED);
-}
-
 /*
  * Try to interpret an "ADDR"
  * as a condition code name. Return
@@ -734,7 +766,7 @@ void istuser(ADDR *ap)
  * be interpreted as a condition. The
  * "c" condition is a pain.
  */
-int ccfetch(ADDR *ap)
+static int ccfetch(ADDR *ap)
 {
        if (ap->a_type == (TBR|C))
                return (CC);
index f697569..9093df7 100644 (file)
@@ -25,30 +25,6 @@ int symhash(char *id)
        return (hash&HMASK);
 }
 
-/* We may want to move this out into a a helper app at the end to dump
-   errors without using assembler space */
-
-static char *etext[] = {
-       "unexpected character",
-       "phase error",
-       "multiple definitions",
-       "syntax error",
-       "must be absolute",
-       "missing delimiter",
-       "invalid constant",
-       "JR out of range",
-       "condition required",
-       "invalid register for operation",
-       "address required",
-       "invalid id",
-       "must be C",
-       "divide by 0",
-       "constant out of range",
-       "data in BSS",
-       "segment overflow",
-       "Z180 instruction"
-};
-
 static void errstr(uint8_t code)
 {
        if (code < 10) {
@@ -101,6 +77,17 @@ void qerr(uint8_t code)
        err('q', code);
 }
 
+/*
+ * The next character
+ * in the input must be a comma
+ * or it is a fatal error.
+ */
+void comma(void)
+{
+       if (getnb() != ',')
+               qerr(MISSING_COMMA);
+}
+
 /*
  * Read identifier.
  * The character "c" is the first
index dfbf367..6585d97 100644 (file)
@@ -5,59 +5,20 @@
  */
 #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.
+ * Check if the mode of
+ * an ADDR is TUSER. If not, give
+ * an error.
  */
-void getaddr(ADDR *ap)
+void istuser(ADDR *ap)
 {
-       int reg;
-       int c;
-
-       if ((c=getnb()) != '(') {
-               unget(c);
-               expr1(ap, LOPRI, 0);
-               return;
-       }
-       expr1(ap, LOPRI, 1);
-       if (getnb() != ')')
-               qerr(BRACKET_EXPECTED);
-       reg = ap->a_type&TMREG;
-       switch (ap->a_type&TMMODE) {
-       case TBR:
-               if (reg != C)
-                       aerr(REG_MUST_BE_C);
-               ap->a_type |= TMINDIR;
-               break;
-       case TSR:
-       case TCC:
+       if ((ap->a_type&TMMODE) != TUSER)
                aerr(ADDR_REQUIRED);
-               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(INVALID_REG);
-               else
-                       ap->a_type |= TMINDIR;
-       }
 }
 
+
 static void chkabsolute(ADDR *a)
 {
        /* Not symbols, doesn't matter */
@@ -313,27 +274,6 @@ void expr3(ADDR *ap, int c)
        ap->a_type  = TUSER;
        ap->a_value = value;
        ap->a_segment = ABSOLUTE;
+       ap->a_sym = NULL;
 }
 
-/*
- * 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);
-}
index dfa473e..1205d55 100644 (file)
@@ -22,14 +22,14 @@ void outpass(void)
                /* Lay the file out */
                for (i = 1; i < NSEGMENT; i++) {
                        segbase[i] = base;
-                       if (i != BSS) {
+                       if (i != BSS && i != ZP) {
                                obh.o_segbase[i] = base;
                                base += segsize[i] + 2; /* 2 for the EOF mark */
                        }
                        obh.o_size[i] = truesize[i];
                }
                obh.o_magic = 0;
-               obh.o_arch = OA_8080;
+               obh.o_arch = ARCH;
                obh.o_flags = 0;
                obh.o_cpuflags = cpu_flags;
                obh.o_symbase = base;
@@ -69,11 +69,18 @@ void outaw(uint16_t w)
        outab(w >> 8);
 }
 
+static void check_store_allowed(uint8_t segment, uint16_t value)
+{
+       if (segment == BSS)
+               err('b', DATA_IN_BSS);
+       if (segment == ZP)
+               err('z', DATA_IN_ZP);
+}
+
 void outraw(ADDR *a)
 {
        if (a->a_segment != ABSOLUTE) {
-               if (segment == BSS)
-                       err('b', DATA_IN_BSS);
+               check_store_allowed(segment, a->a_value);
                if (a->a_sym == NULL) {
                        outbyte(REL_ESC);
                        outbyte((1 << 4) | REL_SIMPLE | a->a_segment);
@@ -95,8 +102,8 @@ void outraw(ADDR *a)
 void outab(uint8_t b)
 {
        /* Not allowed to put data in the BSS except zero */
-       if (segment == BSS && b)
-               err('b', DATA_IN_BSS);
+       check_store_allowed(segment, b);
+       /* FIXME: wrong error ?? */
        if (segment == ABSOLUTE)
                err('A', MUST_BE_ABSOLUTE);
        outbyte(b);
@@ -119,8 +126,7 @@ void outrab(ADDR *a)
 {
        /* FIXME: handle symbols */
        if (a->a_segment != ABSOLUTE) {
-               if (segment == BSS)
-                       err('b', DATA_IN_BSS);
+               check_store_allowed(segment, a->a_value);
                if (a->a_sym == NULL) {
                        outbyte(REL_ESC);
                        outbyte((0 << 4) | REL_SIMPLE | a->a_segment);
index 9cd6c52..acb4dcb 100644 (file)
@@ -161,3 +161,47 @@ void syminit(void)
                ++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"
+};
+
+/*
+ * 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);
+}
index a1802f9..35efc3c 100644 (file)
@@ -281,7 +281,7 @@ struct object *load_object(FILE * fp, off_t off, int lib, const char *path)
        sp = o->syment;
        for (i = 0; i < nsym; i++) {
                type = fgetc(fp);
-               if (!(type & S_UNKNOWN) && (type & S_SEGMENT) > BSS)
+               if (!(type & S_UNKNOWN) && (type & S_SEGMENT) > ZP)
                        error("bad symbol");
                fread(name, 16, 1, fp);
                name[16] = 0;
@@ -345,6 +345,8 @@ static void set_segment_bases(void)
                }
                base[3] = base[2] + size[2];
 
+               /* ZP if any is assumed to be set on input */
+
                if (base[3] < base[2] || base[3] + size[3] < base[3])
                        error("image too large");
                /* Whoopee it fits */
@@ -429,7 +431,7 @@ static void relocate_stream(struct object *o, FILE * op, FILE * ip)
                if (code & REL_SIMPLE) {
                        uint8_t seg = code & S_SEGMENT;
                        /* Check entry is valid */
-                       if (seg == ABSOLUTE || seg > BSS || size > 2)
+                       if (seg == ABSOLUTE || seg > ZP || size > 2)
                                error("invalid reloc");
                        /* If we are not building an absolute then keep the tag */
                        if (ldmode != LD_ABSOLUTE) {
@@ -659,6 +661,8 @@ int main(int argc, char *argv[])
                        break;
                case 'b':
                        ldmode = LD_ABSOLUTE;
+                       strip = 1;
+                       break;
                case 'v':
                        printf("FuzixLD 0.1\n");
                        break;
index 4030955..da1611d 100644 (file)
@@ -8,6 +8,7 @@ struct objhdr
     uint16_t o_magic;
     uint8_t o_arch;
 #define OA_8080                1
+#define OA_6502                2
     uint8_t o_flags;
     uint16_t o_cpuflags;
 #define OA_8080_Z80    1
@@ -15,6 +16,15 @@ struct objhdr
 #define OA_8080_Z280   4
 #define OA_8080_R800   8
 #define OA_8080_8085   16
+
+#define OA_6502_BCD    1       /* Uses BCD instructions */
+#define OA_6502_NMOS   2       /* Uses NMOS undocumented */
+#define OA_6502_65C02  4       /* Uses 65C02 */
+#define OA_6502_BITOPS 8       /* Uses extended bit operations */
+#define OA_6502_65C816 16      /* 65C816 and relatives */
+#define OA_6502_ZPAT0  32      /* Binary Assumes ZP is at 0 */
+#define OA_6502_65CE02 64      /* Does anyone really care ? */
+
     uint32_t o_segbase[OSEG];
     uint16_t o_size[OSEG];
     uint32_t o_symbase;
@@ -66,3 +76,4 @@ struct objhdr
 #define CODE           1
 #define DATA           2
 #define BSS            3
+#define ZP             4