Fixed bug 772726
[fw/sdcc] / src / z80 / gen.c
index 3ed83308e307128d9d3b0679ef09146ea2c773f2..f855a0e2228ed7e778bf9e0faef3f5514d86ce23 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>
 
-#ifdef HAVE_SYS_ISA_DEFS_H
-#include <sys/isa_defs.h>
+#if defined(__BORLANDC__) || defined(_MSC_VER)
+#define STRCASECMP stricmp
+#else
+#define STRCASECMP strcasecmp
 #endif
 
 #include "z80.h"
 #endif
 
 #include "z80.h"
 #include "SDCCglue.h"
 #include "newalloc.h"
 
 #include "SDCCglue.h"
 #include "newalloc.h"
 
-/* this is the down and dirty file with all kinds of kludgy & hacky
+/* This is the down and dirty file with all kinds of kludgy & hacky
    stuff. This is what it is all about CODE GENERATION for a specific MCU.
    Some of the routines may be reusable, will have to see */
 
    stuff. This is what it is all about CODE GENERATION for a specific MCU.
    Some of the routines may be reusable, will have to see */
 
    PENDING: What if the parameter is a long?
    Everything is caller saves. i.e. the caller must save any registers
    that it wants to preserve over the call.
    PENDING: What if the parameter is a long?
    Everything is caller saves. i.e. the caller must save any registers
    that it wants to preserve over the call.
-   The return value is returned in DEHL.  DE is normally used as a
+   GB: The return value is returned in DEHL.  DE is normally used as a
    working register pair.  Caller saves allows it to be used for a
    return value.
    va args functions do not use register parameters.  All arguments
    working register pair.  Caller saves allows it to be used for a
    return value.
    va args functions do not use register parameters.  All arguments
    area.  ix-0 is the top most local variable.
 */
 
    area.  ix-0 is the top most local variable.
 */
 
-enum {
-  DISABLE_DEBUG = 1
+enum 
+{
+  /* Set to enable debugging trace statements in the output assembly code. */
+  DISABLE_DEBUG = 0
 };
 
 static char *_z80_return[] =
 };
 
 static char *_z80_return[] =
@@ -133,6 +139,14 @@ static char **_fTmp;
 
 extern FILE *codeOutFile;
 
 
 extern FILE *codeOutFile;
 
+enum
+  {
+    INT8MIN = -128,
+    INT8MAX = 127
+  };
+
+/** Enum covering all the possible register pairs.
+ */
 typedef enum
   {
     PAIR_INVALID,
 typedef enum
   {
     PAIR_INVALID,
@@ -156,17 +170,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,
@@ -175,12 +185,17 @@ enum
     MSB32
   };
 
     MSB32
   };
 
+/** Code generator persistent data.
+ */
 static struct 
 {
 static struct 
 {
+  /** Used to optimised setting up of a pair by remebering what it
+      contains and adjusting instead of reloading where possible.
+  */
   struct 
   {
     AOP_TYPE last_type;
   struct 
   {
     AOP_TYPE last_type;
-    const char *lit;
+    const char *base;
     int offset;
   } pairs[NUM_PAIRS];
   struct 
     int offset;
   } pairs[NUM_PAIRS];
   struct 
@@ -192,6 +207,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;
@@ -211,12 +233,132 @@ static struct
     lineNode *head;
     lineNode *current;
     int isInline;
     lineNode *head;
     lineNode *current;
     int isInline;
+    allocTrace trace;
   } lines;
 
   } lines;
 
+  struct
+  {
+    allocTrace aops;
+  } trace;
 } _G;
 
 static const char *aopGet (asmop * aop, int offset, bool bit16);
 
 } _G;
 
 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)
+{
+  if (IS_GB)
+    {
+      return PAIR_DE;
+    }
+  else
+    {
+      return PAIR_HL;
+    }
+}
+
+static const char *
+_getTempPairName(void)
+{
+  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)
 {
@@ -240,17 +382,28 @@ _tidyUp (char *buf)
     }
 }
 
     }
 }
 
+static lineNode *
+_newLineNode (char *line)
+{
+  lineNode *pl;
+
+  pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
+  pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
+
+  return pl;
+}
+
 static void
 _vemit2 (const char *szFormat, va_list ap)
 {
   char buffer[256];
 
 static void
 _vemit2 (const char *szFormat, va_list ap)
 {
   char buffer[256];
 
-  tvsprintf (buffer, szFormat, ap);
+  tvsprintf (buffer, sizeof(buffer), szFormat, ap);
 
   _tidyUp (buffer);
   _G.lines.current = (_G.lines.current ?
 
   _tidyUp (buffer);
   _G.lines.current = (_G.lines.current ?
-             connectLine (_G.lines.current, newLineNode (buffer)) :
-             (_G.lines.head = newLineNode (buffer)));
+             connectLine (_G.lines.current, _newLineNode (buffer)) :
+             (_G.lines.head = _newLineNode (buffer)));
 
   _G.lines.current->isInline = _G.lines.isInline;
 }
 
   _G.lines.current->isInline = _G.lines.isInline;
 }
@@ -308,8 +461,8 @@ _emit2 (const char *inst, const char *fmt,...)
   if (lbp && *lbp)
     {
       _G.lines.current = (_G.lines.current ?
   if (lbp && *lbp)
     {
       _G.lines.current = (_G.lines.current ?
-                  connectLine (_G.lines.current, newLineNode (lb)) :
-                  (_G.lines.head = newLineNode (lb)));
+                  connectLine (_G.lines.current, _newLineNode (lb)) :
+                  (_G.lines.head = _newLineNode (lb)));
     }
   _G.lines.current->isInline = _G.lines.isInline;
   va_end (ap);
     }
   _G.lines.current->isInline = _G.lines.isInline;
   va_end (ap);
@@ -318,7 +471,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);
     }
@@ -329,6 +482,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)
 {
@@ -360,22 +528,18 @@ 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;
+            }
+        }
     }
     }
-  wassert (0);
+  wassertl (0, "Tried to get the pair name of something that isn't a pair");
   return NULL;
 }
 
   return NULL;
 }
 
@@ -399,21 +563,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;
 }
@@ -439,6 +599,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)
@@ -446,6 +614,20 @@ genPairPush (asmop * aop)
   emit2 ("push %s", getPairName (aop));
 }
 
   emit2 ("push %s", getPairName (aop));
 }
 
+static void
+_push (PAIR_ID pairId)
+{
+  emit2 ("push %s", _pairs[pairId].name);
+  _G.stack.pushed += 2;
+}
+
+static void
+_pop (PAIR_ID pairId)
+{
+  emit2 ("pop %s", _pairs[pairId].name);
+  _G.stack.pushed -= 2;
+  spillPair (pairId);
+}
 
 /*-----------------------------------------------------------------*/
 /* newAsmop - creates a new asmOp                                  */
 
 /*-----------------------------------------------------------------*/
 /* newAsmop - creates a new asmOp                                  */
@@ -455,7 +637,7 @@ newAsmop (short type)
 {
   asmop *aop;
 
 {
   asmop *aop;
 
-  aop = Safe_calloc (1, sizeof (asmop));
+  aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
   aop->type = type;
   return aop;
 }
   aop->type = type;
   return aop;
 }
@@ -477,13 +659,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;
@@ -493,8 +690,7 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
   if (IS_FUNC (sym->type))
     {
       sym->aop = aop = newAsmop (AOP_IMMD);
   if (IS_FUNC (sym->type))
     {
       sym->aop = aop = newAsmop (AOP_IMMD);
-      aop->aopu.aop_immd = Safe_calloc (1, strlen (sym->rname) + 1);
-      strcpy (aop->aopu.aop_immd, sym->rname);
+      aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
       aop->size = 2;
       return aop;
     }
       aop->size = 2;
       return aop;
     }
@@ -560,8 +756,7 @@ aopForRemat (symbol * sym)
       break;
     }
 
       break;
     }
 
-  aop->aopu.aop_immd = Safe_calloc (1, strlen (buffer) + 1);
-  strcpy (aop->aopu.aop_immd, buffer);
+  aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
   return aop;
 }
 
   return aop;
 }
 
@@ -703,7 +898,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)
@@ -751,6 +948,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)
@@ -761,35 +968,37 @@ 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 
               {
          else 
               {
-                  wassert (0);
+                  wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
               }
          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;
     }
@@ -822,6 +1031,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)
@@ -835,6 +1054,7 @@ dealloc:
            SPIL_LOC (op)->aop = NULL;
        }
     }
            SPIL_LOC (op)->aop = NULL;
        }
     }
+
 }
 
 bool
 }
 
 bool
