* as/hc08/lkaomf51.c (OutputName),
[fw/sdcc] / src / z80 / gen.c
index ea69f7c1e37d907cabc035414aa2434f4207911b..30d500eb8eed3f0427ca013ffa2b9fd4b18c9548 100644 (file)
@@ -1,25 +1,7 @@
 /*-------------------------------------------------------------------------
   gen.c - Z80 specific code generator.
 
-  Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
-            ticks dhry  size
-  Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
-  Improved WORD push                    22784 144 19AE
-  With label1 on                        22694 144 197E
-  With label2 on                        22743 144 198A
-  With label3 on                        22776 144 1999
-  With label4 on                        22776 144 1999
-  With all 'label' on                   22661 144 196F
-  With loopInvariant on                 20919 156 19AB
-  With loopInduction on                 Breaks    198B
-  With all working on                   20796 158 196C
-  Slightly better genCmp(signed)        20597 159 195B
-  Better reg packing, first peephole    20038 163 1873
-  With assign packing                   19281 165 1849
-  5/3/00                                17741 185 17B6
-  With reg params for mul and div       16234 202 162D
-
-  Michael Hope <michaelh@earthling.net> 2000
+  Michael Hope <michaelh@juju.net.nz> 2000
   Based on the mcs51 generator -
       Sandeep Dutta . sandeep.dutta@usa.net (1998)
    and -  Jean-Louis VERN.jlvern@writeme.com (1999)
 
 -------------------------------------------------------------------------*/
 
+/*
+  Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
+                                       ticks dhry  size
+  Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
+  Improved WORD push                    22784 144 19AE
+  With label1 on                        22694 144 197E
+  With label2 on                        22743 144 198A
+  With label3 on                        22776 144 1999
+  With label4 on                        22776 144 1999
+  With all 'label' on                   22661 144 196F
+  With loopInvariant on                 20919 156 19AB
+  With loopInduction on                 Breaks    198B
+  With all working on                   20796 158 196C
+  Slightly better genCmp(signed)        20597 159 195B
+  Better reg packing, first peephole    20038 163 1873
+  With assign packing                   19281 165 1849
+  5/3/00                                17741 185 17B6
+  With reg params for mul and div       16234 202 162D
+
+  1. Starting again at 3 Aug 01         34965  93 219C
+   No asm strings
+   Includes long mul/div in code
+  2. Optimised memcpy for acc use       32102 102 226B
+  3. Optimised strcpy for acc use       27819 117 2237
+  3a Optimised memcpy fun
+  4. Optimised strcmp fun               21999 149 2294
+  5. Optimised strcmp further           21660 151 228C
+  6. Optimised memcpy by unroling       20885 157 2201
+  7. After turning loop induction on    19862 165 236D
+  8. Same as 7 but with more info
+  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
+          - ld hl,#n; push hl: (10+11)*nargs
+  2.  Cost of pull from stack
+        Using asm with ld hl, etc
+          - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
+            10+11+(7+6+7+6)*nargs
+  3.  Cost of fixing stack
+          - pop hl*nargs
+            10*nargs
+
+  So cost is (10+11+7+6+7+10)*nargs+10+11
+      = 51*nargs+21
+      = 123 for mul, div, strcmp, strcpy
+  Saving of (98298+32766+32766+32766)*123 = 24181308
+  At 192 d/s for 682411768t, speed up to 199.  Hmm.
+*/
+
 #include <stdio.h>
 #include <stdlib.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"
 #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 */
 
    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
    IX is used as an index register to the top of the local variable
    area.  ix-0 is the top most local variable.
 */
+
+enum
+{
+  /* Set to enable debugging trace statements in the output assembly code. */
+  DISABLE_DEBUG = 0
+};
+
 static char *_z80_return[] =
 {"l", "h", "e", "d"};
 static char *_gbz80_return[] =
@@ -93,6 +139,14 @@ static char **_fTmp;
 
 extern FILE *codeOutFile;
 
+enum
+  {
+    INT8MIN = -128,
+    INT8MAX = 127
+  };
+
+/** Enum covering all the possible register pairs.
+ */
 typedef enum
   {
     PAIR_INVALID,
@@ -116,18 +170,14 @@ static struct
   {    "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
+#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 
+enum
   {
     LSB,
     MSB16,
@@ -135,15 +185,20 @@ enum
     MSB32
   };
 
-static struct 
+/** Code generator persistent data.
+ */
+static struct
 {
-  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;
-    const char *lit;
+    const char *base;
     int offset;
   } pairs[NUM_PAIRS];
-  struct 
+  struct
   {
     int last;
     int pushed;
@@ -152,11 +207,21 @@ static struct
     int pushedBC;
     int pushedDE;
   } stack;
+
+  struct
+  {
+    int pushedBC;
+    int pushedDE;
+  } calleeSaves;
+
+  bool omitFramePtr;
   int frameId;
   int receiveOffset;
   bool flushStatics;
   bool in_home;
   const char *lastFunctionName;
+  iCode *current_iCode;
+  bool preserveCarry;
 
   set *sendSet;
 
@@ -166,17 +231,139 @@ static struct
     bool saved;
   } saves;
 
-  struct 
+  struct
   {
     lineNode *head;
     lineNode *current;
     int isInline;
+    int isDebug;
+    allocTrace trace;
   } lines;
 
+  struct
+  {
+    allocTrace aops;
+  } trace;
 } _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",
+  "AOP_DUMMY"
+};
+
+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)
 {
@@ -200,22 +387,72 @@ _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[INITIAL_INLINEASM];
+
+  tvsprintf (buffer, sizeof(buffer), szFormat, ap);
+
+  _tidyUp (buffer);
+  _G.lines.current = (_G.lines.current ?
+              connectLine (_G.lines.current, _newLineNode (buffer)) :
+              (_G.lines.head = _newLineNode (buffer)));
+
+  _G.lines.current->isInline = _G.lines.isInline;
+  _G.lines.current->isDebug = _G.lines.isDebug;
+  _G.lines.current->ic = _G.current_iCode;
+}
+
 static void
 emit2 (const char *szFormat,...)
 {
-  char buffer[256];
   va_list ap;
 
   va_start (ap, szFormat);
 
-  tvsprintf (buffer, szFormat, ap);
+  _vemit2 (szFormat, ap);
 
-  _tidyUp (buffer);
-  _G.lines.current = (_G.lines.current ?
-             connectLine (_G.lines.current, newLineNode (buffer)) :
-             (_G.lines.head = newLineNode (buffer)));
+  va_end (ap);
+}
 
-  _G.lines.current->isInline = _G.lines.isInline;
+static void
+emitDebug (const char *szFormat,...)
+{
+  if (!DISABLE_DEBUG)
+    {
+      va_list ap;
+
+      va_start (ap, szFormat);
+
+      _vemit2 (szFormat, ap);
+
+      va_end (ap);
+    }
+}
+
+/*-----------------------------------------------------------------*/
+/* z80_emitDebuggerSymbol - associate the current code location    */
+/*   with a debugger symbol                                        */
+/*-----------------------------------------------------------------*/
+void
+z80_emitDebuggerSymbol (char * debugSym)
+{
+  _G.lines.isDebug = 1;
+  emit2 ("%s !equ .", debugSym);
+  emit2 ("!global", debugSym);
+  _G.lines.isDebug = 0;
 }
 
 /*-----------------------------------------------------------------*/
@@ -244,27 +481,57 @@ _emit2 (const char *inst, const char *fmt,...)
   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;
+  _G.lines.current->ic = _G.current_iCode;
   va_end (ap);
 }
 
 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);
     }
-  else 
+  else
     {
       // Optimise it out.
       // Could leave this to the peephole, but sometimes the peephole is inhibited.
     }
 }
 
+void
+aopDump(const char *plabel, asmop *aop)
+{
+  int i;
+  char regbuf[9];
+  char *rbp = regbuf;
+
+  emitDebug("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
+  switch (aop->type)
+    {
+    case AOP_EXSTK:
+    case AOP_STK:
+      emitDebug(";  aop_stk %d", aop->aopu.aop_stk);
+      break;
+    case AOP_REG:
+      for (i=aop->size-1;i>=0;i--)
+        *rbp++ = *(aop->aopu.aop_reg[i]->name);
+      *rbp = '\0';
+      emitDebug(";  reg = %s", regbuf);
+      break;
+    case AOP_PAIRPTR:
+      emitDebug(";  pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
+
+    default:
+      /* No information. */
+      break;
+    }
+}
+
 static void
 _moveA(const char *moveFrom)
 {
@@ -284,34 +551,30 @@ getPairName (asmop * aop)
   if (aop->type == AOP_REG)
     {
       switch (aop->aopu.aop_reg[0]->rIdx)
-       {
-       case C_IDX:
-         return "bc";
-         break;
-       case E_IDX:
-         return "de";
-         break;
-       case L_IDX:
-         return "hl";
-         break;
-       }
-    }
-  else if (aop->type == AOP_STR)
-    {
-      switch (*aop->aopu.aop_str[0])
-       {
-       case 'c':
-         return "bc";
-         break;
-       case 'e':
-         return "de";
-         break;
-       case 'l':
-         return "hl";
-         break;
-       }
+        {
+        case C_IDX:
+          return "bc";
+          break;
+        case E_IDX:
+          return "de";
+          break;
+        case L_IDX:
+          return "hl";
+          break;
+        }
     }
-  wassert (0);
+  else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
+    {
+      int i;
+      for (i = 0; i < NUM_PAIRS; i++)
+        {
+          if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
+            {
+              return _pairs[i].name;
+            }
+        }
+    }
+  wassertl (0, "Tried to get the pair name of something that isn't a pair");
   return NULL;
 }
 
@@ -321,35 +584,31 @@ getPairId (asmop * aop)
   if (aop->size == 2)
     {
       if (aop->type == AOP_REG)
-       {
-         if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
-           {
-             return PAIR_BC;
-           }
-         if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
-           {
-             return PAIR_DE;
-           }
-         if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
-           {
-             return PAIR_HL;
-           }
-       }
-      if (aop->type == AOP_STR)
-       {
-         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;
-           }
-       }
+        {
+          if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
+            {
+              return PAIR_BC;
+            }
+          if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
+            {
+              return PAIR_DE;
+            }
+          if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
+            {
+              return PAIR_HL;
+            }
+        }
+      else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
+        {
+          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;
 }
@@ -361,6 +620,22 @@ isPair (asmop * aop)
   return (getPairId (aop) != PAIR_INVALID);
 }
 
+/** Returns TRUE if the registers used in aop cannot be split into high
+    and low halves */
+bool
+isUnsplitable (asmop * aop)
+{
+  switch (getPairId (aop))
+    {
+    case PAIR_IX:
+    case PAIR_IY:
+      return TRUE;
+    default:
+      return FALSE;
+    }
+  return FALSE;
+}
+
 bool
 isPtrPair (asmop * aop)
 {
@@ -375,6 +650,38 @@ isPtrPair (asmop * aop)
       return FALSE;
     }
 }
+
+static void
+spillPair (PAIR_ID pairId)
+{
+  _G.pairs[pairId].last_type = AOP_INVALID;
+  _G.pairs[pairId].base = NULL;
+}
+
+/* Given a register name, spill the pair (if any) the register is part of */
+static void
+spillPairReg (const char *regname)
+{
+  if (strlen(regname)==1)
+    {
+      switch (*regname)
+        {
+        case 'h':
+        case 'l':
+          spillPair(PAIR_HL);
+          break;
+        case 'd':
+        case 'e':
+          spillPair(PAIR_DE);
+          break;
+        case 'b':
+        case 'c':
+          spillPair(PAIR_BC);
+          break;
+        }
+    }
+}
+
 /** Push a register pair onto the stack */
 void
 genPairPush (asmop * aop)
@@ -382,29 +689,76 @@ genPairPush (asmop * aop)
   emit2 ("push %s", getPairName (aop));
 }
 
-
-/*-----------------------------------------------------------------*/
-/* newAsmop - creates a new asmOp                                  */
-/*-----------------------------------------------------------------*/
-static asmop *
-newAsmop (short type)
+static void
+_push (PAIR_ID pairId)
 {
-  asmop *aop;
-
-  aop = Safe_calloc (1, sizeof (asmop));
-  aop->type = type;
-  return aop;
+  emit2 ("push %s", _pairs[pairId].name);
+  _G.stack.pushed += 2;
 }
 
-/*-----------------------------------------------------------------*/
-/* aopForSym - for a true symbol                                   */
-/*-----------------------------------------------------------------*/
-static asmop *
-aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
+static void
+_pop (PAIR_ID pairId)
 {
-  asmop *aop;
-  memmap *space;
-
+  emit2 ("pop %s", _pairs[pairId].name);
+  _G.stack.pushed -= 2;
+  spillPair (pairId);
+}
+
+void
+genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
+{
+  switch (dstPair)
+    {
+    case PAIR_IX:
+    case PAIR_IY:
+    case PAIR_AF:
+      _push(srcPair);
+      _pop(dstPair);
+      break;
+    case PAIR_BC:
+    case PAIR_DE:
+    case PAIR_HL:
+      if (srcPair == PAIR_IX || srcPair == PAIR_IY)
+        {
+          _push(srcPair);
+          _pop(dstPair);
+        }
+      else
+        {
+          emit2("ld %s,%s",_pairs[dstPair].l,_pairs[srcPair].l);
+          emit2("ld %s,%s",_pairs[dstPair].h,_pairs[srcPair].h);
+        }
+     default:
+       wassertl (0, "Tried to move a nonphysical pair");
+    }
+  _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
+  _G.pairs[dstPair].base = _G.pairs[srcPair].base;
+  _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
+}
+
+
+/*-----------------------------------------------------------------*/
+/* newAsmop - creates a new asmOp                                  */
+/*-----------------------------------------------------------------*/
+static asmop *
+newAsmop (short type)
+{
+  asmop *aop;
+
+  aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
+  aop->type = type;
+  return aop;
+}
+
+/*-----------------------------------------------------------------*/
+/* aopForSym - for a true symbol                                   */
+/*-----------------------------------------------------------------*/
+static asmop *
+aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
+{
+  asmop *aop;
+  memmap *space;
+
   wassert (ic);
   wassert (sym);
   wassert (sym->etype);
@@ -413,13 +767,28 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
 
   /* if already has one */
   if (sym->aop)
-    return sym->aop;
+    {
+      return sym->aop;
+    }
 
   /* Assign depending on the storage class */
   if (sym->onStack || sym->iaccess)
     {
-      emit2 ("; 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 && (_G.omitFramePtr || 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;
@@ -429,30 +798,45 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
   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;
     }
 
-  if (IS_GB)
+  if( IN_REGSP( space ))
+  { /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
+    if (IS_GB)
     {
       /* if it is in direct space */
-      if (IN_REGSP (space) && !requires_a)
-       {
-         sym->aop = aop = newAsmop (AOP_SFR);
-         aop->aopu.aop_dir = sym->rname;
-         aop->size = getSize (sym->type);
-         emit2 ("; AOP_SFR for %s", sym->rname);
-         return aop;
-       }
+      if( !requires_a )
+      {
+        sym->aop = aop = newAsmop (AOP_SFR);
+        aop->aopu.aop_dir = sym->rname;
+        aop->size = getSize (sym->type);
+          emitDebug ("; AOP_SFR for %s", sym->rname);
+        return aop;
+      }
+    }
+    else
+    { /*.p.t.20030716 adding SFR support to the Z80 port */
+      aop = newAsmop (AOP_SFR);
+      sym->aop          = aop;
+      aop->aopu.aop_dir = sym->rname;
+      aop->size         = getSize( sym->type );
+      aop->paged        = FUNC_REGBANK(sym->type);
+      aop->bcInUse      = isPairInUse( PAIR_BC, ic );
+      aop->deInUse      = isPairInUse( PAIR_DE, ic );
+      emitDebug( ";Z80 AOP_SFR for %s banked:%d bc:%d de:%d", sym->rname, FUNC_REGBANK(sym->type), aop->bcInUse, aop->deInUse );
+
+      return( aop );
     }
+  }
 
   /* only remaining is far space */
   /* in which case DPTR gets the address */
   if (IS_GB)
     {
-      emit2 ("; AOP_HL for %s", sym->rname);
+      emitDebug ("; AOP_HL for %s", sym->rname);
       sym->aop = aop = newAsmop (AOP_HL);
     }
   else
@@ -483,21 +867,20 @@ aopForRemat (symbol * sym)
     {
       /* if plus or minus print the right hand side */
       if (ic->op == '+' || ic->op == '-')
-       {
-         /* PENDING: for re-target */
-         sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
-                  ic->op);
-         s += strlen (s);
-         ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
-         continue;
-       }
+        {
+          /* PENDING: for re-target */
+          sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
+                   ic->op);
+          s += strlen (s);
+          ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
+          continue;
+        }
       /* we reached the end */
       sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
       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;
 }
 
@@ -524,16 +907,16 @@ regsInCommon (operand * op1, operand * op2)
     {
       int j;
       if (!sym1->regs[i])
-       continue;
+        continue;
 
       for (j = 0; j < sym2->nRegs; j++)
-       {
-         if (!sym2->regs[j])
-           continue;
+        {
+          if (!sym2->regs[j])
+            continue;
 
-         if (sym2->regs[j] == sym1->regs[i])
-           return TRUE;
-       }
+          if (sym2->regs[j] == sym1->regs[i])
+            return TRUE;
+        }
     }
 
   return FALSE;
@@ -564,10 +947,10 @@ operandsEqu (operand * op1, operand * op2)
   if (sym1 == sym2)
     return 1;
 
-  if (strcmp (sym1->rname, sym2->rname) == 0)
+  if (sym1->rname[0] && sym2->rname[0]
+      && strcmp (sym1->rname, sym2->rname) == 0)
     return 2;
 
-
   /* if left is a tmp & right is not */
   if (IS_ITEMP (op1) &&
       !IS_ITEMP (op2) &&
@@ -609,7 +992,7 @@ sameRegs (asmop * aop1, asmop * aop2)
 
   for (i = 0; i < aop1->size; i++)
     if (aop1->aopu.aop_reg[i] !=
-       aop2->aopu.aop_reg[i])
+        aop2->aopu.aop_reg[i])
       return FALSE;
 
   return TRUE;
@@ -639,12 +1022,24 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a)
 
   /* if already has a asmop then continue */
   if (op->aop)
-    return;
+    {
+      if (op->aop->type == AOP_SFR)
+        {
+          op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
+          op->aop->deInUse = isPairInUse( PAIR_DE, ic );
+        }
+      return;
+    }
 
   /* if the underlying symbol has a aop */
   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
     {
       op->aop = OP_SYMBOL (op)->aop;
+      if (op->aop->type == AOP_SFR)
+        {
+          op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
+          op->aop->deInUse = isPairInUse( PAIR_DE, ic );
+        }
       return;
     }
 
