* src/pic/ralloc.c (debugLogRegType): Removed some old types to get it to compile.
[fw/sdcc] / src / z80 / gen.c
index d5009fd0f39f347ed547dd3dd4f10a91b11f793d..9e88369d51596624c9c8b7069bf31639fa9529f3 100644 (file)
@@ -1,6 +1,33 @@
 /*-------------------------------------------------------------------------
   gen.c - Z80 specific code generator.
 /*-------------------------------------------------------------------------
   gen.c - Z80 specific code generator.
+     
+  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)
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by the
+  Free Software Foundation; either version 2, or (at your option) any
+  later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
 
 
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+  In other words, you are welcome to use, share and improve this program.
+  You are forbidden to forbid anyone else to use, share and improve
+  what you give them.   Help stamp out software-hoarding!
+
+-------------------------------------------------------------------------*/
+
+/*
   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
   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
   4. Optimised strcmp fun              21999 149 2294
   5. Optimised strcmp further          21660 151 228C
   6. Optimised memcpy by unroling      20885 157 2201
   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
 
 
-  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)
-
-  This program is free software; you can redistribute it and/or modify it
-  under the terms of the GNU General Public License as published by the
-  Free Software Foundation; either version 2, or (at your option) any
-  later version.
-
-  This program is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-  GNU General Public License for more details.
-
-
-  You should have received a copy of the GNU General Public License
-  along with this program; if not, write to the Free Software
-  Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-  In other words, you are welcome to use, share and improve this program.
-  You are forbidden to forbid anyone else to use, share and improve
-  what you give them.   Help stamp out software-hoarding!
-
--------------------------------------------------------------------------*/
+  10 and below are with asm strings off.
+  
+  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 <stdio.h>
 #include <stdlib.h>
@@ -71,7 +96,7 @@
 #include "SDCCglue.h"
 #include "newalloc.h"
 
 #include "SDCCglue.h"
 #include "newalloc.h"
 
-/* this is the down and dirty file with all kinds of kludgy & hacky
+/* This is the down and dirty file with all kinds of kludgy & hacky
    stuff. This is what it is all about CODE GENERATION for a specific MCU.
    Some of the routines may be reusable, will have to see */
 
    stuff. This is what it is all about CODE GENERATION for a specific MCU.
    Some of the routines may be reusable, will have to see */
 
    PENDING: What if the parameter is a long?
    Everything is caller saves. i.e. the caller must save any registers
    that it wants to preserve over the call.
    PENDING: What if the parameter is a long?
    Everything is caller saves. i.e. the caller must save any registers
    that it wants to preserve over the call.
-   The return value is returned in DEHL.  DE is normally used as a
+   GB: The return value is returned in DEHL.  DE is normally used as a
    working register pair.  Caller saves allows it to be used for a
    return value.
    va args functions do not use register parameters.  All arguments
    working register pair.  Caller saves allows it to be used for a
    return value.
    va args functions do not use register parameters.  All arguments
    area.  ix-0 is the top most local variable.
 */
 
    area.  ix-0 is the top most local variable.
 */
 
-enum {
+enum 
+{
+  /* Set to enable debugging trace statements in the output assembly code. */
   DISABLE_DEBUG = 1
 };
 
   DISABLE_DEBUG = 1
 };
 
@@ -108,6 +135,8 @@ static char **_fTmp;
 
 extern FILE *codeOutFile;
 
 
 extern FILE *codeOutFile;
 
+/** Enum covering all the possible register pairs.
+ */
 typedef enum
   {
     PAIR_INVALID,
 typedef enum
   {
     PAIR_INVALID,
@@ -150,12 +179,17 @@ enum
     MSB32
   };
 
     MSB32
   };
 