@@ -855,9 +1075,6 @@ isLitWord (asmop * aop)
 char *
 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
 {
 char *
 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)
     {
@@ -866,11 +1083,21 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
     case AOP_IMMD:
       /* PENDING: for re-target */
       if (with_hash)
     case AOP_IMMD:
       /* PENDING: for re-target */
       if (with_hash)
-       tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
+        {
+          tsprintf (buffer, sizeof(buffer), 
+                   "!hashedstr + %d", aop->aopu.aop_immd, offset);
+        }
+      else if (offset == 0)
+        {
+          tsprintf (buffer, sizeof(buffer),
+                   "%s", aop->aopu.aop_immd);
+        }
       else
       else
-       tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
-
-      return gc_strdup(s);
+        {
+          tsprintf (buffer, sizeof(buffer), 
+                   "%s + %d", aop->aopu.aop_immd, offset);
+        }
+      return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
 
     case AOP_LIT:
       {
 
     case AOP_LIT:
       {
@@ -895,23 +1122,35 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
               }
 
            if (with_hash)
               }
 
            if (with_hash)
-             tsprintf (buffer, "!immedword", v);
+             tsprintf (buffer, sizeof(buffer), "!immedword", v);
            else
            else
-             tsprintf (buffer, "!constword", v);
+             tsprintf (buffer, sizeof(buffer), "!constword", v);
 
 
-            return gc_strdup(buffer);
+            return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
          }
        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 WORDS_BIGENDIAN
+            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, sizeof(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, sizeof(buffer), "!constword", i);
+
+            return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
          }
       }
     default:
          }
       }
     default:
@@ -954,13 +1193,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].lit = NULL;
-}
-
 static void
 spillCached (void)
 {
 static void
 spillCached (void)
 {
@@ -976,40 +1208,22 @@ 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;
     }
 }
 
-static char *
-fetchLitSpecial (asmop * aop, bool negate, bool xor)
-{
-  unsigned long v;
-  value *val = aop->aopu.aop_lit;
-
-  wassert (aop->type == AOP_LIT);
-  wassert (!IS_FLOAT (val->type));
-
-  v = (unsigned long) floatFromVal (val);
-
-  if (xor)
-    v ^= 0x8000;
-  if (negate)
-    v = 0-v;
-  v &= 0xFFFF;
-
-  tsprintf (buffer, "!immedword", v);
-  return gc_strdup (buffer);
-}
-
 static void
 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
 {
 static void
 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
 {
-  const char *l;
+  const char *l, *base;
   const char *pair = _pairs[pairId].name;
   l = aopGetLitWordLong (left, offset, FALSE);
   const char *pair = _pairs[pairId].name;
   l = aopGetLitWordLong (left, offset, FALSE);
-  wassert (l && pair);
+  base = aopGetLitWordLong (left, 0, FALSE);
+  wassert (l && pair && base);
 
   if (isPtr (pair))
     {
 
   if (isPtr (pair))
     {
@@ -1017,14 +1231,14 @@ fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
        {
          if (_G.pairs[pairId].last_type == left->type)
            {
        {
          if (_G.pairs[pairId].last_type == left->type)
            {
-             if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
+             if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
                {
                  if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
                    {
                      adjustPair (pair, &_G.pairs[pairId].offset, offset);
                      return;
                    }
                {
                  if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
                    {
                      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;
                    }
@@ -1032,50 +1246,72 @@ fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
            }
        }
       _G.pairs[pairId].last_type = left->type;
            }
        }
       _G.pairs[pairId].last_type = left->type;
-      _G.pairs[pairId].lit = gc_strdup (l);
-      _G.pairs[pairId].offset = offset;
-    }
-  if (IS_GB && pairId == PAIR_DE && 0)
-    {
-      if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
-       {
-         if (abs (_G.pairs[pairId].offset - offset) < 3)
-           {
-             adjustPair (pair, &_G.pairs[pairId].offset, offset);
-             return;
-           }
-       }
-      _G.pairs[pairId].last_type = left->type;
-      _G.pairs[pairId].lit = gc_strdup (l);
+      _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
       _G.pairs[pairId].offset = offset;
     }
   /* Both a lit on the right and a true symbol on the left */
   emit2 ("ld %s,!hashedstr", pair, l);
 }
 
       _G.pairs[pairId].offset = offset;
     }
   /* Both a lit on the right and a true symbol on the left */
   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);
             aopGet (aop, offset, FALSE);
-            switch (aop->size) {
+            switch (aop->size - offset) {
             case 1:
                 emit2 ("ld l,!*hl");
                 emit2 ("ld h,!immedbyte", 0);
                             break;
             case 2:
             case 1:
                 emit2 ("ld l,!*hl");
                 emit2 ("ld h,!immedbyte", 0);
                             break;
             case 2:
+              // PENDING: Requires that you are only fetching two bytes.
+            case 4:
                 emit2 ("!ldahli");
                 emit2 ("ld h,!*hl");
                 emit2 ("ld l,a");
                 break;
             default:
                 emit2 ("!ldahli");
                 emit2 ("ld h,!*hl");
                 emit2 ("ld l,a");
                 break;
             default:
-                emitDebug ("; WARNING: mlh woosed out.  This code is invalid.");
+              wassertl (0, "Attempted to fetch too much data into HL");
+              break;
             }
         }
         else if (IS_Z80 && aop->type == AOP_IY) {
             }
         }
         else if (IS_Z80 && aop->type == AOP_IY) {
@@ -1089,10 +1325,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);
@@ -1102,7 +1361,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
@@ -1112,23 +1371,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;
@@ -1141,11 +1444,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);
     }
@@ -1165,15 +1473,15 @@ emitLabel (int key)
 static const char *
 aopGet (asmop * aop, int offset, bool bit16)
 {
 static const char *
 aopGet (asmop * aop, int offset, bool bit16)
 {
-  char *s = buffer;
+  // char *s = buffer;
 
   /* offset is greater than size then zero */
   /* PENDING: this seems a bit screwed in some pointer cases. */
   if (offset > (aop->size - 1) &&
       aop->type != AOP_LIT) 
     {
 
   /* offset is greater than size then zero */
   /* PENDING: this seems a bit screwed in some pointer cases. */
   if (offset > (aop->size - 1) &&
       aop->type != AOP_LIT) 
     {
-      tsprintf (s, "!zero");
-      return gc_strdup(s);
+      tsprintf (buffer, sizeof(buffer), "!zero");
+      return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
     }
 
   /* depending on type */
     }
 
   /* depending on type */
@@ -1182,38 +1490,38 @@ aopGet (asmop * aop, int offset, bool bit16)
     case AOP_IMMD:
       /* PENDING: re-target */
       if (bit16)
     case AOP_IMMD:
       /* PENDING: re-target */
       if (bit16)
-       tsprintf (s, "!immedwords", aop->aopu.aop_immd);
+       tsprintf (buffer, sizeof(buffer), "!immedwords", aop->aopu.aop_immd);
       else
        switch (offset)
          {
          case 2:
       else
        switch (offset)
          {
          case 2:
-           tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
+           tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
            break;
          case 1:
            break;
          case 1:
-           tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
+           tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
            break;
          case 0:
            break;
          case 0:
-           tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
+           tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
            break;
          default:
            break;
          default:
-           wassert (0);
+           wassertl (0, "Fetching from beyond the limits of an immediate value.");
          }
 
          }
 
-      return gc_strdup(s);
+      return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
 
     case AOP_DIR:
       wassert (IS_GB);
       emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
 
     case AOP_DIR:
       wassert (IS_GB);
       emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
-      sprintf (s, "a");
+      SNPRINTF (buffer, sizeof(buffer), "a");
 
 
-      return gc_strdup(s);
+      return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
 
     case AOP_SFR:
       wassert (IS_GB);
       emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
 
     case AOP_SFR:
       wassert (IS_GB);
       emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
-      sprintf (s, "a");
+      SNPRINTF (buffer, sizeof(buffer), "a");
 
 
-      return gc_strdup(s);
+      return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
 
     case AOP_REG:
       return aop->aopu.aop_reg[offset]->name;
 
     case AOP_REG:
       return aop->aopu.aop_reg[offset]->name;
@@ -1221,34 +1529,42 @@ aopGet (asmop * aop, int offset, bool bit16)
     case AOP_HL:
       wassert (IS_GB);
       setupPair (PAIR_HL, aop, offset);
     case AOP_HL:
       wassert (IS_GB);
       setupPair (PAIR_HL, aop, offset);
-      tsprintf (s, "!*hl");
+      tsprintf (buffer, sizeof(buffer), "!*hl");
 
 
-      return gc_strdup (s);
+      return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
 
     case AOP_IY:
       wassert (IS_Z80);
       setupPair (PAIR_IY, aop, offset);
 
     case AOP_IY:
       wassert (IS_Z80);
       setupPair (PAIR_IY, aop, offset);
-      tsprintf (s, "!*iyx", offset);
+      tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
 
 
-      return gc_strdup(s);
+      return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
+
+    case AOP_EXSTK:
+      wassert (IS_Z80);
+      setupPair (PAIR_IY, aop, offset);
+      tsprintf (buffer, sizeof(buffer), "!*iyx", offset, offset);
+
+      return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
 
     case AOP_STK:
       if (IS_GB)
        {
          setupPair (PAIR_HL, aop, offset);
 
     case AOP_STK:
       if (IS_GB)
        {
          setupPair (PAIR_HL, aop, offset);
-         tsprintf (s, "!*hl");
+         tsprintf (buffer, sizeof(buffer), "!*hl");
        }
       else
        {
          if (aop->aopu.aop_stk >= 0)
            offset += _G.stack.param_offset;
        }
       else
        {
          if (aop->aopu.aop_stk >= 0)
            offset += _G.stack.param_offset;
-         tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
+         tsprintf (buffer, sizeof(buffer),
+                   "!*ixx", aop->aopu.aop_stk + offset);
        }
 
        }
 
-      return gc_strdup(s);
+      return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
 
     case AOP_CRY:
 
     case AOP_CRY:
-      wassert (0);
+      wassertl (0, "Tried to fetch from a bit variable");
 
     case AOP_ACC:
       if (!offset)
 
     case AOP_ACC:
       if (!offset)
@@ -1257,8 +1573,8 @@ aopGet (asmop * aop, int offset, bool bit16)
        }
       else
         {
        }
       else
         {
-          tsprintf(s, "!zero");
-          return gc_strdup(s);
+          tsprintf(buffer, sizeof(buffer), "!zero");
+          return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
         }
 
     case AOP_HLREG:
         }
 
     case AOP_HLREG:
