as: Fix more bugs, add < and > for lo/hi relocations
authorAlan Cox <alan@linux.intel.com>
Tue, 31 Oct 2017 21:40:35 +0000 (21:40 +0000)
committerAlan Cox <alan@linux.intel.com>
Tue, 31 Oct 2017 21:40:35 +0000 (21:40 +0000)
Still plenty of bugs I am sure.

Applications/MWC/cmd/asz80/as.h
Applications/MWC/cmd/asz80/as1-nova.c
Applications/MWC/cmd/asz80/as1.c
Applications/MWC/cmd/asz80/as3.c
Applications/MWC/cmd/asz80/as4.c
Applications/MWC/cmd/asz80/obj.h

index cb8c766..e562ed8 100644 (file)
@@ -352,7 +352,7 @@ typedef     uint32_t        VALUE;          /* For symbol values */
 /*
  * Segments
  */
-#define UNKNOWN                -1
+#define UNKNOWN                15
 #define ABSOLUTE       0
 #define CODE           1
 #define DATA           2
@@ -375,9 +375,12 @@ typedef    uint32_t        VALUE;          /* For symbol values */
  * Address description.
  */
 typedef        struct  ADDR    {
-       int     a_type;                 /* Type */
+       uint16_t a_type;                        /* Type */
        VALUE   a_value;                /* Index offset, etc */
-       int     a_segment;              /* Segment relative to */
+       uint8_t a_segment;              /* Segment relative to */
+       uint8_t a_flags;                /* To track high */
+#define A_HIGH         1
+#define A_LOW          2
        struct SYM *a_sym;              /* Symbol tied to this address */
                                        /* NULL indicates simple own segment */
 }      ADDR;
index 8db6909..8ca254e 100644 (file)
@@ -19,6 +19,10 @@ void getaddr(ADDR *ap)
        int reg;
        int c;
 
+       ap->a_sym = NULL;
+       ap->a_flags = 0;
+       ap->a_type = 0;
+
        /* 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 */
index b2592bb..de5b16e 100644 (file)
@@ -55,8 +55,16 @@ void getaddr(ADDR *ap)
        int reg;
        int c;
 
+       ap->a_flags = 0;
+       ap->a_sym = NULL;
+
        if ((c=getnb()) != '(') {
-               unget(c);
+               if (c == '<')
+                       ap->a_flags |= A_LOW;
+               else if (c == '>')
+                       ap->a_flags |= A_HIGH;
+               else
+                       unget(c);
                expr1(ap, LOPRI, 0);
                return;
        }
