fixed bug #613764
[fw/sdcc] / src / z80 / gen.c
index 91528e38e39a69db50886042ac72642d3f33a6be..09e50849dd2fa59b94174340d7cbbbb9e57708ba 100644 (file)
@@ -60,7 +60,9 @@
   9. With asm optimised strings                17030 192 2223
 
   10 and below are with asm strings off.
   9. With asm optimised strings                17030 192 2223
 
   10 and below are with asm strings off.
-  
+
+  10 Mucho optimisations               13562 201 1FCC
+
   Apparent advantage of turning on regparams:
   1.  Cost of push
         Decent case is push of a constant 
   Apparent advantage of turning on regparams:
   1.  Cost of push
         Decent case is push of a constant 
 #include <string.h>
 #include <ctype.h>
 
 #include <string.h>
 #include <ctype.h>
 
+#if defined(__BORLANDC__) || defined(_MSC_VER)
+#define STRCASECMP stricmp
+#else
+#define STRCASECMP strcasecmp
+#endif
+
 #ifdef HAVE_SYS_ISA_DEFS_H
 #include <sys/isa_defs.h>
 #endif
 #ifdef HAVE_SYS_ISA_DEFS_H
 #include <sys/isa_defs.h>
 #endif
@@ -135,6 +143,12 @@ static char **_fTmp;
 
 extern FILE *codeOutFile;
 
 
 extern FILE *codeOutFile;
 
+enum
+  {
+    INT8MIN = -128,
+    INT8MAX = 127
+  };
+
 /** Enum covering all the possible register pairs.
  */
 typedef enum
 /** Enum covering all the possible register pairs.
  */
 typedef enum
@@ -160,17 +174,13 @@ static struct
   {    "bc", "c", "b" },
   {    "de", "e", "d" },
   {    "hl", "l", "h" },
   {    "bc", "c", "b" },
   {    "de", "e", "d" },
   {    "hl", "l", "h" },
-  {    "iy", "iy.l?", "iy.h?" },
-  {    "ix", "ix.l?", "ix.h?" }
+  {    "iy", "iyl", "iyh" },
+  {    "ix", "ixl", "ixh" }
 };
 
 // PENDING
 #define ACC_NAME       _pairs[PAIR_AF].h
 
 };
 
 // PENDING
 #define ACC_NAME       _pairs[PAIR_AF].h
 
-#define RESULTONSTACK(x) \
-                         (IC_RESULT(x) && IC_RESULT(x)->aop && \
-                         IC_RESULT(x)->aop->type == AOP_STK )
-
 enum 
   {
     LSB,
 enum 
   {
     LSB,
@@ -201,6 +211,13 @@ static struct
     int pushedBC;
     int pushedDE;
   } stack;
     int pushedBC;
     int pushedDE;
   } stack;
+
+  struct
+  {
+    int pushedBC;
+    int pushedDE;
+  } calleeSaves;
+
   int frameId;
   int receiveOffset;
   bool flushStatics;
   int frameId;
   int receiveOffset;
   bool flushStatics;
@@ -231,6 +248,49 @@ static struct
 
 static const char *aopGet (asmop * aop, int offset, bool bit16);
 
 
 static const char *aopGet (asmop * aop, int offset, bool bit16);
 
+static const char *aopNames[] = {
+  "AOP_INVALID",
+  "AOP_LIT",
+  "AOP_REG",
+  "AOP_DIR",
+  "AOP_SFR",
+  "AOP_STK",
+  "AOP_IMMD",
+  "AOP_STR",
+  "AOP_CRY",
+  "AOP_IY",
+  "AOP_HL",
+  "AOP_ACC",
+  "AOP_HLREG",
+  "AOP_SIMPLELIT",
+  "AOP_EXSTK",
+  "AOP_PAIRPT"
+};
+
+static bool
+isLastUse (iCode *ic, operand *op)
+{
+  bitVect *uses = bitVectCopy (OP_USES (op));
+
+  while (!bitVectIsZero (uses))
+    {
+      if (bitVectFirstBit (uses) == ic->key)
+        {
+          if (bitVectnBitsOn (uses) == 1)
+            {
+              return TRUE;
+            }
+          else
+            {
+              return FALSE;
+            }
+        }
+      bitVectUnSetBit (uses, bitVectFirstBit (uses));
+    }
+
+  return FALSE;
+}
+
 static PAIR_ID
 _getTempPairId(void)
 {
 static PAIR_ID
 _getTempPairId(void)
 {
@@ -250,6 +310,59 @@ _getTempPairName(void)
   return _pairs[_getTempPairId()].name;
 }
 
   return _pairs[_getTempPairId()].name;
 }
 
+static bool
+isPairInUse (PAIR_ID id, iCode *ic)
+{
+  if (id == PAIR_DE)
+    {
+      return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
+    }
+  else if (id == PAIR_BC)
+    {
+      return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX);
+    }
+  else
+    {
+      wassertl (0, "Only implemented for DE and BC");
+      return TRUE;
+    }
+}
+
+static bool
+isPairInUseNotInRet(PAIR_ID id, iCode *ic)
+{
+  bitVect *rInUse;
+  
+  rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
+  
+  if (id == PAIR_DE)
+    {
+      return bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
+    }
+  else
+    {
+      wassertl (0, "Only implemented for DE");
+      return TRUE;
+    }
+}
+
+static PAIR_ID
+getFreePairId (iCode *ic)
+{
+  if (!isPairInUse (PAIR_BC, ic))
+    {
+      return PAIR_BC;
+    }
+  else if (IS_Z80 && !isPairInUse (PAIR_DE, ic))
+    {
+      return PAIR_DE;
+    }
+  else
+    {
+      return PAIR_INVALID;
+    }
+}         
+
 static void
 _tidyUp (char *buf)
 {
 static void
 _tidyUp (char *buf)
 {
@@ -362,7 +475,7 @@ _emit2 (const char *inst, const char *fmt,...)
 static void
 _emitMove(const char *to, const char *from)
 {
 static void
 _emitMove(const char *to, const char *from)
 {
-  if (strcasecmp(to, from) != 0) 
+  if (STRCASECMP(to, from) != 0) 
     {
       emit2("ld %s,%s", to, from);
     }
     {
       emit2("ld %s,%s", to, from);
     }
@@ -373,6 +486,21 @@ _emitMove(const char *to, const char *from)
     }
 }
 
     }
 }
 
+void
+aopDump(const char *plabel, asmop *aop)
+{
+  emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
+  switch (aop->type)
+    {
+    case AOP_STK:
+      emitDebug(";  aop_stk %d", aop->aopu.aop_stk);
+      break;
+    default:
+      /* No information. */
+      break;
+    }
+}
+
 static void
 _moveA(const char *moveFrom)
 {
 static void
 _moveA(const char *moveFrom)
 {
@@ -404,20 +532,16 @@ getPairName (asmop * aop)
          break;
        }
     }
          break;
        }
     }
-  else if (aop->type == AOP_STR)
+  else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
     {
     {
-      switch (*aop->aopu.aop_str[0])
-       {
-       case 'c':
-         return "bc";
-         break;
-       case 'e':
-         return "de";
-         break;
-       case 'l':
-         return "hl";
-         break;
-       }
+      int i;
+      for (i = 0; i < NUM_PAIRS; i++)
+        {
+          if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
+            {
+              return _pairs[i].name;
+            }
+        }
     }
   wassertl (0, "Tried to get the pair name of something that isn't a pair");
   return NULL;
     }
   wassertl (0, "Tried to get the pair name of something that isn't a pair");
   return NULL;
@@ -443,21 +567,17 @@ getPairId (asmop * aop)
              return PAIR_HL;
            }
        }
              return PAIR_HL;
            }
        }
-      if (aop->type == AOP_STR)
+      else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
        {
        {
-         if (!strcmp (aop->aopu.aop_str[0], "c") && !strcmp (aop->aopu.aop_str[1], "b"))
-           {
-             return PAIR_BC;
-           }
-         if (!strcmp (aop->aopu.aop_str[0], "e") && !strcmp (aop->aopu.aop_str[1], "d"))
-           {
-             return PAIR_DE;
-           }
-         if (!strcmp (aop->aopu.aop_str[0], "l") && !strcmp (aop->aopu.aop_str[1], "h"))
-           {
-             return PAIR_HL;
-           }
-       }
+          int i;
+          for (i = 0; i < NUM_PAIRS; i++)
+            {
+              if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
+                {
+                  return i;
+                }
+            }
+        }
     }
   return PAIR_INVALID;
 }
     }
   return PAIR_INVALID;
 }
@@ -483,6 +603,14 @@ isPtrPair (asmop * aop)
       return FALSE;
     }
 }
       return FALSE;
     }
 }
+
+static void
+spillPair (PAIR_ID pairId)
+{
+  _G.pairs[pairId].last_type = AOP_INVALID;
+  _G.pairs[pairId].base = NULL;
+}
+
 /** Push a register pair onto the stack */
 void
 genPairPush (asmop * aop)
 /** Push a register pair onto the stack */
 void
 genPairPush (asmop * aop)
@@ -502,6 +630,7 @@ _pop (PAIR_ID pairId)
 {
   emit2 ("pop %s", _pairs[pairId].name);
   _G.stack.pushed -= 2;
 {
   emit2 ("pop %s", _pairs[pairId].name);
   _G.stack.pushed -= 2;
+  spillPair (pairId);
 }
 
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
@@ -534,13 +663,28 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
 
   /* if already has one */
   if (sym->aop)
 
   /* if already has one */
   if (sym->aop)
-    return sym->aop;
+    {
+      return sym->aop;
+    }
 
   /* Assign depending on the storage class */
   if (sym->onStack || sym->iaccess)
     {
 
   /* Assign depending on the storage class */
   if (sym->onStack || sym->iaccess)
     {
-      emitDebug ("; AOP_STK for %s", sym->rname);
-      sym->aop = aop = newAsmop (AOP_STK);
+      /* The pointer that is used depends on how big the offset is.
+         Normally everything is AOP_STK, but for offsets of < -128 or
+         > 127 on the Z80 an extended stack pointer is used.
+      */
+      if (IS_Z80 && (options.ommitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
+        {
+          emitDebug ("; AOP_EXSTK for %s", sym->rname);
+          sym->aop = aop = newAsmop (AOP_EXSTK);
+        }
+      else
+        {
+          emitDebug ("; AOP_STK for %s", sym->rname);
+          sym->aop = aop = newAsmop (AOP_STK);
+        }
+
       aop->size = getSize (sym->type);
       aop->aopu.aop_stk = sym->stack;
       return aop;
       aop->size = getSize (sym->type);
       aop->aopu.aop_stk = sym->stack;
       return aop;
@@ -758,7 +902,9 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a)
 
   /* if already has a asmop then continue */
   if (op->aop)
 
   /* if already has a asmop then continue */
   if (op->aop)
-    return;
+    {
+      return;
+    }
 
   /* if the underlying symbol has a aop */
   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
 
   /* if the underlying symbol has a aop */
   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
@@ -806,6 +952,16 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a)
          return;
        }
 
          return;
        }
 
+      if (sym->ruonly)
+       {
+         int i;
+         aop = op->aop = sym->aop = newAsmop (AOP_STR);
+         aop->size = getSize (sym->type);
+         for (i = 0; i < 4; i++)
+           aop->aopu.aop_str[i] = _fReturn[i];
+         return;
+       }
+
       if (sym->accuse)
        {
          if (sym->accuse == ACCUSE_A)
       if (sym->accuse)
        {
          if (sym->accuse == ACCUSE_A)
@@ -816,15 +972,22 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a)
 
               aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
            }
 
               aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
            }