@@ -1268,10 +1584,27 @@ aopGet (asmop * aop, int offset, bool bit16)
     case AOP_LIT:
       return aopLiteral (aop->aopu.aop_lit, offset);
 
     case AOP_LIT:
       return aopLiteral (aop->aopu.aop_lit, offset);
 
+    case AOP_SIMPLELIT:
+      {
+        unsigned long v = aop->aopu.aop_simplelit;
+        
+        v >>= (offset * 8);
+        tsprintf (buffer, sizeof(buffer), 
+                 "!immedbyte", (unsigned int) v & 0xff);
+        
+        return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
+      }
     case AOP_STR:
       aop->coff = offset;
       return aop->aopu.aop_str[offset];
 
     case AOP_STR:
       aop->coff = offset;
       return aop->aopu.aop_str[offset];
 
+    case AOP_PAIRPTR:
+      setupPair (aop->aopu.aop_pairId, aop, offset);
+      SNPRINTF (buffer, sizeof(buffer), 
+               "(%s)", _pairs[aop->aopu.aop_pairId].name);
+
+      return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
+
     default:
       break;
     }
     default:
       break;
     }
@@ -1326,7 +1659,7 @@ aopPut (asmop * aop, const char *s, int offset)
     }
 
   // PENDING
     }
 
   // PENDING
-  tsprintf(buffer2, s);
+  tsprintf(buffer2, sizeof(buffer2), s);
   s = buffer2;
 
   /* will assign value to value */
   s = buffer2;
 
   /* will assign value to value */
@@ -1358,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:
@@ -1381,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)
        {
@@ -1409,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;
 
@@ -1417,13 +1770,13 @@ 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
        {
          /* In bit space but not in C - cant happen */
          emit2 ("rla");
        }
       else
        {
          /* In bit space but not in C - cant happen */
-         wassert (0);
+         wassertl (0, "Tried to write into a bit variable");
        }
       break;
 
        }
       break;
 
@@ -1441,8 +1794,7 @@ aopPut (asmop * aop, const char *s, int offset)
        break;
       if (offset > 0)
        {
        break;
       if (offset > 0)
        {
-
-         emitDebug ("; Error aopPut AOP_ACC");
+          wassertl (0, "Tried to access past the end of A");
        }
       else
        {
        }
       else
        {
@@ -1456,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");
@@ -1471,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");
@@ -1480,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);
+        }
     }
 }
 
     }
 }
 
@@ -1496,7 +1865,7 @@ getDataSize (operand * op)
   if (size == 3)
     {
       /* pointer */
   if (size == 3)
     {
       /* pointer */
-      wassert (0);
+      wassertl (0, "Somehow got a three byte data pointer");
     }
   return size;
 }
     }
   return size;
 }
@@ -1508,7 +1877,8 @@ static void
 movLeft2Result (operand * left, int offl,
                operand * result, int offr, int sign)
 {
 movLeft2Result (operand * left, int offl,
                operand * result, int offr, int sign)
 {
-    const char *l;
+  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);
@@ -1519,11 +1889,57 @@ movLeft2Result (operand * left, int offl,
        }
       else
        {
        }
       else
        {
-         wassert (0);
+          if (getDataSize (left) == offl + 1)
+            {
+              emit2 ("ld a,%s", l);
+              aopPut (AOP (result), "a", offr);
+            }
        }
     }
 }
 
        }
     }
 }
 
+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
  */
@@ -1553,8 +1969,7 @@ outBitCLong (operand * result, bool swap_sense)
   /* if the result is bit */
   if (AOP_TYPE (result) == AOP_CRY)
     {
   /* if the result is bit */
   if (AOP_TYPE (result) == AOP_CRY)
     {
-      emitDebug ("; Note: outBitC form 1");
-      aopPut (AOP (result), "blah", 0);
+      wassertl (0, "Tried to write carry to a bit");
     }
   else
     {
     }
   else
     {
@@ -1597,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                          */
 /*-----------------------------------------------------------------*/
@@ -1612,13 +2065,14 @@ genNot (iCode * ic)
   /* if in bit space then a special case */
   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
     {
   /* if in bit space then a special case */
   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Tried to negate a bit");
     }
 
   /* if type float then do float */
   if (IS_FLOAT (optype))
     {
     }
 
   /* if type float then do float */
   if (IS_FLOAT (optype))
     {
-      wassert (0);
+      genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
+      goto release;
     }
 
   _toBoolean (IC_LEFT (ic));
     }
 
   _toBoolean (IC_LEFT (ic));
@@ -1630,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);
@@ -1654,7 +2109,7 @@ genCpl (iCode * ic)
   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
     {
   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Left and the result are in bit space");
     }
 
   size = AOP_SIZE (IC_RESULT (ic));
     }
 
   size = AOP_SIZE (IC_RESULT (ic));
@@ -1671,6 +2126,85 @@ genCpl (iCode * ic)
   freeAsmop (IC_RESULT (ic), NULL, ic);
 }
 
   freeAsmop (IC_RESULT (ic), NULL, ic);
 }
 
+static void
+_gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
+{
+  /* Logic:
+       ld de,right.lw
+       setup hl to left
+       de = hl - de
+       push flags
+       store de into result
+       pop flags
+       ld de,right.hw
+       setup hl
+       de = hl -de
+       store de into result
+  */
+  const char *first = isAdd ? "add" : "sub";
+  const char *later = isAdd ? "adc" : "sbc";
+
+  wassertl (IS_GB, "Code is only relevent to the gbz80");
+  wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
+
+  fetchPair (PAIR_DE, left);
+
+  emit2 ("ld a,e");
+  emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
+  emit2 ("ld e,a");
+  emit2 ("ld a,d");
+  emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
+
+  _push (PAIR_AF);
+  aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
+  aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
+
+  fetchPairLong (PAIR_DE, left, NULL, MSB24);
+  aopGet (right, MSB24, FALSE);
+
+  _pop (PAIR_AF);
+  emit2 ("ld a,e");
+  emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
+  emit2 ("ld e,a");
+  emit2 ("ld a,d");
+  emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
+
+  aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
+  aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
+}
+
+static void
+_gbz80_emitAddSubLong (iCode *ic, bool 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                         */
 /*-----------------------------------------------------------------*/
@@ -1689,7 +2223,7 @@ genUminus (iCode * ic)
   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
     {
   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Left and right are in bit space");
       goto release;
     }
 
       goto release;
     }
 
@@ -1699,12 +2233,23 @@ genUminus (iCode * ic)
   /* if float then do float stuff */
   if (IS_FLOAT (optype))
     {
   /* if float then do float stuff */
   if (IS_FLOAT (optype))
     {
-      wassert (0);
+      genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
       goto release;
     }
 
   /* otherwise subtract from zero */
   size = AOP_SIZE (IC_LEFT (ic));
       goto release;
     }
 
   /* otherwise subtract from zero */
   size = AOP_SIZE (IC_LEFT (ic));
