Added support for gsinit packing.
[fw/sdcc] / src / z80 / gen.c
index 39c048e88f1a8baa65061493efd49c52b5a5bc85..0482186cb9c36f3596c5acae63522b2ff97086d6 100644 (file)
@@ -2,7 +2,7 @@
   gen.c - Z80 specific code generator.
 
   Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
-            ticks dhry  size
+                                       ticks dhry  size
   Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
   Improved WORD push                    22784 144 19AE
   With label1 on                        22694 144 197E
   5/3/00                                17741 185 17B6
   With reg params for mul and div       16234 202 162D
 
-  Michael Hope <michaelh@earthling.net> 2000
+  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
+
+  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)
    IX is used as an index register to the top of the local variable
    area.  ix-0 is the top most local variable.
 */
+
+enum {
+  DISABLE_DEBUG = 1
+};
+
 static char *_z80_return[] =
 {"l", "h", "e", "d"};
 static char *_gbz80_return[] =
@@ -201,12 +217,9 @@ _tidyUp (char *buf)
 }
 
 static void
-emit2 (const char *szFormat,...)
+_vemit2 (const char *szFormat, va_list ap)
 {
   char buffer[256];
-  va_list ap;
-
-  va_start (ap, szFormat);
 
   tvsprintf (buffer, szFormat, ap);
 
@@ -218,6 +231,33 @@ emit2 (const char *szFormat,...)
   _G.lines.current->isInline = _G.lines.isInline;
 }
 
+static void
+emit2 (const char *szFormat,...)
+{
+  va_list ap;
+
+  va_start (ap, szFormat);
+
+  _vemit2 (szFormat, ap);
+
+  va_end (ap);
+}
+
+static void
+emitDebug (const char *szFormat,...)
+{
+  if (!DISABLE_DEBUG)
+    {
+      va_list ap;
+      
+      va_start (ap, szFormat);
+      
+      _vemit2 (szFormat, ap);
+      
+      va_end (ap);
+    }
+}
+
 /*-----------------------------------------------------------------*/
 /* emit2 - writes the code into a file : for now it is simple    */
 /*-----------------------------------------------------------------*/
@@ -418,7 +458,7 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
   /* Assign depending on the storage class */
   if (sym->onStack || sym->iaccess)
     {
-      emit2 ("; AOP_STK for %s", sym->rname);
+      emitDebug ("; AOP_STK for %s", sym->rname);
       sym->aop = aop = newAsmop (AOP_STK);
       aop->size = getSize (sym->type);
       aop->aopu.aop_stk = sym->stack;
@@ -443,7 +483,7 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool 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);
+         emitDebug ("; AOP_SFR for %s", sym->rname);
          return aop;
        }
     }