@@ -680,52 +1075,79 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a)
     {
       /* rematerialize it NOW */
       if (sym->remat)
-       {
-         sym->aop = op->aop = aop =
-           aopForRemat (sym);
-         aop->size = getSize (sym->type);
-         return;
-       }
+        {
+          sym->aop = op->aop = aop =
+            aopForRemat (sym);
+          aop->size = getSize (sym->type);
+          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)
-           {
-             aop = op->aop = sym->aop = newAsmop (AOP_ACC);
-             aop->size = getSize (sym->type);
+        {
+          if (sym->accuse == ACCUSE_A)
+            {
+              aop = op->aop = sym->aop = newAsmop (AOP_ACC);
+              aop->size = getSize (sym->type);
               wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
 
               aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
-           }
-         else if (sym->accuse == ACCUSE_HL)
-           {
-             wassert (!IS_GB);
-             aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
-             aop->size = getSize (sym->type);
+            }
+          else if (sym->accuse == ACCUSE_SCRATCH)
+            {
+              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 
+            }
+          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
               {
-                  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  */
-      sym->aop = op->aop = aop =
-       aopForSym (ic, sym->usl.spillLoc, result, requires_a);
+      if (sym->usl.spillLoc)
+        {
+          asmop *oldAsmOp = NULL;
+
+          if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
+            {
+              /* force a new aop if sizes differ */
+              oldAsmOp = sym->usl.spillLoc->aop;
+              sym->usl.spillLoc->aop = NULL;
+            }
+          sym->aop = op->aop = aop =
+                     aopForSym (ic, sym->usl.spillLoc, result, requires_a);
+          if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
+            {
+              /* Don't reuse the new aop, go with the last one */
+              sym->usl.spillLoc->aop = oldAsmOp;
+            }
+          aop->size = getSize (sym->type);
+          return;
+        }
+
+      /* else must be a dummy iTemp */
+      sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
       aop->size = getSize (sym->type);
       return;
     }
@@ -758,19 +1180,30 @@ freeAsmop (operand * op, asmop * aaop, iCode * ic)
 
   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)
     {
       op->aop = NULL;
       if (IS_SYMOP (op))
-       {
-         OP_SYMBOL (op)->aop = NULL;
-         /* if the symbol has a spill */
-         if (SPIL_LOC (op))
-           SPIL_LOC (op)->aop = NULL;
-       }
+        {
+          OP_SYMBOL (op)->aop = NULL;
+          /* if the symbol has a spill */
+          if (SPIL_LOC (op))
+            SPIL_LOC (op)->aop = NULL;
+        }
     }
+
 }
 
 bool
@@ -791,13 +1224,6 @@ isLitWord (asmop * aop)
 char *
 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
 {
-  char *s = buffer;
-  char *rs;
-
-#if 0
-  if (aop->size != 2 && aop->type != AOP_HL)
-    return NULL;
-#endif
   /* depending on type */
   switch (aop->type)
     {
@@ -806,43 +1232,75 @@ aopGetLitWordLong (asmop * aop, int offset, bool 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
-       tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
-      rs = Safe_calloc (1, strlen (s) + 1);
-      strcpy (rs, s);
-      return rs;
+        {
+          tsprintf (buffer, sizeof(buffer),
+                    "%s + %d", aop->aopu.aop_immd, offset);
+        }
+      return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
+
     case AOP_LIT:
       {
-       value *val = aop->aopu.aop_lit;
-       /* if it is a float then it gets tricky */
-       /* otherwise it is fairly simple */
-       if (!IS_FLOAT (val->type))
-         {
-           unsigned long v = (unsigned long) floatFromVal (val);
-
-           if (offset == 2)
-             v >>= 16;
-
-           if (with_hash)
-             tsprintf (buffer, "!immedword", v);
-           else
-             tsprintf (buffer, "!constword", v);
-           rs = Safe_calloc (1, strlen (buffer) + 1);
-           return strcpy (rs, buffer);
-         }
-       else
-         {
-           /* A float */
-           Z80_FLOAT f;
-           convertFloat (&f, floatFromVal (val));
-           if (with_hash)
-             tsprintf (buffer, "!immedword", f.w[offset / 2]);
-           else
-             tsprintf (buffer, "!constword", f.w[offset / 2]);
-           rs = Safe_calloc (1, strlen (buffer) + 1);
-           return strcpy (rs, buffer);
-         }
+        value *val = aop->aopu.aop_lit;
+        /* if it is a float then it gets tricky */
+        /* otherwise it is fairly simple */
+        if (!IS_FLOAT (val->type))
+          {
+            unsigned long v = (unsigned long) floatFromVal (val);
+
+            if (offset == 2)
+              {
+                v >>= 16;
+              }
+            else if (offset == 0)
+              {
+                // OK
+              }
+            else
+              {
+                wassertl(0, "Encountered an invalid offset while fetching a literal");
+              }
+
+            if (with_hash)
+              tsprintf (buffer, sizeof(buffer), "!immedword", v);
+            else
+              tsprintf (buffer, sizeof(buffer), "!constword", v);
+
+            return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
+          }
+        else
+          {
+            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)
+              tsprintf (buffer, sizeof(buffer), "!immedword", i);
+            else
+              tsprintf (buffer, sizeof(buffer), "!constword", i);
+
+            return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
+          }
       }
     default:
       return NULL;
@@ -884,13 +1342,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)
 {
@@ -906,109 +1357,110 @@ requiresHL (asmop * aop)
     case AOP_IY:
     case AOP_HL:
     case AOP_STK:
+    case AOP_EXSTK:
+    case AOP_HLREG:
       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)
 {
-  const char *l;
+  const char *l, *base;
   const char *pair = _pairs[pairId].name;
-  l = aopGetLitWordLong (left, 0, FALSE);
-  wassert (l && pair);
+  l = aopGetLitWordLong (left, offset, FALSE);
+  base = aopGetLitWordLong (left, 0, FALSE);
+  wassert (l && pair && base);
 
   if (isPtr (pair))
     {
       if (pairId == PAIR_HL || pairId == PAIR_IY)
-       {
-         if (_G.pairs[pairId].last_type == left->type)
-           {
-             if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
-               {
-                 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)
-                   {
-                     return;
-                   }
-               }
-           }
-       }
+        {
+          if (_G.pairs[pairId].last_type == left->type)
+            {
+              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_IY && (offset >= INT8MIN && offset <= INT8MAX))
+                    {
+                      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;
     }
-  if (IS_GB && pairId == PAIR_DE && 0)
+  /* 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 (_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].offset = offset;
+      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;
+        }
     }
-  /* Both a lit on the right and a true symbol on the left */
-  if (offset)
-    emit2 ("ld %s,!hashedstr + %u", pair, l, offset);
   else
-    emit2 ("ld %s,!hashedstr", pair, l);
+    {
+      *pisUsed = TRUE;
+      return PAIR_HL;
+    }
 }
 
 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);
     }
-    else {
+    else
+      {
+        if (getPairId (aop) == pairId)
+          {
+            /* Do nothing */
+          }
         /* we need to get it byte by byte */
-        if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
+        else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
             aopGet (aop, offset, FALSE);
-            switch (aop->size) {
+            switch (aop->size - offset) {
             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 ("; 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) {
@@ -1022,10 +1474,38 @@ fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
                 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 if (isUnsplitable(aop))
+          {
+            emit2("push %s", _pairs[getPairId(aop)].name);
+            emit2("pop %s", _pairs[pairId].name);
+          }
+        else
+          {
             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);
@@ -1035,7 +1515,7 @@ fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
 static void
 fetchPair (PAIR_ID pairId, asmop * aop)
 {
-  fetchPairLong (pairId, aop, 0);
+  fetchPairLong (pairId, aop, NULL, 0);
 }
 
 static void
@@ -1045,40 +1525,107 @@ fetchHL (asmop * aop)
 }
 
 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 (_G.preserveCarry)
+    {
+      _push (PAIR_AF);
+      offset += 2;
+    }
+
+  if (offset < INT8MIN || offset > INT8MAX)
+    {
+      emit2 ("ld hl,!immedword", offset);
+      emit2 ("add hl,sp");
+    }
+  else
+    {
+          emit2 ("!ldahlsp", offset);
+    }
+
+  if (_G.preserveCarry)
+    {
+      _pop (PAIR_AF);
+      offset -= 2;
+    }
+}
 
+static void
+setupPair (PAIR_ID pairId, asmop * aop, int offset)
+{
   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;
+
     case AOP_HL:
+      wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
+
       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. */
+            if (_G.preserveCarry)
+              _push (PAIR_AF);
+            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;
+            if (_G.preserveCarry)
+              _pop (PAIR_AF);
+          }
+      }
+      break;
+
     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;
-         }
-       assert (pairId == PAIR_HL);
-       /* In some cases we can still inc or dec hl */
-       if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
-         {
-           adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
-         }
-       else
-         {
-           emit2 ("!ldahlsp", abso + _G.stack.pushed);
-         }
-       _G.pairs[pairId].offset = abso;
-       break;
+        /* 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;
+          }
+        assert (pairId == PAIR_HL);
+        /* In some cases we can still inc or dec hl */
+        if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
+          {
+            adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
+          }
+        else
+          {
+            setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
+          }
+        _G.pairs[pairId].offset = abso;
+        break;
       }
+
+    case AOP_PAIRPTR:
+      if (pairId != aop->aopu.aop_pairId)
+        genMovePairPair(aop->aopu.aop_pairId, pairId);
+      adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
+      break;
+
     default:
       wassert (0);
     }
@@ -1098,55 +1645,83 @@ emitLabel (int key)
 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) 
+      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 */
   switch (aop->type)
     {
+    case AOP_DUMMY:
+      tsprintf (buffer, sizeof(buffer), "!zero");
+      return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
+
     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:
-           tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
-           break;
-         case 1:
-           tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
-           break;
-         case 0:
-           tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
-           break;
-         default:
-           wassert (0);
-         }
-
-      return gc_strdup(s);
+        switch (offset)
+          {
+          case 2:
+            tsprintf (buffer, sizeof(buffer), "!bankimmeds", aop->aopu.aop_immd);
+            break;
+          case 1:
+            tsprintf (buffer, sizeof(buffer), "!msbimmeds", aop->aopu.aop_immd);
+            break;
+          case 0:
+            tsprintf (buffer, sizeof(buffer), "!lsbimmeds", aop->aopu.aop_immd);
+            break;
+          default:
+            wassertl (0, "Fetching from beyond the limits of an immediate value.");
+          }
+
+      return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
 
     case AOP_DIR:
       wassert (IS_GB);
-      emit2 ("ld a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
-      sprintf (s, "a");
+      emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
+      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) ; x", aop->aopu.aop_dir, offset);
-      sprintf (s, "a");
+      if( IS_GB )
+      {
+        // wassert (IS_GB);
+        emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
+        SNPRINTF (buffer, sizeof(buffer), "a");
+
+        return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
+      }
+      else
+      { /*.p.t.20030716 handling for i/o port read access for Z80 */
+        if( aop->paged )
+        { /* banked mode */
+          /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
+          emit2( "ld a,!msbimmeds", aop->aopu.aop_dir);
+          emit2( "in a,(!lsbimmeds)", aop->aopu.aop_dir);
+        }
+        else if( z80_opts.port_mode == 180 )
+        { /* z180 in0/out0 mode */
+          emit2( "in0 a,(%s)", aop->aopu.aop_dir );
+        }
+        else
+        { /* 8 bit mode */
+          emit2( "in a,(%s)", aop->aopu.aop_dir );
+        }
+
+        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;
@@ -1154,44 +1729,52 @@ aopGet (asmop * aop, int offset, bool bit16)
     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);
-      tsprintf (s, "!*iyx", offset);
+      tsprintf (buffer, sizeof(buffer), "!*iyx", offset);
+
+      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 gc_strdup(s);
+      return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
 
     case AOP_STK:
       if (IS_GB)
-       {
-         setupPair (PAIR_HL, aop, offset);
-         tsprintf (s, "!*hl");
-       }
+        {
+          setupPair (PAIR_HL, aop, offset);
+          tsprintf (buffer, sizeof(buffer), "!*hl");
+        }
       else
-       {
-         if (aop->aopu.aop_stk >= 0)
-           offset += _G.stack.param_offset;
-         tsprintf (s, "!*ixx ; x", aop->aopu.aop_stk + offset);
-       }
+        {
+          if (aop->aopu.aop_stk >= 0)
+            offset += _G.stack.param_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:
-      wassert (0);
+      wassertl (0, "Tried to fetch from a bit variable");
 
     case AOP_ACC:
       if (!offset)
-       {
-         return "a";
-       }
+        {
+          return "a";
+        }
       else
         {
-          tsprintf(s, "!zero");
-          return gc_strdup(s);
+          tsprintf(buffer, sizeof(buffer), "!zero");
+          return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
         }
 
     case AOP_HLREG:
@@ -1201,12 +1784,36 @@ aopGet (asmop * aop, int offset, bool bit16)
     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];
 
-    default:
-      break;
+    case AOP_PAIRPTR:
+      setupPair (aop->aopu.aop_pairId, aop, offset);
+      if (aop->aopu.aop_pairId==PAIR_IX)
+        SNPRINTF (buffer, sizeof(buffer),
+                  "!*ixx", 0);
+      else if (aop->aopu.aop_pairId==PAIR_IY)
+        SNPRINTF (buffer, sizeof(buffer),
+                  "!*iyx", 0);
+      else
+        SNPRINTF (buffer, sizeof(buffer),
+                  "(%s)", _pairs[aop->aopu.aop_pairId].name);
+
+      return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
+
+    default:
+      break;
     }
   wassertl (0, "aopget got unsupported aop->type");
   exit (0);
@@ -1254,144 +1861,220 @@ aopPut (asmop * aop, const char *s, int offset)
   if (aop->size && offset > (aop->size - 1))
     {
       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
-             "aopPut got offset > aop->size");
+              "aopPut got offset > aop->size");
       exit (0);
     }
 
   // PENDING
-  tsprintf(buffer2, s);
+  tsprintf(buffer2, sizeof(buffer2), s);
   s = buffer2;
 
   /* will assign value to value */
   /* depending on where it is ofcourse */
   switch (aop->type)
     {
+    case AOP_DUMMY:
+      _moveA (s);  /* in case s is volatile */
+      break;
+
     case AOP_DIR:
       /* Direct.  Hmmm. */
       wassert (IS_GB);
       if (strcmp (s, "a"))
-       emit2 ("ld a,%s", s);
+        emit2 ("ld a,%s", s);
       emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
       break;
 
     case AOP_SFR:
-      wassert (IS_GB);
-      if (strcmp (s, "a"))
-       emit2 ("ld a,%s", s);
-      emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
+      if( IS_GB )
+        {
+          //  wassert (IS_GB);
+          if (strcmp (s, "a"))
+            emit2 ("ld a,%s", s);
+          emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
+        }
+      else
+        { /*.p.t.20030716 handling for i/o port read access for Z80 */
+          if (aop->paged)
+            { /* banked mode */
+              if (aop->bcInUse)
+                emit2( "push bc" );
+
+              if (strlen(s) != 1
+                  || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e'
+                      && s[0] != 'h' && s[0] != 'l'))
+                {
+                  emit2( "ld a,%s", s );
+                  s = "a";
+                }
+
+              emit2( "ld bc,#%s", aop->aopu.aop_dir );
+              emit2( "out (c),%s", s );
+
+              if( aop->bcInUse )
+                emit2( "pop bc"    );
+              else
+                spillPair (PAIR_BC);
+            }
+          else if( z80_opts.port_mode == 180 )
+            { /* z180 in0/out0 mode */
+              emit2( "ld a,%s", s );
+              emit2( "out0 (%s),a", aop->aopu.aop_dir );
+            }
+          else
+            { /* 8 bit mode */
+              emit2( "ld a,%s", s );
+              emit2( "out (%s),a", aop->aopu.aop_dir );
+            }
+        }
       break;
 
     case AOP_REG:
       if (!strcmp (s, "!*hl"))
-       emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
+        emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
       else
-       emit2 ("ld %s,%s",
-              aop->aopu.aop_reg[offset]->name, s);
+        emit2 ("ld %s,%s",
+               aop->aopu.aop_reg[offset]->name, s);
+      spillPairReg(aop->aopu.aop_reg[offset]->name);
       break;
 
     case AOP_IY:
       wassert (!IS_GB);
-      setupPair (PAIR_IY, aop, offset);
       if (!canAssignToPtr (s))
-       {
-         emit2 ("ld a,%s", s);
-         emit2 ("ld !*iyx,a", offset);
-       }
+        {
+          emit2 ("ld a,%s", s);
+          setupPair (PAIR_IY, aop, offset);
+          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:
       wassert (IS_GB);
       /* PENDING: for re-target */
       if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
-       {
-         emit2 ("ld a,!*hl");
-         s = "a";
-       }
+        {
+          emit2 ("ld a,!*hl");
+          s = "a";
+        }
       setupPair (PAIR_HL, aop, offset);
 
       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)
-       {
-         /* PENDING: re-target */
-         if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
-           {
-             emit2 ("ld a,!*hl");
-             s = "a";
-           }
-         setupPair (PAIR_HL, aop, offset);
-         if (!canAssignToPtr (s))
-           {
-             emit2 ("ld a,%s", s);
-             emit2 ("ld !*hl,a");
-           }
-         else
-           emit2 ("ld !*hl,%s", s);
-       }
+        {
+          /* PENDING: re-target */
+          if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
+            {
+              emit2 ("ld a,!*hl");
+              s = "a";
+            }
+          setupPair (PAIR_HL, aop, offset);
+          if (!canAssignToPtr (s))
+            {
+              emit2 ("ld a,%s", s);
+              emit2 ("ld !*hl,a");
+            }
+          else
+            emit2 ("ld !*hl,%s", s);
+        }
       else
-       {
-         if (aop->aopu.aop_stk >= 0)
-           offset += _G.stack.param_offset;
-         if (!canAssignToPtr (s))
-           {
-             emit2 ("ld a,%s", s);
-             emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
-           }
-         else
-           emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
-       }
+        {
+          if (aop->aopu.aop_stk >= 0)
+            offset += _G.stack.param_offset;
+          if (!canAssignToPtr (s))
+            {
+              emit2 ("ld a,%s", s);
+              emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
+            }
+          else
+            {
+              emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
+            }
+        }
       break;
 
     case AOP_CRY:
       /* if bit variable */
       if (!aop->aopu.aop_dir)
-       {
-         emit2 ("ld a,#0");
-         emit2 ("rla");
-       }
+        {
+          emit2 ("ld a,!zero");
+          emit2 ("rla");
+        }
       else
-       {
-         /* In bit space but not in C - cant happen */
-         wassert (0);
-       }
+        {
+          /* In bit space but not in C - cant happen */
+          wassertl (0, "Tried to write into a bit variable");
+        }
       break;
 
     case AOP_STR:
       aop->coff = offset;
       if (strcmp (aop->aopu.aop_str[offset], s))
-       {
-         emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
-       }
+        {
+          emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
+        }
+      spillPairReg(aop->aopu.aop_str[offset]);
       break;
 
     case AOP_ACC:
       aop->coff = offset;
       if (!offset && (strcmp (s, "acc") == 0))
-       break;
+        break;
       if (offset > 0)
-       {
-
-         emit2 ("; Error aopPut AOP_ACC");
-       }
+        {
+          wassertl (0, "Tried to access past the end of A");
+        }
       else
-       {
-         if (strcmp (aop->aopu.aop_str[offset], s))
-           emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
-       }
+        {
+          if (strcmp (aop->aopu.aop_str[offset], s))
+            {
+              emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
+              spillPairReg(aop->aopu.aop_str[offset]);
+            }
+        }
       break;
 
     case AOP_HLREG:
       wassert (offset < 2);
       emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
+      spillPairReg(aop->aopu.aop_str[offset]);
+      break;
+
+    case AOP_PAIRPTR:
+      setupPair (aop->aopu.aop_pairId, aop, offset);
+      if (aop->aopu.aop_pairId==PAIR_IX)
+        emit2 ("ld !*ixx,%s", 0, s);
+      else if (aop->aopu.aop_pairId==PAIR_IY)
+        emit2 ("ld !*ixy,%s", 0, s);
+      else
+        emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
       break;
 
     default:
       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
-             "aopPut got unsupported aop->type");
+              "aopPut got unsupported aop->type");
       exit (0);
     }
 }
@@ -1399,12 +2082,13 @@ aopPut (asmop * aop, const char *s, int offset)
 #define AOP(op) op->aop
 #define AOP_TYPE(op) AOP(op)->type
 #define AOP_SIZE(op) AOP(op)->size
-#define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
+#define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
 
 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");
@@ -1413,8 +2097,19 @@ commitPair (asmop * aop, PAIR_ID id)
     }
   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);
+        }
     }
 }
 
@@ -1429,7 +2124,7 @@ getDataSize (operand * op)
   if (size == 3)
     {
       /* pointer */
-      wassert (0);
+      wassertl (0, "Somehow got a three byte data pointer");
     }
   return size;
 }
@@ -1439,24 +2134,71 @@ getDataSize (operand * op)
 /*-----------------------------------------------------------------*/
 static void
 movLeft2Result (operand * left, int offl,
-               operand * result, int offr, int sign)
+                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 (!sign)
-       {
-         aopPut (AOP (result), l, offr);
-       }
+        {
+          aopPut (AOP (result), l, offr);
+        }
       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
  */
@@ -1472,9 +2214,9 @@ outAcc (operand * result)
       offset = 1;
       /* unsigned or positive */
       while (size--)
-       {
-         aopPut (AOP (result), "!zero", offset++);
-       }
+        {
+          aopPut (AOP (result), "!zero", offset++);
+        }
     }
 }
 
@@ -1486,15 +2228,14 @@ outBitCLong (operand * result, bool swap_sense)
   /* if the result is bit */
   if (AOP_TYPE (result) == AOP_CRY)
     {
-      emit2 ("; Note: outBitC form 1");
-      aopPut (AOP (result), "blah", 0);
+      wassertl (0, "Tried to write carry to a bit");
     }
   else
     {
       emit2 ("ld a,!zero");
       emit2 ("rla");
       if (swap_sense)
-       emit2 ("xor a,!immedbyte", 1);
+        emit2 ("xor a,!immedbyte", 1);
       outAcc (result);
     }
 }
@@ -1509,7 +2250,7 @@ outBitC (operand * result)
 /* toBoolean - emit code for orl a,operator(sizeop)                */
 /*-----------------------------------------------------------------*/
 void
-toBoolean (operand * oper)
+_toBoolean (operand * oper)
 {
   int size = AOP_SIZE (oper);
   int offset = 0;
@@ -1518,25 +2259,25 @@ toBoolean (operand * oper)
       emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
       size--;
       while (size--)
-       emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
+        emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
     }
   else
     {
       if (AOP (oper)->type != AOP_ACC)
-       {
-         _clearCarry();
-         emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
-       }
+        {
+          _clearCarry();
+          emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
+        }
     }
 }
 