+/** Code generator persistent data.
+ */
 static struct 
 {
 static struct 
 {
+  /** Used to optimised setting up of a pair by remebering what it
+      contains and adjusting instead of reloading where possible.
+  */
   struct 
   {
     AOP_TYPE last_type;
   struct 
   {
     AOP_TYPE last_type;
-    const char *lit;
+    const char *base;
     int offset;
   } pairs[NUM_PAIRS];
   struct 
     int offset;
   } pairs[NUM_PAIRS];
   struct 
@@ -192,6 +226,25 @@ static struct
 
 static const char *aopGet (asmop * aop, int offset, bool bit16);
 
 
 static const char *aopGet (asmop * aop, int offset, bool bit16);
 
+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 void
 _tidyUp (char *buf)
 {
 static void
 _tidyUp (char *buf)
 {
@@ -421,6 +474,19 @@ genPairPush (asmop * aop)
   emit2 ("push %s", getPairName (aop));
 }
 
   emit2 ("push %s", getPairName (aop));
 }
 
+static void
+_push (PAIR_ID pairId)
+{
+  emit2 ("push %s", _pairs[pairId].name);
+  _G.stack.pushed += 2;
+}
+
+static void
+_pop (PAIR_ID pairId)
+{
+  emit2 ("pop %s", _pairs[pairId].name);
+  _G.stack.pushed -= 2;
+}
 
 /*-----------------------------------------------------------------*/
 /* newAsmop - creates a new asmOp                                  */
 
 /*-----------------------------------------------------------------*/
 /* newAsmop - creates a new asmOp                                  */
@@ -841,10 +907,17 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
     case AOP_IMMD:
       /* PENDING: for re-target */
       if (with_hash)
     case AOP_IMMD:
       /* PENDING: for re-target */
       if (with_hash)
-       tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
+        {
+          tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
+        }
+      else if (offset == 0)
+        {
+          tsprintf (s, "%s", aop->aopu.aop_immd);
+        }
       else
       else
-       tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
-
+        {
+          tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
+        }
       return gc_strdup(s);
 
     case AOP_LIT:
       return gc_strdup(s);
 
     case AOP_LIT:
@@ -933,7 +1006,7 @@ static void
 spillPair (PAIR_ID pairId)
 {
   _G.pairs[pairId].last_type = AOP_INVALID;
 spillPair (PAIR_ID pairId)
 {
   _G.pairs[pairId].last_type = AOP_INVALID;
-  _G.pairs[pairId].lit = NULL;
+  _G.pairs[pairId].base = NULL;
 }
 
 static void
 }
 
 static void
@@ -957,34 +1030,14 @@ requiresHL (asmop * aop)
     }
 }
 
     }
 }
 
