* as/hc08/lkaomf51.c (OutputName): made name unsigned char,
[fw/sdcc] / src / z80 / gen.c
index 0ab78841d45dacc20572a89109cdaaeb06e1490a..72d5726683ebcc6742b85efb135b77742e0331a3 100644 (file)
@@ -220,7 +220,9 @@ static struct
   bool flushStatics;
   bool in_home;
   const char *lastFunctionName;
-
+  iCode *current_iCode;
+  bool preserveCarry;
+  
   set *sendSet;
 
   struct
@@ -234,6 +236,7 @@ static struct
     lineNode *head;
     lineNode *current;
     int isInline;
+    int isDebug;
     allocTrace trace;
   } lines;
 
@@ -261,7 +264,8 @@ static const char *aopNames[] = {
   "AOP_HLREG",
   "AOP_SIMPLELIT",
   "AOP_EXSTK",
-  "AOP_PAIRPT"
+  "AOP_PAIRPT",
+  "AOP_DUMMY"
 };
 
 static bool
@@ -397,7 +401,7 @@ _newLineNode (char *line)
 static void
 _vemit2 (const char *szFormat, va_list ap)
 {
-  char buffer[256];
+  char buffer[INITIAL_INLINEASM];
 
   tvsprintf (buffer, sizeof(buffer), szFormat, ap);
 
@@ -407,6 +411,8 @@ _vemit2 (const char *szFormat, va_list ap)
              (_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
@@ -436,6 +442,19 @@ emitDebug (const char *szFormat,...)
     }
 }
 
+/*-----------------------------------------------------------------*/
+/* 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;
+}
+
 /*-----------------------------------------------------------------*/
 /* emit2 - writes the code into a file : for now it is simple    */
 /*-----------------------------------------------------------------*/
@@ -444,7 +463,7 @@ _emit2 (const char *inst, const char *fmt,...)
 {
   va_list ap;
   char lb[INITIAL_INLINEASM];
-  char *lbp = lb;
+  unsigned char *lbp = lb;
 
   va_start (ap, fmt);
 
@@ -466,6 +485,7 @@ _emit2 (const char *inst, const char *fmt,...)
                   (_G.lines.head = _newLineNode (lb)));
     }
   _G.lines.current->isInline = _G.lines.isInline;
+  _G.lines.current->ic = _G.current_iCode;
   va_end (ap);
 }
 
@@ -486,12 +506,26 @@ _emitMove(const char *to, const char *from)
 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;
@@ -670,6 +704,39 @@ _pop (PAIR_ID pairId)
   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                                  */
 /*-----------------------------------------------------------------*/
@@ -736,18 +803,34 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
       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);
+      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;
-       }
+        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 */
@@ -864,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) &&
@@ -940,6 +1023,11 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a)
   /* if already has a asmop then continue */
   if (op->aop)
     {
+      if (op->aop->type == AOP_SFR)
+        {
+          op->aop->bcInUse = isPairInUse( PAIR_BC, ic );
+          op->aop->deInUse = isPairInUse( PAIR_DE, ic );
+        }
       return;
     }
 
@@ -947,6 +1035,11 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a)
   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;
     }
 
@@ -1032,14 +1125,21 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a)
          return;
        }
 
-      /* else spill location  */
-      if (sym->usl.spillLoc && getSize(sym->type) != getSize(sym->usl.spillLoc->type)) {
-         /* force a new aop if sizes differ */
-         sym->usl.spillLoc->aop = NULL;
-      }
-      sym->aop = op->aop = aop =
-       aopForSym (ic, sym->usl.spillLoc, result, requires_a);
-      wassertl (aop->size >= getSize (sym->type), "Operand doesn't fit in the spill location");
+      if (sym->usl.spillLoc)
+        {
+         if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
+            {
+             /* force a new aop if sizes differ */
+             sym->usl.spillLoc->aop = NULL;
+           }
+         sym->aop = op->aop = aop =
+                    aopForSym (ic, sym->usl.spillLoc, result, requires_a);
+         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;
     }