+
 /*-----------------------------------------------------------------*/
 /* genNot - generate code for ! operation                          */
 /*-----------------------------------------------------------------*/
 static void
 genNot (iCode * ic)
 {
-  sym_link *optype = operandType (IC_LEFT (ic));
 
   /* assign asmOps to operand & result */
   aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
@@ -1545,16 +2286,10 @@ genNot (iCode * ic)
   /* if in bit space then a special case */
   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
     {
-      wassert (0);
-    }
-
-  /* if type float then do float */
-  if (IS_FLOAT (optype))
-    {
-      wassert (0);
+      wassertl (0, "Tried to negate a bit");
     }
 
-  toBoolean (IC_LEFT (ic));
+  _toBoolean (IC_LEFT (ic));
 
   /* Not of A:
      If A == 0, !A = 1
@@ -1587,7 +2322,7 @@ genCpl (iCode * ic)
   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));
@@ -1604,6 +2339,85 @@ genCpl (iCode * 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 bit 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                         */
 /*-----------------------------------------------------------------*/
@@ -1622,7 +2436,7 @@ genUminus (iCode * ic)
   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;
     }
 
@@ -1632,12 +2446,23 @@ genUminus (iCode * ic)
   /* 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));
+
+  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--)
@@ -1655,7 +2480,7 @@ genUminus (iCode * ic)
       emit2 ("rlc a");
       emit2 ("sbc a,a");
       while (size--)
-       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
+        aopPut (AOP (IC_RESULT (ic)), "a", offset++);
     }
 
 release:
@@ -1664,21 +2489,6 @@ release:
   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 -               */
 /*-----------------------------------------------------------------*/
@@ -1688,31 +2498,45 @@ assignResultValue (operand * oper)
   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));
 
-#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);
-      emit2 ("pop de");
-      _G.stack.pushed -= 2;
+      _pop (PAIR_DE);
       aopPut (AOP (oper), _fReturn[0], 2);
       aopPut (AOP (oper), _fReturn[1], 3);
     }
   else
     {
       while (size--)
-       {
-         aopPut (AOP (oper), _fReturn[size], size);
-       }
+        {
+          aopPut (AOP (oper), _fReturn[size], size);
+        }
+    }
+}
+
+/** 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
@@ -1733,7 +2557,7 @@ _saveRegsForCall(iCode *ic, int sendSetSize)
       o Compute if DE and/or BC are used to hold the result value
       o If (DE is used, or in the send set) and is not used in the result, push.
       o If BC is used and is not in the result, push
-      o 
+      o
       o If DE is used in the send set, fetch
       o If HL is used in the send set, fetch
       o Call
@@ -1745,22 +2569,15 @@ _saveRegsForCall(iCode *ic, int sendSetSize)
     bool bcInRet = FALSE, deInRet = FALSE;
     bitVect *rInUse;
 
-    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;
-      }
+    rInUse = bitVectCplAnd (bitVectCopy (ic->rMask),
+                            z80_rUmaskForOp (IC_RESULT(ic)));
 
     deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
     bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
 
     deSending = (sendSetSize > 1);
 
-    emit2 ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
+    emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
 
     if (bcInUse && bcInRet == FALSE) {
       _push(PAIR_BC);
@@ -1792,42 +2609,6 @@ genIpush (iCode * ic)
   if (!ic->parmPush)
     {
       wassertl(0, "Encountered an unsupported spill push.");
-#if 0
-      /* and the item is spilt then do nothing */
-      if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
-       return;
-
-      aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
-      size = AOP_SIZE (IC_LEFT (ic));
-      /* push it on the stack */
-      if (isPair (AOP (IC_LEFT (ic))))
-       {
-         emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
-         _G.stack.pushed += 2;
-       }
-      else
-       {
-         offset = size;
-         while (size--)
-           {
-             /* Simple for now - load into A and PUSH AF */
-             if (AOP (IC_LEFT (ic))->type == AOP_IY)
-               {
-                 char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
-                 wassert (l);
-                 emit2 ("ld a,(%s)", l);
-               }
-             else
-               {
-                 l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
-                 emit2 ("ld a,%s", l);
-               }
-             emit2 ("push af");
-             emit2 ("inc sp");
-             _G.stack.pushed++;
-           }
-       }
-#endif
       return;
     }
 
@@ -1839,7 +2620,7 @@ genIpush (iCode * ic)
     */
     int nAddSets = 0;
     iCode *walk = ic->next;
-    
+
     while (walk) {
       if (walk->op == SEND) {
         nAddSets++;
@@ -1864,7 +2645,7 @@ genIpush (iCode * 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))));
@@ -1872,43 +2653,43 @@ genIpush (iCode * ic)
   else
     {
       if (size == 2)
-       {
-         fetchHL (AOP (IC_LEFT (ic)));
-         emit2 ("push hl");
-         spillPair (PAIR_HL);
-         _G.stack.pushed += 2;
-         goto release;
-       }
+        {
+          fetchHL (AOP (IC_LEFT (ic)));
+          emit2 ("push hl");
+          spillPair (PAIR_HL);
+          _G.stack.pushed += 2;
+          goto release;
+        }
       if (size == 4)
-       {
-         fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
-         emit2 ("push hl");
-         spillPair (PAIR_HL);
-         _G.stack.pushed += 2;
-         fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
-         emit2 ("push hl");
-         spillPair (PAIR_HL);
-         _G.stack.pushed += 2;
-         goto release;
-       }
+        {
+          fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
+          emit2 ("push hl");
+          spillPair (PAIR_HL);
+          _G.stack.pushed += 2;
+          fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
+          emit2 ("push hl");
+          spillPair (PAIR_HL);
+          _G.stack.pushed += 2;
+          goto release;
+        }
       offset = size;
       while (size--)
-       {
-         if (AOP (IC_LEFT (ic))->type == AOP_IY)
-           {
-             char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
-             wassert (l);
-             emit2 ("ld a,(%s)", l);
-           }
-         else
-           {
-             l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
-             emit2 ("ld a,%s", l);
-           }
-         emit2 ("push af");
-         emit2 ("inc sp");
-         _G.stack.pushed++;
-       }
+        {
+          if (AOP (IC_LEFT (ic))->type == AOP_IY)
+            {
+              char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
+              wassert (l);
+              emit2 ("ld a,(%s)", l);
+            }
+          else
+            {
+              l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
+              emit2 ("ld a,%s", l);
+            }
+          emit2 ("push af");
+          emit2 ("inc sp");
+          _G.stack.pushed++;
+        }
     }
 release:
   freeAsmop (IC_LEFT (ic), NULL, ic);
@@ -1937,12 +2718,12 @@ genIpop (iCode * ic)
   else
     {
       while (size--)
-       {
-         emit2 ("dec sp");
-         emit2 ("pop hl");
-         spillPair (PAIR_HL);
-         aopPut (AOP (IC_LEFT (ic)), "l", offset--);
-       }
+        {
+          emit2 ("dec sp");
+          emit2 ("pop hl");
+          spillPair (PAIR_HL);
+          aopPut (AOP (IC_LEFT (ic)), "l", offset--);
+        }
     }
 
   freeAsmop (IC_LEFT (ic), NULL, ic);
@@ -1991,28 +2772,28 @@ _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
     {
       int i;
       for (i = 0; i < aop->size; i++)
-       {
-         if (pairId == PAIR_DE)
-           {
-             emit2 ("; name %s", aop->aopu.aop_reg[i]->name);
-             if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
-               ret++;
-             if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
-               ret++;
-           }
+        {
+          if (pairId == PAIR_DE)
+            {
+              emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
+              if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
+                ret++;
+              if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
+                ret++;
+            }
           else if (pairId == PAIR_BC)
             {
-             emit2 ("; name %s", aop->aopu.aop_reg[i]->name);
-             if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
-               ret++;
-             if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
-               ret++;
+              emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
+              if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
+                ret++;
+              if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
+                ret++;
+            }
+          else
+            {
+              wassert (0);
             }
-         else
-           {
-             wassert (0);
-           }
-       }
+        }
     }
 
   freeAsmop (IC_LEFT (ic), NULL, ic);
@@ -2024,7 +2805,8 @@ _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
 static void
 emitCall (iCode * ic, bool ispcall)
 {
-  sym_link *detype = getSpec (operandType (IC_LEFT (ic)));
+  bool bInRet, cInRet, dInRet, eInRet;
+  sym_link *dtype = operandType (IC_LEFT (ic));
 
   /* if caller saves & we have not saved then */
   if (!ic->regsSaved)
@@ -2096,30 +2878,29 @@ emitCall (iCode * ic, bool ispcall)
 
   if (ispcall)
     {
-      if (IS_BANKEDCALL (detype))
-       {
-         werror (W_INDIR_BANKED);
-       }
+      if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
+        {
+          werror (W_INDIR_BANKED);
+        }
       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
 
       if (isLitWord (AOP (IC_LEFT (ic))))
-       {
-         emit2 ("; Special case where the pCall is to a constant");
-         emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
-       }
+        {
+          emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
+        }
       else
-       {
-         symbol *rlbl = newiTempLabel (NULL);
-         spillPair (PAIR_HL);
-         emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
-         emit2 ("push hl");
-         _G.stack.pushed += 2;
-
-         fetchHL (AOP (IC_LEFT (ic)));
-         emit2 ("jp !*hl");
-         emit2 ("!tlabeldef", (rlbl->key + 100));
-         _G.stack.pushed -= 2;
-       }
+        {
+          symbol *rlbl = newiTempLabel (NULL);
+          spillPair (PAIR_HL);
+          emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
+          emit2 ("push hl");
+          _G.stack.pushed += 2;
+
+          fetchHL (AOP (IC_LEFT (ic)));
+          emit2 ("jp !*hl");
+          emit2 ("!tlabeldef", (rlbl->key + 100));
+          _G.stack.pushed -= 2;
+        }
       freeAsmop (IC_LEFT (ic), NULL, ic);
     }
   else
@@ -2127,27 +2908,27 @@ 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;
-      if (IS_BANKEDCALL (detype))
-       {
-         emit2 ("call banked_call");
-         emit2 ("!dws", name);
-         emit2 ("!dw !bankimmeds", name);
-       }
+      if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
+        {
+          emit2 ("call banked_call");
+          emit2 ("!dws", name);
+          emit2 ("!dw !bankimmeds", name);
+        }
       else
-       {
-         /* make the call */
-         emit2 ("call %s", name);
-       }
+        {
+          /* make the call */
+          emit2 ("call %s", name);
+        }
     }
   spillCached ();
 
-  /* Mark the regsiters as restored. */
+  /* Mark the registers as restored. */
   _G.saves.saved = FALSE;
 
   /* 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)) ||
+        OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
       IS_TRUE_SYMOP (IC_RESULT (ic)))
     {
 
@@ -2165,53 +2946,111 @@ emitCall (iCode * ic, bool ispcall)
 
       _G.stack.pushed -= i;
       if (IS_GB)
-       {
-         emit2 ("!ldaspsp", i);
-       }
+        {
+          emit2 ("!ldaspsp", i);
+        }
       else
-       {
-         spillCached ();
-         if (i > 6)
-           {
-             emit2 ("ld hl,#%d", i);
-             emit2 ("add hl,sp");
-             emit2 ("ld sp,hl");
-           }
-         else
-           {
-             while (i > 1)
-               {
-                 emit2 ("pop hl");
-                 i -= 2;
-               }
-             if (i)
-               emit2 ("inc sp");
-           }
-         spillCached ();
-       }
-    }
-
-  if (_G.stack.pushedDE) 
-    {
-      _pop(PAIR_DE);
-      _G.stack.pushedDE = FALSE;
+        {
+          spillCached ();
+          if (i > 8)
+            {
+              emit2 ("ld iy,!immedword", i);
+              emit2 ("add iy,sp");
+              emit2 ("ld sp,iy");
+            }
+          else
+            {
+              while (i > 1)
+                {
+                  emit2 ("pop af");
+                  i -= 2;
+                }
+              if (i)
+                {
+                  emit2 ("inc sp");
+                }
+            }
+        }
     }
-  
-  if (_G.stack.pushedBC) 
+
+  spillCached ();
+  if (IC_RESULT (ic))
     {
-      _pop(PAIR_BC);
-      _G.stack.pushedBC = FALSE;
+      bitVect *result = z80_rUmaskForOp (IC_RESULT (ic));
+      bInRet = bitVectBitValue(result, B_IDX);
+      cInRet = bitVectBitValue(result, C_IDX);
+      dInRet = bitVectBitValue(result, D_IDX);
+      eInRet = bitVectBitValue(result, E_IDX);
+    }
+  else
+    {
+      bInRet = FALSE;
+      cInRet = FALSE;
+      dInRet = FALSE;
+      eInRet = FALSE;
     }
-}
 
-/*-----------------------------------------------------------------*/
-/* genCall - generates a call statement                            */
-/*-----------------------------------------------------------------*/
-static void
-genCall (iCode * ic)
-{
-  emitCall (ic, FALSE);
-}
+  if (_G.stack.pushedDE)
+    {
+      if (dInRet && eInRet)
+        {
+          wassertl (0, "Shouldn't push DE if it's wiped out by the return");
+        }
+      else if (dInRet)
+        {
+          /* Only restore E */
+          emit2 ("ld a,d");
+          _pop (PAIR_DE);
+          emit2 ("ld d,a");
+        }
+      else if (eInRet)
+        {
+          /* Only restore D */
+          _pop (PAIR_AF);
+          emit2 ("ld d,a");
+        }
+      else
+        {
+          _pop (PAIR_DE);
+        }
+      _G.stack.pushedDE = FALSE;
+    }
+
+  if (_G.stack.pushedBC)
+    {
+      if (bInRet && cInRet)
+        {
+          wassertl (0, "Shouldn't push BC if it's wiped out by the return");
+        }
+      else if (bInRet)
+        {
+          /* Only restore C */
+          emit2 ("ld a,b");
+          _pop (PAIR_BC);
+          emit2 ("ld b,a");
+        }
+      else if (cInRet)
+        {
+          /* Only restore B */
+          _pop (PAIR_AF);
+          emit2 ("ld b,a");
+        }
+      else
+        {
+          _pop (PAIR_BC);
+        }
+      _G.stack.pushedBC = FALSE;
+    }
+}
+
+/*-----------------------------------------------------------------*/
+/* genCall - generates a call statement                            */
+/*-----------------------------------------------------------------*/
+static void
+genCall (iCode * ic)
+{
+  emitCall (ic, FALSE);
+}
 
 /*-----------------------------------------------------------------*/
 /* genPcall - generates a call by pointer statement                */
@@ -2235,7 +3074,7 @@ resultRemat (iCode * ic)
     {
       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
       if (sym->remat && !POINTER_SET (ic))
-       return 1;
+        return 1;
     }
 
   return 0;
@@ -2243,105 +3082,130 @@ resultRemat (iCode * ic)
 
 extern set *publics;
 
-/* Steps:
-    o Check genFunction
-    o Check emitCall and clean up
-    o Check genReturn
-    o Check return puller
-
-    PENDING: Remove this.
-*/
-
 /*-----------------------------------------------------------------*/
 /* genFunction - generated code for function entry                 */
 /*-----------------------------------------------------------------*/
 static void
 genFunction (iCode * ic)
 {
+  bool stackParm;
+
   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
-  sym_link *fetype;
+  sym_link *ftype;
 
-#if CALLEE_SAVES
   bool bcInUse = FALSE;
   bool deInUse = FALSE;
-#endif
 
-  setArea (IS_NONBANKED (sym->etype));
+  setArea (IFFUNC_NONBANKED (sym->type));
 
-  /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
-     else.
+  /* PENDING: Reset the receive offset as it
+     doesn't seem to get reset anywhere else.
   */
   _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);
-  /* PENDING: portability. */
-  emit2 ("__%s_start:", sym->rname);
+  if (!IS_STATIC(sym->etype))
+    {
+      sprintf (buffer, "%s_start", sym->rname);
+      emit2 ("!labeldef", buffer);
+    }
   emit2 ("!functionlabeldef", sym->rname);
 
-  fetype = getSpec (operandType (IC_LEFT (ic)));
+  ftype = operandType (IC_LEFT (ic));
 
-  /* if critical function then turn interrupts off */
-  if (SPEC_CRTCL (fetype))
-    emit2 ("!di");
+  if (IFFUNC_ISNAKED(ftype))
+    {
+      emitDebug("; naked function: no prologue.");
+      return;
+    }
 
-  /* if this is an interrupt service routine then save all potentially used registers. */
-  if (IS_ISR (sym->etype))
+  /* if this is an interrupt service routine
+     then save all potentially used registers. */
+  if (IFFUNC_ISISR (sym->type))
     {
+      /* If critical function then turn interrupts off */
+      /* except when no interrupt number is given then it implies the NMI handler */
+      if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
+        {
+          emit2 ("!di");
+        }
+
       emit2 ("!pusha");
     }
+  else
+    {
+      /* This is a non-ISR function.
+         If critical function then turn interrupts off */
+      if (IFFUNC_ISCRITICAL (sym->type))
+        {
+          if (IS_GB)
+            {
+              emit2 ("!di");
+            }
+          else
+            {
+              //get interrupt enable flag IFF2 into P/O
+              emit2 ("ld a,i");
+              emit2 ("!di");
+              //save P/O flag
+              emit2 ("push af");
+            }
+        }
+    }
+
+  if (options.profile)
+    {
+      emit2 ("!profileenter");
+    }
 
   /* PENDING: callee-save etc */
 
   _G.stack.param_offset = 0;
 
-#if CALLEE_SAVES
+  if (z80_opts.calleeSavesBC)
+    {
+      bcInUse = TRUE;
+    }
+
   /* 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++)
-       {
-         if (bitVectBitValue (sym->regsUsed, i))
-           {
-             switch (i)
-               {
-               case C_IDX:
-               case B_IDX:
+        {
+          if (bitVectBitValue (sym->regsUsed, i))
+            {
+              switch (i)
+                {
+                case C_IDX:
+                case B_IDX:
                   bcInUse = TRUE;
-                 break;
-               case D_IDX:
-               case E_IDX:
-                 if (IS_Z80) {
+                  break;
+                case D_IDX:
+                case E_IDX:
+                  if (IS_Z80) {
                     deInUse = TRUE;
                   }
                   else {
                     /* Other systems use DE as a temporary. */
                   }
-                 break;
-               }
-           }
-       }
+                  break;
+                }
+            }
+        }
     }
 
-  if (bcInUse) 
+  if (bcInUse)
     {
       emit2 ("push bc");
       _G.stack.param_offset += 2;
     }
 
-  _G.stack.pushedBC = bcInUse;
+  _G.calleeSaves.pushedBC = bcInUse;
 
   if (deInUse)
     {
@@ -2349,16 +3213,39 @@ genFunction (iCode * ic)
       _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;
 
-  if (sym->stack)
+  stackParm = FALSE;
+  for (sym = setFirstItem (istack->syms); sym;
+       sym = setNextItem (istack->syms))
+    {
+      if (sym->_isparm && !IS_REGPARM (sym->etype))
+        {
+          stackParm = TRUE;
+          break;
+        }
+    }
+  sym = OP_SYMBOL (IC_LEFT (ic));
+
+  _G.omitFramePtr = options.ommitFramePtr;
+  if (IS_Z80 && !stackParm && !sym->stack)
+    {
+      /* When the conflicts between AOP_EXSTK && AOP_HLREG are fixed, */
+      /* the above !sym->stack condition can be removed. -- EEP       */
+      if (sym->stack)
+        emit2 ("!ldaspsp", -sym->stack);
+      _G.omitFramePtr = TRUE;
+    }
+  else if (sym->stack && IS_GB && sym->stack > -INT8MIN)
+    emit2 ("!enterxl", sym->stack);
+  else if (sym->stack)
     emit2 ("!enterx", sym->stack);
   else
     emit2 ("!enter");
+
   _G.stack.offset = sym->stack;
 }
 
@@ -2370,46 +3257,110 @@ genEndFunction (iCode * ic)
 {
   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
 
-  if (IS_ISR (sym->etype))
+  if (IFFUNC_ISNAKED(sym->type))
+  {
+      emitDebug("; naked function: no epilogue.");
+      return;
+  }
+
+  /* PENDING: calleeSave */
+  if (IS_Z80 && _G.omitFramePtr)
     {
-      wassert (0);
+      if (_G.stack.offset)
+        emit2 ("!ldaspsp", _G.stack.offset);
+    }
+  else 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);
     }
   else
     {
-      if (SPEC_CRTCL (sym->etype))
-       emit2 ("!ei");
+      emit2 ("!leave");
+    }
 
-      /* PENDING: calleeSave */
+  if (_G.calleeSaves.pushedDE)
+    {
+      emit2 ("pop de");
+      _G.calleeSaves.pushedDE = FALSE;
+    }
 
-      if (_G.stack.offset)
-        {
-          emit2 ("!leavex", _G.stack.offset);
-        }
-      else
-        {
-          emit2 ("!leave");
-        }
+  if (_G.calleeSaves.pushedBC)
+    {
+      emit2 ("pop bc");
+      _G.calleeSaves.pushedBC = FALSE;
+    }
+
+  if (options.profile)
+    {
+      emit2 ("!profileexit");
+    }
 