-static char *
-fetchLitSpecial (asmop * aop, bool negate, bool xor)
-{
-  unsigned long v;
-  value *val = aop->aopu.aop_lit;
-
-  wassert (aop->type == AOP_LIT);
-  wassert (!IS_FLOAT (val->type));
-
-  v = (unsigned long) floatFromVal (val);
-
-  if (xor)
-    v ^= 0x8000;
-  if (negate)
-    v = 0-v;
-  v &= 0xFFFF;
-
-  tsprintf (buffer, "!immedword", v);
-  return gc_strdup (buffer);
-}
-
 static void
 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
 {
 static void
 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
 {
-  const char *l;
+  const char *l, *base;
   const char *pair = _pairs[pairId].name;
   l = aopGetLitWordLong (left, offset, FALSE);
   const char *pair = _pairs[pairId].name;
   l = aopGetLitWordLong (left, offset, FALSE);
-  wassert (l && pair);
+  base = aopGetLitWordLong (left, 0, FALSE);
+  wassert (l && pair && base);
 
   if (isPtr (pair))
     {
 
   if (isPtr (pair))
     {
@@ -992,7 +1045,7 @@ fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
        {
          if (_G.pairs[pairId].last_type == left->type)
            {
        {
          if (_G.pairs[pairId].last_type == left->type)
            {
-             if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
+             if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
                {
                  if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
                    {
                {
                  if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
                    {
@@ -1007,21 +1060,7 @@ fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
            }
        }
       _G.pairs[pairId].last_type = left->type;
            }
        }
       _G.pairs[pairId].last_type = left->type;
-      _G.pairs[pairId].lit = gc_strdup (l);
-      _G.pairs[pairId].offset = offset;
-    }
-  if (IS_GB && pairId == PAIR_DE && 0)
-    {
-      if (_G.pairs[pairId].lit && !strcmp (_G.pairs[pairId].lit, l))
-       {
-         if (abs (_G.pairs[pairId].offset - offset) < 3)
-           {
-             adjustPair (pair, &_G.pairs[pairId].offset, offset);
-             return;
-           }
-       }
-      _G.pairs[pairId].last_type = left->type;
-      _G.pairs[pairId].lit = gc_strdup (l);
+      _G.pairs[pairId].base = gc_strdup (base);
       _G.pairs[pairId].offset = offset;
     }
   /* Both a lit on the right and a true symbol on the left */
       _G.pairs[pairId].offset = offset;
     }
   /* Both a lit on the right and a true symbol on the left */
@@ -1039,18 +1078,21 @@ fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
         /* we need to get it byte by byte */
         if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
             aopGet (aop, offset, FALSE);
         /* we need to get it byte by byte */
         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:
             case 1:
                 emit2 ("ld l,!*hl");
                 emit2 ("ld h,!immedbyte", 0);
                             break;
             case 2:
+              // PENDING: Requires that you are only fetching two bytes.
+            case 4:
                 emit2 ("!ldahli");
                 emit2 ("ld h,!*hl");
                 emit2 ("ld l,a");
                 break;
             default:
                 emit2 ("!ldahli");
                 emit2 ("ld h,!*hl");
                 emit2 ("ld l,a");
                 break;
             default:
-                emitDebug ("; WARNING: mlh woosed out.  This code is invalid.");
+              wassertl (0, "Attempted to fetch too much data into HL");
+              break;
             }
         }
         else if (IS_Z80 && aop->type == AOP_IY) {
             }
         }
         else if (IS_Z80 && aop->type == AOP_IY) {
@@ -1243,6 +1285,15 @@ aopGet (asmop * aop, int offset, bool bit16)
     case AOP_LIT:
       return aopLiteral (aop->aopu.aop_lit, offset);
 
     case AOP_LIT:
       return aopLiteral (aop->aopu.aop_lit, offset);
 
+    case AOP_SIMPLELIT:
+      {
+        unsigned long v = aop->aopu.aop_simplelit;
+        
+        v >>= (offset * 8);
+        tsprintf (s, "!immedbyte", (unsigned int) v & 0xff);
+        
+        return gc_strdup(s);
+      }
     case AOP_STR:
       aop->coff = offset;
       return aop->aopu.aop_str[offset];
     case AOP_STR:
       aop->coff = offset;
       return aop->aopu.aop_str[offset];
@@ -1416,8 +1467,7 @@ aopPut (asmop * aop, const char *s, int offset)
        break;
       if (offset > 0)
        {
        break;
       if (offset > 0)
        {
-
-         emitDebug ("; Error aopPut AOP_ACC");
+          wassertl (0, "Tried to access past the end of A");
        }
       else
        {
        }
       else
        {
@@ -1483,7 +1533,7 @@ static void
 movLeft2Result (operand * left, int offl,
                operand * result, int offr, int sign)
 {
 movLeft2Result (operand * left, int offl,
                operand * result, int offr, int sign)
 {
-    const char *l;
+  const char *l;
   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
     {
       l = aopGet (AOP (left), offl, FALSE);
   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
     {
       l = aopGet (AOP (left), offl, FALSE);
@@ -1494,7 +1544,11 @@ movLeft2Result (operand * left, int offl,
        }
       else
        {
        }
       else
        {
-         wassert (0);
+          if (getDataSize (left) == offl + 1)
+            {
+              emit2 ("ld a,%s", l);
+              aopPut (AOP (result), "a", offr);
+            }
        }
     }
 }
        }
     }
 }
@@ -1528,7 +1582,6 @@ outBitCLong (operand * result, bool swap_sense)
   /* if the result is bit */
   if (AOP_TYPE (result) == AOP_CRY)
     {
   /* if the result is bit */
   if (AOP_TYPE (result) == AOP_CRY)
     {
-      emitDebug ("; Note: outBitC form 1");
       aopPut (AOP (result), "blah", 0);
     }
   else
       aopPut (AOP (result), "blah", 0);
     }
   else
@@ -1646,6 +1699,59 @@ genCpl (iCode * ic)
   freeAsmop (IC_RESULT (ic), NULL, ic);
 }
 
   freeAsmop (IC_RESULT (ic), NULL, ic);
 }
 
+static void
+_gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
+{
+  /* Logic:
+       ld de,right.lw
+       setup hl to left
+       de = hl - de
+       push flags
+       store de into result
+       pop flags
+       ld de,right.hw
+       setup hl
+       de = hl -de
+       store de into result
+  */
+  const char *first = isAdd ? "add" : "sub";
+  const char *later = isAdd ? "adc" : "sbc";
+
+  wassertl (IS_GB, "Code is only relevent to the gbz80");
+  wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
+
+  fetchPair (PAIR_DE, left);
+
+  emit2 ("ld a,e");
+  emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
+  emit2 ("ld e,a");
+  emit2 ("ld a,d");
+  emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
+
+  _push (PAIR_AF);
+  aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
+  aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
+
+  fetchPairLong (PAIR_DE, left, 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);
+}
+
 /*-----------------------------------------------------------------*/
 /* genUminus - unary minus code generation                         */
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 /* genUminus - unary minus code generation                         */
 /*-----------------------------------------------------------------*/
@@ -1680,6 +1786,17 @@ genUminus (iCode * ic)
 
   /* otherwise subtract from zero */
   size = AOP_SIZE (IC_LEFT (ic));
 
   /* otherwise subtract from zero */
   size = AOP_SIZE (IC_LEFT (ic));
+
+  if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
+    {
+      /* Create a new asmop with value zero */
+      asmop *azero = newAsmop (AOP_SIMPLELIT);
+      azero->aopu.aop_simplelit = 0;
+      azero->size = size;
+      _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
+      goto release;
+    }
+
   offset = 0;
   _clearCarry();
   while (size--)
   offset = 0;
   _clearCarry();
   while (size--)
@@ -1706,21 +1823,6 @@ release:
   freeAsmop (IC_RESULT (ic), NULL, ic);
 }
 
   freeAsmop (IC_RESULT (ic), NULL, ic);
 }
 
-static void
-_push (PAIR_ID pairId)
-{
-  emit2 ("push %s", _pairs[pairId].name);
-  _G.stack.pushed += 2;
-}
-
-static void
-_pop (PAIR_ID pairId)
-{
-  emit2 ("pop %s", _pairs[pairId].name);
-  _G.stack.pushed -= 2;
-}
-
-
 /*-----------------------------------------------------------------*/
 /* assignResultValue -               */
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 /* assignResultValue -               */
 /*-----------------------------------------------------------------*/
@@ -1733,18 +1835,13 @@ assignResultValue (operand * oper)
   wassert (size <= 4);
   topInA = requiresHL (AOP (oper));
 
   wassert (size <= 4);
   topInA = requiresHL (AOP (oper));
 
-#if 0
-  if (!IS_GB)
-    wassert (size <= 2);
-#endif
   if (IS_GB && size == 4 && requiresHL (AOP (oper)))
     {
       /* We do it the hard way here. */
       _push (PAIR_HL);
       aopPut (AOP (oper), _fReturn[0], 0);
       aopPut (AOP (oper), _fReturn[1], 1);
   if (IS_GB && size == 4 && requiresHL (AOP (oper)))
     {
       /* We do it the hard way here. */
       _push (PAIR_HL);
       aopPut (AOP (oper), _fReturn[0], 0);
       aopPut (AOP (oper), _fReturn[1], 1);
-      emit2 ("pop de");
-      _G.stack.pushed -= 2;
+      _pop (PAIR_DE);
       aopPut (AOP (oper), _fReturn[0], 2);
       aopPut (AOP (oper), _fReturn[1], 3);
     }
       aopPut (AOP (oper), _fReturn[0], 2);
       aopPut (AOP (oper), _fReturn[1], 3);
     }
@@ -1787,19 +1884,7 @@ _saveRegsForCall(iCode *ic, int sendSetSize)
     bool bcInRet = FALSE, deInRet = FALSE;
     bitVect *rInUse;
 
     bool bcInRet = FALSE, deInRet = FALSE;
     bitVect *rInUse;
 
-#if 1
     rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
     rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
-#else
-    if (IC_RESULT(ic))
-      {
-        rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), z80_rUmaskForOp (IC_RESULT(ic)));
-      }
-    else 
-      {
-        /* Has no result, so in use is all of in use */
-        rInUse = ic->rMask;
-      }
-#endif
 
     deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
     bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
 
     deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
     bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