@@ -452,7 +492,7 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
   /* 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
@@ -794,10 +834,6 @@ 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)
     {
@@ -809,9 +845,9 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
        tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
       else
        tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
-      rs = Safe_calloc (1, strlen (s) + 1);
-      strcpy (rs, s);
-      return rs;
+
+      return gc_strdup(s);
+
     case AOP_LIT:
       {
        value *val = aop->aopu.aop_lit;
@@ -822,14 +858,24 @@ aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
            unsigned long v = (unsigned long) floatFromVal (val);
 
            if (offset == 2)
-             v >>= 16;
+              {
+                v >>= 16;
+              }
+            else if (offset == 0)
+              {
+                // OK
+              }
+            else 
+              {
+                wassertl(0, "Encountered an invalid offset while fetching a literal");
+              }
 
            if (with_hash)
              tsprintf (buffer, "!immedword", v);
            else
              tsprintf (buffer, "!constword", v);
-           rs = Safe_calloc (1, strlen (buffer) + 1);
-           return strcpy (rs, buffer);
+
+            return gc_strdup(buffer);
          }
        else
          {
@@ -938,7 +984,7 @@ fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
 {
   const char *l;
   const char *pair = _pairs[pairId].name;
-  l = aopGetLitWordLong (left, 0, FALSE);
+  l = aopGetLitWordLong (left, offset, FALSE);
   wassert (l && pair);
 
   if (isPtr (pair))
@@ -980,10 +1026,7 @@ fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
       _G.pairs[pairId].offset = offset;
     }
   /* 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);
+  emit2 ("ld %s,!hashedstr", pair, l);
 }
 
 static void
@@ -1008,7 +1051,7 @@ fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
                 emit2 ("ld l,a");
                 break;
             default:
-                emit2 ("; WARNING: mlh woosed out.  This code is invalid.");
+                emitDebug ("; WARNING: mlh woosed out.  This code is invalid.");
             }
         }
         else if (IS_Z80 && aop->type == AOP_IY) {
@@ -1136,14 +1179,14 @@ aopGet (asmop * aop, int offset, bool bit16)
 
     case AOP_DIR:
       wassert (IS_GB);
-      emit2 ("ld a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
+      emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
       sprintf (s, "a");
 
       return gc_strdup(s);
 
     case AOP_SFR:
       wassert (IS_GB);
-      emit2 ("ldh a,(%s+%d) ; x", aop->aopu.aop_dir, offset);
+      emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
       sprintf (s, "a");
 
       return gc_strdup(s);
@@ -1175,7 +1218,7 @@ aopGet (asmop * aop, int offset, bool bit16)
        {
          if (aop->aopu.aop_stk >= 0)
            offset += _G.stack.param_offset;
-         tsprintf (s, "!*ixx ; x", aop->aopu.aop_stk + offset);
+         tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
        }
 
       return gc_strdup(s);
@@ -1375,7 +1418,7 @@ aopPut (asmop * aop, const char *s, int offset)
       if (offset > 0)
        {
 
-         emit2 ("; Error aopPut AOP_ACC");
+         emitDebug ("; Error aopPut AOP_ACC");
        }
       else
        {
@@ -1486,7 +1529,7 @@ outBitCLong (operand * result, bool swap_sense)
   /* if the result is bit */
   if (AOP_TYPE (result) == AOP_CRY)
     {
-      emit2 ("; Note: outBitC form 1");
+      emitDebug ("; Note: outBitC form 1");
       aopPut (AOP (result), "blah", 0);
     }
   else
@@ -1509,7 +1552,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;
@@ -1554,7 +1597,7 @@ genNot (iCode * ic)
       wassert (0);
     }
 
-  toBoolean (IC_LEFT (ic));
+  _toBoolean (IC_LEFT (ic));
 
   /* Not of A:
      If A == 0, !A = 1
@@ -1764,7 +1807,7 @@ _saveRegsForCall(iCode *ic, int sendSetSize)
 
     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);
@@ -1796,42 +1839,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;
     }
 
@@ -1998,7 +2005,7 @@ _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
        {
          if (pairId == PAIR_DE)
            {
-             emit2 ("; name %s", aop->aopu.aop_reg[i]->name);
+             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"))
@@ -2006,7 +2013,7 @@ _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
            }
           else if (pairId == PAIR_BC)
             {
-             emit2 ("; name %s", aop->aopu.aop_reg[i]->name);
+             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"))
@@ -2110,7 +2117,7 @@ emitCall (iCode * ic, bool ispcall)
 
       if (isLitWord (AOP (IC_LEFT (ic))))
        {
-         emit2 ("; Special case where the pCall is to a constant");
+         emitDebug ("; Special case where the pCall is to a constant");
          emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
        }
       else
@@ -2291,15 +2298,6 @@ 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                 */
 /*-----------------------------------------------------------------*/
@@ -2338,6 +2336,11 @@ genFunction (iCode * ic)
   emit2 ("__%s_start:", sym->rname);
   emit2 ("!functionlabeldef", sym->rname);
 
+  if (options.profile) 
+    {
+      emit2 ("!profileenter");
+    }
+
   fetype = getSpec (operandType (IC_LEFT (ic)));
 
   /* if critical function then turn interrupts off */
@@ -2452,6 +2455,12 @@ genEndFunction (iCode * ic)
         }
 #endif
 