-#if CALLEE_SAVES
-      if (_G.stack.pushedDE) 
+  /* if this is an interrupt service routine
+     then save all potentially used registers. */
+  if (IFFUNC_ISISR (sym->type))
+    {
+      emit2 ("!popa");
+
+      /* If critical function then turn interrupts back on */
+      /* except when no interrupt number is given then it implies the NMI handler */
+      if (IFFUNC_ISCRITICAL (sym->type) && (FUNC_INTNO(sym->type) != INTNO_UNSPEC))
         {
-          emit2 ("pop de");
-          _G.stack.pushedDE = FALSE;
+          emit2 ("!ei");
         }
-
-      if (_G.stack.pushedDE) 
+    }
+  else
+    {
+      /* This is a non-ISR function.
+         If critical function then turn interrupts back on */
+      if (IFFUNC_ISCRITICAL (sym->type))
         {
-          emit2 ("pop bc");
-          _G.stack.pushedDE = FALSE;
+          if (IS_GB)
+            {
+              emit2 ("!ei");
+            }
+          else
+            {
+              symbol *tlbl = newiTempLabel (NULL);
+              //restore P/O flag
+              emit2 ("pop af");
+              //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
+              //don't enable interrupts as they were off before
+              emit2 ("jp po,!tlabel", tlbl->key + 100);
+              emit2 ("!ei");
+              emit2 ("!tlabeldef", (tlbl->key + 100));
+            }
         }
-#endif
+    }
 
-      /* Both baned and non-banked just ret */
+  if (options.debug && currFunc)
+    {
+      debugFile->writeEndFunction (currFunc, ic, 1);
+    }
+
+  if (IFFUNC_ISISR (sym->type))
+    {
+      /* "critical interrupt" is used to imply NMI handler */
+      if (IS_Z80 && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO(sym->type) == INTNO_UNSPEC)
+        emit2 ("retn");
+      else
+        emit2 ("reti");
+    }
+  else
+    {
+      /* Both banked and non-banked just ret */
       emit2 ("ret");
+    }
 
-      /* PENDING: portability. */
-      emit2 ("__%s_end:", sym->rname);
+  if (!IS_STATIC(sym->etype))
+    {
+      sprintf (buffer, "%s_end", sym->rname);
+      emit2 ("!labeldef", buffer);
     }
+
   _G.flushStatics = 1;
   _G.stack.pushed = 0;
   _G.stack.offset = 0;
@@ -2436,34 +3387,43 @@ genRet (iCode * ic)
   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
   size = AOP_SIZE (IC_LEFT (ic));
 
+  aopDump("IC_LEFT", AOP(IC_LEFT(ic)));
+
+  #if 0
   if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
     {
       if (IS_GB)
-       {
-         emit2 ("ld de,%s", l);
-       }
+        {
+          emit2 ("ld de,%s", l);
+        }
       else
-       {
-         emit2 ("ld hl,%s", l);
-       }
+        {
+          emit2 ("ld hl,%s", l);
+        }
+    }
+  #endif
+  if (size==2)
+    {
+      fetchPair(IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)));
     }
   else
     {
       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);
-       }
+        {
+          fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
+          fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 2);
+        }
       else
-       {
-         while (size--)
-           {
-             l = aopGet (AOP (IC_LEFT (ic)), offset,
-                         FALSE);
-             if (strcmp (_fReturn[offset], l))
-               emit2 ("ld %s,%s", _fReturn[offset++], l);
-           }
-       }
+        {
+          while (size--)
+            {
+              l = aopGet (AOP (IC_LEFT (ic)), offset,
+                          FALSE);
+              if (strcmp (_fReturn[offset], l))
+                emit2 ("ld %s,%s", _fReturn[offset], l);
+              offset++;
+            }
+        }
     }
   freeAsmop (IC_LEFT (ic), NULL, ic);
 
@@ -2471,7 +3431,7 @@ jumpret:
   /* generate a jump to the return label
      if the next is not the return statement */
   if (!(ic->next && ic->next->op == LABEL &&
-       IC_LABEL (ic->next) == returnLabel))
+        IC_LABEL (ic->next) == returnLabel))
 
     emit2 ("jp !tlabel", returnLabel->key + 100);
 }
@@ -2514,7 +3474,7 @@ genPlusIncr (iCode * ic)
   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
     return FALSE;
 
-  emit2 ("; genPlusIncr");
+  emitDebug ("; genPlusIncr");
 
   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
 
@@ -2522,30 +3482,49 @@ genPlusIncr (iCode * ic)
   if (resultId != PAIR_INVALID)
     {
       if (isLitWord (AOP (IC_LEFT (ic))))
-       {
-         fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
-         return TRUE;
-       }
+        {
+          fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
+          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;
+        return FALSE;
       /* Inc a pair */
       if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
-       {
-         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);
-       }
+        {
+          if (icount > 2)
+            return FALSE;
+          movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
+        }
       while (icount--)
-       {
-         emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
-       }
+        {
+          emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
+        }
+      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;
     }
 
@@ -2564,13 +3543,13 @@ genPlusIncr (iCode * ic)
       symbol *tlbl = NULL;
       tlbl = newiTempLabel (NULL);
       while (size--)
-       {
-         emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
-         if (size)
-           {
-             emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
-           }
-       }
+        {
+          emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
+          if (size)
+            {
+              emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+            }
+        }
       emitLabel (tlbl->key + 100);
       return TRUE;
     }
@@ -2580,13 +3559,27 @@ genPlusIncr (iCode * ic)
       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 */
   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
     {
       while (icount--)
-       emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
+        {
+          emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
+        }
       return TRUE;
     }
 
@@ -2603,7 +3596,7 @@ outBitAcc (operand * result)
   /* if the result is a bit */
   if (AOP_TYPE (result) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Tried to write A into a bit");
     }
   else
     {
@@ -2614,6 +3607,91 @@ 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);
+          /* check result again, in case right == result */
+          if (couldDestroyCarry (result))
+            shiftIntoPair (1, result);
+        }
+      else if (couldDestroyCarry (right))
+        {
+          if (getPairId (result) == PAIR_HL)
+            _G.preserveCarry = TRUE;
+          else
+            shiftIntoPair (0, right);
+        }
+      else if (couldDestroyCarry (result))
+        {
+          shiftIntoPair (0, result);
+        }
+      else
+        {
+          /* Fine */
+        }
+    }
+}
+
 /*-----------------------------------------------------------------*/
 /* genPlus - generates code for addition                           */
 /*-----------------------------------------------------------------*/
@@ -2635,7 +3713,7 @@ genPlus (iCode * ic)
      in ACC */
 
   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
-      (AOP_NEEDSACC (IC_LEFT (ic))) ||
+      (AOP_NEEDSACC (IC_RIGHT (ic))) ||
       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
     {
       operand *t = IC_RIGHT (ic);
@@ -2649,7 +3727,7 @@ genPlus (iCode * ic)
       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 */
@@ -2657,7 +3735,7 @@ genPlus (iCode * ic)
       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
@@ -2665,7 +3743,7 @@ genPlus (iCode * ic)
   if (genPlusIncr (ic) == TRUE)
     goto release;
 
-  emit2 ("; genPlusIncr failed");
+  emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
 
   size = getDataSize (IC_RESULT (ic));
 
@@ -2673,26 +3751,63 @@ genPlus (iCode * ic)
   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);
-      if (left && right)
-       {
-         /* It's a pair */
-         /* PENDING: fix */
-         char buffer[100];
-         sprintf (buffer, "#(%s + %s)", left, right);
-         emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
-         goto release;
-       }
+
+      if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
+          left && right)
+        {
+          /* It's a pair */
+          /* PENDING: fix */
+          char buffer[100];
+          sprintf (buffer, "#(%s + %s)", left, right);
+          emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
+          goto release;
+        }
     }
 
-  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 */
+      PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
+      PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
+
       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))));
+      spillCached();
+      commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
       goto release;
     }
 
@@ -2727,68 +3842,75 @@ genPlus (iCode * ic)
   if (IS_GB)
     {
       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
-         AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
-         AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
-       {
-         if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
-              AOP_SIZE (IC_RIGHT (ic)) == 2) &&
-             (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
-              AOP_SIZE (IC_RIGHT (ic)) <= 2))
-           {
-             if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
-               {
-                 /* Swap left and right */
-                 operand *t = IC_RIGHT (ic);
-                 IC_RIGHT (ic) = IC_LEFT (ic);
-                 IC_LEFT (ic) = t;
-               }
-             if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
-               {
-                 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
-                 emit2 ("add hl,bc");
-               }
-             else
-               {
-                 fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
-                 fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
-                 emit2 ("add hl,de");
-               }
-             commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
-             goto release;
-           }
-         else if (size == 4)
-           {
-             emit2 ("; WARNING: This add is probably broken.\n");
-           }
-       }
+          AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
+          AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
+        {
+          if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
+               AOP_SIZE (IC_RIGHT (ic)) == 2) &&
+              (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
+               AOP_SIZE (IC_RIGHT (ic)) <= 2))
+            {
+              if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
+                {
+                  /* Swap left and right */
+                  operand *t = IC_RIGHT (ic);
+                  IC_RIGHT (ic) = IC_LEFT (ic);
+                  IC_LEFT (ic) = t;
+                }
+              if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
+                {
+                  fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
+                  emit2 ("add hl,bc");
+                }
+              else
+                {
+                  fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
+                  fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
+                  emit2 ("add hl,de");
+                }
+              commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
+              goto release;
+            }
+        }
+      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)
-       {
-         _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
-         if (offset == 0)
-           emit2 ("add a,%s",
-                  aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
-         else
-           emit2 ("adc a,%s",
-                  aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
-       }
+        {
+          _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
+          if (offset == 0)
+            emit2 ("add a,%s",
+                   aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
+          else
+            emit2 ("adc a,%s",
+                   aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
+        }
       else
-       {
-         _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
-         if (offset == 0)
-           emit2 ("add a,%s",
-                  aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
-         else
-           emit2 ("adc a,%s",
-                  aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
-       }
+        {
+          _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
+          if (offset == 0)
+            emit2 ("add a,%s",
+                   aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
+          else
+            emit2 ("adc a,%s",
+                   aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
+        }
       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
     }
 
 release:
+  _G.preserveCarry = FALSE;
   freeAsmop (IC_LEFT (ic), NULL, ic);
   freeAsmop (IC_RIGHT (ic), NULL, ic);
   freeAsmop (IC_RESULT (ic), NULL, ic);
@@ -2816,46 +3938,42 @@ genMinusDec (iCode * ic)
 
   size = getDataSize (IC_RESULT (ic));
 
-#if 0
-  /* if increment 16 bits in register */
-  if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
-      (size > 1) &&
-      (icount == 1))
-    {
-      symbol *tlbl = newiTempLabel (NULL);
-      emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
-      emit2 ("jp np," LABEL_STR, tlbl->key + 100);
-
-      emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE));
-      if (size == 4)
-       {
-         wassert (0);
-       }
-      emitLabel (tlbl->key + 100);
-      return TRUE;
-    }
-#endif
-
   /* if decrement 16 bits in register */
   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
       (size > 1) && isPair (AOP (IC_RESULT (ic))))
     {
       while (icount--)
-       emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
+        emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
       return TRUE;
     }
 
   /* 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))));
+        emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
       return TRUE;
     }
 
-  /* if the sizes are greater than 1 then we cannot */
+  /* if increment 16 bits in register */
+  if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
+      (size == 2)
+      )
+    {
+      fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
+
+      while (icount--) {
+        emit2 ("dec %s", _getTempPairName());
+      }
+
+      commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
+
+      return TRUE;
+    }
+
+
+  /* if the sizes are greater than 1 then we cannot */
   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
       AOP_SIZE (IC_LEFT (ic)) > 1)
     return FALSE;
@@ -2865,7 +3983,7 @@ genMinusDec (iCode * ic)
   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
     {
       while (icount--)
-       emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
+        emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
       return TRUE;
     }
 
@@ -2890,7 +4008,7 @@ genMinus (iCode * ic)
   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;
     }
 