+
+  if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
+    {
+      /* Create a new asmop with value zero */
+      asmop *azero = newAsmop (AOP_SIMPLELIT);
+      azero->aopu.aop_simplelit = 0;
+      azero->size = size;
+      _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
+      goto release;
+    }
+
   offset = 0;
   _clearCarry();
   while (size--)
   offset = 0;
   _clearCarry();
   while (size--)
@@ -1731,21 +2276,6 @@ release:
   freeAsmop (IC_RESULT (ic), NULL, ic);
 }
 
   freeAsmop (IC_RESULT (ic), NULL, ic);
 }
 
-static void
-_push (PAIR_ID pairId)
-{
-  emit2 ("push %s", _pairs[pairId].name);
-  _G.stack.pushed += 2;
-}
-
-static void
-_pop (PAIR_ID pairId)
-{
-  emit2 ("pop %s", _pairs[pairId].name);
-  _G.stack.pushed -= 2;
-}
-
-
 /*-----------------------------------------------------------------*/
 /* assignResultValue -               */
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 /* assignResultValue -               */
 /*-----------------------------------------------------------------*/
@@ -1755,21 +2285,16 @@ assignResultValue (operand * oper)
   int size = AOP_SIZE (oper);
   bool topInA = 0;
 
   int size = AOP_SIZE (oper);
   bool topInA = 0;
 
-  wassert (size <= 4);
+  wassertl (size <= 4, "Got a result that is bigger than four bytes");
   topInA = requiresHL (AOP (oper));
 
   topInA = requiresHL (AOP (oper));
 
-#if 0
-  if (!IS_GB)
-    wassert (size <= 2);
-#endif
   if (IS_GB && size == 4 && requiresHL (AOP (oper)))
     {
       /* We do it the hard way here. */
       _push (PAIR_HL);
       aopPut (AOP (oper), _fReturn[0], 0);
       aopPut (AOP (oper), _fReturn[1], 1);
   if (IS_GB && size == 4 && requiresHL (AOP (oper)))
     {
       /* We do it the hard way here. */
       _push (PAIR_HL);
       aopPut (AOP (oper), _fReturn[0], 0);
       aopPut (AOP (oper), _fReturn[1], 1);
-      emit2 ("pop de");
-      _G.stack.pushed -= 2;
+      _pop (PAIR_DE);
       aopPut (AOP (oper), _fReturn[0], 2);
       aopPut (AOP (oper), _fReturn[1], 3);
     }
       aopPut (AOP (oper), _fReturn[0], 2);
       aopPut (AOP (oper), _fReturn[1], 3);
     }
@@ -1782,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)
 {
@@ -1812,19 +2356,7 @@ _saveRegsForCall(iCode *ic, int sendSetSize)
     bool bcInRet = FALSE, deInRet = FALSE;
     bitVect *rInUse;
 
     bool bcInRet = FALSE, deInRet = FALSE;
     bitVect *rInUse;
 
-#if 1
     rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
     rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
-#else
-    if (IC_RESULT(ic))
-      {
-        rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), z80_rUmaskForOp (IC_RESULT(ic)));
-      }
-    else 
-      {
-        /* Has no result, so in use is all of in use */
-        rInUse = ic->rMask;
-      }
-#endif
 
     deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
     bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
 
     deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
     bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
@@ -1899,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))));
@@ -1916,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;
@@ -2059,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)
@@ -2133,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);
        }
@@ -2141,7 +2671,6 @@ emitCall (iCode * ic, bool ispcall)
 
       if (isLitWord (AOP (IC_LEFT (ic))))
        {
 
       if (isLitWord (AOP (IC_LEFT (ic))))
        {
-         emitDebug ("; Special case where the pCall is to a constant");
          emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
        }
       else
          emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
        }
       else
@@ -2164,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);
@@ -2208,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;
     }
@@ -2329,35 +2865,25 @@ 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.
   */
   _G.receiveOffset = 0;
 
 
   /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
      else.
   */
   _G.receiveOffset = 0;
 
-#if 0
-  /* PENDING: hack */
-  if (!IS_STATIC (sym->etype))
-    {
-      addSetIfnotP (&publics, sym);
-    }
-#endif
-
   /* Record the last function name for debugging. */
   _G.lastFunctionName = sym->rname;
   
   /* Create the function header */
   emit2 ("!functionheader", sym->name);
   /* Record the last function name for debugging. */
   _G.lastFunctionName = sym->rname;
   
   /* 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) 
@@ -2365,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");
     }
@@ -2381,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++)
@@ -2416,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)
     {
@@ -2424,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");
@@ -2445,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))
     {
     {
-      wassert (0);
+      wassertl (0, "Tried to close an interrupt support function");
     }
   else
     {
     }
   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);
         }
@@ -2465,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) 
         {
@@ -2488,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;
@@ -2533,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
        {
@@ -2604,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;
@@ -2620,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--)
        {
@@ -2630,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)
@@ -2661,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 */
@@ -2686,7 +3250,7 @@ outBitAcc (operand * result)
   /* if the result is a bit */
   if (AOP_TYPE (result) == AOP_CRY)
     {
   /* if the result is a bit */
   if (AOP_TYPE (result) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Tried to write A into a bit");
     }
   else
     {
     }
   else
     {
@@ -2697,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                           */
 /*-----------------------------------------------------------------*/
@@ -2732,7 +3376,7 @@ genPlus (iCode * ic)
       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
     {
       /* Cant happen */
       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
     {
       /* Cant happen */
-      wassert (0);
+      wassertl (0, "Tried to add two bits");
     }
 
   /* if left in bit space & right literal */
     }
 
   /* if left in bit space & right literal */
@@ -2740,7 +3384,7 @@ genPlus (iCode * ic)
       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
     {
       /* Can happen I guess */
       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
     {
       /* Can happen I guess */
-      wassert (0);
+      wassertl (0, "Tried to add a bit to a literal");
     }
 
   /* if I can do an increment instead
     }
 
   /* if I can do an increment instead
@@ -2748,7 +3392,7 @@ genPlus (iCode * ic)
   if (genPlusIncr (ic) == TRUE)
     goto release;
 
   if (genPlusIncr (ic) == TRUE)
     goto release;
 
-  emitDebug ("; genPlusIncr failed");
+  emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
 
   size = getDataSize (IC_RESULT (ic));
 
 
   size = getDataSize (IC_RESULT (ic));
 
@@ -2756,10 +3400,11 @@ genPlus (iCode * ic)
   if (isPair (AOP (IC_RESULT (ic))))
     {
       char *left, *right;
   if (isPair (AOP (IC_RESULT (ic))))
     {
       char *left, *right;
-
       left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
       right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
       left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
       right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
-      if (left && right)
+
+      if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
+          left && right)
        {
          /* It's a pair */
          /* PENDING: fix */
        {
          /* It's a pair */
          /* PENDING: fix */
@@ -2770,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;
     }
 
@@ -2839,13 +3520,19 @@ genPlus (iCode * ic)
              commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
              goto release;
            }
              commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
              goto release;
            }
-         else if (size == 4)
-           {
-             emitDebug ("; WARNING: This add is probably broken.\n");
-           }
        }
        }
+      if (size == 4)
+        {
+          /* Be paranoid on the GB with 4 byte variables due to how C
+             can be trashed by lda hl,n(sp).
+          */
+          _gbz80_emitAddSubLong (ic, TRUE);
+          goto release;
+        }
     }
 
     }
 
+  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)
@@ -2911,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;
@@ -2920,15 +3606,16 @@ genMinusDec (iCode * ic)
 
   /* if increment 16 bits in register */
   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
 
   /* if increment 16 bits in register */
   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
-      (size == 2))
+      (size == 2)
+      )
     {
     {
-      fetchPair (PAIR_HL, AOP (IC_RESULT (ic)));
+      fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
 
       while (icount--) {
 
       while (icount--) {
-        emit2 ("dec hl");
+        emit2 ("dec %s", _getTempPairName());
       }
       }
-      aopPut (AOP (IC_RESULT (ic)), "l", LSB);
-      aopPut (AOP (IC_RESULT (ic)), "h", MSB16);
+
+      commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
 
       return TRUE;
     }
 
       return TRUE;
     }
@@ -2969,7 +3656,7 @@ genMinus (iCode * ic)
   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
     {
   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Tried to subtract two bits");
       goto release;
     }
 
       goto release;
     }
 
@@ -3023,17 +3710,26 @@ 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;
            }