-         else if (sym->accuse == ACCUSE_HL)
+         else if (sym->accuse == ACCUSE_SCRATCH)
            {
            {
-             wassert (!IS_GB);
              aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
              aop->size = getSize (sym->type);
               wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
               aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
               aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
            }
              aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
              aop->size = getSize (sym->type);
               wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
               aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
               aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
            }
+          else if (sym->accuse == ACCUSE_IY)
+            {
+             aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
+             aop->size = getSize (sym->type);
+              wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
+              aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
+              aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
+            }
          else 
               {
                   wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
          else 
               {
                   wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
@@ -832,19 +995,14 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a)
          return;
        }
 
          return;
        }
 
-      if (sym->ruonly)
-       {
-         int i;
-         aop = op->aop = sym->aop = newAsmop (AOP_STR);
-         aop->size = getSize (sym->type);
-         for (i = 0; i < 4; i++)
-           aop->aopu.aop_str[i] = _fReturn[i];
-         return;
-       }
-
       /* else spill location  */
       /* else spill location  */
+      if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) {
+         /* force a new aop if sizes differ */
+         sym->usl.spillLoc->aop = NULL;
+      }
       sym->aop = op->aop = aop =
        aopForSym (ic, sym->usl.spillLoc, result, requires_a);
       sym->aop = op->aop = aop =
        aopForSym (ic, sym->usl.spillLoc, result, requires_a);
+      wassertl (aop->size >= getSize (sym->type), "Operand doesn't fit in the spill location");
       aop->size = getSize (sym->type);
       return;
     }
       aop->size = getSize (sym->type);
       return;
     }
@@ -877,6 +1035,16 @@ freeAsmop (operand * op, asmop * aaop, iCode * ic)
 
   aop->freed = 1;
 
 
   aop->freed = 1;
 
+  if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
+    {
+      _pop (aop->aopu.aop_pairId);
+    }
+
+  if (getPairId (aop) == PAIR_HL)
+    {
+      spillPair (PAIR_HL);
+    }
+
 dealloc:
   /* all other cases just dealloc */
   if (op)
 dealloc:
   /* all other cases just dealloc */
   if (op)
@@ -890,6 +1058,7 @@ dealloc:
            SPIL_LOC (op)->aop = NULL;
        }
     }
            SPIL_LOC (op)->aop = NULL;
        }
     }
+
 }
 
 bool
 }
 
 bool
@@ -911,7 +1080,6 @@ char *
 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
 {
   char *s = buffer;
 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
 {
   char *s = buffer;
-  char *rs;
 
   /* depending on type */
   switch (aop->type)
 
   /* depending on type */
   switch (aop->type)
@@ -965,15 +1133,27 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
          }
        else
          {
          }
        else
          {
-           /* A float */
-           Z80_FLOAT f;
-           convertFloat (&f, floatFromVal (val));
+            union {
+              float f;
+              unsigned char c[4];
+            }
+            fl;
+            unsigned int i;
+
+            /* it is type float */
+            fl.f = (float) floatFromVal (val);
+
+#ifdef _BIG_ENDIAN
+            i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
+#else
+            i = fl.c[offset] | (fl.c[offset+1]<<8);
+#endif
            if (with_hash)
            if (with_hash)
-             tsprintf (buffer, "!immedword", f.w[offset / 2]);
+             tsprintf (buffer, "!immedword", i);
            else
            else
-             tsprintf (buffer, "!constword", f.w[offset / 2]);
-           rs = Safe_calloc (1, strlen (buffer) + 1);
-           return strcpy (rs, buffer);
+             tsprintf (buffer, "!constword", i);
+
+            return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
          }
       }
     default:
          }
       }
     default:
@@ -1016,13 +1196,6 @@ adjustPair (const char *pair, int *pold, int new)
     }
 }
 
     }
 }
 
-static void
-spillPair (PAIR_ID pairId)
-{
-  _G.pairs[pairId].last_type = AOP_INVALID;
-  _G.pairs[pairId].base = NULL;
-}
-
 static void
 spillCached (void)
 {
 static void
 spillCached (void)
 {
@@ -1038,6 +1211,8 @@ requiresHL (asmop * aop)
     case AOP_IY:
     case AOP_HL:
     case AOP_STK:
     case AOP_IY:
     case AOP_HL:
     case AOP_STK:
+    case AOP_EXSTK:
+    case AOP_HLREG:
       return TRUE;
     default:
       return FALSE;
       return TRUE;
     default:
       return FALSE;
@@ -1066,7 +1241,7 @@ fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
                      adjustPair (pair, &_G.pairs[pairId].offset, offset);
                      return;
                    }
                      adjustPair (pair, &_G.pairs[pairId].offset, offset);
                      return;
                    }
-                 if (pairId == PAIR_IY && abs (offset) < 127)
+                 if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
                    {
                      return;
                    }
                    {
                      return;
                    }
@@ -1081,16 +1256,49 @@ fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
   emit2 ("ld %s,!hashedstr", pair, l);
 }
 
   emit2 ("ld %s,!hashedstr", pair, l);
 }
 
+static PAIR_ID
+makeFreePairId (iCode *ic, bool *pisUsed)
+{
+  *pisUsed = FALSE;
+
+  if (ic != NULL)
+    {
+      if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue(ic->rMask, C_IDX))
+        {
+          return PAIR_BC;
+        }
+      else if (IS_Z80 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue(ic->rMask, E_IDX))
+        {
+          return PAIR_DE;
+        }
+      else
+        {
+          *pisUsed = TRUE;
+          return PAIR_HL;
+        }
+    }
+  else
+    {
+      *pisUsed = TRUE;
+      return PAIR_HL;
+    }
+}
+
 static void
 static void
-fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
+fetchPairLong (PAIR_ID pairId, asmop * aop, iCode *ic, int offset)
 {
     /* if this is remateriazable */
     if (isLitWord (aop)) {
         fetchLitPair (pairId, aop, offset);
     }
 {
     /* if this is remateriazable */
     if (isLitWord (aop)) {
         fetchLitPair (pairId, aop, offset);
     }
-    else {
+    else 
+      {
+        if (getPairId (aop) == pairId)
+          {
+            /* Do nothing */
+          }
         /* we need to get it byte by byte */
         /* we need to get it byte by byte */
-        if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
+        else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
             aopGet (aop, offset, FALSE);
             switch (aop->size - offset) {
             case 1:
             aopGet (aop, offset, FALSE);
             switch (aop->size - offset) {
             case 1:
@@ -1120,10 +1328,33 @@ fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
                 emit2("ld %s,!zero", _pairs[pairId].h);
             }
         }
                 emit2("ld %s,!zero", _pairs[pairId].h);
             }
         }
-        else {
+        else if (pairId == PAIR_IY)
+          {
+            if (isPair (aop))
+              {
+                emit2 ("push %s", _pairs[getPairId(aop)].name);
+                emit2 ("pop iy");
+              }
+            else
+              {
+                bool isUsed;
+                PAIR_ID id = makeFreePairId (ic, &isUsed);
+                if (isUsed)
+                  _push (id);
+                /* Can't load into parts, so load into HL then exchange. */
+                emit2 ("ld %s,%s", _pairs[id].l, aopGet (aop, offset, FALSE));
+                emit2 ("ld %s,%s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
+                emit2 ("push %s", _pairs[id].name);
+                emit2 ("pop iy");
+                if (isUsed)
+                  _pop (id);
+              }
+          }
+        else 
+          {
             emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
             emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
             emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
             emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
-        }
+          }
         /* PENDING: check? */
         if (pairId == PAIR_HL)
             spillPair (PAIR_HL);
         /* PENDING: check? */
         if (pairId == PAIR_HL)
             spillPair (PAIR_HL);
@@ -1133,7 +1364,7 @@ fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
 static void
 fetchPair (PAIR_ID pairId, asmop * aop)
 {
 static void
 fetchPair (PAIR_ID pairId, asmop * aop)
 {
-  fetchPairLong (pairId, aop, 0);
+  fetchPairLong (pairId, aop, NULL, 0);
 }
 
 static void
 }
 
 static void
@@ -1143,23 +1374,67 @@ fetchHL (asmop * aop)
 }
 
 static void
 }
 
 static void
-setupPair (PAIR_ID pairId, asmop * aop, int offset)
+setupPairFromSP (PAIR_ID id, int offset)
 {
 {
-  assert (pairId == PAIR_HL || pairId == PAIR_IY);
+  wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
+
+  if (offset < INT8MIN || offset > INT8MAX)
+    {
+      emit2 ("ld hl,!immedword", offset);
+      emit2 ("add hl,sp");
+    }
+  else
+    {
+      emit2 ("!ldahlsp", offset);
+    }
+}
 
 
+static void
+setupPair (PAIR_ID pairId, asmop * aop, int offset)
+{
   switch (aop->type)
     {
     case AOP_IY:
   switch (aop->type)
     {
     case AOP_IY:
+      wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
       fetchLitPair (pairId, aop, 0);
       break;
       fetchLitPair (pairId, aop, 0);
       break;
+
     case AOP_HL:
     case AOP_HL:
+      wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
+      
       fetchLitPair (pairId, aop, offset);
       _G.pairs[pairId].offset = offset;
       break;
       fetchLitPair (pairId, aop, offset);
       _G.pairs[pairId].offset = offset;
       break;
+
+    case AOP_EXSTK:
+      wassertl (IS_Z80, "Only the Z80 has an extended stack");
+      wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
+
+      {
+       int offset = aop->aopu.aop_stk + _G.stack.offset;
+
+        if (_G.pairs[pairId].last_type == aop->type &&
+            _G.pairs[pairId].offset == offset)
+          {
+            /* Already setup */
+          }
+        else
+          {
+            /* PENDING: Do this better. */
+            sprintf (buffer, "%d", offset + _G.stack.pushed);
+            emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
+            emit2 ("add %s,sp", _pairs[pairId].name);
+            _G.pairs[pairId].last_type = aop->type;
+            _G.pairs[pairId].offset = offset;
+          }
+      }
+      break;
+
     case AOP_STK:
       {
        /* Doesnt include _G.stack.pushed */
        int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
     case AOP_STK:
       {
        /* Doesnt include _G.stack.pushed */
        int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
+
        if (aop->aopu.aop_stk > 0)
          {
            abso += _G.stack.param_offset;
        if (aop->aopu.aop_stk > 0)
          {
            abso += _G.stack.param_offset;
@@ -1172,11 +1447,16 @@ setupPair (PAIR_ID pairId, asmop * aop, int offset)
          }
        else
          {
          }
        else
          {
-           emit2 ("!ldahlsp", abso + _G.stack.pushed);
+            setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
          }
        _G.pairs[pairId].offset = abso;
        break;
       }
          }
        _G.pairs[pairId].offset = abso;
        break;
       }
+
+    case AOP_PAIRPTR:
+      adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
+      break;
+      
     default:
       wassert (0);
     }
     default:
       wassert (0);
     }
@@ -1263,6 +1543,13 @@ aopGet (asmop * aop, int offset, bool bit16)
 
       return traceAlloc(&_G.trace.aops, Safe_strdup(s));
 
 
       return traceAlloc(&_G.trace.aops, Safe_strdup(s));
 
+    case AOP_EXSTK:
+      wassert (IS_Z80);
+      setupPair (PAIR_IY, aop, offset);
+      tsprintf (s, "!*iyx", offset, offset);
+
+      return traceAlloc(&_G.trace.aops, Safe_strdup(s));
+
     case AOP_STK:
       if (IS_GB)
        {
     case AOP_STK:
       if (IS_GB)
        {
@@ -1312,6 +1599,12 @@ aopGet (asmop * aop, int offset, bool bit16)
       aop->coff = offset;
       return aop->aopu.aop_str[offset];
 
       aop->coff = offset;
       return aop->aopu.aop_str[offset];
 
+    case AOP_PAIRPTR:
+      setupPair (aop->aopu.aop_pairId, aop, offset);
+      sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name);
+
+      return traceAlloc(&_G.trace.aops, Safe_strdup(s));
+
     default:
       break;
     }
     default:
       break;
     }
@@ -1398,14 +1691,17 @@ aopPut (asmop * aop, const char *s, int offset)
 
     case AOP_IY:
       wassert (!IS_GB);
 
     case AOP_IY:
       wassert (!IS_GB);
-      setupPair (PAIR_IY, aop, offset);
       if (!canAssignToPtr (s))
        {
          emit2 ("ld a,%s", s);
       if (!canAssignToPtr (s))
        {
          emit2 ("ld a,%s", s);
+          setupPair (PAIR_IY, aop, offset);
          emit2 ("ld !*iyx,a", offset);
        }
       else
          emit2 ("ld !*iyx,a", offset);
        }
       else
-       emit2 ("ld !*iyx,%s", offset, s);
+        {
+          setupPair (PAIR_IY, aop, offset);
+          emit2 ("ld !*iyx,%s", offset, s);
+        }
       break;
 
     case AOP_HL:
       break;
 
     case AOP_HL:
@@ -1421,6 +1717,21 @@ aopPut (asmop * aop, const char *s, int offset)
       emit2 ("ld !*hl,%s", s);
       break;
 
       emit2 ("ld !*hl,%s", s);
       break;
 
+    case AOP_EXSTK:
+      wassert (!IS_GB);
+      if (!canAssignToPtr (s))
+       {
+         emit2 ("ld a,%s", s);
+          setupPair (PAIR_IY, aop, offset);
+         emit2 ("ld !*iyx,a", offset);
+       }
+      else
+        {
+          setupPair (PAIR_IY, aop, offset);
+          emit2 ("ld !*iyx,%s", offset, s);
+        }
+      break;
+
     case AOP_STK:
       if (IS_GB)
        {
     case AOP_STK:
       if (IS_GB)
        {
@@ -1449,7 +1760,9 @@ aopPut (asmop * aop, const char *s, int offset)
              emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
            }
          else
              emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
            }
          else
-           emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
+            {
+              emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
+            }
        }
       break;
 
        }
       break;
 