index 25e7df0..f86da3c 100644 (file)
@@ -67,12 +67,12 @@ static void chksegment(ADDR *left, ADDR *right, int op)
        /* Subtraction within segment produces an absolute */
        if (op == '-') {
                /* Unknown symbols may get segment forced as a result */
-               if (left->a_segment == -1) {
+               if (left->a_segment == UNKNOWN) {
                        left->a_segment = right->a_segment;
                        if (left->a_sym)
                                setsegment(left->a_sym, left->a_segment);
                }
-               if (right->a_segment == -1) {
+               if (right->a_segment == UNKNOWN) {
                        right->a_segment = left->a_segment;
                        if (right->a_sym)
                                setsegment(right->a_sym, right->a_segment);
@@ -204,6 +204,8 @@ void expr2(ADDR *ap)
                        ap->a_value = 0;
                        return;
                }
+               if (mode != TNEW && mode != TUSER)
+                       qerr(SYNTAX_ERROR);
                /* An external symbol has to be tracked and output in
                   the relocations. Any known internal symbol is just
                   encoded as a relocation relative to a segment */
index a2164c7..2776710 100644 (file)
@@ -82,6 +82,8 @@ void outaw(uint16_t w)
 
 static void check_store_allowed(uint8_t segment, uint16_t value)
 {
+       if (value == 0)
+               return;
        if (segment == BSS)
                err('b', DATA_IN_BSS);
        if (segment == ZP)
@@ -91,22 +93,38 @@ static void check_store_allowed(uint8_t segment, uint16_t value)
 /*
  *     Symbol numbers and relocatios are always written little endian
  *     for simplicity.
+ *
+ *     A_LOW and A_HIGH indicate 8bit partial relocations. We handle these
+ *     internally.
  */
 void outraw(ADDR *a)
 {
+       int s = 1 << 4;
        if (a->a_segment != ABSOLUTE) {
-               check_store_allowed(segment, a->a_value);
+               outbyte(REL_ESC);
+               check_store_allowed(segment, 1);
+               /* low bits of 16 bit is an 8bit relocation with
+                  overflow suppressed */
+               if (a->a_flags & A_LOW) {
+                       outbyte(REL_OVERFLOW);
+                       s = 0 << 4;
+               }
+               if (a->a_flags & A_HIGH)
+                       outbyte(REL_HIGH);
                if (a->a_sym == NULL) {
-                       outbyte(REL_ESC);
-                       outbyte((1 << 4) | REL_SIMPLE | a->a_segment);
+                       /* low bits of 16 bit is an 8bit relocation with
+                          overflow suppressed */
+                       outbyte(s | REL_SIMPLE | a->a_segment);
                } else {
-                       outbyte(REL_ESC);
-                       outbyte((1 << 4 ) | REL_SYMBOL);
+                       outbyte(s | REL_SYMBOL);
                        outbyte(a->a_sym->s_number & 0xFF);
                        outbyte(a->a_sym->s_number >> 8);
                }
        }
-       outaw(a->a_value);
+       if (a->a_flags & A_LOW)
+               outab(a->a_value);
+       else
+               outaw(a->a_value);
 }
 
 /*
@@ -140,7 +158,7 @@ void outabchk(uint16_t b)
 void outrabrel(ADDR *a)
 {
        if (a->a_segment != ABSOLUTE) {
-               check_store_allowed(segment, a->a_value);
+               check_store_allowed(segment, 1);
                if (a->a_sym) {
                        outbyte(REL_ESC);
                        outbyte((0 << 4 ) | REL_PCREL);
@@ -157,21 +175,36 @@ void outrabrel(ADDR *a)
        outab(a->a_value);
 }
 
+/*
+ *     We should probably fold outraw and outrab as they are not very
+ *     different except in the default value of s.
+ */
 void outrab(ADDR *a)
 {
+       int s = 0;
        if (a->a_segment != ABSOLUTE) {
-               check_store_allowed(segment, a->a_value);
+               check_store_allowed(segment, 1);
+               outbyte(REL_ESC);
+               if (a->a_flags & A_LOW) {
+                       outbyte(REL_OVERFLOW);
+                       a->a_value &= 0xFF;
+               }
+               if (a->a_flags & A_HIGH) {
+                       outbyte(REL_HIGH);
+                       s = 1 << 4;
+               }
                if (a->a_sym == NULL) {
-                       outbyte(REL_ESC);
-                       outbyte((0 << 4) | REL_SIMPLE | a->a_segment);
+                       outbyte(s | REL_SIMPLE | a->a_segment);
                } else {
-                       outbyte(REL_ESC);
-                       outbyte((0 << 4 ) | REL_SYMBOL);
+                       outbyte(s | REL_SYMBOL);
                        outbyte(a->a_sym->s_number & 0xFF);
                        outbyte(a->a_sym->s_number >> 8);
                }
        }
-       outabchk(a->a_value);
+       if (s)
+               outaw(a->a_value);
+       else
+               outabchk(a->a_value);
 }
 
 static void putsymbol(SYM *s, FILE *ofp)
@@ -184,7 +217,7 @@ static void putsymbol(SYM *s, FILE *ofp)
                if (s->s_type & TPUBLIC)
                        flag |= S_PUBLIC;
        }
-       /* 0 absolute, 1-n segments, -1 don't care */
+       /* 0 absolute, 1-n segments, 15 don't care */
        flag |= (s->s_segment & S_SEGMENT);
        putc(flag, ofp);
        fwrite(s->s_id, 16, 1, ofp);
index 855b663..32b59a5 100644 (file)
@@ -85,7 +85,7 @@ struct objhdr
 /*
  * Segments
  */
-#define UNKNOWN                -1
+#define UNKNOWN                15
 #define ABSOLUTE       0               /* Constant, not relocated */
 #define CODE           1               /* Relocated versus code */
 #define DATA           2               /* Relocated versus data */