-         else if (size == 4)
-           {
-             emitDebug ("; WARNING: This sub is probably broken.\n");
-           }
        }
        }
+      if (size == 4)
+        {
+          /* Be paranoid on the GB with 4 byte variables due to how C
+             can be trashed by lda hl,n(sp).
+          */
+          _gbz80_emitAddSubLong (ic, FALSE);
+          goto release;
+        }
     }
 
     }
 
+  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--)
     {
@@ -3061,7 +3757,9 @@ genMinus (iCode * ic)
   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
       AOP_SIZE (IC_LEFT (ic)) == 3 &&
       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
       AOP_SIZE (IC_LEFT (ic)) == 3 &&
       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
-    wassert (0);
+    {
+      wassertl (0, "Tried to subtract on a long pointer");
+    }
 
 release:
   freeAsmop (IC_LEFT (ic), NULL, ic);
 
 release:
   freeAsmop (IC_LEFT (ic), NULL, ic);
@@ -3075,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 */
-  wassert (0);
+  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);
 }
 
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
@@ -3086,7 +3870,7 @@ static void
 genDiv (iCode * ic)
 {
   /* Shouldn't occur - all done through function calls */
 genDiv (iCode * ic)
 {
   /* Shouldn't occur - all done through function calls */
-  wassert (0);
+  wassertl (0, "Division is handled through support function calls");
 }
 
 /*-----------------------------------------------------------------*/
 }
 
 /*-----------------------------------------------------------------*/
@@ -3125,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 */
@@ -3147,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 */
@@ -3164,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);
@@ -3174,36 +3980,15 @@ genIfxJump (iCode * ic, char *jval)
   ic->generated = 1;
 }
 
   ic->generated = 1;
 }
 
+#if DISABLED
 static const char *
 _getPairIdName (PAIR_ID id)
 {
   return _pairs[id].name;
 }
 static const char *
 _getPairIdName (PAIR_ID id)
 {
   return _pairs[id].name;
 }
+#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 */
-      wassert (0);
-    }
-  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))
@@ -3217,47 +4002,86 @@ genCmp (operand * left, operand * right,
          else
            emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
        }
          else
            emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
        }
+      else if (size == 4 && 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--)
+            {
+              if (size == 0 && sign)
+                {
+                  // Highest byte when signed needs the bits flipped
+                  // Save the flags
+                  emit2 ("push af");
+                  emit2 ("ld a,(de)");
+                  emit2 ("xor !immedbyte", 0x80);
+                  emit2 ("ld e,a");
+                  emit2 ("ld a,(hl)");
+                  emit2 ("xor !immedbyte", 0x80);
+                  emit2 ("ld d,a");
+                  emit2 ("pop af");
+                  emit2 ("ld a,e");
+                  emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
+                }
+              else
+                {
+                  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);
+        }
+      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
        {
       else
        {
-         /* Special cases:
-            On the GB:
-            If the left or the right is a lit:
-            Load -lit into HL, add to right via, check sense.
-          */
-         if (IS_GB && size == 2 && (AOP_TYPE (right) == AOP_LIT || AOP_TYPE (left) == AOP_LIT))
-           {
-             PAIR_ID id = PAIR_DE;
-             asmop *lit = AOP (right);
-             asmop *op = AOP (left);
-             swap_sense = TRUE;
-
-             if (AOP_TYPE (left) == AOP_LIT)
-               {
-                 swap_sense = FALSE;
-                 lit = AOP (left);
-                 op = AOP (right);
-               }
-             if (sign)
-               {
-                 emit2 ("ld e,%s", aopGet (op, 0, 0));
-                 emit2 ("ld a,%s", aopGet (op, 1, 0));
-                 emit2 ("xor a,!immedbyte", 0x80);
-                 emit2 ("ld d,a");
-               }
-             else
-               {
-                 id = getPairId (op);
-                 if (id == PAIR_INVALID)
-                   {
-                     fetchPair (PAIR_DE, op);
-                     id = PAIR_DE;
-                   }
-               }
-             spillPair (PAIR_HL);
-             emit2 ("ld hl,%s", fetchLitSpecial (lit, TRUE, sign));
-             emit2 ("add hl,%s", _getPairIdName (id));
-             goto release;
-           }
          if (AOP_TYPE (right) == AOP_LIT)
            {
              lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
          if (AOP_TYPE (right) == AOP_LIT)
            {
              lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
@@ -3284,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 */
@@ -3316,12 +4141,6 @@ genCmp (operand * left, operand * right,
                  emit2 ("ld %s,a", _fTmp[1]);
                  fDidXor = TRUE;
                }
                  emit2 ("ld %s,a", _fTmp[1]);
                  fDidXor = TRUE;
                }
-             if (!fDidXor)
-               _clearCarry();
-           }
-         else
-           {
-             _clearCarry();
            }
          while (size--)
            {
            }
          while (size--)
            {
@@ -3333,20 +4152,120 @@ genCmp (operand * left, operand * right,
              if (sign && size == 0)
                {
                  emit2 ("ld a,%s", _fTmp[0]);
              if (sign && size == 0)
                {
                  emit2 ("ld a,%s", _fTmp[0]);
-                 emit2 ("sbc a,%s", _fTmp[1]);
+                 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
                }
              else
                {
                  /* Subtract through, propagating the carry */
                }
              else
                {
                  /* Subtract through, propagating the carry */
-                 emit2 ("sbc a,%s", aopGet (AOP (right), offset++, FALSE));
+                 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
+                 offset++;
                }
            }
        }
     }
                }
            }
        }
     }
+#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
@@ -3355,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 */
     }
 }