@@ -1457,7 +1770,7 @@ aopPut (asmop * aop, const char *s, int offset)
       /* if bit variable */
       if (!aop->aopu.aop_dir)
        {
       /* if bit variable */
       if (!aop->aopu.aop_dir)
        {
-         emit2 ("ld a,#0");
+         emit2 ("ld a,!zero");
          emit2 ("rla");
        }
       else
          emit2 ("rla");
        }
       else
@@ -1495,6 +1808,11 @@ aopPut (asmop * aop, const char *s, int offset)
       emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
       break;
 
       emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
       break;
 
+    case AOP_PAIRPTR:
+      setupPair (aop->aopu.aop_pairId, aop, offset);
+      emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
+      break;
+
     default:
       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
              "aopPut got unsupported aop->type");
     default:
       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
              "aopPut got unsupported aop->type");
@@ -1510,7 +1828,8 @@ aopPut (asmop * aop, const char *s, int offset)
 static void
 commitPair (asmop * aop, PAIR_ID id)
 {
 static void
 commitPair (asmop * aop, PAIR_ID id)
 {
-  if (id == PAIR_HL && requiresHL (aop))
+  /* PENDING: Verify this. */
+  if (id == PAIR_HL && requiresHL (aop) && IS_GB)
     {
       emit2 ("ld a,l");
       emit2 ("ld d,h");
     {
       emit2 ("ld a,l");
       emit2 ("ld d,h");
@@ -1519,8 +1838,19 @@ commitPair (asmop * aop, PAIR_ID id)
     }
   else
     {
     }
   else
     {
-      aopPut (aop, _pairs[id].l, 0);
-      aopPut (aop, _pairs[id].h, 1);
+      /* Special cases */
+      if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
+        {
+          char *l = aopGetLitWordLong (aop, 0, FALSE);
+          wassert (l);
+
+          emit2 ("ld (%s),%s", l, _pairs[id].name);
+        }
+      else
+        {
+          aopPut (aop, _pairs[id].l, 0);
+          aopPut (aop, _pairs[id].h, 1);
+        }
     }
 }
 
     }
 }
 
@@ -1548,6 +1878,7 @@ movLeft2Result (operand * left, int offl,
                operand * result, int offr, int sign)
 {
   const char *l;
                operand * result, int offr, int sign)
 {
   const char *l;
+
   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
     {
       l = aopGet (AOP (left), offl, FALSE);
   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
     {
       l = aopGet (AOP (left), offl, FALSE);
@@ -1567,6 +1898,48 @@ movLeft2Result (operand * left, int offl,
     }
 }
 
     }
 }
 
+static void
+movLeft2ResultLong (operand * left, int offl,
+               operand * result, int offr, int sign,
+                int size)
+{
+  if (size == 1)
+    {
+      movLeft2Result (left, offl, result, offr, sign);
+    }
+  else
+    {
+      wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
+      wassertl (size == 2, "Only implemented for two bytes or one");
+
+      if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
+        {
+          emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
+          emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
+          emit2 ("ld l,a");
+         spillPair (PAIR_HL);
+        }
+      else if ( getPairId ( AOP (result)) == PAIR_IY)
+        {
+          PAIR_ID id = getPairId (AOP (left));
+          if (id != PAIR_INVALID) 
+            {
+              emit2("push %s", _pairs[id].name);
+              emit2("pop iy");
+            }
+          else
+            {
+              /* PENDING */
+              emitDebug("Error");
+            }
+        }
+      else
+        {
+          movLeft2Result (left, offl, result, offr, sign);
+          movLeft2Result (left, offl+1, result, offr+1, sign);
+        }
+    }
+}
 
 /** Put Acc into a register set
  */
 
 /** Put Acc into a register set
  */
@@ -1639,6 +2012,44 @@ _toBoolean (operand * oper)
     }
 }
 
     }
 }
 
+/*-----------------------------------------------------------------*/
+/* genNotFloat - generates not for float operations              */
+/*-----------------------------------------------------------------*/
+static void
+genNotFloat (operand * op, operand * res)
+{
+  int size, offset;
+  symbol *tlbl;
+
+  emitDebug ("; genNotFloat");
+
+  /* we will put 127 in the first byte of
+     the result */
+  aopPut (AOP (res), "!immedbyte", 0x7F);
+  size = AOP_SIZE (op) - 1;
+  offset = 1;
+
+  _moveA (aopGet (op->aop, offset++, FALSE));
+
+  while (size--)
+    {
+      emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE));
+    }
+
+  tlbl = newiTempLabel (NULL);
+  aopPut (res->aop, "!one", 1);
+  emit2 ("!shortjp z !tlabel", tlbl->key + 100);
+  aopPut (res->aop, "!zero", 1);
+
+  emitLabel(tlbl->key + 100);
+
+  size = res->aop->size - 2;
+  offset = 2;
+  /* put zeros in the rest */
+  while (size--)
+    aopPut (res->aop, "!zero", offset++);
+}
+
 /*-----------------------------------------------------------------*/
 /* genNot - generate code for ! operation                          */
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 /* genNot - generate code for ! operation                          */
 /*-----------------------------------------------------------------*/
@@ -1660,7 +2071,8 @@ genNot (iCode * ic)
   /* if type float then do float */
   if (IS_FLOAT (optype))
     {
   /* if type float then do float */
   if (IS_FLOAT (optype))
     {
-      wassertl (0, "Tried to negate a float");
+      genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
+      goto release;
     }
 
   _toBoolean (IC_LEFT (ic));
     }
 
   _toBoolean (IC_LEFT (ic));
@@ -1672,6 +2084,7 @@ genNot (iCode * ic)
   emit2 ("sub a,!one");
   outBitC (IC_RESULT (ic));
 
   emit2 ("sub a,!one");
   outBitC (IC_RESULT (ic));
 
+ release:
   /* release the aops */
   freeAsmop (IC_LEFT (ic), NULL, ic);
   freeAsmop (IC_RESULT (ic), NULL, ic);
   /* release the aops */
   freeAsmop (IC_LEFT (ic), NULL, ic);
   freeAsmop (IC_RESULT (ic), NULL, ic);
@@ -1746,7 +2159,7 @@ _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
   aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
   aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
 
   aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
   aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
 
-  fetchPairLong (PAIR_DE, left, MSB24);
+  fetchPairLong (PAIR_DE, left, NULL, MSB24);
   aopGet (right, MSB24, FALSE);
 
   _pop (PAIR_AF);
   aopGet (right, MSB24, FALSE);
 
   _pop (PAIR_AF);
@@ -1766,6 +2179,32 @@ _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
   _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
 }
 
   _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
 }
 
+/*-----------------------------------------------------------------*/
+/* genUminusFloat - unary minus for floating points                */
+/*-----------------------------------------------------------------*/
+static void
+genUminusFloat (operand * op, operand * result)
+{
+  int size, offset = 0;
+
+  emitDebug("; genUminusFloat");
+
+  /* for this we just need to flip the
+     first it then copy the rest in place */
+  size = AOP_SIZE (op) - 1;
+
+  _moveA(aopGet (AOP (op), MSB32, FALSE));
+
+  emit2("xor a,!immedbyte", 0x80);
+  aopPut (AOP (result), "a", MSB32);
+
+  while (size--)
+    {
+      aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
+      offset++;
+    }
+}
+
 /*-----------------------------------------------------------------*/
 /* genUminus - unary minus code generation                         */
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 /* genUminus - unary minus code generation                         */
 /*-----------------------------------------------------------------*/
@@ -1794,7 +2233,7 @@ genUminus (iCode * ic)
   /* if float then do float stuff */
   if (IS_FLOAT (optype))
     {
   /* if float then do float stuff */
   if (IS_FLOAT (optype))
     {
-      wassertl (0, "Tried to do a unary minus on a float");
+      genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
       goto release;
     }
 
       goto release;
     }
 
@@ -1868,6 +2307,25 @@ assignResultValue (operand * oper)
     }
 }
 
     }
 }
 
