* src/mcs51/gen.c (genFunction): optimize RECEIVE in reentrant
[fw/sdcc] / src / ds390 / gen.c
index d472def121beccea35767220bdd208722ab912a6..e5670acc03530c9791114e466cfdc17316beaeed 100644 (file)
@@ -31,6 +31,7 @@
 #include <ctype.h>
 
 #include "common.h"
+#include "main.h"
 #include "ralloc.h"
 #include "gen.h"
 #include "SDCCglobl.h"
@@ -79,6 +80,7 @@ static struct
     short dptrInUse;
     short dptr1InUse;
     set *sendSet;
+    iCode *current_iCode;
   }
 _G;
 
@@ -130,6 +132,9 @@ static unsigned char SRMask[] =
                                emitcode ("","!tlabeldef",lbl->key+100);        \
                        }}
 
+static int _currentDPS;                /* Current processor DPS. */
+static int _desiredDPS;                /* DPS value compiler thinks we should be using. */
+static int _lazyDPS = 0;       /* if non-zero, we are doing lazy evaluation of DPS changes. */
 
 /*-----------------------------------------------------------------*/
 /* emitcode - writes the code into a file : for now it is simple    */
@@ -177,6 +182,8 @@ emitcode (char *inst, char *fmt,...)
     
     lineCurr->isInline = _G.inLine;
     lineCurr->isDebug = _G.debugLine;
+    lineCurr->ic = _G.current_iCode;
+    lineCurr->aln = ds390newAsmLineNode(_currentDPS);
     va_end (ap);
 }
 
@@ -310,9 +317,6 @@ newAsmop (short type)
   return aop;
 }
 
-static int _currentDPS;                /* Current processor DPS. */
-static int _desiredDPS;                /* DPS value compiler thinks we should be using. */
-static int _lazyDPS = 0;       /* if non-zero, we are doing lazy evaluation of DPS changes. */
 
 /*-----------------------------------------------------------------*/
 /* genSetDPTR: generate code to select which DPTR is in use (zero  */
@@ -438,6 +442,72 @@ pointerCode (sym_link * etype)
 
 }
 
+/*-----------------------------------------------------------------*/
+/* leftRightUseAcc - returns size of accumulator use by operands   */
+/*-----------------------------------------------------------------*/
+static int
+leftRightUseAcc(iCode *ic)
+{
+  operand *op;
+  int size;
+  int accuseSize = 0;
+  int accuse = 0;
+  
+  if (!ic)
+    {
+      werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
+             "null iCode pointer");
+      return 0;
+    }
+
+  if (ic->op == IFX)
+    {
+      op = IC_COND (ic);
+      if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
+        {
+          accuse = 1;
+          size = getSize (OP_SYMBOL (op)->type);
+          if (size>accuseSize)
+            accuseSize = size;
+        }
+    }
+  else if (ic->op == JUMPTABLE)
+    {
+      op = IC_JTCOND (ic);
+      if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
+        {
+          accuse = 1;
+          size = getSize (OP_SYMBOL (op)->type);
+          if (size>accuseSize)
+            accuseSize = size;
+        }
+    }
+  else
+    {
+      op = IC_LEFT (ic);
+      if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
+        {
+          accuse = 1;
+          size = getSize (OP_SYMBOL (op)->type);
+          if (size>accuseSize)
+            accuseSize = size;
+        }
+      op = IC_RIGHT (ic);
+      if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
+        {
+          accuse = 1;
+          size = getSize (OP_SYMBOL (op)->type);
+          if (size>accuseSize)
+            accuseSize = size;
+        }
+    }
+  
+  if (accuseSize)
+    return accuseSize;
+  else
+    return accuse;
+}
+
 /*-----------------------------------------------------------------*/
 /* aopForSym - for a true symbol                                   */
 /*-----------------------------------------------------------------*/
@@ -446,10 +516,17 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
 {
   asmop *aop;
   memmap *space = SPEC_OCLS (sym->etype);
+  int accuse = leftRightUseAcc (ic);
 
   /* if already has one */
   if (sym->aop)
-    return sym->aop;
+    {
+      if ((sym->aop->type == AOP_DPTR && useDP2)
+          || (sym->aop->type == AOP_DPTR2 && !useDP2))
+       sym->aop = NULL;
+      else
+        return sym->aop;
+    }
 
   /* assign depending on the storage class */
   /* if it is on the stack or indirectly addressable */
@@ -467,10 +544,10 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
 
          if (sym->onStack)
            {
-             if (_G.accInUse)
+             if (_G.accInUse || accuse)
                emitcode ("push", "acc");
 
-             if (_G.bInUse)
+             if (_G.bInUse || (accuse>1))
                emitcode ("push", "b");
 
              emitcode ("mov", "a,_bp");
@@ -481,10 +558,10 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
              emitcode ("mov", "%s,a",
                        aop->aopu.aop_ptr->name);
 
-             if (_G.bInUse)
+             if (_G.bInUse || (accuse>1))
                emitcode ("pop", "b");
 
-             if (_G.accInUse)
+             if (_G.accInUse || accuse)
                emitcode ("pop", "acc");
            }
          else
@@ -518,14 +595,20 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
        if (stack_val < 0 && stack_val > -5) { /* between -5 & -1 */
            if (useDP2) {
                if (options.model == MODEL_FLAT24)
-                   emitcode ("mov", "dpx1,#!constbyte", (options.stack_loc >> 16) & 0xff);
-               TR_DPTR("#2");
+               {
+                   emitcode ("mov", "dpx1,#!constbyte",
+                             (options.stack_loc >> 16) & 0xff);
+               }
                emitcode ("mov", "dph1,_bpx+1");
+               
                emitcode ("mov", "dpl1,_bpx");
                emitcode ("mov","dps,#1");
            } else {
                if (options.model == MODEL_FLAT24)
-                   emitcode ("mov", "dpx,#!constbyte", (options.stack_loc >> 16) & 0xff);
+               {
+                   emitcode ("mov", "dpx,#!constbyte",
+                             (options.stack_loc >> 16) & 0xff);
+               }
                emitcode ("mov", "dph,_bpx+1");
                emitcode ("mov", "dpl,_bpx");
            }
@@ -537,10 +620,10 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
                emitcode("mov","dps,#0");
            }
        }  else {
-           if (_G.accInUse)
+           if (_G.accInUse || accuse)
                emitcode ("push", "acc");
            
-           if (_G.bInUse)
+           if (_G.bInUse || (accuse>1))
                emitcode ("push", "b");
        
            emitcode ("mov", "a,_bpx");
@@ -551,21 +634,26 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
            emitcode ("subb","a,#!constbyte",(stack_val >> 8) & 0xff);
            if (useDP2) {
                if (options.model == MODEL_FLAT24)
-                   emitcode ("mov", "dpx1,#!constbyte", (options.stack_loc >> 16) & 0xff);
-               TR_DPTR("#2");
+               {
+                   emitcode ("mov", "dpx1,#!constbyte",
+                             (options.stack_loc >> 16) & 0xff);
+               }
                emitcode ("mov", "dph1,a");
                emitcode ("mov", "dpl1,b");
            } else {
                if (options.model == MODEL_FLAT24)
-                   emitcode ("mov", "dpx,#!constbyte", (options.stack_loc >> 16) & 0xff);
+               {
+                   emitcode ("mov", "dpx,#!constbyte",
+                             (options.stack_loc >> 16) & 0xff);
+               }
                emitcode ("mov", "dph,a");
                emitcode ("mov", "dpl,b");
            }
            
-           if (_G.bInUse)
+           if (_G.bInUse || (accuse>1))
                emitcode ("pop", "b");
            
-           if (_G.accInUse)
+           if (_G.accInUse || accuse)
                emitcode ("pop", "acc");
        }
        sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
@@ -591,14 +679,14 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
     }
 
   /* special case for a function */
-  if (IS_FUNC (sym->type))
+  if (IS_FUNC (sym->type) && !(sym->isitmp))
     {
       sym->aop = aop = newAsmop (AOP_IMMD);
-      aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);  
+      aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
       aop->size = FPTRSIZE;
       return aop;
     }
-  
+
   /* only remaining is far space */
   /* in which case DPTR gets the address */
   sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
@@ -784,6 +872,14 @@ operandsEqu (operand * op1, operand * op2)
       (sym2->usl.spillLoc == sym1))
     return TRUE;
 
+  /* are they spilt to the same location */
+  if (IS_ITEMP (op2) &&
+      IS_ITEMP (op1) &&
+      sym2->isspilt &&
+      sym1->isspilt &&
+      (sym1->usl.spillLoc == sym2->usl.spillLoc))
+    return TRUE;
+    
   return FALSE;
 }
 
@@ -843,13 +939,23 @@ aopOp (operand * op, iCode * ic, bool result, bool useDP2)
 
   /* if already has a asmop then continue */
   if (op->aop)
-    return;
+    {
+      if ((op->aop->type == AOP_DPTR && useDP2)
+          || (op->aop->type == AOP_DPTR2 && !useDP2))
+       op->aop = NULL;
+      else
+        return;
+    }
 
   /* if the underlying symbol has a aop */
   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
     {
       op->aop = OP_SYMBOL (op)->aop;
-      return;
+      if ((op->aop->type == AOP_DPTR && useDP2)
+          || (op->aop->type == AOP_DPTR2 && !useDP2))
+       op->aop = NULL;
+      else
+        return;
     }
 
   /* if this is a true symbol */
@@ -928,13 +1034,22 @@ aopOp (operand * op, iCode * ic, bool result, bool useDP2)
          aop->aopu.dptr = sym->dptr;
          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, useDP2);
+      
+      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, useDP2);
+         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;
     }