+      if (options.profile) 
+        {
+          emit2 ("!profileexit");
+        }
+
+
       /* Both baned and non-banked just ret */
       emit2 ("ret");
 
@@ -2562,7 +2571,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);
 
@@ -2634,7 +2643,9 @@ genPlusIncr (iCode * ic)
   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;
     }
 
@@ -2713,7 +2724,7 @@ genPlus (iCode * ic)
   if (genPlusIncr (ic) == TRUE)
     goto release;
 
-  emit2 ("; genPlusIncr failed");
+  emitDebug ("; genPlusIncr failed");
 
   size = getDataSize (IC_RESULT (ic));
 
@@ -2806,7 +2817,7 @@ genPlus (iCode * ic)
            }
          else if (size == 4)
            {
-             emit2 ("; WARNING: This add is probably broken.\n");
+             emitDebug ("; WARNING: This add is probably broken.\n");
            }
        }
     }
@@ -2864,26 +2875,6 @@ 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))))
@@ -2903,6 +2894,22 @@ genMinusDec (iCode * ic)
       return TRUE;
     }
 
+  /* if increment 16 bits in register */
+  if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
+      (size == 2))
+    {
+      fetchPair (PAIR_HL, AOP (IC_RESULT (ic)));
+
+      while (icount--) {
+        emit2 ("dec hl");
+      }
+      aopPut (AOP (IC_RESULT (ic)), "l", LSB);
+      aopPut (AOP (IC_RESULT (ic)), "h", MSB16);
+
+      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)
@@ -2998,7 +3005,7 @@ genMinus (iCode * ic)
            }
          else if (size == 4)
            {
-             emit2 ("; WARNING: This sub is probably broken.\n");
+             emitDebug ("; WARNING: This sub is probably broken.\n");
            }
        }
     }
@@ -3307,7 +3314,7 @@ genCmp (operand * left, operand * right,
              else
                {
                  /* Subtract through, propagating the carry */
-                 emit2 ("sbc a,%s ; 2", aopGet (AOP (right), offset++, FALSE));
+                 emit2 ("sbc a,%s", aopGet (AOP (right), offset++, FALSE));
                }
            }
        }
@@ -3437,7 +3444,7 @@ gencjneshort (operand * left, operand * right, symbol * lbl)
        {
          while (size--)
            {
-             emit2 ("ld a,%s ; 2", aopGet (AOP (left), offset, FALSE));
+             emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
              if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
                emit2 ("or a,a");
              else
@@ -3462,7 +3469,7 @@ gencjneshort (operand * left, operand * right, symbol * lbl)
            emit2 ("jp nz,!tlabel", lbl->key + 100);
          else
            {
-             emit2 ("cp %s ; 4", aopGet (AOP (right), offset, FALSE));
+             emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
              emit2 ("jp nz,!tlabel", lbl->key + 100);
            }
          offset++;
@@ -3475,7 +3482,7 @@ gencjneshort (operand * left, operand * right, symbol * lbl)
       while (size--)
        {
          _moveA (aopGet (AOP (right), offset, FALSE));
-         emit2 ("cp %s ; 5", aopGet (AOP (left), offset, FALSE));
+         emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
          emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
          offset++;
        }
@@ -3512,7 +3519,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\n", 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.
@@ -3637,9 +3644,9 @@ genAndOp (iCode * ic)
   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);
     }
@@ -3674,9 +3681,9 @@ genOrOp (iCode * ic)
   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);
     }
@@ -3747,10 +3754,10 @@ genAnd (iCode * ic, iCode * ifx)
   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
 
 #ifdef DEBUG_TYPE