@@ -2116,7 +2201,6 @@ emitCall (iCode * ic, bool ispcall)
 
       if (isLitWord (AOP (IC_LEFT (ic))))
        {
 
       if (isLitWord (AOP (IC_LEFT (ic))))
        {
-         emitDebug ("; Special case where the pCall is to a constant");
          emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
        }
       else
          emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
        }
       else
@@ -2318,14 +2402,6 @@ genFunction (iCode * ic)
   */
   _G.receiveOffset = 0;
 
   */
   _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;
   
   /* Record the last function name for debugging. */
   _G.lastFunctionName = sym->rname;
   
@@ -2723,7 +2799,7 @@ genPlus (iCode * ic)
   if (genPlusIncr (ic) == TRUE)
     goto release;
 
   if (genPlusIncr (ic) == TRUE)
     goto release;
 
-  emitDebug ("; genPlusIncr failed");
+  emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
 
   size = getDataSize (IC_RESULT (ic));
 
 
   size = getDataSize (IC_RESULT (ic));
 
@@ -2731,10 +2807,11 @@ genPlus (iCode * ic)
   if (isPair (AOP (IC_RESULT (ic))))
     {
       char *left, *right;
   if (isPair (AOP (IC_RESULT (ic))))
     {
       char *left, *right;
-
       left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
       right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
       left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
       right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
-      if (left && right)
+
+      if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
+          left && right)
        {
          /* It's a pair */
          /* PENDING: fix */
        {
          /* It's a pair */
          /* PENDING: fix */
@@ -2814,11 +2891,15 @@ genPlus (iCode * ic)
              commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
              goto release;
            }
              commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
              goto release;
            }
-         else if (size == 4)
-           {
-             emitDebug ("; WARNING: This add is probably broken.\n");
-           }
        }
        }
+      if (size == 4)
+        {
+          /* Be paranoid on the GB with 4 byte variables due to how C
+             can be trashed by lda hl,n(sp).
+          */
+          _gbz80_emitAddSubLong (ic, TRUE);
+          goto release;
+        }
     }
 
   while (size--)
     }
 
   while (size--)
@@ -2895,15 +2976,16 @@ genMinusDec (iCode * ic)
 
   /* if increment 16 bits in register */
   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
 
   /* if increment 16 bits in register */
   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
-      (size == 2))
+      (size == 2)
+      )
     {
     {
-      fetchPair (PAIR_HL, AOP (IC_RESULT (ic)));
+      fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
 
       while (icount--) {
 
       while (icount--) {
-        emit2 ("dec hl");
+        emit2 ("dec %s", _getTempPairName());
       }
       }
-      aopPut (AOP (IC_RESULT (ic)), "l", LSB);
-      aopPut (AOP (IC_RESULT (ic)), "h", MSB16);
+
+      commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
 
       return TRUE;
     }
 
       return TRUE;
     }