@@ -1421,6 +1521,12 @@ setupPairFromSP (PAIR_ID id, int offset)
 {
   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);
@@ -1428,7 +1534,13 @@ setupPairFromSP (PAIR_ID id, int offset)
     }
   else
     {
-      emit2 ("!ldahlsp", offset);
+          emit2 ("!ldahlsp", offset);
+    }
+
+  if (_G.preserveCarry)
+    {
+      _pop (PAIR_AF);
+      offset -= 2;
     }
 }
 
@@ -1464,11 +1576,15 @@ setupPair (PAIR_ID pairId, asmop * aop, int offset)
         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;
@@ -1497,6 +1613,8 @@ setupPair (PAIR_ID pairId, asmop * aop, int offset)
       }
 
     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;
       
@@ -1533,6 +1651,10 @@ aopGet (asmop * aop, int offset, bool bit16)
   /* 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)
@@ -1563,11 +1685,35 @@ aopGet (asmop * aop, int offset, bool bit16)
       return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
 
     case AOP_SFR:
-      wassert (IS_GB);
-      emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
-      SNPRINTF (buffer, sizeof(buffer), "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));
+        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 traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
+      }
 
     case AOP_REG:
       return aop->aopu.aop_reg[offset]->name;
@@ -1646,8 +1792,15 @@ aopGet (asmop * aop, int offset, bool bit16)
 
     case AOP_PAIRPTR:
       setupPair (aop->aopu.aop_pairId, aop, offset);
-      SNPRINTF (buffer, sizeof(buffer), 
-               "(%s)", _pairs[aop->aopu.aop_pairId].name);
+      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));
 
@@ -1712,6 +1865,10 @@ aopPut (asmop * aop, const char *s, int offset)
   /* 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);
@@ -1721,10 +1878,47 @@ aopPut (asmop * aop, const char *s, int 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:
@@ -1862,7 +2056,12 @@ aopPut (asmop * aop, const char *s, int offset)
 
     case AOP_PAIRPTR:
       setupPair (aop->aopu.aop_pairId, aop, offset);
-      emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
+      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:
@@ -1875,7 +2074,7 @@ 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)
@@ -2196,7 +2395,7 @@ genUminusFloat (operand * op, operand * result)
   emitDebug("; genUminusFloat");
 
   /* for this we just need to flip the
-     first it then copy the rest in place */
+     first bit then copy the rest in place */
   size = AOP_SIZE (op) - 1;
 
   _moveA(aopGet (AOP (op), MSB32, FALSE));
@@ -2362,7 +2561,8 @@ _saveRegsForCall(iCode *ic, int sendSetSize)
     bool bcInRet = FALSE, deInRet = FALSE;
     bitVect *rInUse;
 
-    rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
+    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);
@@ -2597,6 +2797,7 @@ _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
 static void
 emitCall (iCode * ic, bool ispcall)
 {
+  bool bInRet, cInRet, dInRet, eInRet;
   sym_link *dtype = operandType (IC_LEFT (ic));
 
   /* if caller saves & we have not saved then */
@@ -2713,7 +2914,7 @@ emitCall (iCode * ic, bool ispcall)
     }
   spillCached ();
 
-  /* Mark the regsiters as restored. */
+  /* Mark the registers as restored. */
   _G.saves.saved = FALSE;
 
   /* if we need assign a result value */
@@ -2765,12 +2966,24 @@ emitCall (iCode * ic, bool ispcall)
     }
 
   spillCached ();