@@ -2913,78 +4031,90 @@ genMinus (iCode * ic)
   if (IS_GB)
     {
       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
-         AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
-         AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
-       {
-         if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
-              AOP_SIZE (IC_RIGHT (ic)) == 2) &&
-             (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
-              AOP_SIZE (IC_RIGHT (ic)) <= 2))
-           {
-             PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
-             PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
-
-             if (left == PAIR_INVALID && right == PAIR_INVALID)
-               {
-                 left = PAIR_DE;
-                 right = PAIR_HL;
-               }
-             else if (right == PAIR_INVALID)
-               right = PAIR_DE;
-             else if (left == PAIR_INVALID)
-               left = PAIR_DE;
-
-             fetchPair (left, AOP (IC_LEFT (ic)));
-             /* Order is important.  Right may be HL */
-             fetchPair (right, AOP (IC_RIGHT (ic)));
-
-             emit2 ("ld a,%s", _pairs[left].l);
-             emit2 ("sub a,%s", _pairs[right].l);
-             emit2 ("ld e,a");
-             emit2 ("ld a,%s", _pairs[left].h);
-             emit2 ("sbc a,%s", _pairs[right].h);
-
-             aopPut (AOP (IC_RESULT (ic)), "a", 1);
-             aopPut (AOP (IC_RESULT (ic)), "e", 0);
-             goto release;
-           }
-         else if (size == 4)
-           {
-             emit2 ("; WARNING: This sub is probably broken.\n");
-           }
-       }
+          AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
+          AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
+        {
+          if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
+               AOP_SIZE (IC_RIGHT (ic)) == 2) &&
+              (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
+               AOP_SIZE (IC_RIGHT (ic)) <= 2))
+            {
+              PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
+              PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
+
+              if (left == PAIR_INVALID && right == PAIR_INVALID)
+                {
+                  left = PAIR_DE;
+                  right = PAIR_HL;
+                }
+              else if (right == PAIR_INVALID)
+                right = PAIR_DE;
+              else if (left == PAIR_INVALID)
+                left = PAIR_DE;
+
+              fetchPair (left, AOP (IC_LEFT (ic)));
+              /* Order is important.  Right may be HL */
+              fetchPair (right, AOP (IC_RIGHT (ic)));
+
+              emit2 ("ld a,%s", _pairs[left].l);
+              emit2 ("sub a,%s", _pairs[right].l);
+              emit2 ("ld e,a");
+              emit2 ("ld a,%s", _pairs[left].h);
+              emit2 ("sbc a,%s", _pairs[right].h);
+
+              if ( AOP_SIZE (IC_RESULT (ic)) > 1)
+                {
+                  aopPut (AOP (IC_RESULT (ic)), "a", 1);
+                }
+              aopPut (AOP (IC_RESULT (ic)), "e", 0);
+              goto release;
+            }
+        }
+      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--)
     {
       _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
-       {
-         if (!offset)
-           emit2 ("sub a,%s",
-                     aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
-         else
-           emit2 ("sbc a,%s",
-                     aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
-       }
+        {
+          if (!offset)
+            emit2 ("sub a,%s",
+                      aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
+          else
+            emit2 ("sbc a,%s",
+                      aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
+        }
       else
-       {
-         /* first add without previous c */
-         if (!offset)
-           emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
-         else
-           emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
-       }
+        {
+          /* first add without previous c */
+          if (!offset)
+            emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
+          else
+            emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
+        }
       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
     }
 
   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:
+  _G.preserveCarry = FALSE;
   freeAsmop (IC_LEFT (ic), NULL, ic);
   freeAsmop (IC_RIGHT (ic), NULL, ic);
   freeAsmop (IC_RESULT (ic), NULL, ic);
@@ -2996,8 +4126,104 @@ release:
 static void
 genMult (iCode * ic)
 {
+  int val;
+  int count, i;
+  /* If true then the final operation should be a subtract */
+  bool active = FALSE;
+  bool byteResult;
+
   /* 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);
+
+  byteResult =  (AOP_SIZE (IC_RESULT (ic)) == 1);
+
+  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));
+      if (!byteResult)
+        {
+          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");
+              if (!byteResult)
+                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;
+    }
+
+  if (byteResult)
+    aopPut (AOP (IC_RESULT (ic)), _pairs[PAIR_HL].l, 0);
+  else
+    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);
 }
 
 /*-----------------------------------------------------------------*/
@@ -3007,7 +4233,7 @@ static void
 genDiv (iCode * ic)
 {
   /* Shouldn't occur - all done through function calls */
-  wassert (0);
+  wassertl (0, "Division is handled through support function calls");
 }
 
 /*-----------------------------------------------------------------*/
@@ -3035,44 +4261,60 @@ genIfxJump (iCode * ic, char *jval)
     {
       jlbl = IC_TRUE (ic);
       if (!strcmp (jval, "a"))
-       {
-         inst = "nz";
-       }
+        {
+          inst = "nz";
+        }
       else if (!strcmp (jval, "c"))
-       {
-         inst = "c";
-       }
+        {
+          inst = "c";
+        }
       else if (!strcmp (jval, "nc"))
-       {
-         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 */
-         inst = "nz";
-       }
+        {
+          /* The buffer contains the bit on A that we should test */
+          inst = "nz";
+        }
     }
   else
     {
       /* false label is present */
       jlbl = IC_FALSE (ic);
       if (!strcmp (jval, "a"))
-       {
-         inst = "z";
-       }
+        {
+          inst = "z";
+        }
       else if (!strcmp (jval, "c"))
-       {
-         inst = "nc";
-       }
+        {
+          inst = "nc";
+        }
       else if (!strcmp (jval, "nc"))
-       {
-         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 */
-         inst = "z";
-       }
+        {
+          /* The buffer contains the bit on A that we should test */
+          inst = "z";
+        }
     }
   /* Z80 can do a conditional long jump */
   if (!strcmp (jval, "a"))
@@ -3085,6 +4327,12 @@ genIfxJump (iCode * ic, char *jval)
   else if (!strcmp (jval, "nc"))
     {
     }
+  else if (!strcmp (jval, "m"))
+    {
+    }
+  else if (!strcmp (jval, "p"))
+    {
+    }
   else
     {
       emit2 ("bit %s,a", jval);
@@ -3095,17 +4343,196 @@ genIfxJump (iCode * ic, char *jval)
   ic->generated = 1;
 }
 
+#if DISABLED
 static const char *
 _getPairIdName (PAIR_ID id)
 {
   return _pairs[id].name;
 }
+#endif
+
+#if OLD
+      /* if unsigned char cmp with lit, just compare */
+      if ((size == 1) &&
+          (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
+        {
+          emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
+          if (sign)
+            {
+              emit2 ("xor a,!immedbyte", 0x80);
+              emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
+            }
+          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
+        {
+          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 == 0L)
+                {
+                  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
+                        emit2 ("rlc a");
+                    }
+                  goto release;
+                }
+            }
+
+          if (sign)
+            {
+              /* First setup h and l contaning the top most bytes XORed */
+              bool fDidXor = FALSE;
+              if (AOP_TYPE (left) == AOP_LIT)
+                {
+                  unsigned long lit = (unsigned long)
+                  floatFromVal (AOP (left)->aopu.aop_lit);
+                  emit2 ("ld %s,!immedbyte", _fTmp[0],
+                         0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
+                }
+              else
+                {
+                  emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
+                  emit2 ("xor a,!immedbyte", 0x80);
+                  emit2 ("ld %s,a", _fTmp[0]);
+                  fDidXor = TRUE;
+                }
+              if (AOP_TYPE (right) == AOP_LIT)
+                {
+                  unsigned long lit = (unsigned long)
+                  floatFromVal (AOP (right)->aopu.aop_lit);
+                  emit2 ("ld %s,!immedbyte", _fTmp[1],
+                         0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
+                }
+              else
+                {
+                  emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
+                  emit2 ("xor a,!immedbyte", 0x80);
+                  emit2 ("ld %s,a", _fTmp[1]);
+                  fDidXor = TRUE;
+                }
+            }
+          while (size--)
+            {
+              /* Do a long subtract */
+              if (!sign || size)
+                {
+                  _moveA (aopGet (AOP (left), offset, FALSE));
+                }
+              if (sign && size == 0)
+                {
+                  emit2 ("ld a,%s", _fTmp[0]);
+                  emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
+                }
+              else
+                {
+                  /* Subtract through, propagating the carry */
+                  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)
+        operand * result, iCode * ifx, int sign)
 {
   int size, offset = 0;
   unsigned long lit = 0L;
@@ -3116,158 +4543,92 @@ genCmp (operand * left, operand * right,
       AOP_TYPE (right) == AOP_CRY)
     {
       /* Cant happen on the Z80 */
-      wassert (0);
+      wassertl (0, "Tried to compare two bits");
     }
   else
     {
-      /* subtract right from left if at the
-         end the carry flag is set then we know that
-         left is greater than right */
+      /* Do a long subtract of right from left. */
       size = max (AOP_SIZE (left), AOP_SIZE (right));
 
-      /* if unsigned char cmp with lit, just compare */
-      if ((size == 1) &&
-         (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
-       {
-         emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
-         if (sign)
-           {
-             emit2 ("xor a,!immedbyte", 0x80);
-             emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
-           }
-         else
-           emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
-       }
-      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 (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);
-             /* optimize if(x < 0) or if(x >= 0) */
-             if (lit == 0L)
-               {
-                 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
-                       emit2 ("rlc a");
-                   }
-                 goto release;
-               }
-           }
-         if (sign)
-           {
-             /* First setup h and l contaning the top most bytes XORed */
-             bool fDidXor = FALSE;
-             if (AOP_TYPE (left) == AOP_LIT)
-               {
-                 unsigned long lit = (unsigned long)
-                 floatFromVal (AOP (left)->aopu.aop_lit);
-                 emit2 ("ld %s,!immedbyte", _fTmp[0],
-                        0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
-               }
-             else
-               {
-                 emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
-                 emit2 ("xor a,!immedbyte", 0x80);
-                 emit2 ("ld %s,a", _fTmp[0]);
-                 fDidXor = TRUE;
-               }
-             if (AOP_TYPE (right) == AOP_LIT)
-               {
-                 unsigned long lit = (unsigned long)
-                 floatFromVal (AOP (right)->aopu.aop_lit);
-                 emit2 ("ld %s,!immedbyte", _fTmp[1],
-                        0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
-               }
-             else
-               {
-                 emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
-                 emit2 ("xor a,!immedbyte", 0x80);
-                 emit2 ("ld %s,a", _fTmp[1]);
-                 fDidXor = TRUE;
-               }
-             if (!fDidXor)
-               _clearCarry();
-           }
-         else
-           {
-             _clearCarry();
-           }
-         while (size--)
-           {
-             /* Do a long subtract */
-             if (!sign || size)
-               {
-                 _moveA (aopGet (AOP (left), offset, FALSE));
-               }
-             if (sign && size == 0)
-               {
-                 emit2 ("ld a,%s", _fTmp[0]);
-                 emit2 ("sbc a,%s", _fTmp[1]);
-               }
-             else
-               {
-                 /* Subtract through, propagating the carry */
-                 emit2 ("sbc a,%s ; 2", aopGet (AOP (right), offset++, FALSE));
-               }
-           }
-       }
+      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))
     {
+      if (sign)
+        {
+          /* Shift the sign bit up into carry */
+          emit2 ("rlca");
+        }
       outBitCLong (result, swap_sense);
     }
   else
@@ -3276,9 +4637,33 @@ release:
          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
-       outBitCLong (result, swap_sense);
+        {
+          if (sign)
+            {
+              /* Shift the sign bit up into carry */
+              emit2 ("rlca");
+            }
+          outBitCLong (result, swap_sense);
+        }
       /* leave the result in acc */
     }
 }
@@ -3361,76 +4746,76 @@ gencjneshort (operand * left, operand * right, symbol * lbl)
     }
 
   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 &&
       AOP_TYPE (left) != AOP_DIR)
     {
       if (lit == 0)
-       {
-         emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
-         if (size > 1)
-           {
-             size--;
-             offset++;
-             while (size--)
-               {
-                 emit2 ("or a,%s", aopGet (AOP (left), offset, FALSE));
-               }
-           }
-         else
-           {
-             emit2 ("or a,a");
-           }
-         emit2 ("jp nz,!tlabel", lbl->key + 100);
-       }
+        {
+          emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
+          if (size > 1)
+            {
+              while (--size)
+                {
+                  emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
+                }
+            }
+          else
+            {
+              emit2 ("or a,a");
+            }
+          emit2 ("jp nz,!tlabel", lbl->key + 100);
+        }
       else
-       {
-         while (size--)
-           {
-             emit2 ("ld a,%s ; 2", aopGet (AOP (left), offset, FALSE));
-             if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
-               emit2 ("or a,a");
-             else
-               emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
-             emit2 ("jp nz,!tlabel", lbl->key + 100);
-             offset++;
-           }
-       }
+        {
+          while (size--)
+            {
+              emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
+              if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
+                emit2 ("or a,a");
+              else
+                emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
+              emit2 ("jp nz,!tlabel", lbl->key + 100);
+              offset++;
+            }
+        }
     }
   /* if the right side is in a register or in direct space or
      if the left is a pointer register & right is not */
   else if (AOP_TYPE (right) == AOP_REG ||
-          AOP_TYPE (right) == AOP_DIR ||
-          (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
+           AOP_TYPE (right) == AOP_DIR ||
+           (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
     {
       while (size--)
-       {
-         _moveA (aopGet (AOP (left), offset, FALSE));
-         if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
-             ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
-           /* PENDING */
-           emit2 ("jp nz,!tlabel", lbl->key + 100);
-         else
-           {
-             emit2 ("cp %s ; 4", aopGet (AOP (right), offset, FALSE));
-             emit2 ("jp nz,!tlabel", lbl->key + 100);
-           }
-         offset++;
-       }
+        {
+          _moveA (aopGet (AOP (left), offset, FALSE));
+          if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
+              ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
+            /* PENDING */
+            emit2 ("jp nz,!tlabel", lbl->key + 100);
+          else
+            {
+              emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
+              emit2 ("jp nz,!tlabel", lbl->key + 100);
+            }
+          offset++;
+        }
     }
   else
     {
       /* right is a pointer reg need both a & b */
       /* PENDING: is this required? */
       while (size--)
-       {
-         _moveA (aopGet (AOP (right), offset, FALSE));
-         emit2 ("cp %s ; 5", aopGet (AOP (left), offset, FALSE));
-         emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
-         offset++;
-       }
+        {
+          _moveA (aopGet (AOP (right), offset, FALSE));
+          emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
+          emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
+          offset++;
+        }
     }
 }
 
@@ -3464,7 +4849,7 @@ genCmpEq (iCode * ic, iCode * ifx)
   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
 
-  emit2("; 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.
@@ -3481,29 +4866,29 @@ genCmpEq (iCode * ic, iCode * ifx)
       symbol *tlbl;
       /* if they are both bit variables */
       if (AOP_TYPE (left) == AOP_CRY &&
-         ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
-       {
-         wassert (0);
-       }
+          ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
+        {
+          wassertl (0, "Tried to compare two bits");
+        }
       else
-       {
-         tlbl = newiTempLabel (NULL);
-         gencjneshort (left, right, tlbl);
-         if (IC_TRUE (ifx))
-           {
-             emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
-             emitLabel (tlbl->key + 100);
-           }
-         else
-           {
-             /* PENDING: do this better */
-             symbol *lbl = newiTempLabel (NULL);
-             emit2 ("!shortjp !tlabel", lbl->key + 100);
-             emitLabel (tlbl->key + 100);
-             emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
-             emitLabel (lbl->key + 100);
-           }
-       }
+        {
+          tlbl = newiTempLabel (NULL);
+          gencjneshort (left, right, tlbl);
+          if (IC_TRUE (ifx))
+            {
+              emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
+              emitLabel (tlbl->key + 100);
+            }
+          else
+            {
+              /* PENDING: do this better */
+              symbol *lbl = newiTempLabel (NULL);
+              emit2 ("!shortjp !tlabel", lbl->key + 100);
+              emitLabel (tlbl->key + 100);
+              emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
+              emitLabel (lbl->key + 100);
+            }
+        }
       /* mark the icode as generated */
       ifx->generated = 1;
       goto release;
@@ -3513,26 +4898,30 @@ genCmpEq (iCode * ic, iCode * ifx)
   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
     {
+      emitDebug(";4");
+
       gencjne (left, right, newiTempLabel (NULL));
       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
-       {
-         wassert (0);
-       }
+        {
+          wassert (0);
+        }
       if (ifx)
-       {
-         genIfxJump (ifx, "a");
-         goto release;
-       }
+        {
+          emitDebug(";5");
+          genIfxJump (ifx, "a");
+          goto release;
+        }
       /* if the result is used in an arithmetic operation
          then put the result in place */
       if (AOP_TYPE (result) != AOP_CRY)
-       {
-         outAcc (result);
-       }
+        {
+          emitDebug(";6");
+          outAcc (result);
+        }
       /* leave the result in acc */
     }
 
@@ -3584,14 +4973,14 @@ genAndOp (iCode * ic)
   if (AOP_TYPE (left) == AOP_CRY &&
       AOP_TYPE (right) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Tried to and two bits");
     }
   else
     {
       tlbl = newiTempLabel (NULL);
-      toBoolean (left);
+      _toBoolean (left);
       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
-      toBoolean (right);
+      _toBoolean (right);
       emitLabel (tlbl->key + 100);
       outBitAcc (result);
     }
@@ -3621,14 +5010,14 @@ genOrOp (iCode * ic)
   if (AOP_TYPE (left) == AOP_CRY &&
       AOP_TYPE (right) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Tried to OR two bits");
     }
   else
     {
       tlbl = newiTempLabel (NULL);
-      toBoolean (left);
+      _toBoolean (left);
       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
-      toBoolean (right);
+      _toBoolean (right);
       emitLabel (tlbl->key + 100);
       outBitAcc (result);
     }
@@ -3698,18 +5087,9 @@ genAnd (iCode * ic, iCode * ifx)
   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
 
-#ifdef DEBUG_TYPE
-  emit2 ("; Type res[%d] = l[%d]&r[%d]",
-           AOP_TYPE (result),
-           AOP_TYPE (left), AOP_TYPE (right));
-  emit2 ("; 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))
+      (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
     {
       operand *tmp = right;
       right = left;
@@ -3739,7 +5119,7 @@ genAnd (iCode * ic, iCode * ifx)
 
   if (AOP_TYPE (left) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Tried to perform an AND with a bit as an operand");
       goto release;
     }
 
@@ -3749,80 +5129,46 @@ genAnd (iCode * ic, iCode * ifx)
       (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;
-           }
-       }
+      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++;
+        }
+      // bit = left & literal
+      if (size)
+        {
+          emit2 ("clr c");
+          emit2 ("!tlabeldef", tlbl->key + 100);
+        }
+      // if(left & literal)
       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);
-                   }
-               }
-             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;
-           }
-       }
+        {
+          if (ifx)
+            {
+              jmpTrueOrFalse (ifx, tlbl);
+            }
+          goto release;
+        }
       outBitC (result);
       goto release;
     }
@@ -3831,82 +5177,82 @@ genAnd (iCode * ic, iCode * ifx)
   if (sameRegs (AOP (result), AOP (left)))
     {
       for (; size--; offset++)
-       {
-         if (AOP_TYPE (right) == AOP_LIT)
-           {
-             if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
-               continue;
-             else
-               {
-                 if (bytelit == 0)
-                   aopPut (AOP (result), "!zero", offset);
-                 else
-                   {
-                     _moveA (aopGet (AOP (left), offset, FALSE));
-                     emit2 ("and a,%s",
-                               aopGet (AOP (right), offset, FALSE));
-                     aopPut (AOP (left), "a", offset);
-                   }
-               }
-
-           }
-         else
-           {
-             if (AOP_TYPE (left) == AOP_ACC)
-               {
-                 wassert (0);
-               }
-             else
-               {
-                 _moveA (aopGet (AOP (left), offset, FALSE));
-                 emit2 ("and a,%s",
-                           aopGet (AOP (right), offset, FALSE));
-                 aopPut (AOP (left), "a", offset);
-               }
-           }
-       }
+        {
+          if (AOP_TYPE (right) == AOP_LIT)
+            {
+              if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
+                continue;
+              else
+                {
+                  if (bytelit == 0)
+                    aopPut (AOP (result), "!zero", offset);
+                  else
+                    {
+                      _moveA (aopGet (AOP (left), offset, FALSE));
+                      emit2 ("and a,%s",
+                                aopGet (AOP (right), offset, FALSE));
+                      aopPut (AOP (left), "a", offset);
+                    }
+                }
+
+            }
+          else
+            {
+              if (AOP_TYPE (left) == AOP_ACC)
+                {
+                  wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
+                }
+              else
+                {
+                  _moveA (aopGet (AOP (left), offset, FALSE));
+                  emit2 ("and a,%s",
+                            aopGet (AOP (right), offset, FALSE));
+                  aopPut (AOP (left), "a", offset);
+                }
+            }
+        }
     }
   else
     {
       // 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
-       {
-         for (; (size--); offset++)
-           {
-             // normal case
-             // result = left & right
-             if (AOP_TYPE (right) == AOP_LIT)
-               {
-                 if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
-                   {
-                     aopPut (AOP (result),
-                             aopGet (AOP (left), offset, FALSE),
-                             offset);
-                     continue;
-                   }
-                 else if (bytelit == 0)
-                   {
-                     aopPut (AOP (result), "!zero", offset);
-                     continue;
-                   }
-               }
-             // faster than result <- left, anl result,right
-             // and better if result is SFR
-             if (AOP_TYPE (left) == AOP_ACC)
-               emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
-             else
-               {
-                 _moveA (aopGet (AOP (left), offset, FALSE));
-                 emit2 ("and a,%s",
-                           aopGet (AOP (right), offset, FALSE));
-               }
-             aopPut (AOP (result), "a", offset);
-           }
-       }
+        {
+          for (; (size--); offset++)
+            {
+              // normal case
+              // result = left & right
+              if (AOP_TYPE (right) == AOP_LIT)
+                {
+                  if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
+                    {
+                      aopPut (AOP (result),
+                              aopGet (AOP (left), offset, FALSE),
+                              offset);
+                      continue;
+                    }
+                  else if (bytelit == 0)
+                    {
+                      aopPut (AOP (result), "!zero", offset);
+                      continue;
+                    }
+                }
+              // faster than result <- left, anl result,right
+              // and better if result is SFR
+              if (AOP_TYPE (left) == AOP_ACC)
+                emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
+              else
+                {
+                  _moveA (aopGet (AOP (left), offset, FALSE));
+                  emit2 ("and a,%s",
+                            aopGet (AOP (right), offset, FALSE));
+                }
+              aopPut (AOP (result), "a", offset);
+            }
+        }
 
     }
 
@@ -3925,23 +5271,15 @@ genOr (iCode * ic, iCode * ifx)
   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);
 
-#if 1
-  emit2 ("; Type res[%d] = l[%d]&r[%d]",
-           AOP_TYPE (result),
-           AOP_TYPE (left), AOP_TYPE (right));
-  emit2 ("; 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))
+      (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
     {
       operand *tmp = right;
       right = left;
@@ -3971,15 +5309,39 @@ genOr (iCode * ic, iCode * ifx)
 
   if (AOP_TYPE (left) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Tried to OR where left is a bit");
       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))
     {
-      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 inefficient. */
+      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;
     }
 
@@ -3987,71 +5349,71 @@ genOr (iCode * ic, iCode * ifx)
   if (sameRegs (AOP (result), AOP (left)))
     {
       for (; size--; offset++)
-       {
-         if (AOP_TYPE (right) == AOP_LIT)
-           {
-             if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
-               continue;
-             else
-               {
-                 _moveA (aopGet (AOP (left), offset, FALSE));
-                 emit2 ("or a,%s",
-                           aopGet (AOP (right), offset, FALSE));
-                 aopPut (AOP (result), "a", offset);
-               }
-           }
-         else
-           {
-             if (AOP_TYPE (left) == AOP_ACC)
-               emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
-             else
-               {
-                 _moveA (aopGet (AOP (left), offset, FALSE));
-                 emit2 ("or a,%s",
-                           aopGet (AOP (right), offset, FALSE));
-                 aopPut (AOP (result), "a", offset);
-               }
-           }
-       }
+        {
+          if (AOP_TYPE (right) == AOP_LIT)
+            {
+              if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
+                continue;
+              else
+                {
+                  _moveA (aopGet (AOP (left), offset, FALSE));
+                  emit2 ("or a,%s",
+                            aopGet (AOP (right), offset, FALSE));
+                  aopPut (AOP (result), "a", offset);
+                }
+            }
+          else
+            {
+              if (AOP_TYPE (left) == AOP_ACC)
+                emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
+              else
+                {
+                  _moveA (aopGet (AOP (left), offset, FALSE));
+                  emit2 ("or a,%s",
+                            aopGet (AOP (right), offset, FALSE));
+                  aopPut (AOP (result), "a", offset);
+                }
+            }
+        }
     }
   else
     {
       // 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++)
-         {
-           // normal case
-           // result = left & right
-           if (AOP_TYPE (right) == AOP_LIT)
-             {
-               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
-                 {
-                   aopPut (AOP (result),
-                           aopGet (AOP (left), offset, FALSE),
-                           offset);
-                   continue;
-                 }
-             }
-           // faster than result <- left, anl result,right
-           // and better if result is SFR
-           if (AOP_TYPE (left) == AOP_ACC)
-             emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
-           else
-             {
-               _moveA (aopGet (AOP (left), offset, FALSE));
-               emit2 ("or a,%s",
-                         aopGet (AOP (right), offset, FALSE));
-             }
-           aopPut (AOP (result), "a", offset);
-           /* PENDING: something weird is going on here.  Add exception. */
-           if (AOP_TYPE (result) == AOP_ACC)
-             break;
-         }
-    }
+        for (; (size--); offset++)
+          {
+            // normal case
+            // result = left & right
+            if (AOP_TYPE (right) == AOP_LIT)
+              {
+                if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
+                  {
+                    aopPut (AOP (result),
+                            aopGet (AOP (left), offset, FALSE),
+                            offset);
+                    continue;
+                  }
+              }
+            // faster than result <- left, anl result,right
+            // and better if result is SFR
+            if (AOP_TYPE (left) == AOP_ACC)
+              emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
+            else
+              {
+                _moveA (aopGet (AOP (left), offset, FALSE));
+                emit2 ("or a,%s",
+                          aopGet (AOP (right), offset, FALSE));
+              }
+            aopPut (AOP (result), "a", offset);
+            /* PENDING: something weird is going on here.  Add exception. */
+            if (AOP_TYPE (result) == AOP_ACC)
+              break;
+          }
+    }
 
 release:
   freeAsmop (left, NULL, ic);
@@ -4075,7 +5437,7 @@ genXor (iCode * ic, iCode * ifx)
 
   /* 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))
+      (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
     {
       operand *tmp = right;
       right = left;
@@ -4105,15 +5467,39 @@ genXor (iCode * ic, iCode * ifx)
 
   if (AOP_TYPE (left) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Tried to XOR a bit");
       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))
     {
-      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;
     }
 
@@ -4121,68 +5507,71 @@ genXor (iCode * ic, iCode * ifx)
   if (sameRegs (AOP (result), AOP (left)))
     {
       for (; size--; offset++)
-       {
-         if (AOP_TYPE (right) == AOP_LIT)
-           {
-             if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
-               continue;
-             else
-               {
-                 _moveA (aopGet (AOP (right), offset, FALSE));
-                 emit2 ("xor a,%s",
-                           aopGet (AOP (left), offset, FALSE));
-                 aopPut (AOP (result), "a", 0);
-               }
-           }
-         else
-           {
-             if (AOP_TYPE (left) == AOP_ACC)
-               emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
-             else
-               {
-                 _moveA (aopGet (AOP (right), offset, FALSE));
-                 emit2 ("xor a,%s",
-                           aopGet (AOP (left), offset, FALSE));
-                 aopPut (AOP (result), "a", 0);
-               }
-           }
-       }
+        {
+          if (AOP_TYPE (right) == AOP_LIT)
+            {
+              if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
+                continue;
+              else
+                {
+                  _moveA (aopGet (AOP (left), offset, FALSE));
+                  emit2 ("xor a,%s",
+                            aopGet (AOP (right), offset, FALSE));
+                  aopPut (AOP (result), "a", offset);
+                }
+            }
+          else
+            {
+              if (AOP_TYPE (left) == AOP_ACC)
+                {
+                  emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
+                }
+              else
+                {
+                  _moveA (aopGet (AOP (left), offset, FALSE));
+                  emit2 ("xor a,%s",
+                            aopGet (AOP (right), offset, FALSE));
+                  aopPut (AOP (result), "a", offset);
+                }
+            }
+        }
     }
   else
     {
       // 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++)
-         {
-           // normal case
-           // result = left & right
-           if (AOP_TYPE (right) == AOP_LIT)
-             {
-               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
-                 {
-                   aopPut (AOP (result),
-                           aopGet (AOP (left), offset, FALSE),
-                           offset);
-                   continue;
-                 }
-             }
-           // faster than result <- left, anl result,right
-           // and better if result is SFR
-           if (AOP_TYPE (left) == AOP_ACC)
-             emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
-           else
-             {
-               _moveA (aopGet (AOP (right), offset, FALSE));
-               emit2 ("xor a,%s",
-                         aopGet (AOP (left), offset, FALSE));
-               aopPut (AOP (result), "a", 0);
-             }
-           aopPut (AOP (result), "a", offset);
-         }
+        for (; (size--); offset++)
+          {
+            // normal case
+            // result = left & right
+            if (AOP_TYPE (right) == AOP_LIT)
+              {
+                if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
+                  {
+                    aopPut (AOP (result),
+                            aopGet (AOP (left), offset, FALSE),
+                            offset);
+                    continue;
+                  }
+              }
+            // faster than result <- left, anl result,right
+            // and better if result is SFR
+            if (AOP_TYPE (left) == AOP_ACC)
+              {
+                emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
+              }
+            else
+              {
+                _moveA (aopGet (AOP (left), offset, FALSE));
+                emit2 ("xor a,%s",
+                          aopGet (AOP (right), offset, FALSE));
+              }
+            aopPut (AOP (result), "a", offset);
+          }
     }
 
 release:
@@ -4208,24 +5597,24 @@ genInline (iCode * ic)
   while (*bp)
     {
       if (*bp == '\n')
-       {
-         *bp++ = '\0';
-         emit2 (bp1);
-         bp1 = bp;
-       }
+        {
+          *bp++ = '\0';
+          emit2 (bp1);
+          bp1 = bp;
+        }
       else
-       {
-         if (*bp == ':')
-           {
-             bp++;
-             *bp = '\0';
-             bp++;
-             emit2 (bp1);
-             bp1 = bp;
-           }
-         else
-           bp++;
-       }
+        {
+          if (*bp == ':')
+            {
+              bp++;
+              *bp = '\0';
+              bp++;
+              emit2 (bp1);
+              bp1 = bp;
+            }
+          else
+            bp++;
+        }
     }
   if (bp1 != bp)
     emit2 (bp1);
@@ -4251,53 +5640,97 @@ genRLC (iCode * ic)
   wassert (0);
 }
 
+/*-----------------------------------------------------------------*/
+/* genGetHbit - generates code get highest order bit               */
+/*-----------------------------------------------------------------*/
+static void
+genGetHbit (iCode * ic)
+{
+  operand *left, *result;
+  left = IC_LEFT (ic);
+  result = IC_RESULT (ic);
+
+  aopOp (left, ic, FALSE, FALSE);
+  aopOp (result, ic, FALSE, FALSE);
+
+  /* get the highest order byte into a */
+  emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
+
+  if (AOP_TYPE (result) == AOP_CRY)
+    {
+      emit2 ("rl a");
+      outBitC (result);
+    }
+  else
+    {
+      emit2 ("rlc a");
+      emit2 ("and a,!one");
+      outAcc (result);
+    }
+
+
+  freeAsmop (left, NULL, ic);
+  freeAsmop (result, NULL, ic);
+}
+
+static void
+emitRsh2 (asmop *aop, int size, int is_signed)
+{
+  int offset = 0;
+
+  while (size--)
+    {
+      const char *l = aopGet (aop, size, FALSE);
+      if (offset == 0)
+        {
+          emit2 ("%s %s", is_signed ? "sra" : "srl", l);
+        }
+      else
+        {
+          emit2 ("rr %s", l);
+        }
+      offset++;
+    }
+}
+
 /*-----------------------------------------------------------------*/
 /* shiftR2Left2Result - shift right two bytes from left to result  */
 /*-----------------------------------------------------------------*/
 static void
 shiftR2Left2Result (operand * left, int offl,
-                   operand * result, int offr,
-                   int shCount, int sign)
+                    operand * result, int offr,
+                    int shCount, int is_signed)
 {
+  int size = 2;
+  symbol *tlbl, *tlbl1;
+
   movLeft2Result (left, offl, result, offr, 0);
   movLeft2Result (left, offl + 1, result, offr + 1, 0);
 
-  if (sign)
+  /*  if (AOP(result)->type == AOP_REG) { */
+
+  tlbl = newiTempLabel (NULL);
+  tlbl1 = newiTempLabel (NULL);
+
+  /* Left is already in result - so now do the shift */
+  if (shCount <= 4)
     {
-      wassert (0);
+      while (shCount--)
+        {
+          emitRsh2 (AOP (result), size, is_signed);
+        }
     }
   else
     {
-      /*  if (AOP(result)->type == AOP_REG) { */
-      int size = 2;
-      int offset = 0;
-      symbol *tlbl, *tlbl1;
-      const char *l;
-
-      tlbl = newiTempLabel (NULL);
-      tlbl1 = newiTempLabel (NULL);
+      emit2 ("ld a,!immedbyte+1", shCount);
+      emit2 ("!shortjp !tlabel", tlbl1->key + 100);
+      emitLabel (tlbl->key + 100);
 
-      /* 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);
-       }
+      emitRsh2 (AOP (result), size, is_signed);
 
-      emit2 ("or a,a");
-      offset = size;
-      while (size--)
-       {
-         l = aopGet (AOP (result), --offset, FALSE);
-         emit2 ("rr %s", l);
-       }
-      if (shCount > 1)
-       {
-         emitLabel (tlbl1->key + 100);
-         emit2 ("dec a");
-         emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
-       }
+      emitLabel (tlbl1->key + 100);
+      emit2 ("dec a");
+      emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
     }
 }
 
@@ -4306,7 +5739,7 @@ shiftR2Left2Result (operand * left, int offl,
 /*-----------------------------------------------------------------*/
 static void
 shiftL2Left2Result (operand * left, int offl,
-                   operand * result, int offr, int shCount)
+                    operand * result, int offr, int shCount)
 {
   if (sameRegs (AOP (result), AOP (left)) &&
       ((offl + MSB16) == offr))
@@ -4319,9 +5752,16 @@ shiftL2Left2Result (operand * left, int offl,
       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;
@@ -4330,25 +5770,56 @@ shiftL2Left2Result (operand * left, int offl,
     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);
 
-    emit2 ("or a,a");
-    while (size--)
-      {
-       l = aopGet (AOP (result), offset++, FALSE);
-       emit2 ("rl %s", l);
+                if (offset == 0)
+                  {
+                    emit2 ("sla %s", l);
+                  }
+                else
+                  {
+                    emit2 ("rl %s", l);
+                  }
+              }
+          }
       }
-    if (shCount > 1)
+    else
       {
-       emitLabel (tlbl1->key + 100);
-       emit2 ("dec a");
-       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
+        /* 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);
+          }
+
+        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);
+          }
       }
   }
 }
@@ -4359,43 +5830,81 @@ shiftL2Left2Result (operand * left, int offl,
 static void
 AccRol (int shCount)
 {
-  shCount &= 0x0007;           // shCount : 0..7
+  shCount &= 0x0007;            // shCount : 0..7
 
+#if 0
   switch (shCount)
     {
     case 0:
       break;
     case 1:
-      emit2 ("rl a");
+      emit2 ("sla a");
       break;
     case 2:
-      emit2 ("rl a");
+      emit2 ("sla a");
       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 ("sla a");
       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 ("srl a");
       emit2 ("rr a");
       break;
     case 7:
-      emit2 ("rr a");
+      emit2 ("srl a");
+      break;
+    }
+#else
+  switch (shCount)
+    {
+    case 0:
+      break;
+    case 1:
+      emit2 ("rlca");
+      break;
+    case 2:
+      emit2 ("rlca");
+      emit2 ("rlca");
+      break;
+    case 3:
+      emit2 ("rlca");
+      emit2 ("rlca");
+      emit2 ("rlca");
+      break;
+    case 4:
+      emit2 ("rlca");
+      emit2 ("rlca");
+      emit2 ("rlca");
+      emit2 ("rlca");
+      break;
+    case 5:
+      emit2 ("rrca");
+      emit2 ("rrca");
+      emit2 ("rrca");
+      break;
+    case 6:
+      emit2 ("rrca");
+      emit2 ("rrca");
+      break;
+    case 7:
+      emit2 ("rrca");
       break;
     }
+#endif
 }
 
 /*-----------------------------------------------------------------*/
@@ -4412,21 +5921,21 @@ AccLsh (int shCount)
   if (shCount != 0)
     {
       if (shCount == 1)
-       {
-         emit2 ("add a,a");
-       }
+        {
+          emit2 ("add a,a");
+        }
       else if (shCount == 2)
-       {
-         emit2 ("add a,a");
-         emit2 ("add a,a");
-       }
+        {
+          emit2 ("add a,a");
+          emit2 ("add a,a");
+        }
       else
-       {
-         /* rotate left accumulator */
-         AccRol (shCount);
-         /* and kill the lower order bits */
-         emit2 ("and a,!immedbyte", SLMask[shCount]);
-       }
+        {
+          /* rotate left accumulator */
+          AccRol (shCount);
+          /* and kill the lower order bits */
+          emit2 ("and a,!immedbyte", SLMask[shCount]);
+        }
     }
 }
 
@@ -4435,7 +5944,7 @@ AccLsh (int shCount)
 /*-----------------------------------------------------------------*/
 static void
 shiftL1Left2Result (operand * left, int offl,
-                   operand * result, int offr, int shCount)
+                    operand * result, int offr, int shCount)
 {
   const char *l;
   l = aopGet (AOP (left), offl, FALSE);
@@ -4461,35 +5970,35 @@ genlshTwo (operand * result, operand * left, int shCount)
     {
       shCount -= 8;
       if (size > 1)
-       {
-         if (shCount)
-           {
-             movLeft2Result (left, LSB, result, MSB16, 0);
-             aopPut (AOP (result), "!zero", 0);
-             shiftL1Left2Result (left, MSB16, result, MSB16, shCount);
-           }
-         else
-           {
-             movLeft2Result (left, LSB, result, MSB16, 0);
-             aopPut (AOP (result), "!zero", 0);
-           }
-       }
+        {
+          if (shCount)
+            {
+              movLeft2Result (left, LSB, result, MSB16, 0);
+              aopPut (AOP (result), "!zero", 0);
+              shiftL1Left2Result (left, LSB, result, MSB16, shCount);
+            }
+          else
+            {
+              movLeft2Result (left, LSB, result, MSB16, 0);
+              aopPut (AOP (result), "!zero", 0);
+            }
+        }
       else
-       {
-         aopPut (AOP (result), "!zero", LSB);
-       }
+        {
+          aopPut (AOP (result), "!zero", LSB);
+        }
     }
   /*  1 <= shCount <= 7 */
   else
     {
       if (size == 1)
-       {
-         wassert (0);
-       }
+        {
+          wassert (0);
+        }
       else
-       {
-         shiftL2Left2Result (left, LSB, result, LSB, shCount);
-       }
+        {
+          shiftL2Left2Result (left, LSB, result, LSB, shCount);
+        }
     }
 }
 
@@ -4507,9 +6016,9 @@ genlshOne (operand * result, operand * left, int shCount)
 /*-----------------------------------------------------------------*/
 static void
 genLeftShiftLiteral (operand * left,
-                    operand * right,
-                    operand * result,
-                    iCode * ic)
+                     operand * right,
+                     operand * result,
+                     iCode * ic)
 {
   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
   int size;
@@ -4521,11 +6030,6 @@ genLeftShiftLiteral (operand * left,
 
   size = getSize (operandType (result));
 
-#if VIEW_SIZE
-  emit2 ("; shift left  result %d, left %d", size,
-           AOP_SIZE (left));
-#endif
-
   /* I suppose that the left size >= result size */
   if (shCount == 0)
     {
@@ -4533,24 +6037,28 @@ genLeftShiftLiteral (operand * left,
     }
 
   else if (shCount >= (size * 8))
-    while (size--)
-      aopPut (AOP (result), "!zero", size);
+    {
+      while (size--)
+        {
+          aopPut (AOP (result), "!zero", size);
+        }
+    }
   else
     {
       switch (size)
-       {
-       case 1:
-         genlshOne (result, left, shCount);
-         break;
-       case 2:
-         genlshTwo (result, left, shCount);
-         break;
-       case 4:
-         wassert (0);
-         break;
-       default:
-         wassert (0);
-       }
+        {
+        case 1:
+          genlshOne (result, left, shCount);
+          break;
+        case 2:
+          genlshTwo (result, left, shCount);
+          break;
+        case 4:
+          wassertl (0, "Shifting of longs is currently unsupported");
+          break;
+        default:
+          wassert (0);
+        }
     }
   freeAsmop (left, NULL, ic);
   freeAsmop (result, NULL, ic);
@@ -4591,46 +6099,50 @@ genLeftShift (iCode * ic)
   aopOp (left, ic, FALSE, FALSE);
   aopOp (result, ic, FALSE, FALSE);
 
+  if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
+     _push (PAIR_AF);
+
   /* now move the left to the result if they are not the
      same */
-#if 1
+
   if (!sameRegs (AOP (left), AOP (result)))
     {
 
       size = AOP_SIZE (result);
       offset = 0;
       while (size--)
-       {
-         l = aopGet (AOP (left), offset, FALSE);
-         aopPut (AOP (result), l, offset);
-         offset++;
-       }
-    }
-#else
-  size = AOP_SIZE (result);
-  offset = 0;
-  while (size--)
-    {
-      l = aopGet (AOP (left), offset, FALSE);
-      aopPut (AOP (result), l, offset);
-      offset++;
+        {
+          l = aopGet (AOP (left), offset, FALSE);
+          aopPut (AOP (result), l, offset);
+          offset++;
+        }
     }
-#endif
-
 
   tlbl = newiTempLabel (NULL);
   size = AOP_SIZE (result);
   offset = 0;
   tlbl1 = newiTempLabel (NULL);
 
+  if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
+     _pop (PAIR_AF);
+
   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
   emitLabel (tlbl->key + 100);
   l = aopGet (AOP (result), offset, FALSE);
-  emit2 ("or a,a");
+
   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");
@@ -4644,7 +6156,7 @@ genLeftShift (iCode * ic)
 /* genrshOne - left shift two bytes by known amount != 0           */
 /*-----------------------------------------------------------------*/
 static void
-genrshOne (operand * result, operand * left, int shCount)
+genrshOne (operand * result, operand * left, int shCount, int is_signed)
 {
   /* Errk */
   int size = AOP_SIZE (result);
@@ -4654,20 +6166,23 @@ genrshOne (operand * result, operand * left, int shCount)
   wassert (shCount < 8);
 
   l = aopGet (AOP (left), 0, FALSE);
+
   if (AOP (result)->type == AOP_REG)
     {
       aopPut (AOP (result), l, 0);
       l = aopGet (AOP (result), 0, FALSE);
       while (shCount--)
-       emit2 ("srl %s", l);
+        {
+          emit2 ("%s %s", is_signed ? "sra" : "srl", l);
+        }
     }
   else
     {
       _moveA (l);
       while (shCount--)
-       {
-         emit2 ("srl a");
-       }
+        {
+          emit2 ("%s a", is_signed ? "sra" : "srl");
+        }
       aopPut (AOP (result), "a", 0);
     }
 }
@@ -4697,13 +6212,16 @@ AccRsh (int shCount)
 /*-----------------------------------------------------------------*/
 static void
 shiftR1Left2Result (operand * left, int offl,
-                   operand * result, int offr,
-                   int shCount, int sign)
+                    operand * result, int offr,
+                    int shCount, int sign)
 {
   _moveA (aopGet (AOP (left), offl, FALSE));
   if (sign)
     {
-      wassert (0);
+      while (shCount--)
+        {
+          emit2 ("%s a", sign ? "sra" : "srl");
+        }
     }
   else
     {
@@ -4717,22 +6235,34 @@ shiftR1Left2Result (operand * left, int offl,
 /*-----------------------------------------------------------------*/
 static void
 genrshTwo (operand * result, operand * left,
-          int shCount, int sign)
+           int shCount, int sign)
 {
   /* if shCount >= 8 */
   if (shCount >= 8)
     {
       shCount -= 8;
       if (shCount)
-       {
-         shiftR1Left2Result (left, MSB16, result, LSB,
-                             shCount, sign);
-       }
+        {
+          shiftR1Left2Result (left, MSB16, result, LSB,
+                              shCount, sign);
+        }
+      else
+        {
+          movLeft2Result (left, MSB16, result, LSB, sign);
+        }
+      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
-       {
-         movLeft2Result (left, MSB16, result, LSB, sign);
-       }
-      aopPut (AOP (result), "!zero", 1);
+        {
+          aopPut (AOP (result), "!zero", 1);
+        }
     }
   /*  1 <= shCount <= 7 */
   else
@@ -4746,9 +6276,10 @@ genrshTwo (operand * result, operand * left,
 /*-----------------------------------------------------------------*/
 static void
 genRightShiftLiteral (operand * left,
-                     operand * right,
-                     operand * result,
-                     iCode * ic)
+                      operand * right,
+                      operand * result,
+                      iCode * ic,
+                      int sign)
 {
   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
   int size;
@@ -4760,35 +6291,41 @@ genRightShiftLiteral (operand * left,
 
   size = getSize (operandType (result));
 
-  emit2 ("; shift right  result %d, left %d", size,
-           AOP_SIZE (left));
-
   /* 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--)
-      aopPut (AOP (result), "!zero", size);
+      aopPut (AOP (result), s, size);
+  }
   else
     {
       switch (size)
-       {
-       case 1:
-         genrshOne (result, left, shCount);
-         break;
-       case 2:
-         /* PENDING: sign support */
-         genrshTwo (result, left, shCount, FALSE);
-         break;
-       case 4:
-         wassert (0);
-         break;
-       default:
-         wassert (0);
-       }
+        {
+        case 1:
+          genrshOne (result, left, shCount, sign);
+          break;
+        case 2:
+          genrshTwo (result, left, shCount, sign);
+          break;
+        case 4:
+          wassertl (0, "Asked to shift right a long which should be a function call");
+          break;
+        default:
+          wassertl (0, "Entered default case in right shift delegate");
+        }
     }
   freeAsmop (left, NULL, ic);
   freeAsmop (result, NULL, ic);
@@ -4831,53 +6368,57 @@ genRightShift (iCode * ic)
      as efficiently as possible */
   if (AOP_TYPE (right) == AOP_LIT)
     {
-      genRightShiftLiteral (left, right, result, ic);
+      genRightShiftLiteral (left, right, result, ic, is_signed);
       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);
 
+  if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
+     _push (PAIR_AF);
+
   /* 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);
       offset = 0;
       while (size--)
-       {
-         l = aopGet (AOP (left), offset, FALSE);
-         aopPut (AOP (result), l, offset);
-         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);
-
   tlbl = newiTempLabel (NULL);
   tlbl1 = newiTempLabel (NULL);
   size = AOP_SIZE (result);
   offset = size - 1;
 
+  if (AOP_TYPE (left) != AOP_REG || AOP_TYPE (result) != AOP_REG)
+     _pop (PAIR_AF);
+
   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
   emitLabel (tlbl->key + 100);
   while (size--)
     {
       l = aopGet (AOP (result), offset--, FALSE);
       if (first)
-       {
-         if (is_signed)
-           emit2 ("sra %s", l);
-         else
-           emit2 ("srl %s", l);
-         first = 0;
-       }
+        {
+          emit2 ("%s %s", is_signed ? "sra" : "srl", l);
+          first = 0;
+        }
       else
-       emit2 ("rr %s", l);
+        {
+          emit2 ("rr %s", l);
+        }
     }
   emitLabel (tlbl1->key + 100);
   emit2 ("dec a");
@@ -4887,12 +6428,130 @@ genRightShift (iCode * ic)
   freeAsmop (result, NULL, ic);
 }
 
+
+/*-----------------------------------------------------------------*/
+/* genUnpackBits - generates code for unpacking bits               */
+/*-----------------------------------------------------------------*/
+static void
+genUnpackBits (operand * result, int pair)
+{
+  int offset = 0;       /* result byte offset */
+  int rsize;            /* result size */
+  int rlen = 0;         /* remaining bitfield length */
+  sym_link *etype;      /* bitfield type information */
+  int blen;             /* bitfield length */
+  int bstr;             /* bitfield starting bit within byte */
+
+  emitDebug ("; genUnpackBits");
+
+  etype = getSpec (operandType (result));
+  rsize = getSize (operandType (result));
+  blen = SPEC_BLEN (etype);
+  bstr = SPEC_BSTR (etype);
+
+  /* If the bitfield length is less than a byte */
+  if (blen < 8)
+    {
+      emit2 ("ld a,!*pair", _pairs[pair].name);
+      AccRol (8 - bstr);
+      emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - blen));
+      if (!SPEC_USIGN (etype))
+        {
+          /* signed bitfield */
+          symbol *tlbl = newiTempLabel (NULL);
+
+          emit2 ("bit %d,a", blen - 1);
+          emit2 ("jp z,!tlabel", tlbl->key + 100);
+          emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
+          emitLabel (tlbl->key + 100);
+        }
+      aopPut (AOP (result), "a", offset++);
+      goto finish;
+    }
+
+  /* TODO: what if pair == PAIR_DE ? */
+  if (getPairId (AOP (result)) == PAIR_HL)
+    {
+      wassertl (rsize == 2, "HL must be of size 2");
+      emit2 ("ld a,!*hl");
+      emit2 ("inc hl");
+      emit2 ("ld h,!*hl");
+      emit2 ("ld l,a");
+      emit2 ("ld a,h");
+      emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (16 - blen));
+      if (!SPEC_USIGN (etype))
+        {
+          /* signed bitfield */
+          symbol *tlbl = newiTempLabel (NULL);
+
+          emit2 ("bit %d,a", blen - 1);
+          emit2 ("jp z,!tlabel", tlbl->key + 100);
+          emit2 ("or a,!immedbyte", (unsigned char) (0xff << blen));
+          emitLabel (tlbl->key + 100);
+        }
+      emit2 ("ld h,a");
+      spillPair (PAIR_HL);
+      return;
+    }
+
+  /* Bit field did not fit in a byte. Copy all
+     but the partial byte at the end.  */
+  for (rlen=blen;rlen>=8;rlen-=8)
+    {
+      emit2 ("ld a,!*pair", _pairs[pair].name);
+      aopPut (AOP (result), "a", offset++);
+      if (rlen>8)
+        {
+          emit2 ("inc %s", _pairs[pair].name);
+          _G.pairs[pair].offset++;
+        }
+    }
+
+  /* Handle the partial byte at the end */
+  if (rlen)
+    {
+      emit2 ("ld a,!*pair", _pairs[pair].name);
+      emit2 ("and a,!immedbyte", ((unsigned char) -1) >> (8 - rlen));
+      if (!SPEC_USIGN (etype))
+        {
+          /* signed bitfield */
+          symbol *tlbl = newiTempLabel (NULL);
+
+          emit2 ("bit %d,a", rlen - 1);
+          emit2 ("jp z,!tlabel", tlbl->key + 100);
+          emit2 ("or a,!immedbyte", (unsigned char) (0xff << rlen));
+          emitLabel (tlbl->key + 100);
+        }
+      aopPut (AOP (result), "a", offset++);
+    }
+
+finish:
+  if (offset < rsize)
+    {
+      char *source;
+
+      if (SPEC_USIGN (etype))
+        source = "!zero";
+      else
+        {
+          /* signed bitfield: sign extension with 0x00 or 0xff */
+          emit2 ("rla");
+          emit2 ("sbc a,a");
+
+          source = "a";
+        }
+      rsize -= offset;
+      while (rsize--)
+        aopPut (AOP (result), source, offset++);
+    }
+}
+
 /*-----------------------------------------------------------------*/
 /* genGenPointerGet -  get value from generic pointer space        */
 /*-----------------------------------------------------------------*/
 static void
 genGenPointerGet (operand * left,
-                 operand * result, iCode * ic)
+                  operand * result, iCode * ic)
 {
   int size, offset;
   sym_link *retype = getSpec (operandType (result));
@@ -4904,19 +6563,38 @@ genGenPointerGet (operand * left,
   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 && !IS_BITVAR (retype))
     {
       /* Just do it */
       if (isPtrPair (AOP (left)))
-       {
-         tsprintf (buffer, "!*pair", getPairName (AOP (left)));
-         aopPut (AOP (result), buffer, 0);
-       }
+        {
+          tsprintf (buffer, sizeof(buffer),
+                    "!*pair", getPairName (AOP (left)));
+          aopPut (AOP (result), buffer, 0);
+        }
       else
-       {
-         emit2 ("ld a,!*pair", getPairName (AOP (left)));
-         aopPut (AOP (result), "a", 0);
-       }
+        {
+          emit2 ("ld a,!*pair", getPairName (AOP (left)));
+          aopPut (AOP (result), "a", 0);
+        }
+      freeAsmop (left, NULL, ic);
+      goto release;
+    }
+
+  if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype))
+    {
+      /* 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;
     }
@@ -4925,13 +6603,51 @@ genGenPointerGet (operand * left,
   /* 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);
+      genUnpackBits (result, pair);
+      freeAsmop (left, NULL, ic);
+      goto release;
+      //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
     {
@@ -4939,25 +6655,28 @@ genGenPointerGet (operand * left,
       offset = 0;
 
       while (size--)
-       {
-         /* PENDING: make this better */
-         if (!IS_GB && AOP (result)->type == 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++;
-           }
-       }
+        {
+          /* PENDING: make this better */
+          if (!IS_GB &&
+              (AOP_TYPE (result) == AOP_REG || AOP_TYPE (result) == AOP_HLREG))
+            {
+              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++;
+            }
+        }
     }
 
+  freeAsmop (left, NULL, ic);
+
 release:
   freeAsmop (result, NULL, ic);
 }