@@ -3002,11 +3084,15 @@ genMinus (iCode * ic)
              aopPut (AOP (IC_RESULT (ic)), "e", 0);
              goto release;
            }
              aopPut (AOP (IC_RESULT (ic)), "e", 0);
              goto release;
            }
-         else if (size == 4)
-           {
-             emitDebug ("; WARNING: This sub is probably broken.\n");
-           }
        }
        }
+      if (size == 4)
+        {
+          /* Be paranoid on the GB with 4 byte variables due to how C
+             can be trashed by lda hl,n(sp).
+          */
+          _gbz80_emitAddSubLong (ic, FALSE);
+          goto release;
+        }
     }
 
   /* if literal, add a,#-lit, else normal subb */
     }
 
   /* if literal, add a,#-lit, else normal subb */
@@ -3149,11 +3235,13 @@ genIfxJump (iCode * ic, char *jval)
   ic->generated = 1;
 }
 
   ic->generated = 1;
 }
 
+#if DISABLED
 static const char *
 _getPairIdName (PAIR_ID id)
 {
   return _pairs[id].name;
 }
 static const char *
 _getPairIdName (PAIR_ID id)
 {
   return _pairs[id].name;
 }
+#endif
 
 /** Generic compare for > or <
  */
 
 /** Generic compare for > or <
  */
@@ -3192,47 +3280,49 @@ genCmp (operand * left, operand * right,
          else
            emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
        }
          else
            emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
        }
+      else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
+        {
+          // On the Gameboy we can't afford to adjust HL as it may trash the carry.
+          // Pull left into DE and right into HL
+          aopGet (AOP(left), LSB, FALSE);
+          emit2 ("ld d,h");
+          emit2 ("ld e,l");
+          aopGet (AOP(right), LSB, FALSE);
+
+          while (size--)
+            {
+              if (size == 0 && sign)
+                {
+                  // Highest byte when signed needs the bits flipped
+                  // Save the flags
+                  emit2 ("push af");
+                  emit2 ("ld a,(de)");
+                  emit2 ("xor #0x80");
+                  emit2 ("ld e,a");
+                  emit2 ("ld a,(hl)");
+                  emit2 ("xor #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
        {
       else
        {
-         /* Special cases:
-            On the GB:
-            If the left or the right is a lit:
-            Load -lit into HL, add to right via, check sense.
-          */
-         if (IS_GB && size == 2 && (AOP_TYPE (right) == AOP_LIT || AOP_TYPE (left) == AOP_LIT))
-           {
-             PAIR_ID id = PAIR_DE;
-             asmop *lit = AOP (right);
-             asmop *op = AOP (left);
-             swap_sense = TRUE;
-
-             if (AOP_TYPE (left) == AOP_LIT)
-               {
-                 swap_sense = FALSE;
-                 lit = AOP (left);
-                 op = AOP (right);
-               }
-             if (sign)
-               {
-                 emit2 ("ld e,%s", aopGet (op, 0, 0));
-                 emit2 ("ld a,%s", aopGet (op, 1, 0));
-                 emit2 ("xor a,!immedbyte", 0x80);
-                 emit2 ("ld d,a");
-               }
-             else
-               {
-                 id = getPairId (op);
-                 if (id == PAIR_INVALID)
-                   {
-                     fetchPair (PAIR_DE, op);
-                     id = PAIR_DE;
-                   }
-               }
-             spillPair (PAIR_HL);
-             emit2 ("ld hl,%s", fetchLitSpecial (lit, TRUE, sign));
-             emit2 ("add hl,%s", _getPairIdName (id));
-             goto release;
-           }
          if (AOP_TYPE (right) == AOP_LIT)
            {
              lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
          if (AOP_TYPE (right) == AOP_LIT)
            {
              lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
@@ -3291,12 +3381,6 @@ genCmp (operand * left, operand * right,
                  emit2 ("ld %s,a", _fTmp[1]);
                  fDidXor = TRUE;
                }
                  emit2 ("ld %s,a", _fTmp[1]);
                  fDidXor = TRUE;
                }
-             if (!fDidXor)
-               _clearCarry();
-           }
-         else
-           {
-             _clearCarry();
            }
          while (size--)
            {
            }
          while (size--)
            {
@@ -3308,12 +3392,12 @@ genCmp (operand * left, operand * right,
              if (sign && size == 0)
                {
                  emit2 ("ld a,%s", _fTmp[0]);
              if (sign && size == 0)
                {
                  emit2 ("ld a,%s", _fTmp[0]);
-                 emit2 ("sbc a,%s", _fTmp[1]);
+                 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
                }
              else
                {
                  /* Subtract through, propagating the carry */
                }
              else
                {
                  /* Subtract through, propagating the carry */
-                 emit2 ("sbc a,%s", aopGet (AOP (right), offset++, FALSE));
+                 emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset++, FALSE));
                }
            }
        }
                }
            }
        }
@@ -3752,15 +3836,6 @@ genAnd (iCode * ic, iCode * ifx)
   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
 
   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
 
-#ifdef DEBUG_TYPE
-  emitDebug ("; Type res[%d] = l[%d]&r[%d]",
-           AOP_TYPE (result),
-           AOP_TYPE (left), AOP_TYPE (right));
-  emitDebug ("; Size res[%d] = l[%d]&r[%d]",
-           AOP_SIZE (result),
-           AOP_SIZE (left), AOP_SIZE (right));
-#endif
-
   /* if left is a literal & right is not then exchange them */
   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
       AOP_NEEDSACC (left))
   /* if left is a literal & right is not then exchange them */
   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
       AOP_NEEDSACC (left))