@@ -3440,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 &&
@@ -3451,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
@@ -3543,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.
@@ -3562,7 +4505,7 @@ genCmpEq (iCode * ic, iCode * ifx)
       if (AOP_TYPE (left) == AOP_CRY &&
          ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
        {
       if (AOP_TYPE (left) == AOP_CRY &&
          ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
        {
-         wassert (0);
+         wassertl (0, "Tried to compare two bits");
        }
       else
        {
        }
       else
        {
@@ -3592,10 +4535,12 @@ genCmpEq (iCode * ic, iCode * ifx)
   if (AOP_TYPE (left) == AOP_CRY &&
       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
     {
   if (AOP_TYPE (left) == AOP_CRY &&
       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
     {
-      wassert (0);
+      wassertl (0, "Tried to compare a bit to either a literal or another bit");
     }
   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))
        {
@@ -3603,6 +4548,7 @@ genCmpEq (iCode * ic, iCode * ifx)
        }
       if (ifx)
        {
        }
       if (ifx)
        {
+          emitDebug(";5");
          genIfxJump (ifx, "a");
          goto release;
        }
          genIfxJump (ifx, "a");
          goto release;
        }
@@ -3610,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 */
@@ -3663,7 +4610,7 @@ genAndOp (iCode * ic)
   if (AOP_TYPE (left) == AOP_CRY &&
       AOP_TYPE (right) == AOP_CRY)
     {
   if (AOP_TYPE (left) == AOP_CRY &&
       AOP_TYPE (right) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Tried to and two bits");
     }
   else
     {
     }
   else
     {
@@ -3700,7 +4647,7 @@ genOrOp (iCode * ic)
   if (AOP_TYPE (left) == AOP_CRY &&
       AOP_TYPE (right) == AOP_CRY)
     {
   if (AOP_TYPE (left) == AOP_CRY &&
       AOP_TYPE (right) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Tried to OR two bits");
     }
   else
     {
     }
   else
     {
@@ -3777,15 +4724,6 @@ genAnd (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);
 
-#ifdef DEBUG_TYPE
-  emitDebug ("; Type res[%d] = l[%d]&r[%d]",
-           AOP_TYPE (result),
-           AOP_TYPE (left), AOP_TYPE (right));
-  emitDebug ("; Size res[%d] = l[%d]&r[%d]",
-           AOP_SIZE (result),
-           AOP_SIZE (left), AOP_SIZE (right));
-#endif
-
   /* if left is a literal & right is not then exchange them */
   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
       AOP_NEEDSACC (left))
   /* if left is a literal & right is not then exchange them */
   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
       AOP_NEEDSACC (left))
@@ -3818,7 +4756,7 @@ genAnd (iCode * ic, iCode * ifx)
 
   if (AOP_TYPE (left) == AOP_CRY)
     {
 
   if (AOP_TYPE (left) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Tried to perform an AND with a bit as an operand");
       goto release;
     }
 
       goto release;
     }
 
@@ -3828,80 +4766,46 @@ genAnd (iCode * ic, iCode * ifx)
       (AOP_TYPE (result) == AOP_CRY) &&
       (AOP_TYPE (left) != AOP_CRY))
     {
       (AOP_TYPE (result) == AOP_CRY) &&
       (AOP_TYPE (left) != AOP_CRY))
     {
-      int posbit = isLiteralBit (lit);
-      /* left &  2^n */
-      if (posbit)
-       {
-         posbit--;
-         _moveA (aopGet (AOP (left), posbit >> 3, FALSE));
-         // bit = left & 2^n
-         if (size)
-           {
-             wassert (0);
-             emit2 ("mov c,acc.%d", posbit & 0x07);
-           }
-         // if(left &  2^n)
-         else
-           {
-             if (ifx)
-               {
-                 sprintf (buffer, "%d", posbit & 0x07);
-                 genIfxJump (ifx, buffer);
-               }
-             else
-               {
-                 wassert (0);
-               }
-             goto release;
-           }
-       }
-      else
-       {
-         symbol *tlbl = newiTempLabel (NULL);
-         int sizel = AOP_SIZE (left);
-         if (size)
-           {
-             wassert (0);
-             emit2 ("setb c");
-           }
-         while (sizel--)
-           {
-             if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
-               {
-                 _moveA (aopGet (AOP (left), offset, FALSE));
-                 // byte ==  2^n ?
-                 if ((posbit = isLiteralBit (bytelit)) != 0)
-                   {
-                     wassert (0);
-                     emit2 ("jb acc.%d,%05d$", (posbit - 1) & 0x07, tlbl->key + 100);
-                   }
-                 else
-                   {
-                     if (bytelit != 0x0FFL)
-                       emit2 ("and a,%s",
-                                 aopGet (AOP (right), offset, FALSE));
-                     else
-                       /* For the flags */
-                       emit2 ("or a,a");
-                     emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
-                   }
-               }
+      symbol *tlbl = newiTempLabel (NULL);
+      int sizel = AOP_SIZE (left);
+      if (size)
+        {
+          /* PENDING: Test case for this. */
+          emit2 ("scf");
+        }
+      while (sizel--)
+        {
+          if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
+            {
+              _moveA (aopGet (AOP (left), offset, FALSE));
+              if (bytelit != 0x0FFL)
+                {
+                  emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
+                }
+              else
+                {
+                  /* For the flags */
+                  emit2 ("or a,a");
+                }
+              emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+            }
              offset++;
              offset++;
-           }
-         // bit = left & literal
-         if (size)
-           {
-             emit2 ("clr c");
-             emit2 ("!tlabeldef", tlbl->key + 100);
-           }
-         // if(left & literal)
-         else
-           {
-             if (ifx)
-               jmpTrueOrFalse (ifx, tlbl);
-             goto release;
-           }
-       }
+        }
+      // bit = left & literal
+      if (size)
+        {
+          emit2 ("clr c");
+          emit2 ("!tlabeldef", tlbl->key + 100);
+        }
+      // if(left & literal)
+      else
+        {
+          if (ifx)
+            {
+              jmpTrueOrFalse (ifx, tlbl);
+            }
+          goto release;
+        }
       outBitC (result);
       goto release;
     }
       outBitC (result);
       goto release;
     }
@@ -3933,7 +4837,7 @@ genAnd (iCode * ic, iCode * ifx)
            {
              if (AOP_TYPE (left) == AOP_ACC)
                {
            {
              if (AOP_TYPE (left) == AOP_ACC)
                {
-                 wassert (0);
+                 wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
                }
              else
                {
                }
              else
                {
@@ -3950,7 +4854,7 @@ genAnd (iCode * ic, iCode * ifx)
       // left & result in different registers
       if (AOP_TYPE (result) == AOP_CRY)
        {
       // left & result in different registers
       if (AOP_TYPE (result) == AOP_CRY)
        {
-         wassert (0);
+         wassertl (0, "Tried to AND where the result is in carry");
        }
       else
        {
        }
       else
        {
@@ -4004,20 +4908,12 @@ genOr (iCode * ic, iCode * ifx)
   operand *left, *right, *result;
   int size, offset = 0;
   unsigned long lit = 0L;
   operand *left, *right, *result;
   int size, offset = 0;
   unsigned long lit = 0L;
+  int bytelit = 0;
 
   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
 
 
   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
 
-#if 1
-  emitDebug ("; Type res[%d] = l[%d]&r[%d]",
-           AOP_TYPE (result),
-           AOP_TYPE (left), AOP_TYPE (right));
-  emitDebug ("; Size res[%d] = l[%d]&r[%d]",
-           AOP_SIZE (result),
-           AOP_SIZE (left), AOP_SIZE (right));
-#endif
-
   /* if left is a literal & right is not then exchange them */
   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
       AOP_NEEDSACC (left))
   /* if left is a literal & right is not then exchange them */
   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
       AOP_NEEDSACC (left))
@@ -4050,15 +4946,39 @@ genOr (iCode * ic, iCode * ifx)
 
   if (AOP_TYPE (left) == AOP_CRY)
     {
 
   if (AOP_TYPE (left) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Tried to OR where left is a bit");
       goto release;
     }
 
       goto release;
     }
 
+  // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
+  // bit = val | 0xZZ     - size = 1, ifx = FALSE -
   if ((AOP_TYPE (right) == AOP_LIT) &&
       (AOP_TYPE (result) == AOP_CRY) &&
       (AOP_TYPE (left) != AOP_CRY))
     {
   if ((AOP_TYPE (right) == AOP_LIT) &&
       (AOP_TYPE (result) == AOP_CRY) &&
       (AOP_TYPE (left) != AOP_CRY))
     {
-      wassert (0);
+      symbol *tlbl = newiTempLabel (NULL);
+      int sizel = AOP_SIZE (left);
+
+      if (size)
+        {
+          wassertl (0, "Result is assigned to a bit");
+        }
+      /* PENDING: Modeled after the AND code which is inefficent. */
+      while (sizel--)
+        {
+          bytelit = (lit >> (offset * 8)) & 0x0FFL;
+
+          _moveA (aopGet (AOP (left), offset, FALSE));
+          /* OR with any literal is the same as OR with itself. */
+          emit2 ("or a,a");
+          emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+
+          offset++;
+        }
+      if (ifx)
+        {
+          jmpTrueOrFalse (ifx, tlbl);
+        }
       goto release;
     }
 
       goto release;
     }
 
@@ -4098,7 +5018,7 @@ genOr (iCode * ic, iCode * ifx)
       // left & result in different registers
       if (AOP_TYPE (result) == AOP_CRY)
        {
       // left & result in different registers
       if (AOP_TYPE (result) == AOP_CRY)
        {
-         wassert (0);
+         wassertl (0, "Result of OR is in a bit");
        }
       else
        for (; (size--); offset++)
        }
       else
        for (; (size--); offset++)
@@ -4184,15 +5104,39 @@ genXor (iCode * ic, iCode * ifx)
 
   if (AOP_TYPE (left) == AOP_CRY)
     {
 
   if (AOP_TYPE (left) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Tried to XOR a bit");
       goto release;
     }
 
       goto release;
     }
 
+  // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
+  // bit = val & 0xZZ     - size = 1, ifx = FALSE -
   if ((AOP_TYPE (right) == AOP_LIT) &&
       (AOP_TYPE (result) == AOP_CRY) &&
       (AOP_TYPE (left) != AOP_CRY))
     {
   if ((AOP_TYPE (right) == AOP_LIT) &&
       (AOP_TYPE (result) == AOP_CRY) &&
       (AOP_TYPE (left) != AOP_CRY))
     {
-      wassert (0);
+      symbol *tlbl = newiTempLabel (NULL);
+      int sizel = AOP_SIZE (left);
+
+      if (size)
+        {
+          /* PENDING: Test case for this. */
+          wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
+        }
+      while (sizel--)
+        {
+          _moveA (aopGet (AOP (left), offset, FALSE));
+          emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
+          emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+          offset++;
+        }
+      if (ifx)
+        {
+          jmpTrueOrFalse (ifx, tlbl);
+        }
+      else
+        {
+          wassertl (0, "Result of XOR was destined for a bit");
+        }
       goto release;
     }
 
       goto release;
     }
 
@@ -4234,7 +5178,7 @@ genXor (iCode * ic, iCode * ifx)
       // left & result in different registers
       if (AOP_TYPE (result) == AOP_CRY)
        {
       // left & result in different registers
       if (AOP_TYPE (result) == AOP_CRY)
        {
-         wassert (0);
+         wassertl (0, "Result of XOR is in a bit");
        }
       else
        for (; (size--); offset++)
        }
       else
        for (; (size--); offset++)
@@ -4342,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);
 
@@ -4356,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);
     }
 
@@ -4406,7 +5350,7 @@ shiftR2Left2Result (operand * left, int offl,
   tlbl1 = newiTempLabel (NULL);
 
   /* Left is already in result - so now do the shift */
   tlbl1 = newiTempLabel (NULL);
 
   /* Left is already in result - so now do the shift */
-  if (shCount <= 2)
+  if (shCount <= 4)
     {
       while (shCount--)
         {
     {
       while (shCount--)
         {
@@ -4445,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;
@@ -4456,28 +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);
+                 }
+             }
+         }
       }
       }
-
-    emit2 ("or a,a");
-    while (size--)
+    else
       {
       {
-       l = aopGet (AOP (result), offset, FALSE);
-
-       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);
+         }
       }
   }
 }
       }
   }
 }