@@ -4985,21 +6704,166 @@ genPointerGet (iCode * ic)
 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;
 }
 
+
+/*-----------------------------------------------------------------*/
+/* genPackBits - generates code for packed bit storage             */
+/*-----------------------------------------------------------------*/
+static void
+genPackBits (sym_link * etype,
+             operand * right,
+             int pair,
+             iCode *ic)
+{
+  int offset = 0;       /* source byte offset */
+  int rlen = 0;         /* remaining bitfield length */
+  int blen;             /* bitfield length */
+  int bstr;             /* bitfield starting bit within byte */
+  int litval;           /* source literal value (if AOP_LIT) */
+  unsigned char mask;   /* bitmask within current byte */
+  int extraPair;        /* a tempory register */
+  bool needPopExtra=0;  /* need to restore original value of temp reg */
+
+  emitDebug (";     genPackBits","");
+
+  blen = SPEC_BLEN (etype);
+  bstr = SPEC_BSTR (etype);
+
+  /* If the bitfield length is less than a byte */
+  if (blen < 8)
+    {
+      mask = ((unsigned char) (0xFF << (blen + bstr)) |
+              (unsigned char) (0xFF >> (8 - bstr)));
+
+      if (AOP_TYPE (right) == AOP_LIT)
+        {
+          /* Case with a bitfield length <8 and literal source
+          */
+          litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
+          litval <<= bstr;
+          litval &= (~mask) & 0xff;
+          emit2 ("ld a,!*pair", _pairs[pair].name);
+          if ((mask|litval)!=0xff)
+            emit2 ("and a,!immedbyte", mask);
+          if (litval)
+            emit2 ("or a,!immedbyte", litval);
+          emit2 ("ld !*pair,a", _pairs[pair].name);
+          return;
+        }
+      else
+        {
+          /* Case with a bitfield length <8 and arbitrary source
+          */
+          _moveA (aopGet (AOP (right), 0, FALSE));
+          /* shift and mask source value */
+          AccLsh (bstr);
+          emit2 ("and a,!immedbyte", (~mask) & 0xff);
+
+          extraPair = getFreePairId(ic);
+          if (extraPair == PAIR_INVALID)
+            {
+              extraPair = PAIR_BC;
+              if (getPairId (AOP (right)) != PAIR_BC
+                  || !isLastUse (ic, right))
+                {
+                  _push (extraPair);
+                  needPopExtra = 1;
+                }
+            }
+          emit2 ("ld %s,a", _pairs[extraPair].l);
+          emit2 ("ld a,!*pair", _pairs[pair].name);
+
+          emit2 ("and a,!immedbyte", mask);
+          emit2 ("or a,%s", _pairs[extraPair].l);
+          emit2 ("ld !*pair,a", _pairs[pair].name);
+          if (needPopExtra)
+            _pop (extraPair);
+          return;
+        }
+    }
+
+  /* Bit length is greater than 7 bits. In this case, copy  */
+  /* all except the partial byte at the end                 */
+  for (rlen=blen;rlen>=8;rlen-=8)
+    {
+      emit2 ("ld a,%s", aopGet (AOP (right), offset++, FALSE) );
+      emit2 ("ld !*pair,a", _pairs[pair].name);
+      if (rlen>8)
+        {
+          emit2 ("inc %s", _pairs[pair].name);
+          _G.pairs[pair].offset++;
+        }
+    }
+
+  /* If there was a partial byte at the end */
+  if (rlen)
+    {
+      mask = (((unsigned char) -1 << rlen) & 0xff);
+
+      if (AOP_TYPE (right) == AOP_LIT)
+        {
+          /* Case with partial byte and literal source
+          */
+          litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
+          litval >>= (blen-rlen);
+          litval &= (~mask) & 0xff;
+          emit2 ("ld a,!*pair", _pairs[pair].name);
+          if ((mask|litval)!=0xff)
+            emit2 ("and a,!immedbyte", mask);
+          if (litval)
+            emit2 ("or a,!immedbyte", litval);
+        }
+      else
+        {
+          /* Case with partial byte and arbitrary source
+          */
+          _moveA (aopGet (AOP (right), offset++, FALSE));
+          emit2 ("and a,!immedbyte", (~mask) & 0xff);
+
+          extraPair = getFreePairId(ic);
+          if (extraPair == PAIR_INVALID)
+            {
+              extraPair = getPairId (AOP (right));
+              if (!isLastUse (ic, right) || (extraPair == PAIR_INVALID))
+                extraPair = PAIR_BC;
+
+              if (getPairId (AOP (right)) != PAIR_BC
+                  || !isLastUse (ic, right))
+                {
+                  _push (extraPair);
+                  needPopExtra = 1;
+                }
+            }
+          emit2 ("ld %s,a", _pairs[extraPair].l);
+          emit2 ("ld a,!*pair", _pairs[pair].name);
+
+          emit2 ("and a,!immedbyte", mask);
+          emit2 ("or a,%s", _pairs[extraPair].l);
+          if (needPopExtra)
+            _pop (extraPair);
+
+        }
+      emit2 ("ld !*pair,a", _pairs[pair].name);
+    }
+}
+
+
 /*-----------------------------------------------------------------*/
 /* genGenPointerSet - stores the value into a pointer location        */
 /*-----------------------------------------------------------------*/
 static void
 genGenPointerSet (operand * right,
-                 operand * result, iCode * ic)
+                  operand * result, iCode * ic)
 {
   int size, offset;
   sym_link *retype = getSpec (operandType (right));
+  sym_link *letype = getSpec (operandType (result));
   PAIR_ID pairId = PAIR_HL;
+  bool isBitvar;
 
   aopOp (result, ic, FALSE, FALSE);
   aopOp (right, ic, FALSE, FALSE);
@@ -5007,21 +6871,80 @@ genGenPointerSet (operand * right,
   if (IS_GB)
     pairId = PAIR_DE;
 
+  size = AOP_SIZE (right);
+
+  isBitvar = IS_BITVAR(retype) || IS_BITVAR(letype);
+  emitDebug("; isBitvar = %d", isBitvar);
+
   /* Handle the exceptions first */
-  if (isPair (AOP (result)) && (AOP_SIZE (right) == 1))
+  if (isPair (AOP (result)) && size == 1 && !isBitvar)
     {
       /* Just do it */
       const char *l = aopGet (AOP (right), 0, FALSE);
       const char *pair = getPairName (AOP (result));
       if (canAssignToPtr (l) && isPtr (pair))
-       {
-         emit2 ("ld !*pair,%s", pair, l);
-       }
+        {
+          emit2 ("ld !*pair,%s", pair, l);
+        }
       else
-       {
-         _moveA (l);
-         emit2 ("ld !*pair,a", pair);
-       }
+        {
+          _moveA (l);
+          emit2 ("ld !*pair,a", pair);
+        }
+      goto release;
+    }
+
+  if ( getPairId( AOP (result)) == PAIR_IY && !isBitvar)
+    {
+      /* 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)
+           && !isBitvar)
+    {
+      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;
     }
 
@@ -5031,38 +6954,39 @@ genGenPointerSet (operand * right,
     {
       fetchPair (pairId, AOP (result));
     }
-  /* so hl know contains the address */
+  /* so hl now contains the address */
   freeAsmop (result, NULL, ic);
 
   /* if bit then unpack */
-  if (IS_BITVAR (retype))
+  if (isBitvar)
     {
-      wassert (0);
+      genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
+      goto release;
+      //wassert (0);
     }
   else
     {
-      size = AOP_SIZE (right);
       offset = 0;
 
       while (size--)
-       {
-         const char *l = aopGet (AOP (right), offset, FALSE);
-         if (isRegOrLit (AOP (right)) && !IS_GB)
-           {
-             emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
-           }
-         else
-           {
-             _moveA (l);
-             emit2 ("ld !*pair,a", _pairs[pairId].name);
-           }
-         if (size)
-           {
-             emit2 ("inc %s", _pairs[pairId].name);
-             _G.pairs[pairId].offset++;
-           }
-         offset++;
-       }
+        {
+          const char *l = aopGet (AOP (right), offset, FALSE);
+          if (isRegOrLit (AOP (right)) && !IS_GB)
+            {
+              emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
+            }
+          else
+            {
+              _moveA (l);
+              emit2 ("ld !*pair,a", _pairs[pairId].name);
+            }
+          if (size)
+            {
+              emit2 ("inc %s", _pairs[pairId].name);
+              _G.pairs[pairId].offset++;
+            }
+          offset++;
+        }
     }
 release:
   freeAsmop (right, NULL, ic);
@@ -5101,7 +7025,7 @@ genIfx (iCode * ic, iCode * popIc)
 
   /* get the value into acc */
   if (AOP_TYPE (cond) != AOP_CRY)
-    toBoolean (cond);
+    _toBoolean (cond);
   else
     isbit = 1;
   /* the result is now in the accumulator */
@@ -5139,44 +7063,41 @@ genAddrOf (iCode * ic)
   if (IS_GB)
     {
       if (sym->onStack)
-       {
-         spillCached ();
-         if (sym->stack <= 0)
-           {
-             emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset);
-           }
-         else
-           {
-             emit2 ("!ldahlsp", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
-           }
-         emit2 ("ld d,h");
-         emit2 ("ld e,l");
-       }
+        {
+          spillCached ();
+          if (sym->stack <= 0)
+            {
+              setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
+            }
+          else
+            {
+              setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
+            }
+          commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
+        }
       else
-       {
-         emit2 ("ld de,!hashedstr", sym->rname);
-       }
-      aopPut (AOP (IC_RESULT (ic)), "e", 0);
-      aopPut (AOP (IC_RESULT (ic)), "d", 1);
+        {
+          emit2 ("ld de,!hashedstr", sym->rname);
+          commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
+        }
     }
   else
     {
       spillCached ();
       if (sym->onStack)
-       {
-         /* 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);
-         else
-           emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
-         emit2 ("add hl,sp");
-       }
+        {
+          /* if it has an offset  then we need to compute it */
+          if (sym->stack > 0)
+            emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
+          else
+            emit2 ("ld hl,!immedword", sym->stack + _G.stack.pushed + _G.stack.offset);
+          emit2 ("add hl,sp");
+        }
       else
-       {
-         emit2 ("ld hl,#%s", sym->rname);
-       }
-      aopPut (AOP (IC_RESULT (ic)), "l", 0);
-      aopPut (AOP (IC_RESULT (ic)), "h", 1);
+        {
+          emit2 ("ld hl,!hashedstr", sym->rname);
+        }
+      commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
     }
   freeAsmop (IC_RESULT (ic), NULL, ic);
 }
@@ -5194,14 +7115,12 @@ genAssign (iCode * 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)))
     {
-      emit2 ("; (operands are equal %u)", 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);
@@ -5209,14 +7128,14 @@ genAssign (iCode * ic)
   /* if they are the same registers */
   if (sameRegs (AOP (right), AOP (result)))
     {
-      emit2 ("; (registers are the same)");
+      emitDebug ("; (registers are the same)");
       goto release;
     }
 
   /* if the result is a bit */
   if (AOP_TYPE (result) == AOP_CRY)
     {
-      wassert (0);
+      wassertl (0, "Tried to assign to a bit");
     }
 
   /* general case */
@@ -5224,16 +7143,19 @@ genAssign (iCode * ic)
   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)))
     {
-      fetchPair (getPairId (AOP (result)), AOP (right));
+      fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
     }
   else if ((size > 1) &&
-          (AOP_TYPE (result) != AOP_REG) &&
-          (AOP_TYPE (right) == AOP_LIT) &&
-          !IS_FLOAT (operandType (right)) &&
-          (lit < 256L))
+           (AOP_TYPE (result) != AOP_REG) &&
+           (AOP_TYPE (right) == AOP_LIT) &&
+           !IS_FLOAT (operandType (right)) &&
+           (lit < 256L))
     {
       bool fXored = FALSE;
       offset = 0;
@@ -5241,29 +7163,35 @@ genAssign (iCode * ic)
          Done this way so that we can use the cached copy of 0
          in A for a fast clear */
       while (size--)
-       {
-         if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
-           {
-             if (!fXored && size > 1)
-               {
-                 emit2 ("xor a,a");
-                 fXored = TRUE;
-               }
-             if (fXored)
-               {
-                 aopPut (AOP (result), "a", offset);
-               }
-             else
-               {
-                 aopPut (AOP (result), "!zero", offset);
-               }
-           }
-         else
-           aopPut (AOP (result),
-                   aopGet (AOP (right), offset, FALSE),
-                   offset);
-         offset++;
-       }
+        {
+          if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
+            {
+              if (!fXored && size > 1)
+                {
+                  emit2 ("xor a,a");
+                  fXored = TRUE;
+                }
+              if (fXored)
+                {
+                  aopPut (AOP (result), "a", offset);
+                }
+              else
+                {
+                  aopPut (AOP (result), "!zero", offset);
+                }
+            }
+          else
+            aopPut (AOP (result),
+                    aopGet (AOP (right), offset, FALSE),
+                    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)
     {
@@ -5273,22 +7201,44 @@ genAssign (iCode * ic)
       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 */
-         if (requiresHL (AOP (right)) && requiresHL (AOP (result)))
-           {
-             _moveA (aopGet (AOP (right), offset, FALSE));
-             aopPut (AOP (result), "a", offset);
-           }
-         else
-           aopPut (AOP (result),
-                   aopGet (AOP (right), offset, FALSE),
-                   offset);
-         offset++;
-       }
+        {
+          /* PENDING: do this check better */
+          if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
+            {
+              _moveA (aopGet (AOP (right), offset, FALSE));
+              aopPut (AOP (result), "a", offset);
+            }
+          else
+            aopPut (AOP (result),
+                    aopGet (AOP (right), offset, FALSE),
+                    offset);
+          offset++;
+        }
     }
 
 release:
@@ -5336,7 +7286,7 @@ static void
 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;
 
@@ -5350,7 +7300,7 @@ genCast (iCode * ic)
   /* 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 */
@@ -5359,31 +7309,22 @@ genCast (iCode * ic)
 
       /* if they are in the same place */
       if (sameRegs (AOP (right), AOP (result)))
-       goto release;
+        goto release;
 
       /* if they in different places then copy */
       size = AOP_SIZE (result);
       offset = 0;
       while (size--)
-       {
-         aopPut (AOP (result),
-                 aopGet (AOP (right), offset, FALSE),
-                 offset);
-         offset++;
-       }
+        {
+          aopPut (AOP (result),
+                  aopGet (AOP (right), offset, FALSE),
+                  offset);
+          offset++;
+        }
       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);