+  if (IC_RESULT (ic))
+    {
+      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;
+    }
 
   if (_G.stack.pushedDE) 
     {
-      bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
-      bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
-
       if (dInRet && eInRet)
         {
           wassertl (0, "Shouldn't push DE if it's wiped out by the return");
@@ -2797,9 +3010,6 @@ emitCall (iCode * ic, bool ispcall)
   
   if (_G.stack.pushedBC) 
     {
-      bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
-      bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
-
       if (bInRet && cInRet)
         {
           wassertl (0, "Shouldn't push BC if it's wiped out by the return");
@@ -2890,8 +3100,11 @@ genFunction (iCode * ic)
   
   /* Create the function header */
   emit2 ("!functionheader", sym->name);
-  sprintf (buffer, "%s_start", sym->rname);
-  emit2 ("!labeldef", buffer);
+  if (!IS_STATIC(sym->etype))
+    {
+      sprintf (buffer, "%s_start", sym->rname);
+      emit2 ("!labeldef", buffer);
+    }
   emit2 ("!functionlabeldef", sym->rname);
 
   if (options.profile) 
@@ -2901,14 +3114,21 @@ genFunction (iCode * ic)
 
   ftype = operandType (IC_LEFT (ic));
 
-  /* if critical function then turn interrupts off */
-  if (IFFUNC_ISCRITICAL (ftype))
-    emit2 ("!di");
-
   /* if this is an interrupt service routine then save all potentially used registers. */
   if (IFFUNC_ISISR (sym->type))
     {
-      emit2 ("!pusha");
+      if (!FUNC_ISNAKED( sym->type ))
+        {
+          emit2 ("!pusha");
+       }
+    }
+  else
+    {
+      /* if critical function then turn interrupts off */
+      if (IFFUNC_ISCRITICAL (sym->type))
+        {
+          emit2 ("!di");
+       }
     }
 
   /* PENDING: callee-save etc */
@@ -2992,8 +3212,9 @@ genFunction (iCode * ic)
     emit2 ("!enterxl", sym->stack);
   else if (sym->stack)
     emit2 ("!enterx", sym->stack);
-  else
+  else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
     emit2 ("!enter");
+
   _G.stack.offset = sym->stack;
 }
 
@@ -3005,59 +3226,83 @@ genEndFunction (iCode * ic)
 {
   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
 
-  if (IFFUNC_ISISR (sym->type))
+
+  /* PENDING: calleeSave */
+  if (IS_Z80 && _G.omitFramePtr)
     {
-      wassertl (0, "Tried to close an interrupt support function");
+      if (_G.stack.offset)
+        emit2 ("!ldaspsp", _G.stack.offset);
     }
-  else
+  else if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
     {
-      if (IFFUNC_ISCRITICAL (sym->type))
-       emit2 ("!ei");
-
-      /* PENDING: calleeSave */
-
-      if (IS_Z80 && _G.omitFramePtr)
-        {
-          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
-        {
-          emit2 ("!leave");
-        }
+      emit2 ("!leavexl", _G.stack.offset);
+    }
+  else if (_G.stack.offset)
+    {
+      emit2 ("!leavex", _G.stack.offset);
+    }
+  else if( !FUNC_ISNAKED( sym->type )) /*.p.t.20030716 - now supporting Naked funcitons */
+    {
+      emit2 ("!leave");
+    }
+      
+  if (_G.calleeSaves.pushedDE) 
+    {
+      emit2 ("pop de");
+      _G.calleeSaves.pushedDE = FALSE;
+    }
 
-      if (_G.calleeSaves.pushedDE
-        {
-          emit2 ("pop de");
-          _G.calleeSaves.pushedDE = FALSE;
-        }
+  if (_G.calleeSaves.pushedBC
+    {
+      emit2 ("pop bc");
+      _G.calleeSaves.pushedBC = FALSE;
+    }
 
-      if (_G.calleeSaves.pushedBC) 
-        {
-          emit2 ("pop bc");
-          _G.calleeSaves.pushedBC = FALSE;
-        }
+  if (options.profile) 
+    {
+      emit2 ("!profileexit");
+    }
 
-      if (options.profile) 
+  /* if this is an interrupt service routine then restore all potentially used registers. */
+  if (IFFUNC_ISISR (sym->type))
+    {
+      if (!FUNC_ISNAKED( sym->type ))
         {
-          emit2 ("!profileexit");
+          emit2 ("!popa");
         }
+    }
+  else
+    {
+      /* if critical function then turn interrupts back on */
+      if (IFFUNC_ISCRITICAL (sym->type))
+        emit2 ("!ei");
+    }
 
-
-      /* 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))
+        emit2 ("retn");
+      else
+        emit2 ("reti");
+    }
+  else
+    {
+      /* Both banked and non-banked just ret */
       emit2 ("ret");
-
+    }
+      
+  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;
@@ -3084,6 +3329,9 @@ 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)
@@ -3095,6 +3343,11 @@ genRet (iCode * ic)
          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))))
@@ -3109,7 +3362,8 @@ genRet (iCode * ic)
              l = aopGet (AOP (IC_LEFT (ic)), offset,
                          FALSE);
              if (strcmp (_fReturn[offset], l))
-               emit2 ("ld %s,%s", _fReturn[offset++], l);
+               emit2 ("ld %s,%s", _fReturn[offset], l);
+              offset++;
            }
        }
     }