-  emit2 ("; Type res[%d] = l[%d]&r[%d]",
+  emitDebug ("; Type res[%d] = l[%d]&r[%d]",
            AOP_TYPE (result),
            AOP_TYPE (left), AOP_TYPE (right));
-  emit2 ("; Size res[%d] = l[%d]&r[%d]",
+  emitDebug ("; Size res[%d] = l[%d]&r[%d]",
            AOP_SIZE (result),
            AOP_SIZE (left), AOP_SIZE (right));
 #endif
@@ -3979,10 +3986,10 @@ genOr (iCode * ic, iCode * ifx)
   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
 
 #if 1
-  emit2 ("; Type res[%d] = l[%d]&r[%d]",
+  emitDebug ("; Type res[%d] = l[%d]&r[%d]",
            AOP_TYPE (result),
            AOP_TYPE (left), AOP_TYPE (right));
-  emit2 ("; Size res[%d] = l[%d]&r[%d]",
+  emitDebug ("; Size res[%d] = l[%d]&r[%d]",
            AOP_SIZE (result),
            AOP_SIZE (left), AOP_SIZE (right));
 #endif
@@ -4179,13 +4186,15 @@ genXor (iCode * ic, iCode * ifx)
                  _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);
                }
            }
          else
            {
              if (AOP_TYPE (left) == AOP_ACC)
-               emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
+                {
+                  emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
+                }
              else
                {
                  _moveA (aopGet (AOP (right), offset, FALSE));
@@ -4220,14 +4229,15 @@ genXor (iCode * ic, iCode * ifx)
              }
            // 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));
+           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);
          }
@@ -4299,53 +4309,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");
+      /* PENDING: For re-target. */
+      emit2 ("and a,#1");
+      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)
+                   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 <= 2)
     {
-      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);
     }
 }
 