@@ -4495,34 +5474,34 @@ AccRol (int shCount)
     case 0:
       break;
     case 1:
     case 0:
       break;
     case 1:
-      emit2 ("rl a");
+      emit2 ("sla a");
       break;
     case 2:
       break;
     case 2:
-      emit2 ("rl a");
+      emit2 ("sla a");
       emit2 ("rl a");
       break;
     case 3:
       emit2 ("rl a");
       break;
     case 3:
-      emit2 ("rl a");
+      emit2 ("sla a");
       emit2 ("rl a");
       emit2 ("rl a");
       break;
     case 4:
       emit2 ("rl a");
       emit2 ("rl a");
       break;
     case 4:
-      emit2 ("rl a");
+      emit2 ("sla a");
       emit2 ("rl a");
       emit2 ("rl a");
       emit2 ("rl a");
       break;
     case 5:
       emit2 ("rl a");
       emit2 ("rl a");
       emit2 ("rl a");
       break;
     case 5:
-      emit2 ("rr a");
+      emit2 ("srl a");
       emit2 ("rr a");
       emit2 ("rr a");
       break;
     case 6:
       emit2 ("rr a");
       emit2 ("rr a");
       break;
     case 6:
-      emit2 ("rr a");
+      emit2 ("srl a");
       emit2 ("rr a");
       break;
     case 7:
       emit2 ("rr a");
       break;
     case 7:
-      emit2 ("rr a");
+      emit2 ("srl a");
       break;
     }
 }
       break;
     }
 }
@@ -4595,7 +5574,7 @@ genlshTwo (operand * result, operand * left, int shCount)
            {
              movLeft2Result (left, LSB, result, MSB16, 0);
              aopPut (AOP (result), "!zero", 0);
            {
              movLeft2Result (left, LSB, result, MSB16, 0);
              aopPut (AOP (result), "!zero", 0);
-             shiftL1Left2Result (left, MSB16, result, MSB16, shCount);
+             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
            }
          else
            {
            }
          else
            {
@@ -4650,11 +5629,6 @@ genLeftShiftLiteral (operand * left,
 
   size = getSize (operandType (result));
 
 
   size = getSize (operandType (result));
 
-#if VIEW_SIZE
-  emitDebug ("; shift left  result %d, left %d", size,
-           AOP_SIZE (left));
-#endif
-
   /* I suppose that the left size >= result size */
   if (shCount == 0)
     {
   /* I suppose that the left size >= result size */
   if (shCount == 0)
     {
@@ -4726,7 +5700,7 @@ genLeftShift (iCode * ic)
 
   /* now move the left to the result if they are not the
      same */
 
   /* now move the left to the result if they are not the
      same */
-#if 1
+
   if (!sameRegs (AOP (left), AOP (result)))
     {
 
   if (!sameRegs (AOP (left), AOP (result)))
     {
 
@@ -4739,17 +5713,6 @@ genLeftShift (iCode * ic)
          offset++;
        }
     }
          offset++;
        }
     }
-#else
-  size = AOP_SIZE (result);
-  offset = 0;
-  while (size--)
-    {
-      l = aopGet (AOP (left), offset, FALSE);
-      aopPut (AOP (result), l, offset);
-      offset++;
-    }
-#endif
-
 
   tlbl = newiTempLabel (NULL);
   size = AOP_SIZE (result);
 
   tlbl = newiTempLabel (NULL);
   size = AOP_SIZE (result);
@@ -4760,12 +5723,19 @@ genLeftShift (iCode * ic)
   emitLabel (tlbl->key + 100);
   l = aopGet (AOP (result), offset, FALSE);
 
   emitLabel (tlbl->key + 100);
   l = aopGet (AOP (result), offset, FALSE);
 
-  emit2 ("or a,a");
-
   while (size--)
     {
   while (size--)
     {
-      l = aopGet (AOP (result), offset++, FALSE);
-      emit2 ("rl %s", l);
+      l = aopGet (AOP (result), offset, FALSE);
+
+      if (offset == 0)
+        {
+          emit2 ("sla %s", l);
+        }
+      else
+        {
+          emit2 ("rl %s", l);
+        }
+      offset++;
     }
   emitLabel (tlbl1->key + 100);
   emit2 ("dec a");
     }
   emitLabel (tlbl1->key + 100);
   emit2 ("dec a");
@@ -4790,8 +5760,6 @@ genrshOne (operand * result, operand * left, int shCount, int is_signed)
 
   l = aopGet (AOP (left), 0, FALSE);
 
 
   l = aopGet (AOP (left), 0, FALSE);
 
-  emit2 ("or a,a");
-
   if (AOP (result)->type == AOP_REG)
     {
       aopPut (AOP (result), l, 0);
   if (AOP (result)->type == AOP_REG)
     {
       aopPut (AOP (result), l, 0);
@@ -4843,7 +5811,10 @@ shiftR1Left2Result (operand * left, int offl,
   _moveA (aopGet (AOP (left), offl, FALSE));
   if (sign)
     {
   _moveA (aopGet (AOP (left), offl, FALSE));
   if (sign)
     {
-      wassert (0);
+      while (shCount--)
+       {
+         emit2 ("%s a", sign ? "sra" : "srl");
+       }
     }
   else
     {
     }
   else
     {
@@ -4872,7 +5843,19 @@ genrshTwo (operand * result, operand * left,
        {
          movLeft2Result (left, MSB16, result, LSB, sign);
        }
        {
          movLeft2Result (left, MSB16, result, LSB, sign);
        }
-      aopPut (AOP (result), "!zero", 1);
+      if (sign)
+        {
+          /* Sign extend the result */
+          _moveA(aopGet (AOP (result), 0, FALSE));
+          emit2 ("rlc a");
+          emit2 ("sbc a,a");
+
+          aopPut (AOP (result), ACC_NAME, MSB16);
+        }
+      else
+        {
+          aopPut (AOP (result), "!zero", 1);
+        }
     }
   /*  1 <= shCount <= 7 */
   else
     }
   /*  1 <= shCount <= 7 */
   else
@@ -4901,18 +5884,25 @@ genRightShiftLiteral (operand * left,
 
   size = getSize (operandType (result));
 
 
   size = getSize (operandType (result));
 
-  emitDebug ("; shift right  result %d, left %d", size,
-           AOP_SIZE (left));
-
   /* I suppose that the left size >= result size */
   if (shCount == 0)
     {
       wassert (0);
     }
 
   /* I suppose that the left size >= result size */
   if (shCount == 0)
     {
       wassert (0);
     }
 
-  else if (shCount >= (size * 8))
+  else if (shCount >= (size * 8)) {
+    const char *s;
+    if (!SPEC_USIGN(getSpec(operandType(left)))) {
+      _moveA(aopGet (AOP (left), 0, FALSE));
+      emit2 ("rlc a");
+      emit2 ("sbc a,a");
+      s=ACC_NAME;
+    } else {
+      s="!zero";
+    }
     while (size--)
     while (size--)
-      aopPut (AOP (result), "!zero", size);
+      aopPut (AOP (result), s, size);
+  }
   else
     {
       switch (size)
   else
     {
       switch (size)
@@ -4921,7 +5911,6 @@ genRightShiftLiteral (operand * left,
          genrshOne (result, left, shCount, sign);
          break;
        case 2:
          genrshOne (result, left, shCount, sign);
          break;
        case 2:
-         /* PENDING: sign support */
          genrshTwo (result, left, shCount, sign);
          break;
        case 4:
          genrshTwo (result, left, shCount, sign);
          break;
        case 4:
@@ -4976,13 +5965,16 @@ genRightShift (iCode * ic)
       return;
     }
 
       return;
     }
 
+  emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
+  emit2 ("inc a");
+  freeAsmop (right, NULL, ic);
+
   aopOp (left, ic, FALSE, FALSE);
   aopOp (result, ic, FALSE, FALSE);
 
   /* now move the left to the result if they are not the
      same */
   aopOp (left, ic, FALSE, FALSE);
   aopOp (result, ic, FALSE, FALSE);
 
   /* now move the left to the result if they are not the
      same */
-  if (!sameRegs (AOP (left), AOP (result)) &&
-      AOP_SIZE (result) > 1)
+  if (!sameRegs (AOP (left), AOP (result)))
     {
 
       size = AOP_SIZE (result);
     {
 
       size = AOP_SIZE (result);
@@ -4991,13 +5983,9 @@ genRightShift (iCode * ic)
        {
          l = aopGet (AOP (left), offset, FALSE);
          aopPut (AOP (result), l, offset);
        {
          l = aopGet (AOP (left), offset, FALSE);
          aopPut (AOP (result), l, offset);
-         offset++;
-       }
-    }
-
-  emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
-  emit2 ("inc a");
-  freeAsmop (right, NULL, ic);
+         offset++;
+       }
+    }
 
   tlbl = newiTempLabel (NULL);
   tlbl1 = newiTempLabel (NULL);
 
   tlbl = newiTempLabel (NULL);
   tlbl1 = newiTempLabel (NULL);
@@ -5044,12 +6032,15 @@ 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)))
        {
-         tsprintf (buffer, "!*pair", getPairName (AOP (left)));
+         tsprintf (buffer, sizeof(buffer), 
+                   "!*pair", getPairName (AOP (left)));
          aopPut (AOP (result), buffer, 0);
        }
       else
          aopPut (AOP (result), buffer, 0);
        }
       else
@@ -5061,18 +6052,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, sizeof(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);
@@ -5081,7 +6123,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++);
            }
@@ -5098,6 +6141,8 @@ genGenPointerGet (operand * left,
        }
     }
 
        }
     }
 