@@ -3358,11 +3612,16 @@ setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
       if (couldDestroyCarry (right) && couldDestroyCarry (result))
         {
           shiftIntoPair (0, right);
-          shiftIntoPair (1, result);
+          /* check result again, in case right == result */
+          if (couldDestroyCarry (result))
+            shiftIntoPair (1, result);
         }
       else if (couldDestroyCarry (right))
         {
-          shiftIntoPair (0, right);
+          if (getPairId (result) == PAIR_HL)
+            _G.preserveCarry = TRUE;
+          else
+            shiftIntoPair (0, right);
         }
       else if (couldDestroyCarry (result))
         {
@@ -3396,7 +3655,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);
@@ -3564,7 +3823,7 @@ genPlus (iCode * ic)
           goto release;
         }
     }
-
+  
   setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
 
   while (size--)
@@ -3593,6 +3852,7 @@ genPlus (iCode * ic)
     }
 
 release:
+  _G.preserveCarry = FALSE;
   freeAsmop (IC_LEFT (ic), NULL, ic);
   freeAsmop (IC_RIGHT (ic), NULL, ic);
   freeAsmop (IC_RESULT (ic), NULL, ic);
@@ -3796,6 +4056,7 @@ genMinus (iCode * ic)
     }
 
 release:
+  _G.preserveCarry = FALSE;
   freeAsmop (IC_LEFT (ic), NULL, ic);
   freeAsmop (IC_RIGHT (ic), NULL, ic);
   freeAsmop (IC_RESULT (ic), NULL, ic);
@@ -3811,11 +4072,14 @@ genMult (iCode * ic)
   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 */
   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 ||
@@ -3846,10 +4110,13 @@ genMult (iCode * ic)
   if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
     {
       emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
-      emit2 ("ld a,e");
-      emit2 ("rlc a");
-      emit2 ("sbc a,a");
-      emit2 ("ld d,a");
+      if (!byteResult)
+        {
+          emit2 ("ld a,e");
+          emit2 ("rlc a");
+          emit2 ("sbc a,a");
+          emit2 ("ld d,a");
+       }
     }
   else
     {
@@ -3871,7 +4138,8 @@ genMult (iCode * ic)
           if (active == FALSE)
             {
               emit2 ("ld l,e");
-              emit2 ("ld h,d");
+              if (!byteResult)
+               emit2 ("ld h,d");
             }
           else
             {
@@ -3890,7 +4158,10 @@ genMult (iCode * ic)
       _G.stack.pushedDE = FALSE;
     }
 
-  commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
+  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);
@@ -4760,7 +5031,7 @@ genAnd (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;
@@ -4950,7 +5221,7 @@ genOr (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;
@@ -5108,7 +5379,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;
@@ -5185,9 +5456,9 @@ genXor (iCode * ic, iCode * ifx)
                continue;
              else
                {
-                 _moveA (aopGet (AOP (right), offset, FALSE));
+                 _moveA (aopGet (AOP (left), offset, FALSE));
                  emit2 ("xor a,%s",
-                           aopGet (AOP (left), offset, FALSE));
+                           aopGet (AOP (right), offset, FALSE));
                  aopPut (AOP (result), "a", offset);
                }
            }