+/** Simple restore that doesn't take into account what is used in the
+    return.
+*/
+static void
+_restoreRegsAfterCall(void)
+{
+  if (_G.stack.pushedDE)
+    {
+      _pop ( PAIR_DE);
+      _G.stack.pushedDE = FALSE;
+    }
+  if (_G.stack.pushedBC)
+    {
+      _pop ( PAIR_BC);
+      _G.stack.pushedBC = FALSE;
+    }
+  _G.saves.saved = FALSE;
+}
+
 static void
 _saveRegsForCall(iCode *ic, int sendSetSize)
 {
 static void
 _saveRegsForCall(iCode *ic, int sendSetSize)
 {
@@ -1973,7 +2431,7 @@ genIpush (iCode * ic)
 
   size = AOP_SIZE (IC_LEFT (ic));
 
 
   size = AOP_SIZE (IC_LEFT (ic));
 
-  if (isPair (AOP (IC_LEFT (ic))))
+  if (isPair (AOP (IC_LEFT (ic))) && size == 2)
     {
       _G.stack.pushed += 2;
       emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
     {
       _G.stack.pushed += 2;
       emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
@@ -1990,11 +2448,11 @@ genIpush (iCode * ic)
        }
       if (size == 4)
        {
        }
       if (size == 4)
        {
-         fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
+         fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
          emit2 ("push hl");
          spillPair (PAIR_HL);
          _G.stack.pushed += 2;
          emit2 ("push hl");
          spillPair (PAIR_HL);
          _G.stack.pushed += 2;
-         fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
+         fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
          emit2 ("push hl");
          spillPair (PAIR_HL);
          _G.stack.pushed += 2;
          emit2 ("push hl");
          spillPair (PAIR_HL);
          _G.stack.pushed += 2;
@@ -2133,9 +2591,7 @@ _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
 static void
 emitCall (iCode * ic, bool ispcall)
 {
 static void
 emitCall (iCode * ic, bool ispcall)
 {
-  sym_link *detype = getSpec (operandType (IC_LEFT (ic)));
-
-  bitVect *rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
+  sym_link *dtype = operandType (IC_LEFT (ic));
 
   /* if caller saves & we have not saved then */
   if (!ic->regsSaved)
 
   /* if caller saves & we have not saved then */
   if (!ic->regsSaved)
@@ -2207,7 +2663,7 @@ emitCall (iCode * ic, bool ispcall)
 
   if (ispcall)
     {
 
   if (ispcall)
     {
-      if (IS_BANKEDCALL (detype))
+      if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
        {
          werror (W_INDIR_BANKED);
        }
        {
          werror (W_INDIR_BANKED);
        }
@@ -2237,7 +2693,7 @@ emitCall (iCode * ic, bool ispcall)
       char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
       OP_SYMBOL (IC_LEFT (ic))->rname :
       OP_SYMBOL (IC_LEFT (ic))->name;
       char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
       OP_SYMBOL (IC_LEFT (ic))->rname :
       OP_SYMBOL (IC_LEFT (ic))->name;
-      if (IS_BANKEDCALL (detype))
+      if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
        {
          emit2 ("call banked_call");
          emit2 ("!dws", name);
        {
          emit2 ("call banked_call");
          emit2 ("!dws", name);
@@ -2281,76 +2737,83 @@ emitCall (iCode * ic, bool ispcall)
       else
        {
          spillCached ();
       else
        {
          spillCached ();
-         if (i > 6)
+         if (i > 8)
            {
            {
-             emit2 ("ld hl,#%d", i);
-             emit2 ("add hl,sp");
-             emit2 ("ld sp,hl");
+             emit2 ("ld iy,!immedword", i);
+             emit2 ("add iy,sp");
+             emit2 ("ld sp,iy");
            }
          else
            {
              while (i > 1)
                {
            }
          else
            {
              while (i > 1)
                {
-                 emit2 ("pop hl");
+                 emit2 ("pop af");
                  i -= 2;
                }
              if (i)
                  i -= 2;
                }
              if (i)
-               emit2 ("inc sp");
+                {
+                  emit2 ("inc sp");
+                }
            }
            }
-         spillCached ();
        }
     }
 
        }
     }
 
+  spillCached ();
+
   if (_G.stack.pushedDE) 
     {
   if (_G.stack.pushedDE) 
     {
-      bool dInUse = bitVectBitValue(rInUse, D_IDX);
-      bool eInUse = bitVectBitValue(rInUse, E_IDX);
+      bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
+      bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
 
 
-      if (dInUse && eInUse) 
+      if (dInRet && eInRet)
         {
         {
-          _pop (PAIR_DE);
+          wassertl (0, "Shouldn't push DE if it's wiped out by the return");
         }
         }
-      else if (dInUse)
+      else if (dInRet)
         {
         {
-          _pop(PAIR_HL);
-          emit2 ("ld d,h");
+          /* Only restore E */
+          emit2 ("ld a,d");
+          _pop (PAIR_DE);
+          emit2 ("ld d,a");
         }
         }
-      else if (eInUse)
+      else if (eInRet)
         {
         {
-          _pop(PAIR_HL);
-          emit2 ("ld e,l");
+          /* Only restore D */
+          _pop (PAIR_AF);
+          emit2 ("ld d,a");
         }
       else
         {
         }
       else
         {
-          wassertl (0, "Neither D or E were in use but it was pushed.");
+          _pop (PAIR_DE);
         }
       _G.stack.pushedDE = FALSE;
     }
   
   if (_G.stack.pushedBC) 
     {
         }
       _G.stack.pushedDE = FALSE;
     }
   
   if (_G.stack.pushedBC) 
     {
-      bool bInUse = bitVectBitValue(rInUse, B_IDX);
-      bool cInUse = bitVectBitValue(rInUse, C_IDX);
+      bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
+      bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
 
 
-      // If both B and C are used in the return value, then we won't get
-      // here.
-      if (bInUse && cInUse) 
+      if (bInRet && cInRet)
         {
         {
-          _pop (PAIR_BC);
+          wassertl (0, "Shouldn't push BC if it's wiped out by the return");
         }
         }
-      else if (bInUse)
+      else if (bInRet)
         {
         {
-          _pop(PAIR_HL);
-          emit2 ("ld b,h");
+          /* Only restore C */
+          emit2 ("ld a,b");
+          _pop (PAIR_BC);
+          emit2 ("ld b,a");
         }
         }
-      else if (cInUse)
+      else if (cInRet)
         {
         {
-          _pop(PAIR_HL);
-          emit2 ("ld c,l");
+          /* Only restore B */
+          _pop (PAIR_AF);
+          emit2 ("ld b,a");
         }
       else
         {
         }
       else
         {
-          wassertl (0, "Neither B or C were in use but it was pushed.");
+          _pop (PAIR_BC);
         }
       _G.stack.pushedBC = FALSE;
     }
         }
       _G.stack.pushedBC = FALSE;
     }
@@ -2402,14 +2865,12 @@ static void
 genFunction (iCode * ic)
 {
   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
 genFunction (iCode * ic)
 {
   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
-  sym_link *fetype;
+  sym_link *ftype;
 
 
-#if CALLEE_SAVES
   bool bcInUse = FALSE;
   bool deInUse = FALSE;
   bool bcInUse = FALSE;
   bool deInUse = FALSE;
-#endif
 
 
-  setArea (IS_NONBANKED (sym->etype));
+  setArea (IFFUNC_NONBANKED (sym->type));
 
   /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
      else.
 
   /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
      else.
@@ -2421,8 +2882,8 @@ genFunction (iCode * ic)
   
   /* Create the function header */
   emit2 ("!functionheader", sym->name);
   
   /* Create the function header */
   emit2 ("!functionheader", sym->name);
-  /* PENDING: portability. */
-  emit2 ("__%s_start:", sym->rname);
+  sprintf (buffer, "%s_start", sym->rname);
+  emit2 ("!labeldef", buffer);
   emit2 ("!functionlabeldef", sym->rname);
 
   if (options.profile) 
   emit2 ("!functionlabeldef", sym->rname);
 
   if (options.profile) 
@@ -2430,14 +2891,14 @@ genFunction (iCode * ic)
       emit2 ("!profileenter");
     }
 
       emit2 ("!profileenter");
     }
 
-  fetype = getSpec (operandType (IC_LEFT (ic)));
+  ftype = operandType (IC_LEFT (ic));
 
   /* if critical function then turn interrupts off */
 
   /* if critical function then turn interrupts off */
-  if (SPEC_CRTCL (fetype))
+  if (IFFUNC_ISCRITICAL (ftype))
     emit2 ("!di");
 
   /* if this is an interrupt service routine then save all potentially used registers. */
     emit2 ("!di");
 
   /* if this is an interrupt service routine then save all potentially used registers. */
-  if (IS_ISR (sym->etype))
+  if (IFFUNC_ISISR (sym->type))
     {
       emit2 ("!pusha");
     }
     {
       emit2 ("!pusha");
     }
@@ -2446,9 +2907,13 @@ genFunction (iCode * ic)
 
   _G.stack.param_offset = 0;
 
 
   _G.stack.param_offset = 0;
 
-#if CALLEE_SAVES
+  if (z80_opts.calleeSavesBC)
+    {
+      bcInUse = TRUE;
+    }
+
   /* Detect which registers are used. */
   /* Detect which registers are used. */
-  if (sym->regsUsed)
+  if (IFFUNC_CALLEESAVES(sym->type) && sym->regsUsed)
     {
       int i;
       for (i = 0; i < sym->regsUsed->size; i++)
     {
       int i;
       for (i = 0; i < sym->regsUsed->size; i++)
@@ -2481,7 +2946,7 @@ genFunction (iCode * ic)
       _G.stack.param_offset += 2;
     }
 
       _G.stack.param_offset += 2;
     }
 
-  _G.stack.pushedBC = bcInUse;
+  _G.calleeSaves.pushedBC = bcInUse;
 
   if (deInUse)
     {
 
   if (deInUse)
     {
@@ -2489,13 +2954,14 @@ genFunction (iCode * ic)
       _G.stack.param_offset += 2;
     }
 
       _G.stack.param_offset += 2;
     }
 
-  _G.stack.pushedDE = deInUse;
-#endif
+  _G.calleeSaves.pushedDE = deInUse;
 
   /* adjust the stack for the function */
   _G.stack.last = sym->stack;
 
 
   /* adjust the stack for the function */
   _G.stack.last = sym->stack;
 
-  if (sym->stack)
+  if (sym->stack && IS_GB && sym->stack > -INT8MIN)
+    emit2 ("!enterxl", sym->stack);
+  else if (sym->stack)
     emit2 ("!enterx", sym->stack);
   else
     emit2 ("!enter");
     emit2 ("!enterx", sym->stack);
   else
     emit2 ("!enter");
@@ -2510,18 +2976,22 @@ genEndFunction (iCode * ic)
 {
   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
 
 {
   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
 
-  if (IS_ISR (sym->etype))
+  if (IFFUNC_ISISR (sym->type))
     {
       wassertl (0, "Tried to close an interrupt support function");
     }
   else
     {
     {
       wassertl (0, "Tried to close an interrupt support function");
     }
   else
     {
-      if (SPEC_CRTCL (sym->etype))
+      if (IFFUNC_ISCRITICAL (sym->type))
        emit2 ("!ei");
 
       /* PENDING: calleeSave */
 
        emit2 ("!ei");
 
       /* PENDING: calleeSave */
 
-      if (_G.stack.offset)
+      if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
+        {
+          emit2 ("!leavexl", _G.stack.offset);
+        }
+      else if (_G.stack.offset)
         {
           emit2 ("!leavex", _G.stack.offset);
         }
         {
           emit2 ("!leavex", _G.stack.offset);
         }
@@ -2530,19 +3000,17 @@ genEndFunction (iCode * ic)
           emit2 ("!leave");
         }
 
           emit2 ("!leave");
         }
 
-#if CALLEE_SAVES
-      if (_G.stack.pushedDE) 
+      if (_G.calleeSaves.pushedDE) 
         {
           emit2 ("pop de");
         {
           emit2 ("pop de");
-          _G.stack.pushedDE = FALSE;
+          _G.calleeSaves.pushedDE = FALSE;
         }
 
         }
 
-      if (_G.stack.pushedDE
+      if (_G.calleeSaves.pushedBC
         {
           emit2 ("pop bc");
         {
           emit2 ("pop bc");
-          _G.stack.pushedDE = FALSE;
+          _G.calleeSaves.pushedBC = FALSE;
         }
         }
-#endif
 
       if (options.profile) 
         {
 
       if (options.profile) 
         {
@@ -2553,8 +3021,8 @@ genEndFunction (iCode * ic)
       /* Both baned and non-banked just ret */
       emit2 ("ret");
 
       /* Both baned and non-banked just ret */
       emit2 ("ret");
 
-      /* PENDING: portability. */
-      emit2 ("__%s_end:", sym->rname);
+      sprintf (buffer, "%s_end", sym->rname);
+      emit2 ("!labeldef", buffer);
     }
   _G.flushStatics = 1;
   _G.stack.pushed = 0;
     }
   _G.flushStatics = 1;
   _G.stack.pushed = 0;
@@ -2598,7 +3066,7 @@ genRet (iCode * ic)
       if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
        {
          fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
       if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
        {
          fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
-         fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
+         fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
        }
       else
        {
        }
       else
        {
@@ -2669,14 +3137,27 @@ genPlusIncr (iCode * ic)
     {
       if (isLitWord (AOP (IC_LEFT (ic))))
        {
     {
       if (isLitWord (AOP (IC_LEFT (ic))))
        {
-         fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
+          fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
          return TRUE;
        }
       if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
        {
          return TRUE;
        }
       if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
        {
-         fetchPair (resultId, AOP (IC_RIGHT (ic)));
-         emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
-         return TRUE;
+          if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
+            {
+              PAIR_ID freep = getFreePairId (ic);
+              if (freep != PAIR_INVALID)
+                {
+                  fetchPair (freep, AOP (IC_RIGHT (ic)));
+                  emit2 ("add hl,%s", _pairs[freep].name);
+                  return TRUE;
+                }
+            }
+          else
+            {
+              fetchPair (resultId, AOP (IC_RIGHT (ic)));
+              emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
+              return TRUE;
+            }
        }
       if (icount > 5)
        return FALSE;
        }
       if (icount > 5)
        return FALSE;
@@ -2685,8 +3166,7 @@ genPlusIncr (iCode * ic)
        {
          if (icount > 2)
            return FALSE;
        {
          if (icount > 2)
            return FALSE;
-         movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
-         movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
+         movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
        }
       while (icount--)
        {
        }
       while (icount--)
        {
@@ -2695,6 +3175,13 @@ genPlusIncr (iCode * ic)
       return TRUE;
     }
 
       return TRUE;
     }
 
+  if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
+    {
+      fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
+      commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
+      return TRUE;
+    }
+
   /* if the literal value of the right hand side
      is greater than 4 then it is not worth it */
   if (icount > 4)
   /* if the literal value of the right hand side
      is greater than 4 then it is not worth it */
   if (icount > 4)
@@ -2726,6 +3213,18 @@ genPlusIncr (iCode * ic)
       AOP_SIZE (IC_LEFT (ic)) > 1)
     return FALSE;
 
       AOP_SIZE (IC_LEFT (ic)) > 1)
     return FALSE;
 
+  /* If the result is in a register then we can load then increment.
+   */
+  if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
+    {
+      aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
+      while (icount--)
+        {
+          emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
+        }
+      return TRUE;
+    }
+
   /* we can if the aops of the left & result match or
      if they are in registers and the registers are the
      same */
   /* we can if the aops of the left & result match or
      if they are in registers and the registers are the
      same */
@@ -2762,6 +3261,86 @@ outBitAcc (operand * result)
     }
 }
 
     }
 }
 
+bool
+couldDestroyCarry (asmop *aop)
+{
+  if (aop)
+    {
+      if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
+        {
+          return TRUE;
+        }
+    }
+  return FALSE;
+}
+
+static void
+shiftIntoPair (int idx, asmop *aop)
+{
+  PAIR_ID id = PAIR_INVALID;
+
+  wassertl (IS_Z80, "Only implemented for the Z80");
+  //  wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
+
+  switch (idx) 
+    {
+    case 0:
+      id = PAIR_HL;
+      break;
+    case 1:
+      id = PAIR_DE;
+      _push (PAIR_DE);
+      break;
+    default:
+      wassertl (0, "Internal error - hit default case");
+    }
+
+  emitDebug ("; Shift into pair idx %u", idx);
+
+  if (id == PAIR_HL)
+    {
+      setupPair (PAIR_HL, aop, 0);
+    }
+  else
+    {
+      setupPair (PAIR_IY, aop, 0);
+      emit2 ("push iy");
+      emit2 ("pop %s", _pairs[id].name);
+    }
+
+  aop->type = AOP_PAIRPTR;
+  aop->aopu.aop_pairId = id;
+  _G.pairs[id].offset = 0;
+  _G.pairs[id].last_type = aop->type;
+}
+
+static void 
+setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
+{
+  wassert (left && right);
+
+  if (IS_Z80)
+    {
+      if (couldDestroyCarry (right) && couldDestroyCarry (result))
+        {
+          shiftIntoPair (0, right);
+          shiftIntoPair (1, result);
+        }
+      else if (couldDestroyCarry (right))
+        {
+          shiftIntoPair (0, right);
+        }
+      else if (couldDestroyCarry (result))
+        {
+          shiftIntoPair (0, result);
+        }
+      else
+        {
+          /* Fine */
+        }
+    }
+}
+
 /*-----------------------------------------------------------------*/
 /* genPlus - generates code for addition                           */
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 /* genPlus - generates code for addition                           */
 /*-----------------------------------------------------------------*/
@@ -2836,12 +3415,48 @@ genPlus (iCode * ic)
        }
     }
 
        }
     }
 
-  if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
+  if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
     {
       /* Fetch into HL then do the add */
     {
       /* Fetch into HL then do the add */
+      PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
+      PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
+
       spillPair (PAIR_HL);
       spillPair (PAIR_HL);
+      
+      if (left == PAIR_HL && right != PAIR_INVALID)
+        {
+          emit2 ("add hl,%s", _pairs[right].name);
+          goto release;
+        }
+      else if (right == PAIR_HL && left != PAIR_INVALID)
+        {
+          emit2 ("add hl,%s", _pairs[left].name);
+          goto release;
+        }
+      else if (right != PAIR_INVALID && right != PAIR_HL)
+        {
+          fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
+          emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
+          goto release;
+        }
+      else if (left != PAIR_INVALID && left != PAIR_HL)
+        { 
+          fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
+          emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
+          goto release;
+        }
+      else
+        {
+          /* Can't do it */
+        }
+    }
+
+  if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
+    {
       fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
       emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
       fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
       emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
+      spillCached();
+      commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
       goto release;
     }
 
       goto release;
     }
 
@@ -2916,6 +3531,8 @@ genPlus (iCode * ic)
         }
     }
 
         }
     }
 
+  setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
+
   while (size--)
     {
       if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
   while (size--)
     {
       if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
@@ -2981,8 +3598,7 @@ genMinusDec (iCode * ic)
   /* If result is a pair */
   if (isPair (AOP (IC_RESULT (ic))))
     {
   /* If result is a pair */
   if (isPair (AOP (IC_RESULT (ic))))
     {
-      movLeft2Result (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0);
-      movLeft2Result (IC_LEFT (ic), 1, IC_RESULT (ic), 1, 0);
+      movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
       while (icount--)
        emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
       return TRUE;
       while (icount--)
        emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
       return TRUE;
@@ -3094,7 +3710,10 @@ genMinus (iCode * ic)
              emit2 ("ld a,%s", _pairs[left].h);
              emit2 ("sbc a,%s", _pairs[right].h);
 
              emit2 ("ld a,%s", _pairs[left].h);
              emit2 ("sbc a,%s", _pairs[right].h);
 
-             aopPut (AOP (IC_RESULT (ic)), "a", 1);
+              if ( AOP_SIZE (IC_RESULT (ic)) > 1)
+                {
+                  aopPut (AOP (IC_RESULT (ic)), "a", 1);
+                }
              aopPut (AOP (IC_RESULT (ic)), "e", 0);
              goto release;
            }
              aopPut (AOP (IC_RESULT (ic)), "e", 0);
              goto release;
            }
@@ -3109,6 +3728,8 @@ genMinus (iCode * ic)
         }
     }
 
         }
     }
 