@@ -5391,30 +7332,29 @@ genCast (iCode * ic)
   while (size--)
     {
       aopPut (AOP (result),
-             aopGet (AOP (right), offset, FALSE),
-             offset);
+              aopGet (AOP (right), offset, FALSE),
+              offset);
       offset++;
     }
 
   /* 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 (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
     {
       while (size--)
-       aopPut (AOP (result), "!zero", offset++);
+        aopPut (AOP (result), "!zero", offset++);
     }
   else
     {
       /* we need to extend the sign :{ */
         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
-                       FALSE);
+                        FALSE);
       _moveA (l);
-      emit2 ("; genCast: sign extend untested.");
       emit2 ("rla ");
       emit2 ("sbc a,a");
       while (size--)
-       aopPut (AOP (result), "a", offset++);
+        aopPut (AOP (result), "a", offset++);
     }
 
 release:
@@ -5445,287 +7385,975 @@ genReceive (iCode * ic)
 
         for (i = 0; i < size; i++) {
             aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
-       }
+        }
     }
 
   freeAsmop (IC_RESULT (ic), NULL, ic);
 }
 
 /*-----------------------------------------------------------------*/
-/* genZ80Code - generate code for Z80 based controllers            */
+/* genDummyRead - generate code for dummy read of volatiles        */
 /*-----------------------------------------------------------------*/