@@ -4389,8 +4443,11 @@ shiftL2Left2Result (operand * left, int offl,
     emit2 ("or a,a");
     while (size--)
       {
-       l = aopGet (AOP (result), offset++, FALSE);
+       l = aopGet (AOP (result), offset, FALSE);
+
        emit2 ("rl %s", l);
+
+        offset++;
       }
     if (shCount > 1)
       {
@@ -4570,7 +4627,7 @@ genLeftShiftLiteral (operand * left,
   size = getSize (operandType (result));
 
 #if VIEW_SIZE
-  emit2 ("; shift left  result %d, left %d", size,
+  emitDebug ("; shift left  result %d, left %d", size,
            AOP_SIZE (left));
 #endif
 
@@ -4580,9 +4637,13 @@ genLeftShiftLiteral (operand * left,
       wassert (0);
     }
 
-  else if (shCount >= (size * 8))
-    while (size--)
-      aopPut (AOP (result), "!zero", size);
+  else if (shCount >= (size * 8)) 
+    {
+      while (size--)
+        {
+          aopPut (AOP (result), "!zero", size);
+        }
+    }
   else
     {
       switch (size)
@@ -4594,7 +4655,7 @@ genLeftShiftLiteral (operand * left,
          genlshTwo (result, left, shCount);
          break;
        case 4:
-         wassert (0);
+         wassertl (0, "Shifting of longs is currently unsupported");
          break;
        default:
          wassert (0);
@@ -4674,7 +4735,9 @@ genLeftShift (iCode * ic)
   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);
@@ -4692,7 +4755,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);
@@ -4702,19 +4765,24 @@ genrshOne (operand * result, operand * left, int shCount)
   wassert (shCount < 8);
 
   l = aopGet (AOP (left), 0, FALSE);
+
+  emit2 ("or a,a");
+
   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);
     }
@@ -4796,7 +4864,8 @@ static void
 genRightShiftLiteral (operand * left,
                      operand * right,
                      operand * result,
-                     iCode * ic)
+                     iCode * ic,
+                      int sign)
 {
   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
   int size;
@@ -4808,7 +4877,7 @@ genRightShiftLiteral (operand * left,
 
   size = getSize (operandType (result));
 
-  emit2 ("; shift right  result %d, left %d", size,
+  emitDebug ("; shift right  result %d, left %d", size,
            AOP_SIZE (left));
 
   /* I suppose that the left size >= result size */
@@ -4825,17 +4894,17 @@ genRightShiftLiteral (operand * left,
       switch (size)
        {
        case 1:
-         genrshOne (result, left, shCount);
+         genrshOne (result, left, shCount, sign);
          break;
        case 2:
          /* PENDING: sign support */
-         genrshTwo (result, left, shCount, FALSE);
+         genrshTwo (result, left, shCount, sign);
          break;
        case 4:
-         wassert (0);
+         wassertl (0, "Asked to shift right a long which should be a function call");
          break;
        default:
-         wassert (0);
+         wassertl (0, "Entered default case in right shift delegate");
        }
     }
   freeAsmop (left, NULL, ic);
@@ -4879,7 +4948,7 @@ 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;
     }
 
@@ -4918,14 +4987,13 @@ genRightShift (iCode * ic)
       l = aopGet (AOP (result), offset--, FALSE);
       if (first)
        {
-         if (is_signed)
-           emit2 ("sra %s", l);
-         else
-           emit2 ("srl %s", l);
+          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");
@@ -5149,7 +5217,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 */
@@ -5246,7 +5314,7 @@ genAssign (iCode * ic)
   /* 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
@@ -5257,7 +5325,7 @@ 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;
     }
 
@@ -5458,7 +5526,7 @@ genCast (iCode * ic)
         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
                        FALSE);
       _moveA (l);
-      emit2 ("; genCast: sign extend untested.");
+      emitDebug ("; genCast: sign extend untested.");
       emit2 ("rla ");
       emit2 ("sbc a,a");
       while (size--)
@@ -5499,6 +5567,246 @@ genReceive (iCode * 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            */
 /*-----------------------------------------------------------------*/
@@ -5541,22 +5849,22 @@ genZ80Code (iCode * lic)
       switch (ic->op)
        {
        case '!':
-         emit2 ("; genNot");
+         emitDebug ("; genNot");
          genNot (ic);
          break;
 
        case '~':
-         emit2 ("; genCpl");
+         emitDebug ("; genCpl");
          genCpl (ic);
          break;
 
        case UNARYMINUS:
-         emit2 ("; genUminus");
+         emitDebug ("; genUminus");
          genUminus (ic);
          break;
 
        case IPUSH:
-         emit2 ("; genIpush");
+         emitDebug ("; genIpush");
          genIpush (ic);
          break;
 
@@ -5571,83 +5879,83 @@ genZ80Code (iCode * lic)
              ic->next->op == IFX &&
              regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
            {
-             emit2 ("; genIfx");
+              emitDebug ("; genIfx");
              genIfx (ic->next, ic);
            }
          else
            {
-             emit2 ("; genIpop");
+             emitDebug ("; genIpop");
              genIpop (ic);
            }
          break;
 
        case CALL:
-         emit2 ("; genCall");
+         emitDebug ("; genCall");
          genCall (ic);
          break;
 
        case PCALL:
-         emit2 ("; genPcall");
+         emitDebug ("; genPcall");
          genPcall (ic);
          break;
 
        case FUNCTION:
-         emit2 ("; genFunction");
+         emitDebug ("; genFunction");
          genFunction (ic);
          break;
 
        case ENDFUNCTION:
-         emit2 ("; genEndFunction");
+         emitDebug ("; genEndFunction");
          genEndFunction (ic);
          break;
 
        case RETURN:
-         emit2 ("; genRet");
+         emitDebug ("; genRet");
          genRet (ic);
          break;
 
        case LABEL:
-         emit2 ("; genLabel");
+         emitDebug ("; genLabel");
          genLabel (ic);
          break;
 
        case GOTO:
-         emit2 ("; genGoto");
+         emitDebug ("; genGoto");
          genGoto (ic);
          break;
 
        case '+':
-         emit2 ("; genPlus");
+         emitDebug ("; genPlus");
          genPlus (ic);
          break;
 
        case '-':
-         emit2 ("; genMinus");
+         emitDebug ("; genMinus");
          genMinus (ic);
          break;
 
        case '*':
-         emit2 ("; genMult");
+         emitDebug ("; genMult");
          genMult (ic);
          break;
 
        case '/':
-         emit2 ("; genDiv");
+         emitDebug ("; genDiv");
          genDiv (ic);
          break;
 
        case '%':
-         emit2 ("; genMod");
+         emitDebug ("; genMod");
          genMod (ic);
          break;
 
        case '>':
-         emit2 ("; genCmpGt");
+         emitDebug ("; genCmpGt");
          genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
          break;
 
        case '<':
-         emit2 ("; genCmpLt");
+         emitDebug ("; genCmpLt");
          genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
          break;
 
@@ -5662,66 +5970,67 @@ genZ80Code (iCode * lic)
          break;
 
        case EQ_OP:
-         emit2 ("; genCmpEq");
+         emitDebug ("; genCmpEq");
          genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
          break;
 
        case AND_OP:
-         emit2 ("; genAndOp");
+         emitDebug ("; genAndOp");
          genAndOp (ic);
          break;
 
        case OR_OP:
-         emit2 ("; genOrOp");
+         emitDebug ("; genOrOp");
          genOrOp (ic);
          break;
 
        case '^':
-         emit2 ("; genXor");
+         emitDebug ("; genXor");
          genXor (ic, ifxForOp (IC_RESULT (ic), ic));
          break;
 
        case '|':
-         emit2 ("; genOr");
+         emitDebug ("; genOr");
          genOr (ic, ifxForOp (IC_RESULT (ic), ic));
          break;
 
        case BITWISEAND:
-         emit2 ("; genAnd");
+         emitDebug ("; genAnd");
          genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
          break;
 
        case INLINEASM:
-         emit2 ("; genInline");
+         emitDebug ("; genInline");
          genInline (ic);
          break;
 
        case RRC:
-         emit2 ("; genRRC");
+         emitDebug ("; genRRC");
          genRRC (ic);
          break;
 
        case RLC:
-         emit2 ("; genRLC");
+         emitDebug ("; genRLC");
          genRLC (ic);
          break;
 
        case GETHBIT:
-         emit2 ("; genHBIT");
-         wassert (0);
+         emitDebug ("; genGetHBIT");
+         genGetHbit (ic);
+          break;
 
        case LEFT_OP:
-         emit2 ("; genLeftShift");
+         emitDebug ("; genLeftShift");
          genLeftShift (ic);
          break;
 
        case RIGHT_OP:
-         emit2 ("; genRightShift");
+         emitDebug ("; genRightShift");
          genRightShift (ic);
          break;
 
        case GET_VALUE_AT_ADDRESS:
-         emit2 ("; genPointerGet");
+         emitDebug ("; genPointerGet");
          genPointerGet (ic);
          break;
 
@@ -5729,46 +6038,50 @@ genZ80Code (iCode * lic)
 
          if (POINTER_SET (ic))
            {
-             emit2 ("; genAssign (pointer)");
+             emitDebug ("; genAssign (pointer)");
              genPointerSet (ic);
            }
          else
            {
-             emit2 ("; genAssign");
+             emitDebug ("; genAssign");
              genAssign (ic);
            }
          break;
 
        case IFX:
-         emit2 ("; genIfx");
+          emitDebug ("; genIfx");
          genIfx (ic, NULL);
          break;
 
        case ADDRESS_OF:
-         emit2 ("; genAddrOf");
+         emitDebug ("; genAddrOf");
          genAddrOf (ic);
          break;
 
        case JUMPTABLE:
-         emit2 ("; genJumpTab");
+         emitDebug ("; genJumpTab");
          genJumpTab (ic);
          break;
 
        case CAST:
-         emit2 ("; genCast");
+         emitDebug ("; genCast");
          genCast (ic);
          break;
 
        case RECEIVE:
-         emit2 ("; genReceive");
+         emitDebug ("; genReceive");
          genReceive (ic);
          break;
 
        case SEND:
-         emit2 ("; addSet");
+         emitDebug ("; addSet");
          addSet (&_G.sendSet, ic);
          break;
 
+       case ARRAYINIT:
+           genArrayInit(ic);
+           break;
+           
        default:
          ic = ic;
          /*      piCode(ic,stdout); */