+  setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
+
   /* if literal, add a,#-lit, else normal subb */
   while (size--)
     {
   /* if literal, add a,#-lit, else normal subb */
   while (size--)
     {
@@ -3152,8 +3773,94 @@ release:
 static void
 genMult (iCode * ic)
 {
 static void
 genMult (iCode * ic)
 {
+  int val;
+  int count, i;
+  /* If true then the final operation should be a subtract */
+  bool active = FALSE;
+
   /* Shouldn't occur - all done through function calls */
   /* Shouldn't occur - all done through function calls */
-  wassertl (0, "Multiplication is handled through support function calls");
+  aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
+  aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
+  aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
+
+  if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
+      AOP_SIZE (IC_RIGHT (ic)) > 2 ||
+      AOP_SIZE (IC_RESULT (ic)) > 2)
+    {
+      wassertl (0, "Multiplication is handled through support function calls");
+    }
+
+  /* Swap left and right such that right is a literal */
+  if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
+    {
+      operand *t = IC_RIGHT (ic);
+      IC_RIGHT (ic) = IC_LEFT (ic);
+      IC_LEFT (ic) = t;
+    }
+
+  wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
+
+  val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
+  //  wassertl (val > 0, "Multiply must be positive");
+  wassertl (val != 1, "Can't multiply by 1");
+
+  if (IS_Z80 && isPairInUseNotInRet (PAIR_DE, ic)) {
+    _push (PAIR_DE);
+    _G.stack.pushedDE = TRUE;
+  }
+
+  if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
+    {
+      emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
+      emit2 ("ld a,e");
+      emit2 ("rlc a");
+      emit2 ("sbc a,a");
+      emit2 ("ld d,a");
+    }
+  else
+    {
+      fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
+    }
+
+  i = val;
+
+  /* Fully unroled version of mul.s.  Not the most efficient.
+   */
+  for (count = 0; count < 16; count++)
+    {
+      if (count != 0 && active)
+        {
+          emit2 ("add hl,hl");
+        }
+      if (i & 0x8000U)
+        {
+          if (active == FALSE)
+            {
+              emit2 ("ld l,e");
+              emit2 ("ld h,d");
+            }
+          else
+            {
+              emit2 ("add hl,de");
+            }
+          active = TRUE;
+        }
+      i <<= 1;
+    }
+
+  spillCached();
+
+  if (IS_Z80 && _G.stack.pushedDE)
+    {
+      _pop (PAIR_DE);
+      _G.stack.pushedDE = FALSE;
+    }
+
+  commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
+
+  freeAsmop (IC_LEFT (ic), NULL, ic);
+  freeAsmop (IC_RIGHT (ic), NULL, ic);
+  freeAsmop (IC_RESULT (ic), NULL, ic);
 }
 
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
@@ -3202,6 +3909,14 @@ genIfxJump (iCode * ic, char *jval)
        {
          inst = "nc";
        }
        {
          inst = "nc";
        }
+      else if (!strcmp (jval, "m"))
+       {
+         inst = "m";
+       }
+      else if (!strcmp (jval, "p"))
+       {
+         inst = "p";
+       }
       else
        {
          /* The buffer contains the bit on A that we should test */
       else
        {
          /* The buffer contains the bit on A that we should test */
@@ -3224,6 +3939,14 @@ genIfxJump (iCode * ic, char *jval)
        {
          inst = "c";
        }
        {
          inst = "c";
        }
+      else if (!strcmp (jval, "m"))
+       {
+         inst = "p";
+       }
+      else if (!strcmp (jval, "p"))
+       {
+         inst = "m";
+       }
       else
        {
          /* The buffer contains the bit on A that we should test */
       else
        {
          /* The buffer contains the bit on A that we should test */
@@ -3241,6 +3964,12 @@ genIfxJump (iCode * ic, char *jval)
   else if (!strcmp (jval, "nc"))
     {
     }
   else if (!strcmp (jval, "nc"))
     {
     }
+  else if (!strcmp (jval, "m"))
+    {
+    }
+  else if (!strcmp (jval, "p"))
+    {
+    }
   else
     {
       emit2 ("bit %s,a", jval);
   else
     {
       emit2 ("bit %s,a", jval);
@@ -3259,30 +3988,7 @@ _getPairIdName (PAIR_ID id)
 }
 #endif
 
 }
 #endif
 
-/** Generic compare for > or <
- */
-static void
-genCmp (operand * left, operand * right,
-       operand * result, iCode * ifx, int sign)
-{
-  int size, offset = 0;
-  unsigned long lit = 0L;
-  bool swap_sense = FALSE;
-
-  /* if left & right are bit variables */
-  if (AOP_TYPE (left) == AOP_CRY &&
-      AOP_TYPE (right) == AOP_CRY)
-    {
-      /* Cant happen on the Z80 */
-      wassertl (0, "Tried to compare two bits");
-    }
-  else
-    {
-      /* subtract right from left if at the
-         end the carry flag is set then we know that
-         left is greater than right */
-      size = max (AOP_SIZE (left), AOP_SIZE (right));
-
+#if OLD
       /* if unsigned char cmp with lit, just compare */
       if ((size == 1) &&
          (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
       /* if unsigned char cmp with lit, just compare */
       if ((size == 1) &&
          (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
@@ -3313,10 +4019,10 @@ genCmp (operand * left, operand * right,
                   // Save the flags
                   emit2 ("push af");
                   emit2 ("ld a,(de)");
                   // Save the flags
                   emit2 ("push af");
                   emit2 ("ld a,(de)");
-                  emit2 ("xor #0x80");
+                  emit2 ("xor !immedbyte", 0x80);
                   emit2 ("ld e,a");
                   emit2 ("ld a,(hl)");
                   emit2 ("ld e,a");
                   emit2 ("ld a,(hl)");
-                  emit2 ("xor #0x80");
+                  emit2 ("xor !immedbyte", 0x80);
                   emit2 ("ld d,a");
                   emit2 ("pop af");
                   emit2 ("ld a,e");
                   emit2 ("ld d,a");
                   emit2 ("pop af");
                   emit2 ("ld a,e");
@@ -3337,6 +4043,43 @@ genCmp (operand * left, operand * right,
             }
           spillPair (PAIR_HL);
         }
             }
           spillPair (PAIR_HL);
         }
+      else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
+        {
+          setupPair (PAIR_HL, AOP (left), 0);
+          aopGet (AOP(right), LSB, FALSE);
+
+          while (size--)
+            {
+              if (size == 0 && sign)
+                {
+                  // Highest byte when signed needs the bits flipped
+                  // Save the flags
+                  emit2 ("push af");
+                  emit2 ("ld a,(hl)");
+                  emit2 ("xor !immedbyte", 0x80);
+                  emit2 ("ld l,a");
+                  emit2 ("ld a,%d(iy)", offset);
+                  emit2 ("xor !immedbyte", 0x80);
+                  emit2 ("ld h,a");
+                  emit2 ("pop af");
+                  emit2 ("ld a,l");
+                  emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
+                }
+              else
+                {
+                  emit2 ("ld a,(hl)");
+                  emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
+                }
+              
+              if (size != 0)
+                {
+                  emit2 ("inc hl");
+                }
+              offset++;
+            }
+          spillPair (PAIR_HL);
+          spillPair (PAIR_IY);
+        }
       else
        {
          if (AOP_TYPE (right) == AOP_LIT)
       else
        {
          if (AOP_TYPE (right) == AOP_LIT)
@@ -3365,6 +4108,7 @@ genCmp (operand * left, operand * right,
                  goto release;
                }
            }
                  goto release;
                }
            }
+          
          if (sign)
            {
              /* First setup h and l contaning the top most bytes XORed */
          if (sign)
            {
              /* First setup h and l contaning the top most bytes XORed */
@@ -3419,10 +4163,109 @@ genCmp (operand * left, operand * right,
            }
        }
     }
            }
        }
     }
+#endif
+
+/** Generic compare for > or <
+ */
+static void
+genCmp (operand * left, operand * right,
+       operand * result, iCode * ifx, int sign)
+{
+  int size, offset = 0;
+  unsigned long lit = 0L;
+  bool swap_sense = FALSE;
+
+  /* if left & right are bit variables */
+  if (AOP_TYPE (left) == AOP_CRY &&
+      AOP_TYPE (right) == AOP_CRY)
+    {
+      /* Cant happen on the Z80 */
+      wassertl (0, "Tried to compare two bits");
+    }
+  else
+    {
+      /* Do a long subtract of right from left. */
+      size = max (AOP_SIZE (left), AOP_SIZE (right));
+
+      if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
+        {
+          // On the Gameboy we can't afford to adjust HL as it may trash the carry.
+          // Pull left into DE and right into HL
+          aopGet (AOP(left), LSB, FALSE);
+          emit2 ("ld d,h");
+          emit2 ("ld e,l");
+          aopGet (AOP(right), LSB, FALSE);
+
+          while (size--)
+            {
+              emit2 ("ld a,(de)");
+              emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
+              
+              if (size != 0)
+                {
+                  emit2 ("inc hl");
+                  emit2 ("inc de");
+                }
+              offset++;
+            }
+          spillPair (PAIR_HL);
+          goto release;
+        }
+
+      if (AOP_TYPE (right) == AOP_LIT)
+        {
+          lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+          /* optimize if(x < 0) or if(x >= 0) */
+          if (lit == 0)
+            {
+              if (!sign)
+                {
+                  /* No sign so it's always false */
+                  _clearCarry();
+                }
+              else
+                {
+                  /* Just load in the top most bit */
+                  _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
+                  if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
+                    {
+                      genIfxJump (ifx, "7");
+                      return;
+                    }
+                  else
+                    {
+                      if (!sign) 
+                        {
+                          emit2 ("rlc a");
+                        }
+                      if (ifx)
+                        {
+                          genIfxJump (ifx, swap_sense ? "c" : "nc");
+                          return;
+                        }
+                    }
+                }
+              goto release;
+            }
+        }
+
+      while (size--)
+        {
+          _moveA (aopGet (AOP (left), offset, FALSE));
+          /* Subtract through, propagating the carry */
+          emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
+          offset++;
+        }
+    }
 
 release:
   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
     {
 
 release:
   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
     {
+      if (sign)
+        {
+          /* Shift the sign bit up into carry */
+          emit2 ("rlca");
+        }
       outBitCLong (result, swap_sense);
     }
   else
       outBitCLong (result, swap_sense);
     }
   else
@@ -3431,9 +4274,33 @@ release:
          ifx conditional branch then generate
          code a little differently */
       if (ifx)
          ifx conditional branch then generate
          code a little differently */
       if (ifx)
-       genIfxJump (ifx, swap_sense ? "nc" : "c");
+        {
+          if (sign)
+            {
+              if (IS_GB)
+                {
+                  emit2 ("rlca");
+                  genIfxJump (ifx, swap_sense ? "nc" : "c");
+                }
+              else
+                {
+                  genIfxJump (ifx, swap_sense ? "p" : "m");
+                }
+            }
+          else
+            {
+              genIfxJump (ifx, swap_sense ? "nc" : "c");
+            }
+        }
       else
       else
-       outBitCLong (result, swap_sense);
+        {
+          if (sign)
+            {
+              /* Shift the sign bit up into carry */
+              emit2 ("rlca");
+            }
+          outBitCLong (result, swap_sense);
+        }
       /* leave the result in acc */
     }
 }
       /* leave the result in acc */
     }
 }
@@ -3516,7 +4383,9 @@ gencjneshort (operand * left, operand * right, symbol * lbl)
     }
 
   if (AOP_TYPE (right) == AOP_LIT)
     }
 
   if (AOP_TYPE (right) == AOP_LIT)
-    lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+    {
+      lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+    }
 
   /* if the right side is a literal then anything goes */
   if (AOP_TYPE (right) == AOP_LIT &&
 
   /* if the right side is a literal then anything goes */
   if (AOP_TYPE (right) == AOP_LIT &&
@@ -3527,11 +4396,9 @@ gencjneshort (operand * left, operand * right, symbol * lbl)
          emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
          if (size > 1)
            {
          emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
          if (size > 1)
            {
-             size--;
-             offset++;
-             while (size--)
+             while (--size)
                {
                {
-                 emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE));
+                 emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
                }
            }
          else
                }
            }
          else
@@ -3619,7 +4486,7 @@ genCmpEq (iCode * ic, iCode * ifx)
   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
 
   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
 
-  emitDebug ("; genCmpEq: left %u, right %u, result %u\n", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
+  emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
 
   /* Swap operands if it makes the operation easier. ie if:
      1.  Left is a literal.
 
   /* Swap operands if it makes the operation easier. ie if:
      1.  Left is a literal.
@@ -3672,6 +4539,8 @@ genCmpEq (iCode * ic, iCode * ifx)
     }
   else
     {
     }
   else
     {
+      emitDebug(";4");
+      
       gencjne (left, right, newiTempLabel (NULL));
       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
        {
       gencjne (left, right, newiTempLabel (NULL));
       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
        {
@@ -3679,6 +4548,7 @@ genCmpEq (iCode * ic, iCode * ifx)
        }
       if (ifx)
        {
        }
       if (ifx)
        {
+          emitDebug(";5");
          genIfxJump (ifx, "a");
          goto release;
        }
          genIfxJump (ifx, "a");
          goto release;
        }
@@ -3686,6 +4556,7 @@ genCmpEq (iCode * ic, iCode * ifx)
          then put the result in place */
       if (AOP_TYPE (result) != AOP_CRY)
        {
          then put the result in place */
       if (AOP_TYPE (result) != AOP_CRY)
        {
+          emitDebug(";6");
          outAcc (result);
        }
       /* leave the result in acc */
          outAcc (result);
        }
       /* leave the result in acc */
@@ -4415,6 +5286,7 @@ genGetHbit (iCode * ic)
   operand *left, *result;
   left = IC_LEFT (ic);
   result = IC_RESULT (ic);
   operand *left, *result;
   left = IC_LEFT (ic);
   result = IC_RESULT (ic);
+
   aopOp (left, ic, FALSE, FALSE);
   aopOp (result, ic, FALSE, FALSE);
 
   aopOp (left, ic, FALSE, FALSE);
   aopOp (result, ic, FALSE, FALSE);
 
@@ -4429,8 +5301,7 @@ genGetHbit (iCode * ic)
   else
     {
       emit2 ("rlc a");
   else
     {
       emit2 ("rlc a");
-      /* PENDING: For re-target. */
-      emit2 ("and a,#1");
+      emit2 ("and a,!one");
       outAcc (result);
     }
 
       outAcc (result);
     }
 
@@ -4518,9 +5389,16 @@ shiftL2Left2Result (operand * left, int offl,
       movLeft2Result (left, offl, result, offr, 0);
       movLeft2Result (left, offl + 1, result, offr + 1, 0);
     }
       movLeft2Result (left, offl, result, offr, 0);
       movLeft2Result (left, offl + 1, result, offr + 1, 0);
     }
-  /* PENDING: for now just see if it'll work. */
-  /*if (AOP(result)->type == AOP_REG) { */
-  {
+
+  if (getPairId (AOP (result)) == PAIR_HL)
+    {
+      while (shCount--)
+       {
+         emit2 ("add hl,hl");
+       }
+    }
+  else
+    {
     int size = 2;
     int offset = 0;
     symbol *tlbl, *tlbl1;
     int size = 2;
     int offset = 0;
     symbol *tlbl, *tlbl1;
@@ -4529,34 +5407,56 @@ shiftL2Left2Result (operand * left, int offl,
     tlbl = newiTempLabel (NULL);
     tlbl1 = newiTempLabel (NULL);
 
     tlbl = newiTempLabel (NULL);
     tlbl1 = newiTempLabel (NULL);
 
-    /* Left is already in result - so now do the shift */
-    if (shCount > 1)
+    if (AOP (result)->type == AOP_REG)
       {
       {
-       emit2 ("ld a,!immedbyte+1", shCount);
-       emit2 ("!shortjp !tlabel", tlbl1->key + 100);
-       emitLabel (tlbl->key + 100);
+       while (shCount--)
+         {
+           for (offset = 0; offset < size; offset++)
+             {
+               l = aopGet (AOP (result), offset, FALSE);
+           
+               if (offset == 0)
+                 {
+                   emit2 ("sla %s", l);
+                 }
+               else
+                 {
+                   emit2 ("rl %s", l);
+                 }
+             }
+         }
       }
       }
-
-    while (size--)
+    else
       {
       {
-       l = aopGet (AOP (result), offset, FALSE);
-
-        if (offset == 0)
-          {
-            emit2 ("sla %s", l);
-          }
-        else
-          {
-            emit2 ("rl %s", l);
-          }
+       /* Left is already in result - so now do the shift */
+       if (shCount > 1)
+         {
+           emit2 ("ld a,!immedbyte+1", shCount);
+           emit2 ("!shortjp !tlabel", tlbl1->key + 100);
+           emitLabel (tlbl->key + 100);
+         }
 
 
-        offset++;
-      }
-    if (shCount > 1)
-      {
-       emitLabel (tlbl1->key + 100);
-       emit2 ("dec a");
-       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+       while (size--)
+         {
+           l = aopGet (AOP (result), offset, FALSE);
+           
+           if (offset == 0)
+             {
+               emit2 ("sla %s", l);
+             }
+           else
+             {
+               emit2 ("rl %s", l);
+             }
+           
+           offset++;
+         }
+       if (shCount > 1)
+         {
+           emitLabel (tlbl1->key + 100);
+           emit2 ("dec a");
+           emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+         }
       }
   }
 }
       }
   }
 }