@@ -1104,6 +1219,8 @@ aopGet (asmop *aop,
   /* depending on type */
   switch (aop->type)
     {
+    case AOP_DUMMY:
+      return zero;
 
     case AOP_R0:
     case AOP_R1:
@@ -1305,6 +1422,10 @@ aopPut (asmop * aop, char *s, int offset)
   /* depending on where it is ofcourse */
   switch (aop->type)
     {
+    case AOP_DUMMY:
+      MOVA (s);                /* read s in case it was volatile */
+      break;
+      
     case AOP_DIR:
         if (offset)
        {
@@ -1596,47 +1717,6 @@ reAdjustPreg (asmop * aop)
       emitcode("nop", "; workaround for DS80C390 div bug.");  \
     }
 
-/*-----------------------------------------------------------------*/
-/* genNotFloat - generates not for float operations              */
-/*-----------------------------------------------------------------*/
-static void
-genNotFloat (operand * op, operand * res)
-{
-  int size, offset;
-  symbol *tlbl;
-
-  D (emitcode (";", "genNotFloat "););
-
-  /* we will put 127 in the first byte of
-     the result */
-  aopPut (AOP (res), "#127", 0);
-  size = AOP_SIZE (op) - 1;
-  offset = 1;
-
-  _startLazyDPSEvaluation ();
-  MOVA(aopGet(op->aop, offset++, FALSE, FALSE, NULL));
-
-  while (size--)
-    {
-      emitcode ("orl", "a,%s",
-               aopGet (op->aop,
-                       offset++, FALSE, FALSE,
-                       DP2_RESULT_REG));
-    }
-  _endLazyDPSEvaluation ();
-
-  tlbl = newiTempLabel (NULL);
-  aopPut (res->aop, one, 1);
-  emitcode ("jz", "!tlabel", (tlbl->key + 100));
-  aopPut (res->aop, zero, 1);
-  emitcode ("", "!tlabeldef", (tlbl->key + 100));
-
-  size = res->aop->size - 2;
-  offset = 2;
-  /* put zeros in the rest */
-  while (size--)
-    aopPut (res->aop, zero, offset++);
-}
 
 /*-----------------------------------------------------------------*/
 /* opIsGptr: returns non-zero if the passed operand is       */
@@ -1786,7 +1866,6 @@ static void
 genNot (iCode * ic)
 {
   symbol *tlbl;
-  sym_link *optype = operandType (IC_LEFT (ic));
 
   D (emitcode (";", "genNot "););
 
@@ -1803,13 +1882,6 @@ genNot (iCode * ic)
       goto release;
     }
 
-  /* if type float then do float */
-  if (IS_FLOAT (optype))
-    {
-      genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
-      goto release;
-    }
-
   toBoolean (IC_LEFT (ic));
 
   tlbl = newiTempLabel (NULL);
@@ -1917,7 +1989,7 @@ genUminus (iCode * ic)
 
   /* assign asmops */
   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
-  aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
+  aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
 
   /* if both in bit space then special
      case */
@@ -2034,8 +2106,8 @@ saveRegisters (iCode * lic)
 
   /* if the registers have been saved already then
      do nothing */
-  if (ic->regsSaved || 
-      (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic)))))
+  if (ic->regsSaved 
+      || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
     return ;
 
   /* special case if DPTR alive across a function call then must save it 
@@ -2510,6 +2582,18 @@ static void genSend(set *sendSet)
     }
 }
 
+static void
+adjustEsp(const char *reg)
+{
+    emitcode ("anl","%s,#3", reg);
+    if (TARGET_IS_DS400)
+    {
+       emitcode ("orl","%s,#!constbyte",
+                 reg,
+                 (options.stack_loc >> 8) & 0xff);
+    }
+}
+
 /*-----------------------------------------------------------------*/
 /* genCall - generates a call statement                            */
 /*-----------------------------------------------------------------*/
@@ -2526,7 +2610,7 @@ genCall (iCode * ic)
      the same register bank then we need to save the
      destination registers on the stack */
   dtype = operandType (IC_LEFT (ic));
-  if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
+  if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
       IFFUNC_ISISR (currFunc->type))
   {
@@ -2595,9 +2679,16 @@ genCall (iCode * ic)
          if (size > 1)
            {
              emitcode ("mov", "b,%s", fReturn[1]);
+             _G.bInUse++;
            }
 
+         _G.accInUse++;
          aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
+         _G.accInUse--;
+         
+         if (size > 1)
+           _G.bInUse--;
+
          aopPut (AOP (IC_RESULT (ic)), "a", 0);
 
          if (size > 1)
@@ -2608,9 +2699,9 @@ genCall (iCode * ic)
        }
       else
        {
-         _G.accInUse++;
+         _G.bInUse++;
          aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
-         _G.accInUse--;
+         _G.bInUse--;
 
          assignResultValue (IC_RESULT (ic));
 
@@ -2635,7 +2726,7 @@ genCall (iCode * ic)
              emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
              emitcode ("mov","sp,a");
              emitcode ("mov","a,esp");
-             emitcode ("anl","a,#3");
+             adjustEsp("a");
              emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
              emitcode ("mov","esp,a");   
              UNPROTECT_SP;
@@ -2682,7 +2773,7 @@ genPcall (iCode * ic)
      the same register bank then we need to save the
      destination registers on the stack */
   dtype = operandType (IC_LEFT (ic));
-  if (currFunc && dtype && !IFFUNC_ISNAKED(dtype) &&
+  if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
       IFFUNC_ISISR (currFunc->type) &&
       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
@@ -2753,7 +2844,7 @@ genPcall (iCode * ic)
              emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
              emitcode ("mov","sp,a");
              emitcode ("mov","a,esp");
-             emitcode ("anl","a,#3");
+             adjustEsp("a");
              emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
              emitcode ("mov","esp,a");   
              UNPROTECT_SP;
@@ -2809,22 +2900,22 @@ resultRemat (iCode * ic)
 /*-----------------------------------------------------------------*/
 /* inExcludeList - return 1 if the string is in exclude Reg list   */
 /*-----------------------------------------------------------------*/
+static int
+regsCmp(void *p1, void *p2)
+{
+  return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
+}
+
 static bool
 inExcludeList (char *s)
 {
-  int i = 0;
+  const char *p = setFirstItem(options.excludeRegsSet);
 
-  if (options.excludeRegs[i] &&
-      STRCASECMP (options.excludeRegs[i], "none") == 0)
+  if (p == NULL || STRCASECMP(p, "none") == 0)
     return FALSE;
 
-  for (i = 0; options.excludeRegs[i]; i++)
-    {
-      if (options.excludeRegs[i] &&
-         STRCASECMP (s, options.excludeRegs[i]) == 0)
-       return TRUE;
-    }
-  return FALSE;
+
+  return isinSetWith(options.excludeRegsSet, s, regsCmp);
 }
 
 /*-----------------------------------------------------------------*/
@@ -2856,9 +2947,6 @@ genFunction (iCode * ic)
   
   if (options.stack_probe) 
       emitcode ("lcall","__stack_probe");
-  /* if critical function then turn interrupts off */
-  if (IFFUNC_ISCRITICAL (ftype))
-    emitcode ("clr", "ea");
 
   /* here we need to generate the equates for the
      register bank if required */
@@ -2929,12 +3017,10 @@ genFunction (iCode * ic)
                  /* save the registers used */
                  for (i = 0; i < sym->regsUsed->size; i++)
                    {
-                     if (bitVectBitValue (sym->regsUsed, i) ||
-                         (ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
+                     if (bitVectBitValue (sym->regsUsed, i))
                        emitcode ("push", "%s", ds390_regWithIdx (i)->dname);
                    }
                }
-
            }
          else
            {
@@ -3054,8 +3140,7 @@ genFunction (iCode * ic)
              /* save the registers used */
              for (i = 0; i < sym->regsUsed->size; i++)
                {
-                 if (bitVectBitValue (sym->regsUsed, i) ||
-                     (ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
+                 if (bitVectBitValue (sym->regsUsed, i))
                    {
                      emitcode ("push", "%s", ds390_regWithIdx (i)->dname);
                      _G.nRegsSaved++;
@@ -3080,7 +3165,7 @@ genFunction (iCode * ic)
          emitcode ("push","_bpx+1");
          emitcode ("mov","_bpx,%s",spname);
          emitcode ("mov","_bpx+1,esp");
-         emitcode ("anl","_bpx+1,#3");
+         adjustEsp("_bpx+1");
       } else {
          if (options.useXstack) {
              emitcode ("mov", "r0,%s", spname);
@@ -3109,7 +3194,7 @@ genFunction (iCode * ic)
              emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
              emitcode ("mov","sp,a");
              emitcode ("mov","a,esp");
-             emitcode ("anl","a,#3");
+             adjustEsp("a");
              emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
              emitcode ("mov","esp,a");
              UNPROTECT_SP;
@@ -3137,6 +3222,17 @@ genFunction (iCode * ic)
       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
       emitcode ("mov", "_spx,a");
     }
+  
+  /* if critical function then turn interrupts off */
+  if (IFFUNC_ISCRITICAL (ftype))
+    {
+      symbol *tlbl = newiTempLabel (NULL);
+      emitcode ("setb", "c");
+      emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
+      emitcode ("clr", "c");
+      emitcode ("", "%05d$:", (tlbl->key + 100));
+      emitcode ("push", "psw"); /* save old ea via c in psw */
+    }
 
 }
 
@@ -3147,6 +3243,11 @@ static void
 genEndFunction (iCode * ic)
 {
   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
+  lineNode *lnp = lineCurr;
+  bitVect *regsUsed;
+  bitVect *regsUsedPrologue;
+  bitVect *regsUnneeded;
+  int idx;
 
   D (emitcode (";", "genEndFunction "););
 
@@ -3156,6 +3257,12 @@ genEndFunction (iCode * ic)
       return;
   }
 
+  if (IFFUNC_ISCRITICAL (sym->type))
+    {
+      emitcode ("pop", "psw"); /* restore ea via c in psw */
+      emitcode ("mov", "ea,c");
+    }
+  
   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
 
@@ -3232,12 +3339,10 @@ genEndFunction (iCode * ic)
                  /* save the registers used */
                  for (i = sym->regsUsed->size; i >= 0; i--)
                    {
-                     if (bitVectBitValue (sym->regsUsed, i) ||
-                         (ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
+                     if (bitVectBitValue (sym->regsUsed, i))
                        emitcode ("pop", "%s", ds390_regWithIdx (i)->dname);
                    }
                }
-
            }
          else
            {
@@ -3300,9 +3405,6 @@ genEndFunction (iCode * ic)
       if (!inExcludeList ("acc"))
        emitcode ("pop", "acc");
 
-      if (IFFUNC_ISCRITICAL (sym->type))
-       emitcode ("setb", "ea");
-
       /* if debug then send end of function */
       if (options.debug && currFunc) {
          _G.debugLine = 1;
@@ -3320,9 +3422,6 @@ genEndFunction (iCode * ic)
     }
   else
     {
-      if (IFFUNC_ISCRITICAL (sym->type))
-       emitcode ("setb", "ea");
-
       if (IFFUNC_CALLEESAVES(sym->type))
        {
          int i;
@@ -3333,12 +3432,10 @@ genEndFunction (iCode * ic)
              /* save the registers used */
              for (i = sym->regsUsed->size; i >= 0; i--)
                {
-                 if (bitVectBitValue (sym->regsUsed, i) ||
-                     (ds390_ptrRegReq && (i == R0_IDX || i == R1_IDX)))
+                 if (bitVectBitValue (sym->regsUsed, i))
                    emitcode ("pop", "%s", ds390_regWithIdx (i)->dname);
                }
            }
-
        }
 
       /* if debug then send end of function */
@@ -3358,6 +3455,111 @@ genEndFunction (iCode * ic)
       emitcode ("ret", "");
     }
 
+  if (!port->peep.getRegsRead || !port->peep.getRegsWritten)
+    return;
+  
+  /* If this was an interrupt handler using bank 0 that called another */
+  /* function, then all registers must be saved; nothing to optimized. */
+  if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
+      && !FUNC_REGBANK(sym->type))
+    return;
+    
+  /* There are no push/pops to optimize if not callee-saves or ISR */
+  if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
+    return;
+  
+  /* If there were stack parameters, we cannot optimize without also    */
+  /* fixing all of the stack offsets; this is too dificult to consider. */
+  if (FUNC_HASSTACKPARM(sym->type))
+    return;
+  
+  /* Compute the registers actually used */
+  regsUsed = newBitVect (ds390_nRegs);
+  regsUsedPrologue = newBitVect (ds390_nRegs);
+  while (lnp)
+    {
+      if (lnp->ic && lnp->ic->op == FUNCTION)
+        regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
+      else
+        regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
+      
+      if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
+          && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
+       break;
+      if (!lnp->prev)
+        break;
+      lnp = lnp->prev;
+    }
+
+  if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
+      && !bitVectBitValue (regsUsed, DPS_IDX))
+    {
+      bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
+    }
+    
+  if (bitVectBitValue (regsUsedPrologue, CND_IDX)
+      && !bitVectBitValue (regsUsed, CND_IDX))
+    {
+      regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
+      if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK(sym->type)
+          && !sym->stack)
+        bitVectUnSetBit (regsUsed, CND_IDX);
+    }
+  else
+    regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
+    
+  /* If this was an interrupt handler that called another function */
+  /* function, then assume working registers may be modified by it. */
+  if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
+    {
+      regsUsed = bitVectSetBit (regsUsed, AP_IDX);
+      regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
+      regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
+      regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
+      regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
+      regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
+      regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
+      regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
+      regsUsed = bitVectSetBit (regsUsed, B_IDX);
+      regsUsed = bitVectSetBit (regsUsed, A_IDX);
+      regsUsed = bitVectSetBit (regsUsed, CND_IDX);
+    }
+
+  /* Remove the unneeded push/pops */
+  regsUnneeded = newBitVect (ds390_nRegs);
+  while (lnp)
+    {
+      if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
+        {
+         if (!strncmp(lnp->line, "push", 4))
+           {
+             idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
+             if (idx>=0 && !bitVectBitValue (regsUsed, idx))
+               {
+                 connectLine (lnp->prev, lnp->next);
+                 regsUnneeded = bitVectSetBit (regsUnneeded, idx);
+               }
+           }
+         if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
+           {
+             idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
+             if (idx>=0 && !bitVectBitValue (regsUsed, idx))
+               {
+                 connectLine (lnp->prev, lnp->next);
+                 regsUnneeded = bitVectSetBit (regsUnneeded, idx);
+               }
+           }
+       }
+      lnp = lnp->next;
+    }  
+  
+  for (idx = 0; idx < regsUnneeded->size; idx++)
+    if (bitVectBitValue (regsUnneeded, idx))
+      emitcode ("", ";\teliminated unneeded push/pop %s", ds390_regWithIdx (idx)->dname);
+  
+  freeBitVect (regsUnneeded);
+  freeBitVect (regsUsed);
+  freeBitVect (regsUsedPrologue);
 }
 
 /*-----------------------------------------------------------------*/
@@ -3799,7 +4001,7 @@ bool aopOp3(iCode * ic)
 {
     bool dp1InUse, dp2InUse;
     bool useDp2;
-    
+
     // First, generate the right opcode. DPTR may be used if neither left nor result are
     // of type AOP_STR.
     
@@ -3812,11 +4014,21 @@ bool aopOp3(iCode * ic)
 //            AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
 //            AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
 //            AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
-//      );      
-
+//      );
     
-    // Right uses DPTR unless left or result is an AOP_STR.
-    aopOp (IC_RIGHT(ic),ic,FALSE, AOP_IS_STR(IC_LEFT(ic)) || AOP_IS_STR(IC_RESULT(ic)));
+    // Right uses DPTR unless left or result is an AOP_STR; however,
+    // if right is an AOP_STR, it must use DPTR regardless.
+    if ((AOP_IS_STR(IC_LEFT(ic)) || AOP_IS_STR(IC_RESULT(ic)))
+     && !AOP_IS_STR(IC_RIGHT(ic)))
+    {
+       useDp2 = TRUE;
+    }
+    else
+    {
+       useDp2 = FALSE;
+    }
+       
+    aopOp (IC_RIGHT(ic),ic,FALSE, useDp2);
     
     // if the right used DPTR, left MUST use DPTR2.
     // if the right used DPTR2, left MUST use DPTR.
@@ -3845,16 +4057,34 @@ bool aopOp3(iCode * ic)
     }
 
     aopOp(IC_LEFT(ic), ic, FALSE, useDp2);
-    
+
+        
     // We've op'd the left & right. So, if left or right are the same operand as result, 
     // we know aopOp will succeed, and we can just do it & bail.
-    if (isOperandEqual(IC_LEFT(ic),IC_RESULT(ic)) ||
-       isOperandEqual(IC_RIGHT(ic),IC_RESULT(ic)))
-    {
+    if (isOperandEqual(IC_LEFT(ic),IC_RESULT(ic)))
+      {
+       aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
+       return TRUE;
+      }
+    if (isOperandEqual(IC_RIGHT(ic),IC_RESULT(ic)))
+      {
 //     D(emitcode(";", "aopOp3: (left | right) & result equal"););
-       aopOp(IC_RESULT(ic),ic,TRUE, FALSE);
+       aopOp(IC_RESULT(ic),ic,TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
        return TRUE;
-    }
+      }
+    
+    // Operands may be equivalent (but not equal) if they share a spill location. If
+    // so, use the same DPTR or DPTR2.
+    if (operandsEqu (IC_LEFT(ic), IC_RESULT(ic)))
+      {
+        aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
+       return TRUE;
+      }
+    if (operandsEqu (IC_RIGHT(ic), IC_RESULT(ic)))
+      {
+        aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
+       return TRUE;
+      }
     
     // Note which dptrs are currently in use.
     dp1InUse = AOP_USESDPTR(IC_LEFT(ic)) || AOP_USESDPTR(IC_RIGHT(ic));
@@ -3967,7 +4197,7 @@ genPlus (iCode * ic)
   if ( AOP_IS_STR(IC_LEFT(ic)) &&
       isOperandLiteral(IC_RIGHT(ic)) && OP_SYMBOL(IC_RESULT(ic))->ruonly) {
       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
-      size = floatFromVal (AOP (IC_RIGHT(ic))->aopu.aop_lit);
+      size = (int)floatFromVal (AOP (IC_RIGHT(ic))->aopu.aop_lit);
       if (size <= 9) {
          while (size--) emitcode ("inc","dptr");
       } else {
@@ -4492,9 +4722,11 @@ genMultOneByte (operand * left,
                operand * result,
                iCode   * ic)
 {
-  sym_link *opetype = operandType (result);
+  int size;
   symbol *lbl;
-
+  bool runtimeSign, compiletimeSign;
+  bool lUnsigned, rUnsigned;
+  
 
   /* (if two literals: the value is computed before) */
   /* if one literal, literal on the right */
@@ -4506,105 +4738,197 @@ genMultOneByte (operand * left,
       emitcode (";", "swapped left and right");
     }
 
-  if (SPEC_USIGN(opetype)
-      // ignore the sign of left and right, what else can we do?
-      || (SPEC_USIGN(operandType(left)) && 
-         SPEC_USIGN(operandType(right)))) {
-    // just an unsigned 8*8=8/16 multiply
-    //emitcode (";","unsigned");
-    emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
-    MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
-    emitcode ("mul", "ab");
-   
-    _G.accInUse++; _G.bInUse++;
-    aopOp(result, ic, TRUE, FALSE);
-      
-      if (AOP_SIZE(result)<1 || AOP_SIZE(result)>2) 
-      {
-         // this should never happen
-         fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n", 
-                  AOP_SIZE(result), __FILE__, lineno);
-         exit (1);
-      }      
-      
-    aopPut (AOP (result), "a", 0);
-    _G.accInUse--; _G.bInUse--;
-    if (AOP_SIZE(result)==2) 
+  /* (if two literals: the value is computed before) */
+  /* if one literal, literal on the right */
+  if (AOP_TYPE (left) == AOP_LIT)
     {
-      aopPut (AOP (result), "b", 1);
+      operand *t = right;
+      right = left;
+      left = t;
+      /* emitcode (";", "swapped left and right"); */
+    }
+  /* if no literal, unsigned on the right: shorter code */
+  if (   AOP_TYPE (right) != AOP_LIT
+      && SPEC_USIGN (getSpec (operandType (left))))
+    {
+      operand *t = right;
+      right = left;
+      left = t;
     }
-    return;
-  }
 
-  // we have to do a signed multiply
+  lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
+  rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
 
-  emitcode (";", "signed");
-  emitcode ("clr", "F0"); // reset sign flag
-  MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+  if ((lUnsigned && rUnsigned)
+/* sorry, I don't know how to get size
+   without calling aopOp (result,...);
+   see Feature Request  */
+      /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
+                  no need to take care about the signedness! */
+    {
+      /* just an unsigned 8 * 8 = 8 multiply
+         or 8u * 8u = 16u */
+      /* emitcode (";","unsigned"); */
+      emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
+      MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+      emitcode ("mul", "ab");
+    
+      _G.accInUse++; _G.bInUse++;
+      aopOp (result, ic, TRUE, FALSE);
+      size = AOP_SIZE (result);
+  
+      if (size < 1 || size > 2)
+        {
+          /* this should never happen */
+          fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
+                  size, __FILE__, lineno);
+          exit (1);
+        }
+  
+      aopPut (AOP (result), "a", 0);
+      _G.accInUse--; _G.bInUse--;
+      if (size == 2) 
+       aopPut (AOP (result), "b", 1);
+      return;
+    }
 
-  lbl=newiTempLabel(NULL);
-  emitcode ("jnb", "acc.7,!tlabel",  lbl->key+100);
-  // left side is negative, 8-bit two's complement, this fails for -128
-  emitcode ("setb", "F0"); // set sign flag
-  emitcode ("cpl", "a");
-  emitcode ("inc", "a");
+  /* we have to do a signed multiply */
+  /* emitcode (";", "signed"); */
+  
+  /* now sign adjust for both left & right */
 
-  emitcode ("", "!tlabeldef", lbl->key+100);
+  /* let's see what's needed: */
+  /* apply negative sign during runtime */
+  runtimeSign = FALSE;
+  /* negative sign from literals */
+  compiletimeSign = FALSE;
 
-  /* if literal */
-  if (AOP_TYPE(right)==AOP_LIT) {
-    signed char val=floatFromVal (AOP (right)->aopu.aop_lit);
-    /* AND literal negative */
-    if ((int) val < 0) {
-      emitcode ("cpl", "F0"); // complement sign flag
-      emitcode ("mov", "b,#!constbyte", -val);
-    } else {
-      emitcode ("mov", "b,#!constbyte", val);
+  if (!lUnsigned)
+    {
+      if (AOP_TYPE(left) == AOP_LIT)
+        {
+          /* signed literal */
+          signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
+          if (val < 0)
+            compiletimeSign = TRUE;
+        }
+      else
+        /* signed but not literal */
+        runtimeSign = TRUE;
     }
-  } else {
-    lbl=newiTempLabel(NULL);
-    emitcode ("mov", "b,a");
-    emitcode ("mov", "a,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
-    emitcode ("jnb", "acc.7,!tlabel", lbl->key+100);
-    // right side is negative, 8-bit two's complement
-    emitcode ("cpl", "F0"); // complement sign flag
-    emitcode ("cpl", "a");
-    emitcode ("inc", "a");
-    emitcode ("", "!tlabeldef", lbl->key+100);
-  }
-  emitcode ("mul", "ab");
-    
-  _G.accInUse++;_G.bInUse++;
-  aopOp(result, ic, TRUE, FALSE);
-    
-  if (AOP_SIZE(result)<1 || AOP_SIZE(result)>2) 
-  {
-    // this should never happen
-      fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n", 
-              AOP_SIZE(result), __FILE__, lineno);
-      exit (1);
-  }    
-    
-  lbl=newiTempLabel(NULL);
-  emitcode ("jnb", "F0,!tlabel", lbl->key+100);
-  // only ONE op was negative, we have to do a 8/16-bit two's complement
-  emitcode ("cpl", "a"); // lsb
-  if (AOP_SIZE(result)==1) {
-    emitcode ("inc", "a");
-  } else {
-    emitcode ("add", "a,#1");
-    emitcode ("xch", "a,b");
-    emitcode ("cpl", "a"); // msb
-    emitcode ("addc", "a,#0");
-    emitcode ("xch", "a,b");
-  }
 
-  emitcode ("", "!tlabeldef", lbl->key+100);
-  aopPut (AOP (result), "a", 0);
-  _G.accInUse--;_G.bInUse--;
-  if (AOP_SIZE(result)==2) {
-    aopPut (AOP (result), "b", 1);
-  }
+  if (!rUnsigned)
+    {
+      if (AOP_TYPE(right) == AOP_LIT)
+        {
+          /* signed literal */
+          signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
+          if (val < 0)
+            compiletimeSign ^= TRUE;
+        }
+      else
+        /* signed but not literal */
+        runtimeSign = TRUE;
+    }
+
+  /* initialize F0, which stores the runtime sign */
+  if (runtimeSign)
+    {
+      if (compiletimeSign)
+       emitcode ("setb", "F0"); /* set sign flag */
+      else
+       emitcode ("clr", "F0"); /* reset sign flag */
+    }
+  
+  /* save the signs of the operands */
+  if (AOP_TYPE(right) == AOP_LIT)
+    {
+      signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
+
+      if (!rUnsigned && val < 0)
+        emitcode ("mov", "b,#!constbyte", -val);
+      else
+        emitcode ("mov", "b,#!constbyte", (unsigned char) val);
+    }
+  else /* ! literal */
+    {
+      if (rUnsigned)  /* emitcode (";", "signed"); */
+        emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
+      else
+        {
+         MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
+         lbl = newiTempLabel (NULL);
+         emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
+         emitcode ("cpl", "F0"); /* complement sign flag */
+         emitcode ("cpl", "a");  /* 2's complement */
+         emitcode ("inc", "a");
+         emitcode ("", "!tlabeldef", lbl->key + 100);
+         emitcode ("mov", "b,a");
+       }
+    }
+
+  if (AOP_TYPE(left) == AOP_LIT)
+    {
+      signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
+
+      if (!lUnsigned && val < 0)
+        emitcode ("mov", "a,#!constbyte", -val);
+      else
+        emitcode ("mov", "a,#!constbyte", (unsigned char) val);
+    }
+  else /* ! literal */
+    {
+      if (lUnsigned)  /* emitcode (";", "signed"); */
+
+        emitcode ("mov", "a,%s", aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+      else
+        {
+         MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+         lbl = newiTempLabel (NULL);
+         emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
+         emitcode ("cpl", "F0"); /* complement sign flag */
+         emitcode ("cpl", "a");  /* 2's complement */
+         emitcode ("inc", "a");
+         emitcode ("", "!tlabeldef", lbl->key + 100);
+       }
+    }
+
+  /* now the multiplication */
+  emitcode ("mul", "ab");
+  _G.accInUse++;_G.bInUse++;
+  aopOp(result, ic, TRUE, FALSE);
+  size = AOP_SIZE (result);
+
+  if (size < 1 || size > 2) 
+    {
+      /* this should never happen */
+      fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n", 
+               size, __FILE__, lineno);
+      exit (1);
+    }    
+    
+  if (runtimeSign || compiletimeSign)
+    {
+      lbl = newiTempLabel (NULL);
+      if (runtimeSign)
+        emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
+      emitcode ("cpl", "a"); /* lsb 2's complement */
+      if (size != 2)
+        emitcode ("inc", "a"); /* inc doesn't set carry flag */
+      else
+        {
+          emitcode ("add", "a,#1"); /* this sets carry flag */
+          emitcode ("xch", "a,b");
+          emitcode ("cpl", "a"); /* msb 2's complement */
+          emitcode ("addc", "a,#0");
+          emitcode ("xch", "a,b");
+        }
+      emitcode ("", "!tlabeldef", lbl->key + 100);
+    }
+  aopPut (AOP (result), "a", 0);
+  _G.accInUse--;_G.bInUse--;
+  if (size == 2)
+    aopPut (AOP (result), "b", 1);
 }
 
 /*-----------------------------------------------------------------*/
@@ -4634,7 +4958,7 @@ static void genMultTwoByte (operand *left, operand *right,
        if (!umult) {
                emitcode("clr","F0");
                if (AOP_TYPE(right) == AOP_LIT) {
-                       int val=floatFromVal (AOP (right)->aopu.aop_lit);
+                       int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
                        if (val < 0) {
                                emitcode("setb","F0");
                                val = -val;
@@ -4843,94 +5167,182 @@ genDivOneByte (operand * left,
               operand * result,
               iCode   * ic)
 {
-  sym_link *opetype = operandType (result);
+  bool lUnsigned, rUnsigned;
+  bool runtimeSign, compiletimeSign;
   char *l;
   symbol *lbl;
   int size, offset;
 
   offset = 1;
+  lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
+  rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
+  
   /* signed or unsigned */
-  if (SPEC_USIGN (opetype))
+  if (lUnsigned && rUnsigned)
     {
-       /* unsigned is easy */
-       LOAD_AB_FOR_DIV (left, right, l);
-       emitcode ("div", "ab");
+      /* unsigned is easy */
+      LOAD_AB_FOR_DIV (left, right, l);
+      emitcode ("div", "ab");
 
-       _G.accInUse++;
-       aopOp(result, ic, TRUE, FALSE);
-       aopPut (AOP (result), "a", 0);
-       _G.accInUse--;
+      _G.accInUse++;
+      aopOp (result, ic, TRUE, FALSE);
+      aopPut (AOP (result), "a", 0);
+      _G.accInUse--;
 
-       size = AOP_SIZE (result) - 1;
-       
-       while (size--)
-       {
-           aopPut (AOP (result), zero, offset++);
-       }
+      size = AOP_SIZE (result) - 1;
+      
+      while (size--)
+       aopPut (AOP (result), zero, offset++);
       return;
     }
 
   /* signed is a little bit more difficult */
 
-  /* save the signs of the operands */
-  MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
-  emitcode ("xrl", "a,%s", aopGet (AOP (right), 0, FALSE, TRUE, FALSE));
-  emitcode ("push", "acc");    /* save it on the stack */
-
   /* now sign adjust for both left & right */
-  MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
-  lbl = newiTempLabel (NULL);
-  emitcode ("jnb", "acc.7,!tlabel", (lbl->key + 100));
-  emitcode ("cpl", "a");
-  emitcode ("inc", "a");
-  emitcode ("", "!tlabeldef", (lbl->key + 100));
-  emitcode ("mov", "b,a");
 
-  /* sign adjust left side */
-  MOVA( aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+  /* let's see what's needed: */
+  /* apply negative sign during runtime */
+  runtimeSign = FALSE;
+  /* negative sign from literals */
+  compiletimeSign = FALSE;
 
-  lbl = newiTempLabel (NULL);
-  emitcode ("jnb", "acc.7,!tlabel", (lbl->key + 100));
-  emitcode ("cpl", "a");
-  emitcode ("inc", "a");
-  emitcode ("", "!tlabeldef", (lbl->key + 100));
+  if (!lUnsigned)
+    {
+      if (AOP_TYPE(left) == AOP_LIT)
+        {
+          /* signed literal */
+          signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
+          if (val < 0)
+            compiletimeSign = TRUE;
+        }
+      else
+        /* signed but not literal */
+        runtimeSign = TRUE;
+    }
+
+  if (!rUnsigned)
+    {
+      if (AOP_TYPE(right) == AOP_LIT)
+        {
+          /* signed literal */
+          signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
+          if (val < 0)
+            compiletimeSign ^= TRUE;
+        }
+      else
+        /* signed but not literal */
+        runtimeSign = TRUE;
+    }
+
+  /* initialize F0, which stores the runtime sign */
+  if (runtimeSign)
+    {
+      if (compiletimeSign)
+       emitcode ("setb", "F0"); /* set sign flag */
+      else
+       emitcode ("clr", "F0"); /* reset sign flag */
+    }
+
+  /* save the signs of the operands */
+  if (AOP_TYPE(right) == AOP_LIT)
+    {
+      signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
+
+      if (!rUnsigned && val < 0)
+        emitcode ("mov", "b,#0x%02x", -val);
+      else
+        emitcode ("mov", "b,#0x%02x", (unsigned char) val);
+    }
+  else /* ! literal */
+    {
+      if (rUnsigned)
+        emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
+      else
+        {
+          MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
+         lbl = newiTempLabel (NULL);
+         emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
+         emitcode ("cpl", "F0"); /* complement sign flag */
+         emitcode ("cpl", "a");  /* 2's complement */
+         emitcode ("inc", "a");
+         emitcode ("", "!tlabeldef", lbl->key + 100);
+          emitcode ("mov", "b,a");
+       }
+    }
 
+  if (AOP_TYPE(left) == AOP_LIT)
+    {
+      signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
+
+      if (!lUnsigned && val < 0)
+        emitcode ("mov", "a,#0x%02x", -val);
+      else
+        emitcode ("mov", "a,#0x%02x", (unsigned char) val);
+    }
+  else /* ! literal */
+    {
+      if (lUnsigned)
+        emitcode ("mov", "a,%s", aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+      else
+        {
+          MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+         lbl = newiTempLabel (NULL);
+         emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
+         emitcode ("cpl", "F0"); /* complement sign flag */
+         emitcode ("cpl", "a");  /* 2's complement */
+         emitcode ("inc", "a");
+         emitcode ("", "!tlabeldef", lbl->key + 100);
+       }
+    }
+  
   /* now the division */
   emitcode ("nop", "; workaround for DS80C390 div bug.");
   emitcode ("div", "ab");
-  /* we are interested in the lower order
-     only */
-  emitcode ("mov", "b,a");
-  lbl = newiTempLabel (NULL);
-  emitcode ("pop", "acc");
-  /* if there was an over flow we don't
-     adjust the sign of the result */
-  emitcode ("jb", "ov,!tlabel", (lbl->key + 100));
-  emitcode ("jnb", "acc.7,!tlabel", (lbl->key + 100));
-  CLRC;
-  emitcode ("clr", "a");
-  emitcode ("subb", "a,b");
-  emitcode ("mov", "b,a");
-  emitcode ("", "!tlabeldef", (lbl->key + 100));
-
-  /* now we are done */
-  _G.accInUse++;     _G.bInUse++;
-    aopOp(result, ic, TRUE, FALSE);
-    
-    aopPut (AOP (result), "b", 0);
-    
-    size = AOP_SIZE (result) - 1;
-    
-    if (size > 0)
+  
+  if (runtimeSign || compiletimeSign)
     {
-      emitcode ("mov", "c,b.7");
-      emitcode ("subb", "a,acc");
+      lbl = newiTempLabel (NULL);
+      if (runtimeSign)
+        emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
+      emitcode ("cpl", "a"); /* lsb 2's complement */
+      emitcode ("inc", "a");
+      emitcode ("", "!tlabeldef", lbl->key + 100);
+
+      _G.accInUse++;     _G.bInUse++;
+      aopOp (result, ic, TRUE, FALSE);
+      size = AOP_SIZE (result) - 1;
+
+      if (size > 0)
+       {
+         /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
+            then the result will be in b, a */
+         emitcode ("mov", "b,a"); /* 1 */
+         /* msb is 0x00 or 0xff depending on the sign */
+         if (runtimeSign)
+           {
+             emitcode ("mov",  "c,F0");
+             emitcode ("subb", "a,acc");
+             emitcode ("xch",  "a,b"); /* 2 */
+             while (size--)
+               aopPut (AOP (result), "b", offset++); /* write msb's */
+           }
+         else /* compiletimeSign */
+           while (size--)
+             aopPut (AOP (result), "#0xff", offset++); /* write msb's */
+       }
+      aopPut (AOP (result), "a", 0); /* 3: write lsb */
     }
-    while (size--)
+  else
     {
-       aopPut (AOP (result), "a", offset++);
+      _G.accInUse++;     _G.bInUse++;
+      aopOp(result, ic, TRUE, FALSE);
+      size = AOP_SIZE (result) - 1;
+      
+      aopPut (AOP (result), "a", 0);
+      while (size--)
+       aopPut (AOP (result), zero, offset++);
     }
-    _G.accInUse--;     _G.bInUse--;
+  _G.accInUse--;     _G.bInUse--;
 
 }
 
@@ -4977,7 +5389,7 @@ static void genDivTwoByte (operand *left, operand *right,
        /* load up MB with right */
        if (!umult) {
                if (AOP_TYPE(right) == AOP_LIT) {
-                       int val=floatFromVal (AOP (right)->aopu.aop_lit);
+                       int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
                        if (val < 0) {
                                lbl = newiTempLabel(NULL);
                                emitcode ("jbc","F0,!tlabel",lbl->key+100);
@@ -5126,70 +5538,146 @@ genModOneByte (operand * left,
               operand * result,
               iCode   * ic)
 {
-  sym_link *opetype = operandType (result);
+  bool lUnsigned, rUnsigned;
+  bool runtimeSign, compiletimeSign;
   char *l;
   symbol *lbl;
+  int size, offset;
 
+  offset = 1;
+  lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
+  rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
+  
   /* signed or unsigned */
-  if (SPEC_USIGN (opetype))
+  if (lUnsigned && rUnsigned)
     {
       /* unsigned is easy */
       LOAD_AB_FOR_DIV (left, right, l);
       emitcode ("div", "ab");
-      aopOp(result, ic, TRUE, FALSE);  
+      aopOp (result, ic, TRUE, FALSE); 
       aopPut (AOP (result), "b", 0);
+
+      for (size = AOP_SIZE (result) - 1; size--;)
+       aopPut (AOP (result), zero, offset++);
       return;
     }
 
   /* signed is a little bit more difficult */
 
-  /* save the signs of the operands */
-  MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
-
-  emitcode ("xrl", "a,%s", aopGet (AOP (right), 0, FALSE, FALSE, FALSE));
-  emitcode ("push", "acc");    /* save it on the stack */
-
   /* now sign adjust for both left & right */
-  MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
 
-  lbl = newiTempLabel (NULL);
-  emitcode ("jnb", "acc.7,!tlabel", (lbl->key + 100));
-  emitcode ("cpl", "a");
-  emitcode ("inc", "a");
-  emitcode ("", "!tlabeldef", (lbl->key + 100));
-  emitcode ("mov", "b,a");
+  /* modulus: sign of the right operand has no influence on the result! */
+  if (AOP_TYPE(right) == AOP_LIT)
+    {
+      signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
 
-  /* sign adjust left side */
-  MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+      if (!rUnsigned && val < 0)
+        emitcode ("mov", "b,#0x%02x", -val);
+      else
+        emitcode ("mov", "b,#0x%02x", (unsigned char) val);
+    }
+  else /* ! literal */
+    {
+      if (rUnsigned)
+        emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
+      else
+        {
+          MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
+         lbl = newiTempLabel (NULL);
+         emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
+         emitcode ("cpl", "a");  /* 2's complement */
+         emitcode ("inc", "a");
+         emitcode ("", "!tlabeldef", lbl->key + 100);
+          emitcode ("mov", "b,a");
+       }
+    }
+  
+  /* let's see what's needed: */
+  /* apply negative sign during runtime */
+  runtimeSign = FALSE;
+  /* negative sign from literals */
+  compiletimeSign = FALSE;
 
-  lbl = newiTempLabel (NULL);
-  emitcode ("jnb", "acc.7,!tlabel", (lbl->key + 100));
-  emitcode ("cpl", "a");
-  emitcode ("inc", "a");
-  emitcode ("", "!tlabeldef", (lbl->key + 100));
+  /* sign adjust left side */
+  if (AOP_TYPE(left) == AOP_LIT)
+    {
+      signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
 
-  /* now the multiplication */
+      if (!lUnsigned && val < 0)
+       {
+         compiletimeSign = TRUE; /* set sign flag */
+         emitcode ("mov", "a,#0x%02x", -val);
+       }
+      else
+        emitcode ("mov", "a,#0x%02x", (unsigned char) val);
+    }
+  else /* ! literal */
+    {
+      MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+      
+      if (!lUnsigned)
+        {
+         runtimeSign = TRUE;
+         emitcode ("clr", "F0"); /* clear sign flag */
+         
+         lbl = newiTempLabel (NULL);
+         emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
+         emitcode ("setb", "F0"); /* set sign flag */
+         emitcode ("cpl", "a");   /* 2's complement */
+         emitcode ("inc", "a");
+         emitcode ("", "!tlabeldef", lbl->key + 100);
+       }
+    }
+  
+  /* now the modulus */
   emitcode ("nop", "; workaround for DS80C390 div bug.");
   emitcode ("div", "ab");
-  /* we are interested in the lower order
-     only */
-  lbl = newiTempLabel (NULL);
-  emitcode ("pop", "acc");
-  /* if there was an over flow we don't
-     adjust the sign of the result */
-  emitcode ("jb", "ov,!tlabel", (lbl->key + 100));
-  emitcode ("jnb", "acc.7,!tlabel", (lbl->key + 100));
-  CLRC;
-  emitcode ("clr", "a");
-  emitcode ("subb", "a,b");
-  emitcode ("mov", "b,a");
-  emitcode ("", "!tlabeldef", (lbl->key + 100));
   
-  _G.bInUse++;
-  /* now we are done */
-  aopOp(result, ic, TRUE, FALSE);    
-  aopPut (AOP (result), "b", 0);
-  _G.bInUse--;
+  if (runtimeSign || compiletimeSign)
+    {
+      emitcode ("mov", "a,b");
+      lbl = newiTempLabel (NULL);
+      if (runtimeSign)
+        emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
+      emitcode ("cpl", "a"); /* lsb 2's complement */
+      emitcode ("inc", "a");
+      emitcode ("", "!tlabeldef", lbl->key + 100);
+
+      _G.accInUse++;     _G.bInUse++;
+      aopOp (result, ic, TRUE, FALSE);
+      size = AOP_SIZE (result) - 1;
+      
+      if (size > 0)
+       {
+         /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
+            then the result will be in b, a */
+         emitcode ("mov", "b,a"); /* 1 */
+         /* msb is 0x00 or 0xff depending on the sign */
+         if (runtimeSign)
+           {
+             emitcode ("mov",  "c,F0");
+             emitcode ("subb", "a,acc");
+             emitcode ("xch",  "a,b"); /* 2 */
+             while (size--)
+               aopPut (AOP (result), "b", offset++); /* write msb's */
+           }
+         else /* compiletimeSign */
+           while (size--)
+             aopPut (AOP (result), "#0xff", offset++); /* write msb's */
+       }
+      aopPut (AOP (result), "a", 0); /* 3: write lsb */
+    }
+  else
+    {
+      _G.accInUse++;     _G.bInUse++;
+      aopOp(result, ic, TRUE, FALSE);
+      size = AOP_SIZE (result) - 1;
+      
+      aopPut (AOP (result), "b", 0);
+      while (size--)
+       aopPut (AOP (result), zero, offset++);
+    }
+  _G.accInUse--;     _G.bInUse--;
 
 }
 
@@ -5234,7 +5722,7 @@ static void genModTwoByte (operand *left, operand *right,
        /* load up MB with right */
        if (!umult) {
                if (AOP_TYPE(right) == AOP_LIT) {
-                       int val=floatFromVal (AOP (right)->aopu.aop_lit);
+                       int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
                        if (val < 0) {
                                val = -val;
                        } 
@@ -5388,7 +5876,7 @@ genCmp (operand * left, operand * right,
       AOP_TYPE (right) == AOP_CRY)
     {
       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
-      emitcode ("anl", "c,/%s", AOP (left)->aopu.aop_dir);
+      emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
     }
   else
     {
@@ -5586,6 +6074,7 @@ gencjneshort (operand * left, operand * right, symbol * lbl)
      if the right is in a pointer register and left
      is not */
   if ((AOP_TYPE (left) == AOP_LIT) ||
+      (AOP_TYPE (left) == AOP_IMMD) ||
       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
     {
       operand *t = right;
@@ -5624,6 +6113,8 @@ gencjneshort (operand * left, operand * right, symbol * lbl)
      if the left is a pointer register & right is not */
   else if (AOP_TYPE (right) == AOP_REG ||
           AOP_TYPE (right) == AOP_DIR ||
+           AOP_TYPE (right) == AOP_LIT ||
+           AOP_TYPE (right) == AOP_IMMD ||
           (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
           (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
     {
@@ -6310,6 +6801,8 @@ genAnd (iCode * ic, iCode * ifx)
            {
              if (ifx)
                jmpTrueOrFalse (ifx, tlbl);
+              else
+               emitcode ("", "!tlabeldef", tlbl->key + 100);
              goto release;
            }
        }
@@ -6400,6 +6893,8 @@ genAnd (iCode * ic, iCode * ifx)
            }
          else if (ifx)
            jmpTrueOrFalse (ifx, tlbl);
+          else
+           emitcode ("", "!tlabeldef", tlbl->key + 100);
        }
       else
        {
@@ -6718,6 +7213,8 @@ genOr (iCode * ic, iCode * ifx)
            }
          else if (ifx)
            jmpTrueOrFalse (ifx, tlbl);
+          else
+           emitcode ("", "!tlabeldef", tlbl->key + 100);
        }
       else
        {
@@ -7254,6 +7751,65 @@ genGetHbit (iCode * ic)
   freeAsmop (result, NULL, ic, TRUE);
 }
 
+/*-----------------------------------------------------------------*/
+/* genSwap - generates code to swap nibbles or bytes               */
+/*-----------------------------------------------------------------*/
+static void
+genSwap (iCode * ic)
+{
+  operand *left, *result;
+
+  D(emitcode (";     genSwap",""));
+
+  left = IC_LEFT (ic);
+  result = IC_RESULT (ic);
+  aopOp (left, ic, FALSE, FALSE);
+  aopOp (result, ic, FALSE, AOP_USESDPTR(left));
+  
+  _startLazyDPSEvaluation ();
+  switch (AOP_SIZE (left))
+    {
+    case 1: /* swap nibbles in byte */
+      MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+      emitcode ("swap", "a");
+      aopPut (AOP (result), "a", 0);
+      break;
+    case 2: /* swap bytes in word */
+      if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
+       {
+         MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+         aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE, NULL), 0);
+         aopPut (AOP (result), "a", 1);
+       }
+      else if (operandsEqu (left, result))
+       {
+          char * reg = "a";
+         MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
+         if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
+           {
+             emitcode ("mov", "b,a");
+              reg = "b";
+              _G.bInUse=1;
+            }
+         aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE, NULL), 0);
+         aopPut (AOP (result), reg, 1);
+          _G.bInUse=0;
+       }
+      else
+       {
+         aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE, NULL), 0);
+         aopPut (AOP (result), aopGet (AOP (left), 0, FALSE, FALSE, NULL), 1);
+       }
+      break;
+    default:
+      wassertl(FALSE, "unsupported SWAP operand size");
+    }
+  _endLazyDPSEvaluation ();
+  
+  freeAsmop (left, NULL, ic, TRUE);
+  freeAsmop (result, NULL, ic, TRUE);
+}
+
 /*-----------------------------------------------------------------*/
 /* AccRol - rotate left accumulator by known count                 */
 /*-----------------------------------------------------------------*/
@@ -7896,8 +8452,6 @@ shiftR2Left2Result (operand * left, int offl,
 }
 #endif
 
-#if 0
-//REMOVE ME!!!
 /*-----------------------------------------------------------------*/
 /* shiftLLeftOrResult - shift left one byte from left, or to result */
 /*-----------------------------------------------------------------*/
@@ -7914,7 +8468,6 @@ shiftLLeftOrResult (operand * left, int offl,
   /* back to result */
   aopPut (AOP (result), "a", offr);
 }
-#endif
 
 #if 0
 //REMOVE ME!!!
@@ -8449,8 +9002,6 @@ genrshTwo (operand * result, operand * left,
 }
 #endif
 
-#if 0
-//REMOVE ME!!!
 /*-----------------------------------------------------------------*/
 /* shiftRLong - shift right one long from left to result           */
 /* offl = LSB or MSB16                                             */
@@ -8466,7 +9017,7 @@ shiftRLong (operand * left, int offl,
     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
   }
 
-  MOVA (aopGet (AOP (left), MSB32, FALSE, NULL));
+  MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE, NULL));
   
   if (offl==MSB16) {
     // shift is > 8
@@ -8474,7 +9025,7 @@ shiftRLong (operand * left, int offl,
       emitcode ("rlc", "a");
       emitcode ("subb", "a,acc");
       emitcode ("xch", "a,%s",
-               aopGet(AOP(left), MSB32, FALSE, DP2_RESULT_REG));
+               aopGet(AOP(left), MSB32, FALSE, FALSE, DP2_RESULT_REG));
     } else {
       aopPut (AOP(result), zero, MSB32);
     }
@@ -8490,34 +9041,31 @@ shiftRLong (operand * left, int offl,
 
   if (isSameRegs && offl==MSB16) {
     emitcode ("xch",
-             "a,%s",aopGet (AOP (left), MSB24, FALSE, DP2_RESULT_REG));
+             "a,%s",aopGet (AOP (left), MSB24, FALSE, FALSE, DP2_RESULT_REG));
   } else {
     aopPut (AOP (result), "a", MSB32);
-    MOVA (aopGet (AOP (left), MSB24, FALSE, NULL));
+    MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE, NULL));
   }
 
   emitcode ("rrc", "a");
   if (isSameRegs && offl==1) {
     emitcode ("xch", "a,%s",
-             aopGet (AOP (left), MSB16, FALSE, DP2_RESULT_REG));
+             aopGet (AOP (left), MSB16, FALSE, FALSE, DP2_RESULT_REG));
   } else {
     aopPut (AOP (result), "a", MSB24);
-    MOVA (aopGet (AOP (left), MSB16, FALSE, NULL));
+    MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE, NULL));
   }
   emitcode ("rrc", "a");
   aopPut (AOP (result), "a", MSB16 - offl);
 
   if (offl == LSB)
     {
-      MOVA (aopGet (AOP (left), LSB, FALSE, NULL));
+      MOVA (aopGet (AOP (left), LSB, FALSE, FALSE, NULL));
       emitcode ("rrc", "a");
       aopPut (AOP (result), "a", LSB);
     }
 }
-#endif
 
-#if 0
-//REMOVE ME!!!
 /*-----------------------------------------------------------------*/
 /* genrshFour - shift four byte by a known amount != 0             */
 /*-----------------------------------------------------------------*/
@@ -8525,22 +9073,24 @@ static void
 genrshFour (operand * result, operand * left,
            int shCount, int sign)
 {
-  D (emitcode (";", "genrshFour");
-    );
+  D (emitcode (";", "genrshFour"););
 
   /* if shifting more that 3 bytes */
   if (shCount >= 24)
     {
       shCount -= 24;
+      _startLazyDPSEvaluation();
       if (shCount)
        shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
       else
        movLeft2Result (left, MSB32, result, LSB, sign);
       addSign (result, MSB16, sign);
+      _endLazyDPSEvaluation();
     }
   else if (shCount >= 16)
     {
       shCount -= 16;
+      _startLazyDPSEvaluation();
       if (shCount)
        shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
       else
@@ -8549,12 +9099,16 @@ genrshFour (operand * result, operand * left,
          movLeft2Result (left, MSB32, result, MSB16, sign);
        }
       addSign (result, MSB24, sign);
+      _endLazyDPSEvaluation();
     }
   else if (shCount >= 8)
     {
       shCount -= 8;
+      _startLazyDPSEvaluation();
       if (shCount == 1)
-       shiftRLong (left, MSB16, result, sign);
+       {
+           shiftRLong (left, MSB16, result, sign);
+       }
       else if (shCount == 0)
        {
          movLeft2Result (left, MSB16, result, LSB, 0);
@@ -8570,9 +9124,11 @@ genrshFour (operand * result, operand * left,
          shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
          addSign (result, MSB32, sign);
        }
+       _endLazyDPSEvaluation();
     }
   else
-    {                          /* 1 <= shCount <= 7 */
+    {  
+       /* 1 <= shCount <= 7 */
       if (shCount <= 2)
        {
          shiftRLong (left, LSB, result, sign);
@@ -8587,7 +9143,6 @@ genrshFour (operand * result, operand * left,
        }
     }
 }
-#endif
 
 #ifdef BETTER_LITERAL_SHIFT
 /*-----------------------------------------------------------------*/
@@ -8611,9 +9166,10 @@ genRightShiftLiteral (operand * left,
   if ((shCount != 0)
    && (shCount < (size * 8))
    && (size != 1)
-   && (size != 2))
+   && (size != 2)
+   && (size != 4))
   {
-      D(emitcode (";", "genRightShiftLiteral wimping out"););  
+      D(emitcode (";", "genRightShiftLiteral wimping out"););
       return FALSE;
   }
 
@@ -8660,7 +9216,7 @@ genRightShiftLiteral (operand * left,
        case 2:
          genrshTwo (result, left, shCount, sign);
          break;
-#if 0
+#if 1
        case 4:
          genrshFour (result, left, shCount, sign);
          break;
@@ -8807,7 +9363,7 @@ static void
 genRightShift (iCode * ic)
 {
   operand *right, *left, *result;
-  sym_link *retype;
+  sym_link *letype;
   int size, offset;
   char *l;
   symbol *tlbl, *tlbl1;
@@ -8816,9 +9372,9 @@ genRightShift (iCode * ic)
 
   /* if signed then we do it the hard way preserve the
      sign bit moving it inwards */
-  retype = getSpec (operandType (IC_RESULT (ic)));
+  letype = getSpec (operandType (IC_LEFT (ic)));
 
-  if (!SPEC_USIGN (retype))
+  if (!SPEC_USIGN (letype))
     {
       genSignedRightShift (ic);
       return;
@@ -8939,116 +9495,148 @@ release:
   freeAsmop (result, NULL, ic, TRUE);
 }
 
+
 /*-----------------------------------------------------------------*/
-/* genUnpackBits - generates code for unpacking bits               */
+/* emitPtrByteGet - emits code to get a byte into A through a      */
+/*                  pointer register (R0, R1, or DPTR). The        */
+/*                  original value of A can be preserved in B.     */
 /*-----------------------------------------------------------------*/
 static void
-genUnpackBits (operand * result, char *rname, int ptype)
+emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
 {
-  int shCnt;
-  int rlen;
-  sym_link *etype;
-  int offset = 0;
-
-  D (emitcode (";", "genUnpackBits "););
-
-  etype = getSpec (operandType (result));
-
-  /* read the first byte  */
-  switch (ptype)
+  switch (p_type)
     {
-
-    case POINTER:
     case IPOINTER:
+    case POINTER:
+      if (preserveAinB)
+        emitcode ("mov", "b,a");
       emitcode ("mov", "a,@%s", rname);
       break;
 
     case PPOINTER:
+      if (preserveAinB)
+        emitcode ("mov", "b,a");
       emitcode ("movx", "a,@%s", rname);
       break;
-
+      
     case FPOINTER:
+      if (preserveAinB)
+        emitcode ("mov", "b,a");
       emitcode ("movx", "a,@dptr");
       break;
 
     case CPOINTER:
+      if (preserveAinB)
+        emitcode ("mov", "b,a");
       emitcode ("clr", "a");
       emitcode ("movc", "a,@a+dptr");
       break;
 
     case GPOINTER:
+      if (preserveAinB)
+        {
+          emitcode ("push", "b");
+          emitcode ("push", "acc");
+        }
       emitcode ("lcall", "__gptrget");
+      if (preserveAinB)
+        emitcode ("pop", "b");
       break;
     }
+}
 
-  /* if we have bitdisplacement then it fits   */
-  /* into this byte completely or if length is */
-  /* less than a byte                          */
-  if (((shCnt = SPEC_BSTR (etype)) != 0) || (SPEC_BLEN (etype) <= 8))
+/*-----------------------------------------------------------------*/
+/* emitPtrByteSet - emits code to set a byte from src through a    */
+/*                  pointer register (R0, R1, or DPTR).            */
+/*-----------------------------------------------------------------*/
+static void
+emitPtrByteSet (char *rname, int p_type, char *src)
+{
+  switch (p_type)
     {
+    case IPOINTER:
+    case POINTER:
+      if (*src=='@')
+        {
+          MOVA (src);
+          emitcode ("mov", "@%s,a", rname);
+        }
+      else
+        emitcode ("mov", "@%s,%s", rname, src);
+      break;
 
-      /* shift right acc */
-      AccRsh (shCnt);
+    case PPOINTER:
+      MOVA (src);
+      emitcode ("movx", "@%s,a", rname);
+      break;
+      
+    case FPOINTER:
+      MOVA (src);
+      emitcode ("movx", "@dptr,a");
+      break;
 
-      emitcode ("anl", "a,#!constbyte",
-               ((unsigned char) -1) >> (8 - SPEC_BLEN (etype)));
-      aopPut (AOP (result), "a", offset);
-      return;
+    case GPOINTER:
+      MOVA (src);
+      emitcode ("lcall", "__gptrput");
+      break;
     }
+}
 
-  /* bit field did not fit in a byte  */
-  rlen = SPEC_BLEN (etype) - 8;
-  aopPut (AOP (result), "a", offset++);
-
-  while (1)
-    {
-
-      switch (ptype)
-       {
-       case POINTER:
-       case IPOINTER:
-         emitcode ("inc", "%s", rname);
-         emitcode ("mov", "a,@%s", rname);
-         break;
-
-       case PPOINTER:
-         emitcode ("inc", "%s", rname);
-         emitcode ("movx", "a,@%s", rname);
-         break;
-
-       case FPOINTER:
-         emitcode ("inc", "dptr");
-         emitcode ("movx", "a,@dptr");
-         break;
+/*-----------------------------------------------------------------*/
+/* genUnpackBits - generates code for unpacking bits               */
+/*-----------------------------------------------------------------*/
+static void
+genUnpackBits (operand * result, char *rname, int ptype)
+{
+  int offset = 0;      /* result byte offset */
+  int rsize;           /* result size */
+  int rlen = 0;                /* remaining bitfield length */
+  sym_link *etype;     /* bitfield type information */
+  int blen;            /* bitfield length */
+  int bstr;            /* bitfield starting bit within byte */
 
-       case CPOINTER:
-         emitcode ("clr", "a");
-         emitcode ("inc", "dptr");
-         emitcode ("movc", "a,@a+dptr");
-         break;
+  D(emitcode (";     genUnpackBits",""));
 
-       case GPOINTER:
-         emitcode ("inc", "dptr");
-         emitcode ("lcall", "__gptrget");
-         break;
-       }
-
-      rlen -= 8;
-      /* if we are done */
-      if (rlen < 8)
-       break;
+  etype = getSpec (operandType (result));
+  rsize = getSize (operandType (result));
+  blen = SPEC_BLEN (etype);
+  bstr = SPEC_BSTR (etype);
 
+  /* If the bitfield length is less than a byte */
+  if (blen < 8)
+    {
+      emitPtrByteGet (rname, ptype, FALSE);
+      AccRsh (bstr);
+      emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
       aopPut (AOP (result), "a", offset++);
+      goto finish;
+    }
 
+  /* Bit field did not fit in a byte. Copy all
+     but the partial byte at the end.  */
+  for (rlen=blen;rlen>=8;rlen-=8)
+    {
+      emitPtrByteGet (rname, ptype, FALSE);
+      aopPut (AOP (result), "a", offset++);
+      if (rlen>8)
+        emitcode ("inc", "%s", rname);
     }
 
+  /* Handle the partial byte at the end */
   if (rlen)
     {
-      emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (rlen));
-      aopPut (AOP (result), "a", offset);
+      emitPtrByteGet (rname, ptype, FALSE);
+      emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
+      aopPut (AOP (result), "a", offset++);
     }
 
-  return;
+finish:
+  if (offset < rsize)
+    {
+      rsize -= offset;
+      while (rsize--)
+       aopPut (AOP (result), zero, offset++);
+    }
 }
 
 
@@ -9112,12 +9700,12 @@ genNearPointerGet (operand * left,
   aopOp (left, ic, FALSE, FALSE);
 
   /* if left is rematerialisable and
-     result is not bit variable type and
+     result is not bitfield variable type and
      the left is pointer to data space i.e
      lower 128 bytes of space */
   if (AOP_TYPE (left) == AOP_IMMD &&
-      !IS_BITVAR (retype) &&
-      !IS_BITVAR (letype) &&
+      !IS_BITFIELD (retype) &&
+      !IS_BITFIELD (letype) &&
       DCL_TYPE (ltype) == POINTER)
     {
       genDataPointerGet (left, result, ic);
@@ -9143,7 +9731,7 @@ genNearPointerGet (operand * left,
   aopOp (result, ic, FALSE, FALSE);
 
   /* if bitfield then unpack the bits */
-  if (IS_BITVAR (retype) || IS_BITVAR (letype))
+  if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
     genUnpackBits (result, rname, POINTER);
   else
     {
@@ -9243,7 +9831,7 @@ genPagedPointerGet (operand * left,
   aopOp (result, ic, FALSE, FALSE);
 
   /* if bitfield then unpack the bits */
-  if (IS_BITVAR (retype) || IS_BITVAR (letype))
+  if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
     genUnpackBits (result, rname, PPOINTER);
   else
     {
@@ -9348,7 +9936,7 @@ genFarPointerGet (operand * left,
   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
 
   /* if bit then unpack */
-  if (IS_BITVAR (retype) || IS_BITVAR (letype)) {
+  if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
       if (AOP_INDPTRn(left)) {
          genSetDPTR(AOP(left)->aopu.dptr);
       }
@@ -9468,7 +10056,7 @@ genCodePointerGet (operand * left,
   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
 
   /* if bit then unpack */
-  if (IS_BITVAR (retype)) {
+  if (IS_BITFIELD (retype)) {
       if (AOP_INDPTRn(left)) {
          genSetDPTR(AOP(left)->aopu.dptr);
       }
@@ -9593,7 +10181,7 @@ genGenPointerGet (operand * left,
   _G.bInUse--;
 
   /* if bit then unpack */
-  if (IS_BITVAR (retype) || IS_BITVAR (letype))
+  if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
   {
     genUnpackBits (result, "dptr", GPOINTER);
   }
@@ -9727,162 +10315,125 @@ genPackBits (sym_link * etype,
             operand * right,
             char *rname, int p_type)
 {
-  int offset = 0;
-  int rLen;
-  int blen, bstr;
-  char *l;
+  int offset = 0;      /* source byte offset */
+  int rlen = 0;                /* remaining bitfield length */
+  int blen;            /* bitfield length */
+  int bstr;            /* bitfield starting bit within byte */
+  int litval;          /* source literal value (if AOP_LIT) */
+  unsigned char mask;  /* bitmask within current byte */
+
+  D(emitcode (";     genPackBits",""));
 
   blen = SPEC_BLEN (etype);
   bstr = SPEC_BSTR (etype);
 
-  MOVA (aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
-
-  /* if the bit lenth is less than or    */
-  /* it exactly fits a byte then         */
-  if (SPEC_BLEN (etype) <= 8)
+  /* If the bitfield length is less than a byte */
+  if (blen < 8)
     {
-      /* shift left acc */
-      AccLsh (SPEC_BSTR (etype));
-
-      if (SPEC_BLEN (etype) < 8)
-       {                       /* if smaller than a byte */
-
-
-         switch (p_type)
-           {
-           case POINTER:
-             emitcode ("mov", "b,a");
-             emitcode ("mov", "a,@%s", rname);
-             break;
-
-           case FPOINTER:
-             emitcode ("mov", "b,a");
-             emitcode ("movx", "a,@dptr");
-             break;
+      mask = ((unsigned char) (0xFF << (blen + bstr)) |
+             (unsigned char) (0xFF >> (8 - bstr)));
 
-           case GPOINTER:
-             emitcode ("push", "b");
-             emitcode ("push", "acc");
-             emitcode ("lcall", "__gptrget");
-             emitcode ("pop", "b");
-             break;
-           }
+      if (AOP_TYPE (right) == AOP_LIT)
+        {
+          /* Case with a bitfield length <8 and literal source
+          */
+          litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
+          litval <<= bstr;
+          litval &= (~mask) & 0xff;
+          emitPtrByteGet (rname, p_type, FALSE);
+          if ((mask|litval)!=0xff)
+            emitcode ("anl","a,#!constbyte", mask);
+          if (litval)
+            emitcode ("orl","a,#!constbyte", litval);
+        }
+      else
+        {
+          if ((blen==1) && (p_type!=GPOINTER))
+            {
+              /* Case with a bitfield length == 1 and no generic pointer
+              */
+              if (AOP_TYPE (right) == AOP_CRY)
+                emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
+              else
+                {
+                  MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
+                  emitcode ("rrc","a");
+                }
+              emitPtrByteGet (rname, p_type, FALSE);
+              emitcode ("mov","acc.%d,c",bstr);
+            }
+          else
+            {
+              /* Case with a bitfield length < 8 and arbitrary source
+              */
+              MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
+              /* shift and mask source value */
+              AccLsh (bstr);
+              emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
+
+             /* transfer A to B and get next byte */
+              emitPtrByteGet (rname, p_type, TRUE);
+
+              emitcode ("anl", "a,#!constbyte", mask);
+              emitcode ("orl", "a,b");
+              if (p_type == GPOINTER)
+                emitcode ("pop", "b");
+           }
+        }
 
-         emitcode ("anl", "a,#!constbyte", (unsigned char)
-                   ((unsigned char) (0xFF << (blen + bstr)) |
-                    (unsigned char) (0xFF >> (8 - bstr))));
-         emitcode ("orl", "a,b");
-         if (p_type == GPOINTER)
-           emitcode ("pop", "b");
-       }
+      emitPtrByteSet (rname, p_type, "a");
+      return;
     }
 
-  switch (p_type)
+  /* Bit length is greater than 7 bits. In this case, copy  */
+  /* all except the partial byte at the end                 */
+  for (rlen=blen;rlen>=8;rlen-=8)
     {
-    case POINTER:
-      emitcode ("mov", "@%s,a", rname);
-      break;
-
-    case FPOINTER:
-      emitcode ("movx", "@dptr,a");
-      break;
-
-    case GPOINTER:
-      emitcode ("lcall", "__gptrput");
-      break;
+      emitPtrByteSet (rname, p_type, 
+                      aopGet (AOP (right), offset++, FALSE, TRUE, NULL) );
+      if (rlen>8)
+        emitcode ("inc", "%s", rname);
     }
 
-  /* if we r done */
-  if (SPEC_BLEN (etype) <= 8)
-    return;
-
-  emitcode ("inc", "%s", rname);
-  rLen = SPEC_BLEN (etype);
-
-  /* now generate for lengths greater than one byte */
-  while (1)
-    {
-
-      l = aopGet (AOP (right), offset++, FALSE, TRUE, NULL);
-
-      rLen -= 8;
-      if (rLen < 8)
-       break;
-
-      switch (p_type)
-       {
-       case POINTER:
-         if (*l == '@')
-           {
-             MOVA (l);
-             emitcode ("mov", "@%s,a", rname);
-           }
-         else
-           emitcode ("mov", "@%s,%s", rname, l);
-         break;
-
-       case FPOINTER:
-         MOVA (l);
-         emitcode ("movx", "@dptr,a");
-         break;
-
-       case GPOINTER:
-         MOVA (l);
-         emitcode ("lcall", "__gptrput");
-         break;
-       }
-      emitcode ("inc", "%s", rname);
-    }
-
-  MOVA (l);
-
-  /* last last was not complete */
-  if (rLen)
+  /* If there was a partial byte at the end */
+  if (rlen)
     {
-      /* save the byte & read byte */
-      switch (p_type)
-       {
-       case POINTER:
-         emitcode ("mov", "b,a");
-         emitcode ("mov", "a,@%s", rname);
-         break;
-
-       case FPOINTER:
-         emitcode ("mov", "b,a");
-         emitcode ("movx", "a,@dptr");
-         break;
-
-       case GPOINTER:
-         emitcode ("push", "b");
-         emitcode ("push", "acc");
-         emitcode ("lcall", "__gptrget");
-         emitcode ("pop", "b");
-         break;
-       }
-
-      emitcode ("anl", "a,#!constbyte", ((unsigned char) -1 << rLen));
-      emitcode ("orl", "a,b");
+      mask = (((unsigned char) -1 << rlen) & 0xff);
+      
+      if (AOP_TYPE (right) == AOP_LIT)
+        {
+          /* Case with partial byte and literal source
+          */
+          litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
+          litval >>= (blen-rlen);
+          litval &= (~mask) & 0xff;
+          emitPtrByteGet (rname, p_type, FALSE);
+          if ((mask|litval)!=0xff)
+            emitcode ("anl","a,#!constbyte", mask);
+          if (litval)
+            emitcode ("orl","a,#!constbyte", litval);
+        }
+      else
+        {
+          /* Case with partial byte and arbitrary source
+          */
+          MOVA (aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
+          emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
+
+         /* transfer A to B and get next byte */
+          emitPtrByteGet (rname, p_type, TRUE);
+
+          emitcode ("anl", "a,#!constbyte", mask);
+          emitcode ("orl", "a,b");
+          if (p_type == GPOINTER)
+            emitcode ("pop", "b");
+        }
+      emitPtrByteSet (rname, p_type, "a");
     }
 
-  if (p_type == GPOINTER)
-    emitcode ("pop", "b");
-
-  switch (p_type)
-    {
-
-    case POINTER:
-      emitcode ("mov", "@%s,a", rname);
-      break;
+}
 
-    case FPOINTER:
-      emitcode ("movx", "@dptr,a");
-      break;
 
-    case GPOINTER:
-      emitcode ("lcall", "__gptrput");
-      break;
-    }
-}
 /*-----------------------------------------------------------------*/
 /* genDataPointerSet - remat pointer to data space                 */
 /*-----------------------------------------------------------------*/
@@ -9967,8 +10518,8 @@ genNearPointerSet (operand * right,
   aopOp (right, ic, FALSE, FALSE);
 
   /* if bitfield then unpack the bits */
-  if (IS_BITVAR (retype) || IS_BITVAR (letype))
-    genPackBits ((IS_BITVAR (retype) ? retype : letype), right, rname, POINTER);
+  if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
+    genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
   else
     {
       /* we have can just get the values */
@@ -10063,8 +10614,8 @@ genPagedPointerSet (operand * right,
   aopOp (right, ic, FALSE, FALSE);
 
   /* if bitfield then unpack the bits */
-  if (IS_BITVAR (retype) || IS_BITVAR (letype))
-    genPackBits ((IS_BITVAR (retype) ? retype : letype), right, rname, PPOINTER);
+  if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
+    genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
   else
     {
       /* we have can just get the values */
@@ -10170,11 +10721,11 @@ genFarPointerSet (operand * right,
   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
 
   /* if bit then unpack */
-  if (IS_BITVAR (retype) || IS_BITVAR (letype)) {
+  if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
       if (AOP_INDPTRn(result)) {
          genSetDPTR(AOP(result)->aopu.dptr);
       }
-      genPackBits ((IS_BITVAR (retype) ? retype : letype), right, "dptr", FPOINTER);
+      genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
       if (AOP_INDPTRn(result)) {
          genSetDPTR(0);
       }
@@ -10292,9 +10843,9 @@ genGenPointerSet (operand * right,
     
 
   /* if bit then unpack */
-  if (IS_BITVAR (retype) || IS_BITVAR (letype))
+  if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
     {
-       genPackBits ((IS_BITVAR (retype) ? retype : letype), right, "dptr", GPOINTER);
+       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
     }
   else
     {
@@ -10499,6 +11050,8 @@ genAddrOf (iCode * ic)
       /* if 10 bit stack */
       if (options.stack10bit) {
          char buff[10];
+         int  offset;
+         
          tsprintf(buff, sizeof(buff), 
                   "#!constbyte",(options.stack_loc >> 16) & 0xff);
          /* if it has an offset then we need to compute it */
@@ -10517,9 +11070,13 @@ genAddrOf (iCode * ic)
                                             ((char) sym->stack )) & 0xff);
              emitcode ("mov", "b,a");
              emitcode ("mov", "a,_bpx+1");
-             emitcode ("addc","a,#!constbyte", (((sym->stack < 0) ? 
-                                             ((short) (sym->stack - _G.nRegsSaved)) :
-                                             ((short) sym->stack )) >> 8) & 0xff);
+             
+             offset = (((sym->stack < 0) ? 
+                        ((short) (sym->stack - _G.nRegsSaved)) :
+                        ((short) sym->stack )) >> 8) & 0xff;
+         
+             emitcode ("addc","a,#!constbyte", offset);
+
              aopPut (AOP (IC_RESULT (ic)), "b", 0);
              aopPut (AOP (IC_RESULT (ic)), "a", 1);
              aopPut (AOP (IC_RESULT (ic)), buff, 2);
@@ -10593,6 +11150,7 @@ release:
 
 }
 
+#if 0 // obsolete, and buggy for != xdata
 /*-----------------------------------------------------------------*/
 /* genArrayInit - generates code for address of                       */
 /*-----------------------------------------------------------------*/
@@ -10701,6 +11259,7 @@ genArrayInit (iCode * ic)
     
     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
 }
+#endif
 
 /*-----------------------------------------------------------------*/
 /* genFarFarAssign - assignment when both are in far space         */
@@ -10972,12 +11531,12 @@ genCast (iCode * ic)
   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
     return;
 
-  aopOp (right, ic, FALSE, FALSE);
-  aopOp (result, ic, FALSE, AOP_USESDPTR(right));
+  aopOp (right, ic, FALSE, AOP_IS_STR (result));
+  aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
 
   /* if the result is a bit */
-  // if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
-  if (IS_BITVAR(OP_SYMBOL(result)->type))
+  if (IS_BITVAR (OP_SYMBOL (result)->type)
+      && !IS_BITFIELD (OP_SYMBOL (result)->type) )
     {
       /* if the right size is a literal then
          we know what the value is */
@@ -11150,7 +11709,7 @@ genCast (iCode * ic)
   /* also, if the source is a bit, we don't need to sign extend, because
    * it can't possibly have set the sign bit.
    */
-  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--)
        {
@@ -12563,6 +13122,127 @@ static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *na
        }
 }
 
+/*-----------------------------------------------------------------*/
+/* genDummyRead - generate code for dummy read of volatiles        */
+/*-----------------------------------------------------------------*/
+static void
+genDummyRead (iCode * ic)
+{
+  operand *op;
+  int size, offset;
+
+  D(emitcode(";     genDummyRead",""));
+
+  op = IC_RIGHT (ic);
+  if (op && IS_SYMOP (op))
+    {
+      aopOp (op, ic, FALSE, FALSE);
+
+      /* if the result is a bit */
+      if (AOP_TYPE (op) == AOP_CRY)
+        emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
+      else
+       {
+         /* bit variables done */
+         /* general case */
+         size = AOP_SIZE (op);
+         offset = 0;
+         while (size--)
+         {
+           MOVA (aopGet (AOP (op), offset, FALSE, FALSE, FALSE));
+           offset++;
+         }
+       }
+
+      freeAsmop (op, NULL, ic, TRUE);
+    }
+
+  op = IC_LEFT (ic);
+  if (op && IS_SYMOP (op))
+    {
+      aopOp (op, ic, FALSE, FALSE);
+
+      /* if the result is a bit */
+      if (AOP_TYPE (op) == AOP_CRY)
+        emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
+      else
+       {
+         /* bit variables done */
+         /* general case */
+         size = AOP_SIZE (op);
+         offset = 0;
+         while (size--)
+         {
+           MOVA (aopGet (AOP (op), offset, FALSE, FALSE, FALSE));
+           offset++;
+         }
+       }
+
+      freeAsmop (op, NULL, ic, TRUE);
+    }
+    
+}
+
+/*-----------------------------------------------------------------*/
+/* genCritical - generate code for start of a critical sequence    */
+/*-----------------------------------------------------------------*/
+static void
+genCritical (iCode *ic)
+{
+  symbol *tlbl = newiTempLabel (NULL);
+
+  D(emitcode(";     genCritical",""));
+  
+  if (IC_RESULT (ic))
+    aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
+
+  emitcode ("setb", "c");
+  emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
+  emitcode ("clr", "c");
+  emitcode ("", "%05d$:", (tlbl->key + 100));
+
+  if (IC_RESULT (ic))
+    outBitC (IC_RESULT (ic)); /* save old ea in an operand */
+  else
+    emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
+
+  if (IC_RESULT (ic))
+    freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genEndCritical - generate code for end of a critical sequence   */
+/*-----------------------------------------------------------------*/
+static void
+genEndCritical (iCode *ic)
+{
+  D(emitcode(";     genEndCritical",""));
+  
+  if (IC_RIGHT (ic))
+    {
+      aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
+      if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
+        {
+         emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
+          emitcode ("mov", "ea,c");
+        }
+      else
+        {
+          MOVA (aopGet (AOP (IC_RIGHT (ic)), 0, FALSE, FALSE, FALSE));
+          emitcode ("rrc", "a");
+          emitcode ("mov", "ea,c");
+        }
+      freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
+    }
+  else
+    {
+      emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
+      emitcode ("mov", "ea,c");
+    }
+}
+
+
+
 /*-----------------------------------------------------------------*/
 /* genBuiltIn - calls the appropriate function to  generating code */
 /* for a built in function                                        */
@@ -12697,7 +13377,7 @@ gen390Code (iCode * lic)
   }
 #if 1
   /* print the allocation information */
-  if (allocInfo)
+  if (allocInfo && currFunc)
     printAllocInfo (currFunc, codeOutFile);
 #endif
   /* if debug information required */
@@ -12721,6 +13401,8 @@ gen390Code (iCode * lic)
   for (ic = lic; ic; ic = ic->next)
     {
 
+      _G.current_iCode = ic;
+      
       if (ic->lineno && cln != ic->lineno)
        {
          if (options.debug)
@@ -12932,9 +13614,27 @@ gen390Code (iCode * lic)
          else addSet (&_G.sendSet, ic);
          break;
 
+       case DUMMY_READ_VOLATILE:
+         genDummyRead (ic);
+         break;
+
+       case CRITICAL:
+         genCritical (ic);
+         break;
+
+       case ENDCRITICAL:
+         genEndCritical (ic);
+         break;
+       
+        case SWAP:
+         genSwap (ic);
+         break;
+          
+#if 0 // obsolete, and buggy for != xdata
        case ARRAYINIT:
            genArrayInit(ic);
            break;
+#endif
            
        default:
          ic = ic;