@@ -5199,9 +5470,9 @@ genXor (iCode * ic, iCode * ifx)
                 }
              else
                {
-                 _moveA (aopGet (AOP (right), offset, FALSE));
+                 _moveA (aopGet (AOP (left), offset, FALSE));
                  emit2 ("xor a,%s",
-                           aopGet (AOP (left), offset, FALSE));
+                           aopGet (AOP (right), offset, FALSE));
                  aopPut (AOP (result), "a", offset);
                }
            }
@@ -5237,9 +5508,9 @@ genXor (iCode * ic, iCode * ifx)
               }
            else
              {
-               _moveA (aopGet (AOP (right), offset, FALSE));
+               _moveA (aopGet (AOP (left), offset, FALSE));
                emit2 ("xor a,%s",
-                         aopGet (AOP (left), offset, FALSE));
+                         aopGet (AOP (right), offset, FALSE));
              }
            aopPut (AOP (result), "a", offset);
          }
@@ -5770,6 +6041,9 @@ 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 */
 
@@ -5791,6 +6065,9 @@ genLeftShift (iCode * ic)
   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);
@@ -6044,6 +6321,9 @@ genRightShift (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 (!sameRegs (AOP (left), AOP (result)))
@@ -6063,6 +6343,9 @@ genRightShift (iCode * ic)
   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);
@@ -6571,7 +6854,7 @@ 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 */
@@ -6957,7 +7240,7 @@ genCast (iCode * ic)
   /* now depending on the sign of the destination */
   size = AOP_SIZE (result) - AOP_SIZE (right);
   /* Unsigned or not an integral type - right fill with zeros */
-  if (SPEC_USIGN (rtype) || !IS_SPEC (rtype) || AOP_TYPE(right)==AOP_CRY)
+  if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE(right)==AOP_CRY)
     {
       while (size--)
        aopPut (AOP (result), "!zero", offset++);
@@ -7014,9 +7297,44 @@ genReceive (iCode * ic)
 static void
 genDummyRead (iCode * ic)
 {
-  emit2 ("; genDummyRead not implemented");
+  operand *op;
+  int size, offset;
+
+  op = IC_RIGHT (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);
+    }
+  
+  op = IC_LEFT (ic);
+  if (op && IS_SYMOP (op))
+    {
+      aopOp (op, ic, FALSE, FALSE);
+  
+      /* general case */
+      size = AOP_SIZE (op);
+      offset = 0;
 
-  ic = ic;
+      while (size--)
+       {
+         _moveA (aopGet (AOP (op), offset, FALSE));
+         offset++;
+       }
+
+      freeAsmop (op, NULL, ic);
+    }
 }
 
 enum
@@ -7129,7 +7447,7 @@ _rleCommit(RLECTX *self)
     chunks.
 */
 static void
-_rleAppend(RLECTX *self, int c)
+_rleAppend(RLECTX *self, unsigned c)
 {
   int i;
 
@@ -7212,13 +7530,27 @@ genArrayInit (iCode * ic)
     
   if (type && type->next)
     {
-      elementSize = getSize(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;
 
@@ -7231,17 +7563,14 @@ genArrayInit (iCode * ic)
     {
       ix = iLoop->count;
 
-      if (ix != 0)
+      for (i = 0; i < ix; i++)
         {
-          for (i = 0; i < ix; i++)
+          for (eIndex = 0; eIndex < elementSize; eIndex++)
             {
-              for (eIndex = 0; eIndex < elementSize; eIndex++)
-                {
-                  val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
-                  _rleAppend(&rle, val);
-                }
+              val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
+              _rleAppend(&rle, val);
             }
-       }
+        }
        
       iLoop = iLoop->next;
     }
@@ -7555,12 +7884,23 @@ genZ80Code (iCode * lic)
     }
 
   _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 (cln != ic->lineno)
+      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));
@@ -7824,6 +8164,7 @@ genZ80Code (iCode * lic)
           break;
 
        case DUMMY_READ_VOLATILE:
+         emitDebug ("; genDummyRead");
          genDummyRead (ic);
          break;