+  freeAsmop (left, NULL, ic);
+
 release:
   freeAsmop (result, NULL, ic);
 }
 release:
   freeAsmop (result, NULL, ic);
 }
@@ -5125,7 +6170,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;
 }
@@ -5140,15 +6185,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);
@@ -5164,6 +6211,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 */
@@ -5181,7 +6281,6 @@ genGenPointerSet (operand * right,
     }
   else
     {
     }
   else
     {
-      size = AOP_SIZE (right);
       offset = 0;
 
       while (size--)
       offset = 0;
 
       while (size--)
@@ -5283,21 +6382,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
     {
@@ -5306,17 +6403,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);
 }
@@ -5334,14 +6430,12 @@ genAssign (iCode * ic)
   result = IC_RESULT (ic);
   right = IC_RIGHT (ic);
 
   result = IC_RESULT (ic);
   right = IC_RIGHT (ic);
 
-#if 1
   /* Dont bother assigning if they are the same */
   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
     {
       emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
       return;
     }
   /* Dont bother assigning if they are the same */
   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
     {
       emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
       return;
     }
-#endif
 
   aopOp (right, ic, FALSE, FALSE);
   aopOp (result, ic, TRUE, FALSE);
 
   aopOp (right, ic, FALSE, FALSE);
   aopOp (result, ic, TRUE, FALSE);
@@ -5356,7 +6450,7 @@ genAssign (iCode * ic)
   /* if the result is a bit */
   if (AOP_TYPE (result) == AOP_CRY)
     {
   /* if the result is a bit */
   if (AOP_TYPE (result) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Tried to assign to a bit");
     }
 
   /* general case */
     }
 
   /* general case */
@@ -5364,10 +6458,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) &&
@@ -5405,6 +6502,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. */
@@ -5413,12 +6516,34 @@ genAssign (iCode * ic)
       aopPut (AOP (result), "a", 0);
       aopPut (AOP (result), "e", 1);
     }
       aopPut (AOP (result), "a", 0);
       aopPut (AOP (result), "e", 1);
     }
+  else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
+    {
+      /* Special case - simple memcpy */
+      aopGet (AOP (right), LSB, FALSE);
+      emit2 ("ld d,h");
+      emit2 ("ld e,l");
+      aopGet (AOP (result), LSB, FALSE);
+
+      while (size--)
+        {
+          emit2 ("ld a,(de)");
+          /* Peephole will optimise this. */
+          emit2 ("ld (hl),a");
+
+          if (size != 0)
+            {
+              emit2 ("inc hl");
+              emit2 ("inc de");
+            }
+        }
+      spillPair (PAIR_HL);
+    }
   else
     {
       while (size--)
        {
          /* PENDING: do this check better */
   else
     {
       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);
@@ -5476,7 +6601,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;
 
@@ -5490,7 +6615,7 @@ genCast (iCode * ic)
   /* if the result is a bit */
   if (AOP_TYPE (result) == AOP_CRY)
     {
   /* if the result is a bit */
   if (AOP_TYPE (result) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Tried to cast to a bit");
     }
 
   /* if they are the same size : or less */
     }
 
   /* if they are the same size : or less */
@@ -5514,16 +6639,7 @@ genCast (iCode * ic)
       goto release;
     }
 
       goto release;
     }
 
-  /* PENDING: should be OK. */
-#if 0
-  /* if the result is of type pointer */
-  if (IS_PTR (ctype))
-    {
-      wassert (0);
-    }
-#endif
-
-  /* so we now know that the size of destination is greater
+  /* So we now know that the size of destination is greater
      than the size of the source */
   /* we move to result for the size of source */
   size = AOP_SIZE (right);
      than the size of the source */
   /* we move to result for the size of source */
   size = AOP_SIZE (right);
@@ -5539,7 +6655,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++);
@@ -5550,7 +6666,6 @@ genCast (iCode * ic)
         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
                        FALSE);
       _moveA (l);
         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
                        FALSE);
       _moveA (l);
-      emitDebug ("; genCast: sign extend untested.");
       emit2 ("rla ");
       emit2 ("sbc a,a");
       while (size--)
       emit2 ("rla ");
       emit2 ("sbc a,a");
       while (size--)
@@ -5716,7 +6831,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
         {
@@ -5741,7 +6856,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++;
@@ -5775,16 +6890,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));
     
@@ -5828,9 +6937,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            */
 /*-----------------------------------------------------------------*/
@@ -5840,7 +7229,7 @@ genZ80Code (iCode * lic)
   iCode *ic;
   int cln = 0;
 
   iCode *ic;
   int cln = 0;
 
-  /* HACK */
+  /* Hack */
   if (IS_GB)
     {
       _fReturn = _gbz80_return;
   if (IS_GB)
     {
       _fReturn = _gbz80_return;
@@ -5859,9 +7248,15 @@ genZ80Code (iCode * lic)
 
       if (cln != ic->lineno)
        {
 
       if (cln != ic->lineno)
        {
-         emit2 ("; %s %d", ic->filename, ic->lineno);
+         if (!options.noCcodeInAsm) {
+           emit2 (";%s:%d: %s", ic->filename, ic->lineno,
+                  printCLine(ic->filename, ic->lineno));
+         }
          cln = ic->lineno;
        }
          cln = ic->lineno;
        }
+      if (options.iCodeInAsm) {
+       emit2 (";ic:%d: %s", ic->key, printILine(ic));
+      }
       /* if the result is marked as
          spilt and rematerializable or code for
          this has already been generated then
       /* if the result is marked as
          spilt and rematerializable or code for
          this has already been generated then
@@ -6098,18 +7493,25 @@ 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:
-           genArrayInit(ic);
-           break;
+         emitDebug ("; genArrayInit");
+          genArrayInit(ic);
+          break;
            
        default:
          ic = ic;
            
        default:
          ic = ic;
-         /*      piCode(ic,stdout); */
-
        }
     }
 
        }
     }
 
@@ -6133,6 +7535,9 @@ genZ80Code (iCode * lic)
       }
     codeOutFile = fp;
   }
       }
     codeOutFile = fp;
   }
+
+  freeTrace(&_G.lines.trace);
+  freeTrace(&_G.trace.aops);
 }
 
 /*
 }
 
 /*
@@ -6155,4 +7560,26 @@ _isPairUsed (iCode * ic, PAIR_ID pairId)
   return ret;
 }
 
   return ret;
 }
 
+static char *
+fetchLitSpecial (asmop * aop, bool negate, bool xor)
+{
+  unsigned long v;
+  value *val = aop->aopu.aop_lit;
+
+  wassert (aop->type == AOP_LIT);
+  wassert (!IS_FLOAT (val->type));
+
+  v = (unsigned long) floatFromVal (val);
+
+  if (xor)
+    v ^= 0x8000;
+  if (negate)
+    v = 0-v;
+  v &= 0xFFFF;
+
+  tsprintf (buffer, sizeof(buffer), "!immedword", v);
+  return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
+}
+
+
 */
 */