@@ -5123,7 +6023,9 @@ genGenPointerGet (operand * left,
   aopOp (left, ic, FALSE, FALSE);
   aopOp (result, ic, FALSE, FALSE);
 
   aopOp (left, ic, FALSE, FALSE);
   aopOp (result, ic, FALSE, FALSE);
 
-  if (isPair (AOP (left)) && AOP_SIZE (result) == 1)
+  size = AOP_SIZE (result);
+
+  if (isPair (AOP (left)) && size == 1)
     {
       /* Just do it */
       if (isPtrPair (AOP (left)))
     {
       /* Just do it */
       if (isPtrPair (AOP (left)))
@@ -5140,18 +6042,69 @@ genGenPointerGet (operand * left,
       goto release;
     }
 
       goto release;
     }
 
+  if (getPairId (AOP (left)) == PAIR_IY)
+    {
+      /* Just do it */
+      offset = 0;
+      while (size--) 
+        {
+          char at[20];
+          tsprintf (at, "!*iyx", offset);
+          aopPut (AOP (result), at, offset);
+          offset++;
+        }
+      freeAsmop (left, NULL, ic);
+      goto release;
+    }
+
   /* For now we always load into IY */
   /* if this is remateriazable */
   fetchPair (pair, AOP (left));
 
   /* For now we always load into IY */
   /* if this is remateriazable */
   fetchPair (pair, AOP (left));
 
-  /* so iy now contains the address */
-  freeAsmop (left, NULL, ic);
-
   /* if bit then unpack */
   if (IS_BITVAR (retype))
     {
       wassert (0);
     }
   /* if bit then unpack */
   if (IS_BITVAR (retype))
     {
       wassert (0);
     }
+  else if (getPairId (AOP (result)) == PAIR_HL)
+    {
+      wassertl (size == 2, "HL must be of size 2");
+      emit2 ("ld a,!*hl");
+      emit2 ("inc hl");
+      emit2 ("ld h,!*hl");
+      emit2 ("ld l,a");
+      spillPair (PAIR_HL);
+    }
+  else if (getPairId (AOP (left)) == PAIR_HL && !isLastUse (ic, left))
+    {
+      size = AOP_SIZE (result);
+      offset = 0;
+
+      while (size--)
+       {
+         /* PENDING: make this better */
+         if (!IS_GB && AOP_TYPE (result) == AOP_REG)
+           {
+             aopPut (AOP (result), "!*hl", offset++);
+           }
+         else
+           {
+             emit2 ("ld a,!*pair", _pairs[pair].name);
+             aopPut (AOP (result), "a", offset++);
+           }
+         if (size)
+           {
+             emit2 ("inc %s", _pairs[pair].name);
+             _G.pairs[pair].offset++;
+           }
+       }
+      /* Fixup HL back down */
+      for (size = AOP_SIZE (result)-1; size; size--)
+        {
+          emit2 ("dec %s", _pairs[pair].name);
+        }
+    }
   else
     {
       size = AOP_SIZE (result);
   else
     {
       size = AOP_SIZE (result);
@@ -5160,7 +6113,8 @@ genGenPointerGet (operand * left,
       while (size--)
        {
          /* PENDING: make this better */
       while (size--)
        {
          /* PENDING: make this better */
-         if (!IS_GB && AOP (result)->type == AOP_REG)
+         if (!IS_GB && 
+              (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
            {
              aopPut (AOP (result), "!*hl", offset++);
            }
            {
              aopPut (AOP (result), "!*hl", offset++);
            }
@@ -5177,6 +6131,8 @@ genGenPointerGet (operand * left,
        }
     }
 
        }
     }
 
+  freeAsmop (left, NULL, ic);
+
 release:
   freeAsmop (result, NULL, ic);
 }
 release:
   freeAsmop (result, NULL, ic);
 }
@@ -5204,7 +6160,7 @@ genPointerGet (iCode * ic)
 bool
 isRegOrLit (asmop * aop)
 {
 bool
 isRegOrLit (asmop * aop)
 {
-  if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
+  if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
     return TRUE;
   return FALSE;
 }
     return TRUE;
   return FALSE;
 }
@@ -5219,15 +6175,17 @@ genGenPointerSet (operand * right,
   int size, offset;
   sym_link *retype = getSpec (operandType (right));
   PAIR_ID pairId = PAIR_HL;
   int size, offset;
   sym_link *retype = getSpec (operandType (right));
   PAIR_ID pairId = PAIR_HL;
-
+  
   aopOp (result, ic, FALSE, FALSE);
   aopOp (right, ic, FALSE, FALSE);
 
   if (IS_GB)
     pairId = PAIR_DE;
 
   aopOp (result, ic, FALSE, FALSE);
   aopOp (right, ic, FALSE, FALSE);
 
   if (IS_GB)
     pairId = PAIR_DE;
 
+  size = AOP_SIZE (right);
+
   /* Handle the exceptions first */
   /* Handle the exceptions first */
-  if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
+  if (isPair (AOP (result)) && size == 1)
     {
       /* Just do it */
       const char *l = aopGet (AOP (right), 0, FALSE);
     {
       /* Just do it */
       const char *l = aopGet (AOP (right), 0, FALSE);
@@ -5243,6 +6201,59 @@ genGenPointerSet (operand * right,
        }
       goto release;
     }
        }
       goto release;
     }
+  
+  if ( getPairId( AOP (result)) == PAIR_IY)
+    {
+      /* Just do it */
+      const char *l = aopGet (AOP (right), 0, FALSE);
+
+      offset = 0;
+      while (size--) 
+        {
+          if (canAssignToPtr (l))
+            {
+              emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
+            }
+          else
+            {
+              _moveA (aopGet (AOP (right), offset, FALSE));
+              emit2 ("ld !*iyx,a", offset);
+            }
+          offset++;
+        }
+      goto release;
+    }
+  else if (getPairId (AOP (result)) == PAIR_HL && !isLastUse (ic, result))
+    {
+      offset = 0;
+
+      while (size--)
+       {
+         const char *l = aopGet (AOP (right), offset, FALSE);
+         if (isRegOrLit (AOP (right)) && !IS_GB)
+           {
+             emit2 ("ld !*pair,%s", _pairs[PAIR_HL].name, l);
+           }
+         else
+           {
+             _moveA (l);
+             emit2 ("ld !*pair,a", _pairs[PAIR_HL].name);
+           }
+         if (size)
+           {
+             emit2 ("inc %s", _pairs[PAIR_HL].name);
+             _G.pairs[PAIR_HL].offset++;
+           }
+         offset++;
+       }
+
+      /* Fixup HL back down */
+      for (size = AOP_SIZE (right)-1; size; size--)
+        {
+          emit2 ("dec %s", _pairs[PAIR_HL].name);
+        }
+      goto release;
+    }
 
   /* if the operand is already in dptr
      then we do nothing else we move the value to dptr */
 
   /* if the operand is already in dptr
      then we do nothing else we move the value to dptr */
@@ -5260,7 +6271,6 @@ genGenPointerSet (operand * right,
     }
   else
     {
     }
   else
     {
-      size = AOP_SIZE (right);
       offset = 0;
 
       while (size--)
       offset = 0;
 
       while (size--)
@@ -5362,21 +6372,19 @@ genAddrOf (iCode * ic)
          spillCached ();
          if (sym->stack <= 0)
            {
          spillCached ();
          if (sym->stack <= 0)
            {
-             emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
+              setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
            }
          else
            {
            }
          else
            {
-             emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
+              setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
            }
            }
-         emit2 ("ld d,h");
-         emit2 ("ld e,l");
+          commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
        }
       else
        {
          emit2 ("ld de,!hashedstr", sym->rname);
        }
       else
        {
          emit2 ("ld de,!hashedstr", sym->rname);
+          commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
        }
        }
-      aopPut (AOP (IC_RESULT (ic)), "e", 0);
-      aopPut (AOP (IC_RESULT (ic)), "d", 1);
     }
   else
     {
     }
   else
     {
@@ -5385,17 +6393,16 @@ genAddrOf (iCode * ic)
        {
          /* if it has an offset  then we need to compute it */
          if (sym->stack > 0)
        {
          /* if it has an offset  then we need to compute it */
          if (sym->stack > 0)
-           emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
+           emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
          else
          else
-           emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
+           emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
          emit2 ("add hl,sp");
        }
       else
        {
          emit2 ("add hl,sp");
        }
       else
        {
-         emit2 ("ld hl,#%s", sym->rname);
+         emit2 ("ld hl,!hashedstr", sym->rname);
        }
        }
-      aopPut (AOP (IC_RESULT (ic)), "l", 0);
-      aopPut (AOP (IC_RESULT (ic)), "h", 1);
+      commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
     }
   freeAsmop (IC_RESULT (ic), NULL, ic);
 }
     }
   freeAsmop (IC_RESULT (ic), NULL, ic);
 }