-void
-genZ80Code (iCode * lic)
+static void
+genDummyRead (iCode * ic)
 {
-  iCode *ic;
-  int cln = 0;
+  operand *op;
+  int size, offset;
 
-  /* HACK */
-  if (IS_GB)
-    {
-      _fReturn = _gbz80_return;
-      _fTmp = _gbz80_return;
-    }
-  else
+  op = IC_RIGHT (ic);
+  if (op && IS_SYMOP (op))
     {
-      _fReturn = _z80_return;
-      _fTmp = _z80_return;
-    }
-
-  _G.lines.head = _G.lines.current = NULL;
+      aopOp (op, ic, FALSE, FALSE);
 
-  for (ic = lic; ic; ic = ic->next)
-    {
+      /* general case */
+      size = AOP_SIZE (op);
+      offset = 0;
 
-      if (cln != ic->lineno)
-       {
-         emit2 ("; %s %d", ic->filename, ic->lineno);
-         cln = ic->lineno;
-       }
+      while (size--)
+        {
+          _moveA (aopGet (AOP (op), offset, FALSE));
+          offset++;
+        }
+
+      freeAsmop (op, NULL, ic);
+    }
+
+  op = IC_LEFT (ic);
+  if (op && IS_SYMOP (op))
+    {
+      aopOp (op, ic, FALSE, FALSE);
+
+      /* general case */
+      size = AOP_SIZE (op);
+      offset = 0;
+
+      while (size--)
+        {
+          _moveA (aopGet (AOP (op), offset, FALSE));
+          offset++;
+        }
+
+      freeAsmop (op, NULL, ic);
+    }
+}
+
+/*-----------------------------------------------------------------*/
+/* genCritical - generate code for start of a critical sequence    */
+/*-----------------------------------------------------------------*/
+static void
+genCritical (iCode *ic)
+{
+  symbol *tlbl = newiTempLabel (NULL);
+
+  if (IS_GB)
+    {
+      emit2 ("!di");
+    }
+  else if (IC_RESULT (ic))
+    {
+      aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
+      aopPut (AOP (IC_RESULT (ic)), "!zero", 0);
+      //get interrupt enable flag IFF2 into P/O
+      emit2 ("ld a,i");
+      //disable interrupt
+      emit2 ("!di");
+      //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
+      emit2 ("jp po,!tlabel", tlbl->key + 100);
+      aopPut (AOP (IC_RESULT (ic)), "!one", 0);
+      emit2 ("!tlabeldef", (tlbl->key + 100));
+      freeAsmop (IC_RESULT (ic), NULL, ic);
+    }
+  else
+    {
+      //get interrupt enable flag IFF2 into P/O
+      emit2 ("ld a,i");
+      //disable interrupt
+      emit2 ("!di");
+      //save P/O flag
+      emit2 ("push af");
+    }
+}
+
+/*-----------------------------------------------------------------*/
+/* genEndCritical - generate code for end of a critical sequence   */
+/*-----------------------------------------------------------------*/
+static void
+genEndCritical (iCode *ic)
+{
+  symbol *tlbl = newiTempLabel (NULL);
+
+  if (IS_GB)
+    {
+      emit2 ("!ei");
+    }
+  else if (IC_RIGHT (ic))
+    {
+      aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
+      _toBoolean (IC_RIGHT (ic));
+      //don't enable interrupts if they were off before
+      emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
+      emit2 ("!ei");
+      emitLabel (tlbl->key + 100);
+      freeAsmop (IC_RIGHT (ic), NULL, ic);
+    }
+  else
+    {
+      //restore P/O flag
+      emit2 ("pop af");
+      //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
+      //don't enable interrupts as they were off before
+      emit2 ("jp po,!tlabel", tlbl->key + 100);
+      emit2 ("!ei");
+      emit2 ("!tlabeldef", (tlbl->key + 100));
+    }
+}
+
+enum
+  {
+    /** Maximum number of bytes to emit per line. */
+    DBEMIT_MAX_RUN = 8
+  };
+
+/** Context for the byte output chunker. */
+typedef struct
+{
+  unsigned char buffer[DBEMIT_MAX_RUN];
+  int pos;
+} DBEMITCTX;
+
+
+/** Flushes a byte chunker by writing out all in the buffer and
+    reseting.
+*/
+static void
+_dbFlush(DBEMITCTX *self)
+{
+  char line[256];
+
+  if (self->pos > 0)
+    {
+      int i;
+      sprintf(line, ".db 0x%02X", self->buffer[0]);
+
+      for (i = 1; i < self->pos; i++)
+        {
+          sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
+        }
+      emit2(line);
+    }
+  self->pos = 0;
+}
+
+/** Write out another byte, buffering until a decent line is
+    generated.
+*/
+static void
+_dbEmit(DBEMITCTX *self, int c)
+{
+  if (self->pos == DBEMIT_MAX_RUN)
+    {
+      _dbFlush(self);
+    }
+  self->buffer[self->pos++] = c;
+}
+
+/** Context for a simple run length encoder. */
+typedef struct
+{
+  unsigned last;
+  unsigned char buffer[128];
+  int pos;
+  /** runLen may be equivalent to pos. */
+  int runLen;
+} RLECTX;
+
+enum
+  {
+    RLE_CHANGE_COST = 4,
+    RLE_MAX_BLOCK = 127
+  };
+
+/** Flush the buffer of a run length encoder by writing out the run or
+    data that it currently contains.
+*/
+static void
+_rleCommit(RLECTX *self)
+{
+  int i;
+  if (self->pos != 0)
+    {
+      DBEMITCTX db;
+      memset(&db, 0, sizeof(db));
+
+      emit2(".db %u", self->pos);
+
+      for (i = 0; i < self->pos; i++)
+        {
+          _dbEmit(&db, self->buffer[i]);
+        }
+      _dbFlush(&db);
+    }
+  /* Reset */
+  self->pos = 0;
+}
+
+/* Encoder design:
+   Can get either a run or a block of random stuff.
+   Only want to change state if a good run comes in or a run ends.
+   Detecting run end is easy.
+   Initial state?
+
+   Say initial state is in run, len zero, last zero.  Then if you get a
+   few zeros then something else then a short run will be output.
+   Seems OK.  While in run mode, keep counting.  While in random mode,
+   keep a count of the run.  If run hits margin, output all up to run,
+   restart, enter run mode.
+*/
+
+/** Add another byte into the run length encoder, flushing as
+    required.  The run length encoder uses the Amiga IFF style, where
+    a block is prefixed by its run length.  A positive length means
+    the next n bytes pass straight through.  A negative length means
+    that the next byte is repeated -n times.  A zero terminates the
+    chunks.
+*/
+static void
+_rleAppend(RLECTX *self, unsigned c)
+{
+  int i;
+
+  if (c != self->last)
+    {
+      /* The run has stopped.  See if it is worthwhile writing it out
+         as a run.  Note that the random data comes in as runs of
+         length one.
+      */
+      if (self->runLen > RLE_CHANGE_COST)
+        {
+          /* Yes, worthwhile. */
+          /* Commit whatever was in the buffer. */
+          _rleCommit(self);
+          emit2("!db !immed-%u,!immedbyte", self->runLen, self->last);
+        }
+      else
+        {
+          /* Not worthwhile.  Append to the end of the random list. */
+          for (i = 0; i < self->runLen; i++)
+            {
+              if (self->pos >= RLE_MAX_BLOCK)
+                {
+                  /* Commit. */
+                  _rleCommit(self);
+                }
+              self->buffer[self->pos++] = self->last;
+            }
+        }
+      self->runLen = 1;
+      self->last = c;
+    }
+  else
+    {
+      if (self->runLen >= RLE_MAX_BLOCK)
+        {
+          /* Commit whatever was in the buffer. */
+          _rleCommit(self);
+
+          emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
+          self->runLen = 0;
+        }
+      self->runLen++;
+    }
+}
+
+static void
+_rleFlush(RLECTX *self)
+{
+  _rleAppend(self, -1);
+  _rleCommit(self);
+  self->pos = 0;
+  self->last = 0;
+  self->runLen = 0;
+}
+
+/** genArrayInit - Special code for initialising an array with constant
+   data.
+*/
+static void
+genArrayInit (iCode * ic)
+{
+  literalList *iLoop;
+  int         ix;
+  int         elementSize = 0, eIndex, i;
+  unsigned    val, lastVal;
+  sym_link    *type;
+  RLECTX      rle;
+
+  memset(&rle, 0, sizeof(rle));
+
+  aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
+
+  _saveRegsForCall(ic, 0);
+
+  fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
+  emit2 ("call __initrleblock");
+
+  type = operandType(IC_LEFT(ic));
+
+  if (type && type->next)
+    {
+      if (IS_SPEC(type->next) || IS_PTR(type->next))
+        {
+          elementSize = getSize(type->next);
+        }
+      else if (IS_ARRAY(type->next) && type->next->next)
+        {
+          elementSize = getSize(type->next->next);
+        }
+      else
+        {
+          printTypeChainRaw (type, NULL);
+          wassertl (0, "Can't determine element size in genArrayInit.");
+        }
+    }
+  else
+    {
+      wassertl (0, "Can't determine element size in genArrayInit.");
+    }
+
+  wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
+
+  iLoop = IC_ARRAYILIST(ic);
+  lastVal = (unsigned)-1;
+
+  /* Feed all the bytes into the run length encoder which will handle
+     the actual output.
+     This works well for mixed char data, and for random int and long
+     data.
+  */
+  while (iLoop)
+    {
+      ix = iLoop->count;
+
+      for (i = 0; i < ix; i++)
+        {
+          for (eIndex = 0; eIndex < elementSize; eIndex++)
+            {
+              val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
+              _rleAppend(&rle, val);
+            }
+        }
+
+      iLoop = iLoop->next;
+    }
+
+  _rleFlush(&rle);
+  /* Mark the end of the run. */
+  emit2(".db 0");
+
+  _restoreRegsAfterCall();
+
+  spillCached ();
+
+  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            */
+/*-----------------------------------------------------------------*/
+void
+genZ80Code (iCode * lic)
+{
+  iCode *ic;
+  int cln = 0;
+
+  /* Hack */
+  if (IS_GB)
+    {
+      _fReturn = _gbz80_return;
+      _fTmp = _gbz80_return;
+    }
+  else
+    {
+      _fReturn = _z80_return;
+      _fTmp = _z80_return;
+    }
+
+  _G.lines.head = _G.lines.current = NULL;
+
+  /* if debug information required */
+  if (options.debug && currFunc)
+    {
+      debugFile->writeFunction (currFunc, lic);
+    }
+
+  for (ic = lic; ic; ic = ic->next)
+    {
+      _G.current_iCode = ic;
+
+      if (ic->lineno && cln != ic->lineno)
+        {
+          if (options.debug)
+            {
+              debugFile->writeCLine (ic);
+            }
+          if (!options.noCcodeInAsm)
+            {
+              emit2 (";%s:%d: %s", ic->filename, ic->lineno,
+                     printCLine(ic->filename, 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
          do nothing */
       if (resultRemat (ic) || ic->generated)
-       continue;
+        continue;
 
       /* depending on the operation */
       switch (ic->op)
-       {
-       case '!':
-         emit2 ("; genNot");
-         genNot (ic);
-         break;
-
-       case '~':
-         emit2 ("; genCpl");
-         genCpl (ic);
-         break;
-
-       case UNARYMINUS:
-         emit2 ("; genUminus");
-         genUminus (ic);
-         break;
-
-       case IPUSH:
-         emit2 ("; genIpush");
-         genIpush (ic);
-         break;
-
-       case IPOP:
-         /* IPOP happens only when trying to restore a
-            spilt live range, if there is an ifx statement
-            following this pop then the if statement might
-            be using some of the registers being popped which
-            would destory the contents of the register so
-            we need to check for this condition and handle it */
-         if (ic->next &&
-             ic->next->op == IFX &&
-             regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
-           {
-             emit2 ("; genIfx");
-             genIfx (ic->next, ic);
-           }
-         else
-           {
-             emit2 ("; genIpop");
-             genIpop (ic);
-           }
-         break;
-
-       case CALL:
-         emit2 ("; genCall");
-         genCall (ic);
-         break;
-
-       case PCALL:
-         emit2 ("; genPcall");
-         genPcall (ic);
-         break;
-
-       case FUNCTION:
-         emit2 ("; genFunction");
-         genFunction (ic);
-         break;
-
-       case ENDFUNCTION:
-         emit2 ("; genEndFunction");
-         genEndFunction (ic);
-         break;
-
-       case RETURN:
-         emit2 ("; genRet");
-         genRet (ic);
-         break;
-
-       case LABEL:
-         emit2 ("; genLabel");
-         genLabel (ic);
-         break;
-
-       case GOTO:
-         emit2 ("; genGoto");
-         genGoto (ic);
-         break;
-
-       case '+':
-         emit2 ("; genPlus");
-         genPlus (ic);
-         break;
-
-       case '-':
-         emit2 ("; genMinus");
-         genMinus (ic);
-         break;
-
-       case '*':
-         emit2 ("; genMult");
-         genMult (ic);
-         break;
-
-       case '/':
-         emit2 ("; genDiv");
-         genDiv (ic);
-         break;
-
-       case '%':
-         emit2 ("; genMod");
-         genMod (ic);
-         break;
-
-       case '>':
-         emit2 ("; genCmpGt");
-         genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
-         break;
-
-       case '<':
-         emit2 ("; genCmpLt");
-         genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
-         break;
-
-       case LE_OP:
-       case GE_OP:
-       case NE_OP:
-
-         /* note these two are xlated by algebraic equivalence
-            during parsing SDCC.y */
-         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
-                 "got '>=' or '<=' shouldn't have come here");
-         break;
-
-       case EQ_OP:
-         emit2 ("; genCmpEq");
-         genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
-         break;
-
-       case AND_OP:
-         emit2 ("; genAndOp");
-         genAndOp (ic);
-         break;
-
-       case OR_OP:
-         emit2 ("; genOrOp");
-         genOrOp (ic);
-         break;
-
-       case '^':
-         emit2 ("; genXor");
-         genXor (ic, ifxForOp (IC_RESULT (ic), ic));
-         break;
-
-       case '|':
-         emit2 ("; genOr");
-         genOr (ic, ifxForOp (IC_RESULT (ic), ic));
-         break;
-
-       case BITWISEAND:
-         emit2 ("; genAnd");
-         genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
-         break;
-
-       case INLINEASM:
-         emit2 ("; genInline");
-         genInline (ic);
-         break;
-
-       case RRC:
-         emit2 ("; genRRC");
-         genRRC (ic);
-         break;
-
-       case RLC:
-         emit2 ("; genRLC");
-         genRLC (ic);
-         break;
-
-       case GETHBIT:
-         emit2 ("; genHBIT");
-         wassert (0);
-
-       case LEFT_OP:
-         emit2 ("; genLeftShift");
-         genLeftShift (ic);
-         break;
-
-       case RIGHT_OP:
-         emit2 ("; genRightShift");
-         genRightShift (ic);
-         break;
-
-       case GET_VALUE_AT_ADDRESS:
-         emit2 ("; genPointerGet");
-         genPointerGet (ic);
-         break;
-
-       case '=':
-
-         if (POINTER_SET (ic))
-           {
-             emit2 ("; genAssign (pointer)");
-             genPointerSet (ic);
-           }
-         else
-           {
-             emit2 ("; genAssign");
-             genAssign (ic);
-           }
-         break;
-
-       case IFX:
-         emit2 ("; genIfx");
-         genIfx (ic, NULL);
-         break;
-
-       case ADDRESS_OF:
-         emit2 ("; genAddrOf");
-         genAddrOf (ic);
-         break;
-
-       case JUMPTABLE:
-         emit2 ("; genJumpTab");
-         genJumpTab (ic);
-         break;
-
-       case CAST:
-         emit2 ("; genCast");
-         genCast (ic);
-         break;
-
-       case RECEIVE:
-         emit2 ("; genReceive");
-         genReceive (ic);
-         break;
-
-       case SEND:
-         emit2 ("; addSet");
-         addSet (&_G.sendSet, ic);
-         break;
-
-       default:
-         ic = ic;
-         /*      piCode(ic,stdout); */
-
-       }
+        {
+        case '!':
+          emitDebug ("; genNot");
+          genNot (ic);
+          break;
+
+        case '~':
+          emitDebug ("; genCpl");
+          genCpl (ic);
+          break;
+
+        case UNARYMINUS:
+          emitDebug ("; genUminus");
+          genUminus (ic);
+          break;
+
+        case IPUSH:
+          emitDebug ("; genIpush");
+          genIpush (ic);
+          break;
+
+        case IPOP:
+          /* IPOP happens only when trying to restore a
+             spilt live range, if there is an ifx statement
+             following this pop then the if statement might
+             be using some of the registers being popped which
+             would destory the contents of the register so
+             we need to check for this condition and handle it */
+          if (ic->next &&
+              ic->next->op == IFX &&
+              regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
+            {
+              emitDebug ("; genIfx");
+              genIfx (ic->next, ic);
+            }
+          else
+            {
+              emitDebug ("; genIpop");
+              genIpop (ic);
+            }
+          break;
+
+        case CALL:
+          emitDebug ("; genCall");
+          genCall (ic);
+          break;
+
+        case PCALL:
+          emitDebug ("; genPcall");
+          genPcall (ic);
+          break;
+
+        case FUNCTION:
+          emitDebug ("; genFunction");
+          genFunction (ic);
+          break;
+
+        case ENDFUNCTION:
+          emitDebug ("; genEndFunction");
+          genEndFunction (ic);
+          break;
+
+        case RETURN:
+          emitDebug ("; genRet");
+          genRet (ic);
+          break;
+
+        case LABEL:
+          emitDebug ("; genLabel");
+          genLabel (ic);
+          break;
+
+        case GOTO:
+          emitDebug ("; genGoto");
+          genGoto (ic);
+          break;
+
+        case '+':
+          emitDebug ("; genPlus");
+          genPlus (ic);
+          break;
+
+        case '-':
+          emitDebug ("; genMinus");
+          genMinus (ic);
+          break;
+
+        case '*':
+          emitDebug ("; genMult");
+          genMult (ic);
+          break;
+
+        case '/':
+          emitDebug ("; genDiv");
+          genDiv (ic);
+          break;
+
+        case '%':
+          emitDebug ("; genMod");
+          genMod (ic);
+          break;
+
+        case '>':
+          emitDebug ("; genCmpGt");
+          genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
+          break;
+
+        case '<':
+          emitDebug ("; genCmpLt");
+          genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
+          break;
+
+        case LE_OP:
+        case GE_OP:
+        case NE_OP:
+
+          /* note these two are xlated by algebraic equivalence
+             during parsing SDCC.y */
+          werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
+                  "got '>=' or '<=' shouldn't have come here");
+          break;
+
+        case EQ_OP:
+          emitDebug ("; genCmpEq");
+          genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
+          break;
+
+        case AND_OP:
+          emitDebug ("; genAndOp");
+          genAndOp (ic);
+          break;
+
+        case OR_OP:
+          emitDebug ("; genOrOp");
+          genOrOp (ic);
+          break;
+
+        case '^':
+          emitDebug ("; genXor");
+          genXor (ic, ifxForOp (IC_RESULT (ic), ic));
+          break;
+
+        case '|':
+          emitDebug ("; genOr");
+          genOr (ic, ifxForOp (IC_RESULT (ic), ic));
+          break;
+
+        case BITWISEAND:
+          emitDebug ("; genAnd");
+          genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
+          break;
+
+        case INLINEASM:
+          emitDebug ("; genInline");
+          genInline (ic);
+          break;
+
+        case RRC:
+          emitDebug ("; genRRC");
+          genRRC (ic);
+          break;
+
+        case RLC:
+          emitDebug ("; genRLC");
+          genRLC (ic);
+          break;
+
+        case GETHBIT:
+          emitDebug ("; genGetHBIT");
+          genGetHbit (ic);
+          break;
+
+        case LEFT_OP:
+          emitDebug ("; genLeftShift");
+          genLeftShift (ic);
+          break;
+
+        case RIGHT_OP:
+          emitDebug ("; genRightShift");
+          genRightShift (ic);
+          break;
+
+        case GET_VALUE_AT_ADDRESS:
+          emitDebug ("; genPointerGet");
+          genPointerGet (ic);
+          break;
+
+        case '=':
+
+          if (POINTER_SET (ic))
+            {
+              emitDebug ("; genAssign (pointer)");
+              genPointerSet (ic);
+            }
+          else
+            {
+              emitDebug ("; genAssign");
+              genAssign (ic);
+            }
+          break;
+
+        case IFX:
+          emitDebug ("; genIfx");
+          genIfx (ic, NULL);
+          break;
+
+        case ADDRESS_OF:
+          emitDebug ("; genAddrOf");
+          genAddrOf (ic);
+          break;
+
+        case JUMPTABLE:
+          emitDebug ("; genJumpTab");
+          genJumpTab (ic);
+          break;
+
+        case CAST:
+          emitDebug ("; genCast");
+          genCast (ic);
+          break;
+
+        case RECEIVE:
+          emitDebug ("; genReceive");
+          genReceive (ic);
+          break;
+
+        case SEND:
+          if (ic->builtinSEND)
+            {
+              emitDebug ("; genBuiltIn");
+              genBuiltIn(ic);
+            }
+          else
+            {
+              emitDebug ("; addSet");
+              addSet (&_G.sendSet, ic);
+            }
+          break;
+
+        case ARRAYINIT:
+          emitDebug ("; genArrayInit");
+          genArrayInit(ic);
+          break;
+
+        case DUMMY_READ_VOLATILE:
+          emitDebug ("; genDummyRead");
+          genDummyRead (ic);
+          break;
+
+        case CRITICAL:
+          emitDebug ("; genCritical");
+          genCritical (ic);
+          break;
+
+        case ENDCRITICAL:
+          emitDebug ("; genEndCritical");
+          genEndCritical (ic);
+          break;
+
+        default:
+          ic = ic;
+        }
     }
 
 
@@ -5743,11 +8371,14 @@ genZ80Code (iCode * lic)
     printLine (_G.lines.head, codeOutFile);
     if (_G.flushStatics)
       {
-       flushStatics ();
-       _G.flushStatics = 0;
+        flushStatics ();
+        _G.flushStatics = 0;
       }
     codeOutFile = fp;
   }
+
+  freeTrace(&_G.lines.trace);
+  freeTrace(&_G.trace.aops);
 }
 
 /*
@@ -5760,9 +8391,9 @@ _isPairUsed (iCode * ic, PAIR_ID pairId)
     {
     case PAIR_DE:
       if (bitVectBitValue (ic->rMask, D_IDX))
-       ret++;
+        ret++;
       if (bitVectBitValue (ic->rMask, E_IDX))
-       ret++;
+        ret++;
       break;
     default:
       wassert (0);
@@ -5770,4 +8401,26 @@ _isPairUsed (iCode * ic, PAIR_ID pairId)
   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));
+}
+
+
 */