@@ -3984,15 +4059,6 @@ genOr (iCode * ic, iCode * ifx)
   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
 
   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
 
-#if 1
-  emitDebug ("; Type res[%d] = l[%d]&r[%d]",
-           AOP_TYPE (result),
-           AOP_TYPE (left), AOP_TYPE (right));
-  emitDebug ("; Size res[%d] = l[%d]&r[%d]",
-           AOP_SIZE (result),
-           AOP_SIZE (left), AOP_SIZE (right));
-#endif
-
   /* if left is a literal & right is not then exchange them */
   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
       AOP_NEEDSACC (left))
   /* if left is a literal & right is not then exchange them */
   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
       AOP_NEEDSACC (left))
@@ -4381,7 +4447,7 @@ shiftR2Left2Result (operand * left, int offl,
   tlbl1 = newiTempLabel (NULL);
 
   /* Left is already in result - so now do the shift */
   tlbl1 = newiTempLabel (NULL);
 
   /* Left is already in result - so now do the shift */
-  if (shCount <= 2)
+  if (shCount <= 4)
     {
       while (shCount--)
         {
     {
       while (shCount--)
         {
@@ -4439,12 +4505,18 @@ shiftL2Left2Result (operand * left, int offl,
        emitLabel (tlbl->key + 100);
       }
 
        emitLabel (tlbl->key + 100);
       }
 
-    emit2 ("or a,a");
     while (size--)
       {
        l = aopGet (AOP (result), offset, FALSE);
 
     while (size--)
       {
        l = aopGet (AOP (result), offset, FALSE);
 
-       emit2 ("rl %s", l);
+        if (offset == 0)
+          {
+            emit2 ("sla %s", l);
+          }
+        else
+          {
+            emit2 ("rl %s", l);
+          }
 
         offset++;
       }
 
         offset++;
       }
@@ -4470,34 +4542,34 @@ AccRol (int shCount)
     case 0:
       break;
     case 1:
     case 0:
       break;
     case 1:
-      emit2 ("rl a");
+      emit2 ("sla a");
       break;
     case 2:
       break;
     case 2:
-      emit2 ("rl a");
+      emit2 ("sla a");
       emit2 ("rl a");
       break;
     case 3:
       emit2 ("rl a");
       break;
     case 3:
-      emit2 ("rl a");
+      emit2 ("sla a");
       emit2 ("rl a");
       emit2 ("rl a");
       break;
     case 4:
       emit2 ("rl a");
       emit2 ("rl a");
       break;
     case 4:
-      emit2 ("rl a");
+      emit2 ("sla a");
       emit2 ("rl a");
       emit2 ("rl a");
       emit2 ("rl a");
       break;
     case 5:
       emit2 ("rl a");
       emit2 ("rl a");
       emit2 ("rl a");
       break;
     case 5:
-      emit2 ("rr a");
+      emit2 ("srl a");
       emit2 ("rr a");
       emit2 ("rr a");
       break;
     case 6:
       emit2 ("rr a");
       emit2 ("rr a");
       break;
     case 6:
-      emit2 ("rr a");
+      emit2 ("srl a");
       emit2 ("rr a");
       break;
     case 7:
       emit2 ("rr a");
       break;
     case 7:
-      emit2 ("rr a");
+      emit2 ("srl a");
       break;
     }
 }
       break;
     }
 }