@@ -5441,10 +6448,13 @@ genAssign (iCode * ic)
   offset = 0;
 
   if (AOP_TYPE (right) == AOP_LIT)
   offset = 0;
 
   if (AOP_TYPE (right) == AOP_LIT)
-    lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+    {
+      lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
+    }
+
   if (isPair (AOP (result)))
     {
   if (isPair (AOP (result)))
     {
-      fetchPair (getPairId (AOP (result)), AOP (right));
+      fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
     }
   else if ((size > 1) &&
           (AOP_TYPE (result) != AOP_REG) &&
     }
   else if ((size > 1) &&
           (AOP_TYPE (result) != AOP_REG) &&
@@ -5482,6 +6492,12 @@ genAssign (iCode * ic)
          offset++;
        }
     }
          offset++;
        }
     }
+  else if (size == 2 && AOP_TYPE (right) == AOP_IY)
+    {
+      emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
+      aopPut (AOP (result), "l", LSB);
+      aopPut (AOP (result), "h", MSB16);
+    }
   else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
     {
       /* Special case.  Load into a and d, then load out. */
   else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
     {
       /* Special case.  Load into a and d, then load out. */
@@ -5517,7 +6533,7 @@ genAssign (iCode * ic)
       while (size--)
        {
          /* PENDING: do this check better */
       while (size--)
        {
          /* PENDING: do this check better */
-         if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
+         if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
            {
              _moveA (aopGet (AOP (right), offset, FALSE));
              aopPut (AOP (result), "a", offset);
            {
              _moveA (aopGet (AOP (right), offset, FALSE));
              aopPut (AOP (result), "a", offset);
@@ -5575,7 +6591,7 @@ static void
 genCast (iCode * ic)
 {
   operand *result = IC_RESULT (ic);
 genCast (iCode * ic)
 {
   operand *result = IC_RESULT (ic);
-  sym_link *ctype = operandType (IC_LEFT (ic));
+  sym_link *rtype = operandType (IC_RIGHT (ic));
   operand *right = IC_RIGHT (ic);
   int size, offset;
 
   operand *right = IC_RIGHT (ic);
   int size, offset;
 
@@ -5629,7 +6645,7 @@ genCast (iCode * ic)
   /* now depending on the sign of the destination */
   size = AOP_SIZE (result) - AOP_SIZE (right);
   /* Unsigned or not an integral type - right fill with zeros */
   /* now depending on the sign of the destination */
   size = AOP_SIZE (result) - AOP_SIZE (right);
   /* Unsigned or not an integral type - right fill with zeros */
-  if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
+  if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY)
     {
       while (size--)
        aopPut (AOP (result), "!zero", offset++);
     {
       while (size--)
        aopPut (AOP (result), "!zero", offset++);
@@ -5805,7 +6821,7 @@ _rleAppend(RLECTX *self, int c)
           /* Yes, worthwhile. */
           /* Commit whatever was in the buffer. */
           _rleCommit(self);
           /* Yes, worthwhile. */
           /* Commit whatever was in the buffer. */
           _rleCommit(self);
-          emit2(".db -%u,0x%02X", self->runLen, self->last);
+          emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
         }
       else
         {
         }
       else
         {
@@ -5830,7 +6846,7 @@ _rleAppend(RLECTX *self, int c)
           /* Commit whatever was in the buffer. */
           _rleCommit(self);
 
           /* Commit whatever was in the buffer. */
           _rleCommit(self);
 
-          emit2 (".db -%u,0x%02X", self->runLen, self->last);
+          emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
           self->runLen = 0;
         }
       self->runLen++;
           self->runLen = 0;
         }
       self->runLen++;
@@ -5864,16 +6880,10 @@ genArrayInit (iCode * ic)
 
   aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
 
 
   aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
 
-  if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
-    {
-      /* Emit the support function call and the destination address. */
-      emit2("call __initrleblock");
-      emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
-    }
-  else
-    {
-      wassertl (0, "Unexpected operand to genArrayInit.\n");
-    }
+  _saveRegsForCall(ic, 0);
+
+  fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
+  emit2 ("call __initrleblock");
     
   type = operandType(IC_LEFT(ic));
     
     
   type = operandType(IC_LEFT(ic));
     
@@ -5917,9 +6927,289 @@ genArrayInit (iCode * ic)
   /* Mark the end of the run. */
   emit2(".db 0");
 
   /* Mark the end of the run. */
   emit2(".db 0");
 
+  _restoreRegsAfterCall();
+
+  spillCached ();
+
   freeAsmop (IC_LEFT(ic), NULL, ic);
 }
 
   freeAsmop (IC_LEFT(ic), NULL, ic);
 }
 
+static void
+_swap (PAIR_ID one, PAIR_ID two)
+{
+  if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
+    {
+      emit2 ("ex de,hl");
+    }
+  else
+    {
+      emit2 ("ld a,%s", _pairs[one].l);
+      emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
+      emit2 ("ld %s,a", _pairs[two].l);
+      emit2 ("ld a,%s", _pairs[one].h);
+      emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
+      emit2 ("ld %s,a", _pairs[two].h);
+    }
+}
+
+/* The problem is that we may have all three pairs used and they may
+   be needed in a different order.
+
+   Note: Have ex de,hl
+
+   Combinations:
+     hl = hl           => unity, fine
+     bc = bc
+     de = de
+
+     hl = hl           hl = hl, swap de <=> bc
+     bc = de
+     de = bc
+
+     hl = bc           Worst case
+     bc = de
+     de = hl
+     
+     hl = bc           de = de, swap bc <=> hl
+     bc = hl
+     de = de
+
+     hl = de           Worst case
+     bc = hl
+     de = bc
+
+     hl = de           bc = bc, swap hl <=> de
+     bc = bc
+     de = hl
+
+   Break it down into:
+    * Any pair = pair are done last
+    * Any pair = iTemp are done last
+    * Any swaps can be done any time
+
+   A worst case:
+    push p1
+    p1 = p2
+    p2 = p3
+    pop  p3
+
+   So how do we detect the cases?
+   How about a 3x3 matrix?
+       source
+   dest x x x x
+        x x x x
+        x x x x (Fourth for iTemp/other)
+
+   First determin which mode to use by counting the number of unity and
+   iTemp assigns.
+     Three - any order
+     Two - Assign the pair first, then the rest
+     One - Swap the two, then the rest
+     Zero - Worst case.
+*/
+static void
+setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
+{
+  PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
+  PAIR_ID dest[3] = {
+    PAIR_BC, PAIR_HL, PAIR_DE
+  };
+  int i, j, nunity = 0;
+  memset (ids, PAIR_INVALID, sizeof (ids));
+
+  /* Sanity checks */
+  wassert (nparams == 3);
+
+  /* First save everything that needs to be saved. */
+  _saveRegsForCall (ic, 0);
+
+  /* Loading HL first means that DE is always fine. */
+  for (i = 0; i < nparams; i++)
+    {
+      aopOp (pparams[i], ic, FALSE, FALSE);
+      ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
+    }
+
+  /* Count the number of unity or iTemp assigns. */
+  for (i = 0; i < 3; i++) 
+    {
+      if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
+        {
+          nunity++;
+        }
+    }
+
+  if (nunity == 3)
+    {
+      /* Any order, fall through. */
+    }
+  else if (nunity == 2)
+    {
+      /* One is assigned.  Pull it out and assign. */
+      for (i = 0; i < 3; i++)
+        {
+          for (j = 0; j < NUM_PAIRS; j++)
+            {
+              if (ids[dest[i]][j] == TRUE)
+                {
+                  /* Found it.  See if it's the right one. */
+                  if (j == PAIR_INVALID || j == dest[i])
+                    {
+                      /* Keep looking. */
+                    }
+                  else
+                    {
+                      fetchPair(dest[i], AOP (pparams[i]));
+                      goto done;
+                    }
+                }
+            }
+        }
+    }
+  else if (nunity == 1)
+    {
+      /* Find the pairs to swap. */
+      for (i = 0; i < 3; i++)
+        {
+          for (j = 0; j < NUM_PAIRS; j++)
+            {
+              if (ids[dest[i]][j] == TRUE)
+                {
+                  if (j == PAIR_INVALID || j == dest[i])
+                    {
+                      /* Keep looking. */
+                    }
+                  else
+                    {
+                      _swap (j, dest[i]);
+                      goto done;
+                    }
+                }
+            }
+        }
+    }
+  else
+    {
+      int next = getPairId (AOP (pparams[0]));
+      emit2 ("push %s", _pairs[next].name);
+
+      if (next == dest[1])
+        {
+          fetchPair (dest[1], AOP (pparams[1]));
+          fetchPair (dest[2], AOP (pparams[2]));
+        }
+      else
+        {
+          fetchPair (dest[2], AOP (pparams[2]));
+          fetchPair (dest[1], AOP (pparams[1]));
+        }
+      emit2 ("pop %s", _pairs[dest[0]].name);
+    }
+ done:
+  /* Finally pull out all of the iTemps */
+  for (i = 0; i < 3; i++)
+    {
+      if (ids[dest[i]][PAIR_INVALID] == 1)
+        {
+          fetchPair (dest[i], AOP (pparams[i]));
+        }
+    }
+}
+
+static void
+genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
+{
+  operand *from, *to;
+  symbol *label;
+  bool deInUse;
+
+  wassertl (nParams == 2, "Built-in strcpy must have two parameters");
+  to = pparams[0];
+  from = pparams[1];
+
+  deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
+
+  setupForBuiltin3 (ic, nParams, pparams);
+
+  label = newiTempLabel(NULL);
+
+  emitLabel (label->key);
+  emit2 ("ld a,(hl)");
+  emit2 ("ldi");
+  emit2 ("or a");
+  emit2 ("!shortjp nz,!tlabel ; 1", label->key);
+
+  freeAsmop (from, NULL, ic->next);
+  freeAsmop (to, NULL, ic);
+}
+
+static void
+genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
+{
+  operand *from, *to, *count;
+  bool deInUse;
+
+  wassertl (nParams == 3, "Built-in memcpy must have two parameters");
+  to = pparams[2];
+  from = pparams[1];
+  count = pparams[0];
+
+  deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
+
+  setupForBuiltin3 (ic, nParams, pparams);
+
+  emit2 ("ldir");
+
+  freeAsmop (count, NULL, ic->next->next);
+  freeAsmop (from, NULL, ic);
+
+  _restoreRegsAfterCall();
+
+  /* if we need assign a result value */
+  if ((IS_ITEMP (IC_RESULT (ic)) &&
+       (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
+       OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
+      IS_TRUE_SYMOP (IC_RESULT (ic)))
+    {
+      aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
+      movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
+      freeAsmop (IC_RESULT (ic), NULL, ic);
+    }
+
+  freeAsmop (to, NULL, ic->next);
+}
+
+/*-----------------------------------------------------------------*/
+/* genBuiltIn - calls the appropriate function to  generating code */
+/* for a built in function                                        */
+/*-----------------------------------------------------------------*/
+static void genBuiltIn (iCode *ic)
+{
+    operand *bi_parms[MAX_BUILTIN_ARGS];
+    int nbi_parms;
+    iCode *bi_iCode;
+    symbol *bif;
+
+    /* get all the arguments for a built in function */
+    bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
+
+    /* which function is it */
+    bif = OP_SYMBOL(IC_LEFT(bi_iCode));
+
+    if (strcmp(bif->name,"__builtin_strcpy")==0) 
+      {
+       genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
+      } 
+    else if (strcmp(bif->name,"__builtin_memcpy")==0) 
+      {
+       genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
+      } 
+    else 
+      {
+       wassertl (0, "Unknown builtin function encountered");
+      }
+}
+
 /*-----------------------------------------------------------------*/
 /* genZ80Code - generate code for Z80 based controllers            */
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 /* genZ80Code - generate code for Z80 based controllers            */
 /*-----------------------------------------------------------------*/
@@ -6187,11 +7477,20 @@ genZ80Code (iCode * lic)
          break;
 
        case SEND:
          break;
 
        case SEND:
-         emitDebug ("; addSet");
-         addSet (&_G.sendSet, ic);
+         if (ic->builtinSEND)
+            {
+              emitDebug ("; genBuiltIn");
+              genBuiltIn(ic);
+            }
+          else
+            {
+              emitDebug ("; addSet");
+              addSet (&_G.sendSet, ic);
+            }
          break;
 
        case ARRAYINIT:
          break;
 
        case ARRAYINIT:
+         emitDebug ("; genArrayInit");
           genArrayInit(ic);
           break;
            
           genArrayInit(ic);
           break;