@@ -4570,7 +4642,7 @@ genlshTwo (operand * result, operand * left, int shCount)
            {
              movLeft2Result (left, LSB, result, MSB16, 0);
              aopPut (AOP (result), "!zero", 0);
            {
              movLeft2Result (left, LSB, result, MSB16, 0);
              aopPut (AOP (result), "!zero", 0);
-             shiftL1Left2Result (left, MSB16, result, MSB16, shCount);
+             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
            }
          else
            {
            }
          else
            {
@@ -4625,11 +4697,6 @@ genLeftShiftLiteral (operand * left,
 
   size = getSize (operandType (result));
 
 
   size = getSize (operandType (result));
 
-#if VIEW_SIZE
-  emitDebug ("; shift left  result %d, left %d", size,
-           AOP_SIZE (left));
-#endif
-
   /* I suppose that the left size >= result size */
   if (shCount == 0)
     {
   /* I suppose that the left size >= result size */
   if (shCount == 0)
     {
@@ -4701,7 +4768,7 @@ genLeftShift (iCode * ic)
 
   /* now move the left to the result if they are not the
      same */
 
   /* now move the left to the result if they are not the
      same */
-#if 1
+
   if (!sameRegs (AOP (left), AOP (result)))
     {
 
   if (!sameRegs (AOP (left), AOP (result)))
     {
 
@@ -4714,17 +4781,6 @@ genLeftShift (iCode * ic)
          offset++;
        }
     }
          offset++;
        }
     }
-#else
-  size = AOP_SIZE (result);
-  offset = 0;
-  while (size--)
-    {
-      l = aopGet (AOP (left), offset, FALSE);
-      aopPut (AOP (result), l, offset);
-      offset++;
-    }
-#endif
-
 
   tlbl = newiTempLabel (NULL);
   size = AOP_SIZE (result);
 
   tlbl = newiTempLabel (NULL);
   size = AOP_SIZE (result);
@@ -4735,12 +4791,19 @@ genLeftShift (iCode * ic)
   emitLabel (tlbl->key + 100);
   l = aopGet (AOP (result), offset, FALSE);
 
   emitLabel (tlbl->key + 100);
   l = aopGet (AOP (result), offset, FALSE);
 
-  emit2 ("or a,a");
-
   while (size--)
     {
   while (size--)
     {
-      l = aopGet (AOP (result), offset++, FALSE);
-      emit2 ("rl %s", l);
+      l = aopGet (AOP (result), offset, FALSE);
+
+      if (offset == 0)
+        {
+          emit2 ("sla %s", l);
+        }
+      else
+        {
+          emit2 ("rl %s", l);
+        }
+      offset++;
     }
   emitLabel (tlbl1->key + 100);
   emit2 ("dec a");
     }
   emitLabel (tlbl1->key + 100);
   emit2 ("dec a");
@@ -4765,8 +4828,6 @@ genrshOne (operand * result, operand * left, int shCount, int is_signed)
 
   l = aopGet (AOP (left), 0, FALSE);
 
 
   l = aopGet (AOP (left), 0, FALSE);
 
-  emit2 ("or a,a");
-
   if (AOP (result)->type == AOP_REG)
     {
       aopPut (AOP (result), l, 0);
   if (AOP (result)->type == AOP_REG)
     {
       aopPut (AOP (result), l, 0);
@@ -4818,7 +4879,10 @@ shiftR1Left2Result (operand * left, int offl,
   _moveA (aopGet (AOP (left), offl, FALSE));
   if (sign)
     {
   _moveA (aopGet (AOP (left), offl, FALSE));
   if (sign)
     {
-      wassert (0);
+      while (shCount--)
+       {
+         emit2 ("%s a", sign ? "sra" : "srl");
+       }
     }
   else
     {
     }
   else
     {
@@ -4847,7 +4911,19 @@ genrshTwo (operand * result, operand * left,
        {
          movLeft2Result (left, MSB16, result, LSB, sign);
        }
        {
          movLeft2Result (left, MSB16, result, LSB, sign);
        }
-      aopPut (AOP (result), "!zero", 1);
+      if (sign)
+        {
+          /* Sign extend the result */
+          _moveA(aopGet (AOP (result), 0, FALSE));
+          emit2 ("rlc a");
+          emit2 ("sbc a,a");
+
+          aopPut (AOP (result), ACC_NAME, MSB16);
+        }
+      else
+        {
+          aopPut (AOP (result), "!zero", 1);
+        }
     }
   /*  1 <= shCount <= 7 */
   else
     }
   /*  1 <= shCount <= 7 */
   else
@@ -4876,9 +4952,6 @@ genRightShiftLiteral (operand * left,
 
   size = getSize (operandType (result));
 
 
   size = getSize (operandType (result));
 
-  emitDebug ("; shift right  result %d, left %d", size,
-           AOP_SIZE (left));
-
   /* I suppose that the left size >= result size */
   if (shCount == 0)
     {
   /* I suppose that the left size >= result size */
   if (shCount == 0)
     {
@@ -4896,7 +4969,6 @@ genRightShiftLiteral (operand * left,
          genrshOne (result, left, shCount, sign);
          break;
        case 2:
          genrshOne (result, left, shCount, sign);
          break;
        case 2:
-         /* PENDING: sign support */
          genrshTwo (result, left, shCount, sign);
          break;
        case 4:
          genrshTwo (result, left, shCount, sign);
          break;
        case 4:
@@ -5309,14 +5381,12 @@ genAssign (iCode * ic)
   result = IC_RESULT (ic);
   right = IC_RIGHT (ic);
 
   result = IC_RESULT (ic);
   right = IC_RIGHT (ic);
 
-#if 1
   /* Dont bother assigning if they are the same */
   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
     {
       emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
       return;
     }
   /* Dont bother assigning if they are the same */
   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
     {
       emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
       return;
     }
-#endif
 
   aopOp (right, ic, FALSE, FALSE);
   aopOp (result, ic, TRUE, FALSE);
 
   aopOp (right, ic, FALSE, FALSE);
   aopOp (result, ic, TRUE, FALSE);
@@ -5388,6 +5458,28 @@ genAssign (iCode * ic)
       aopPut (AOP (result), "a", 0);
       aopPut (AOP (result), "e", 1);
     }
       aopPut (AOP (result), "a", 0);
       aopPut (AOP (result), "e", 1);
     }
+  else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
+    {
+      /* Special case - simple memcpy */
+      aopGet (AOP (right), LSB, FALSE);
+      emit2 ("ld d,h");
+      emit2 ("ld e,l");
+      aopGet (AOP (result), LSB, FALSE);
+
+      while (size--)
+        {
+          emit2 ("ld a,(de)");
+          /* Peephole will optimise this. */
+          emit2 ("ld (hl),a");
+
+          if (size != 0)
+            {
+              emit2 ("inc hl");
+              emit2 ("inc de");
+            }
+        }
+      spillPair (PAIR_HL);
+    }
   else
     {
       while (size--)
   else
     {
       while (size--)
@@ -5489,16 +5581,7 @@ genCast (iCode * ic)
       goto release;
     }
 
       goto release;
     }
 
-  /* PENDING: should be OK. */
-#if 0
-  /* if the result is of type pointer */
-  if (IS_PTR (ctype))
-    {
-      wassert (0);
-    }
-#endif
-
-  /* so we now know that the size of destination is greater
+  /* So we now know that the size of destination is greater
      than the size of the source */
   /* we move to result for the size of source */
   size = AOP_SIZE (right);
      than the size of the source */
   /* we move to result for the size of source */
   size = AOP_SIZE (right);
@@ -5525,7 +5608,6 @@ genCast (iCode * ic)
         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
                        FALSE);
       _moveA (l);
         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
                        FALSE);
       _moveA (l);
-      emitDebug ("; genCast: sign extend untested.");
       emit2 ("rla ");
       emit2 ("sbc a,a");
       while (size--)
       emit2 ("rla ");
       emit2 ("sbc a,a");
       while (size--)
@@ -5566,6 +5648,246 @@ genReceive (iCode * ic)
   freeAsmop (IC_RESULT (ic), NULL, ic);
 }
 
   freeAsmop (IC_RESULT (ic), NULL, ic);
 }
 
+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, int 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 -%u,0x%02X", 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 -%u,0x%02X", 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);
+
+  if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
+    {
+      /* Emit the support function call and the destination address. */
+      emit2("call __initrleblock");
+      emit2(".dw %s", aopGetWord (AOP(IC_LEFT(ic)), 0));
+    }
+  else
+    {
+      wassertl (0, "Unexpected operand to genArrayInit.\n");
+    }
+    
+  type = operandType(IC_LEFT(ic));
+    
+  if (type && type->next)
+    {
+      elementSize = getSize(type->next);
+    }
+  else
+    {
+      wassertl (0, "Can't determine 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;
+
+      if (ix != 0)
+        {
+          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");
+
+  freeAsmop (IC_LEFT(ic), NULL, ic);
+}
+
 /*-----------------------------------------------------------------*/
 /* genZ80Code - generate code for Z80 based controllers            */
 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 /* genZ80Code - generate code for Z80 based controllers            */
 /*-----------------------------------------------------------------*/
@@ -5837,10 +6159,12 @@ genZ80Code (iCode * lic)
          addSet (&_G.sendSet, ic);
          break;
 
          addSet (&_G.sendSet, ic);
          break;
 
+       case ARRAYINIT:
+          genArrayInit(ic);
+          break;
+           
        default:
          ic = ic;
        default:
          ic = ic;
-         /*      piCode(ic,stdout); */
-
        }
     }
 
        }
     }
 
@@ -5886,4 +6210,26 @@ _isPairUsed (iCode * ic, PAIR_ID pairId)
   return ret;
 }
 
   return ret;
 }
 
+static char *
+fetchLitSpecial (asmop * aop, bool negate, bool xor)
+{
+  unsigned long v;
+  value *val = aop->aopu.aop_lit;
+
+  wassert (aop->type == AOP_LIT);
+  wassert (!IS_FLOAT (val->type));
+
+  v = (unsigned long) floatFromVal (val);
+
+  if (xor)
+    v ^= 0x8000;
+  if (negate)
+    v = 0-v;
+  v &= 0xFFFF;
+
+  tsprintf (buffer, "!immedword", v);
+  return gc_strdup (buffer);
+}
+
+
 */
 */