* sdcc.spec: updated
[fw/sdcc] / src / mcs51 / gen.c
index 983c5a1d0419d38e990c8d7dc9331e21f74a4df3..649c643e5ea6f50e6b464777b546b4369137ce52 100644 (file)
@@ -73,6 +73,7 @@ static struct
     short debugLine;
     short nRegsSaved;
     set *sendSet;
+    iCode *current_iCode;
   }
 _G;
 
@@ -139,6 +140,8 @@ emitcode (char *inst, const char *fmt,...)
                (lineHead = newLineNode (lb)));
   lineCurr->isInline = _G.inLine;
   lineCurr->isDebug = _G.debugLine;
+  lineCurr->ic = _G.current_iCode;
+  lineCurr->isComment = (*lbp==';');
   va_end (ap);
 }
 
@@ -279,6 +282,74 @@ 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                                   */
 /*-----------------------------------------------------------------*/
@@ -313,7 +384,7 @@ aopForSym (iCode * ic, symbol * sym, bool result)
 
          if (sym->onStack)
            {
-             if (_G.accInUse)
+             if (_G.accInUse || leftRightUseAcc (ic))
                emitcode ("push", "acc");
 
              emitcode ("mov", "a,_bp");
@@ -324,7 +395,7 @@ aopForSym (iCode * ic, symbol * sym, bool result)
              emitcode ("mov", "%s,a",
                        aop->aopu.aop_ptr->name);
 
-             if (_G.accInUse)
+             if (_G.accInUse || leftRightUseAcc (ic))
                emitcode ("pop", "acc");
            }
          else
@@ -349,6 +420,9 @@ aopForSym (iCode * ic, symbol * sym, bool result)
   /* if it is in direct space */
   if (IN_DIRSPACE (space))
     {
+      //printf("aopForSym, using AOP_DIR for %s (%x)\n", sym->name, sym);
+      //printTypeChainRaw(sym->type, NULL);
+      //printf("space = %s\n", space ? space->sname : "NULL");
       sym->aop = aop = newAsmop (AOP_DIR);
       aop->aopu.aop_dir = sym->rname;
       aop->size = getSize (sym->type);
@@ -634,13 +708,21 @@ aopOp (operand * op, iCode * ic, bool result)
          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);
+      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);
+         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;
     }
@@ -704,7 +786,7 @@ freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
     case AOP_STK:
       {
        int sz = aop->size;
-       int stk = aop->aopu.aop_stk + aop->size;
+       int stk = aop->aopu.aop_stk + aop->size - 1;
        bitVectUnSetBit (ic->rUsed, R0_IDX);
        bitVectUnSetBit (ic->rUsed, R1_IDX);
 
@@ -731,17 +813,17 @@ freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
          }
        op->aop = aop;
        freeAsmop (op, NULL, ic, TRUE);
-       if (_G.r0Pushed)
-         {
-           emitcode ("pop", "ar0");
-           _G.r0Pushed--;
-         }
-
        if (_G.r1Pushed)
          {
            emitcode ("pop", "ar1");
            _G.r1Pushed--;
          }
+
+       if (_G.r0Pushed)
+         {
+           emitcode ("pop", "ar0");
+           _G.r0Pushed--;
+         }
       }
     }
 
@@ -797,6 +879,8 @@ aopGetUsesAcc (asmop *aop, int offset)
       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
        return TRUE;
       return FALSE;
+    case AOP_DUMMY:
+      return FALSE;
     default:
       /* Error case --- will have been caught already */
       wassert(0);
@@ -804,7 +888,6 @@ aopGetUsesAcc (asmop *aop, int offset)
     }
 }
 
-
 /*-----------------------------------------------------------------*/
 /* aopGet - for fetching value of the aop                          */
 /*-----------------------------------------------------------------*/
@@ -823,7 +906,9 @@ aopGet (asmop * aop, int offset, bool bit16, bool dname)
   /* depending on type */
   switch (aop->type)
     {
-
+    case AOP_DUMMY:
+      return zero;
+      
     case AOP_R0:
     case AOP_R1:
       /* if we need to increment it */
@@ -962,6 +1047,10 @@ aopPut (asmop * aop, const char *s, int offset, bool bvolatile)
   /* 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)
        sprintf (d, "(%s + %d)",
@@ -1205,46 +1294,6 @@ reAdjustPreg (asmop * aop)
                       (x->aopu.aop_reg[0] == mcs51_regWithIdx(R0_IDX) || \
                       x->aopu.aop_reg[0] == mcs51_regWithIdx(R1_IDX) )))
 
-/*-----------------------------------------------------------------*/
-/* genNotFloat - generates not for float operations              */
-/*-----------------------------------------------------------------*/
-static void
-genNotFloat (operand * op, operand * res)
-{
-  int size, offset;
-  char *l;
-  symbol *tlbl;
-
-  D(emitcode (";     genNotFloat",""));
-
-  /* we will put 127 in the first byte of
-     the result */
-  aopPut (AOP (res), "#127", 0, isOperandVolatile (op, FALSE));
-  size = AOP_SIZE (op) - 1;
-  offset = 1;
-
-  l = aopGet (op->aop, offset++, FALSE, FALSE);
-  MOVA (l);
-
-  while (size--)
-    {
-      emitcode ("orl", "a,%s",
-               aopGet (op->aop,
-                       offset++, FALSE, FALSE));
-    }
-
-  tlbl = newiTempLabel (NULL);
-  aopPut (res->aop, one, 1, isOperandVolatile (op, FALSE));
-  emitcode ("jz", "%05d$", (tlbl->key + 100));
-  aopPut (res->aop, zero, 1, isOperandVolatile (op, FALSE));
-  emitcode ("", "%05d$:", (tlbl->key + 100));
-
-  size = res->aop->size - 2;
-  offset = 2;
-  /* put zeros in the rest */
-  while (size--)
-    aopPut (res->aop, zero, offset++, isOperandVolatile (op, FALSE));
-}
 
 /*-----------------------------------------------------------------*/
 /* opIsGptr: returns non-zero if the passed operand is       */
@@ -1343,7 +1392,6 @@ static void
 genNot (iCode * ic)
 {
   symbol *tlbl;
-  sym_link *optype = operandType (IC_LEFT (ic));
 
   D(emitcode (";     genNot",""));
 
@@ -1360,13 +1408,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);
@@ -1398,20 +1439,35 @@ genCpl (iCode * ic)
   aopOp (IC_RESULT (ic), ic, TRUE);
 
   /* special case if in bit space */
-  if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY) {
-    if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY) {
-      emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
-      emitcode ("cpl", "c");
-      emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
+  if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
+    {
+      if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
+       {
+         emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
+         emitcode ("cpl", "c");
+         emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
+         goto release;
+       }
+
+      tlbl=newiTempLabel(NULL);
+      if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC ||
+         AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
+         IS_AOP_PREG (IC_LEFT (ic)))
+       {
+         emitcode ("cjne", "%s,#0x01,%05d$",
+                   aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE),
+                   tlbl->key + 100);
+       }
+      else
+       {
+         char *l = aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE);
+         MOVA (l);
+         emitcode ("cjne", "a,#0x01,%05d$", tlbl->key + 100);
+       }
+      emitcode ("", "%05d$:", tlbl->key + 100);
+      outBitC (IC_RESULT(ic));
       goto release;
     }
-    tlbl=newiTempLabel(NULL);
-    emitcode ("cjne", "%s,#0x01,%05d$", 
-             aopGet(AOP(IC_LEFT(ic)), 0, FALSE,FALSE), tlbl->key+100);
-    emitcode ("", "%05d$:", tlbl->key+100);
-    outBitC (IC_RESULT(ic));
-    goto release;
-  }
 
   size = AOP_SIZE (IC_RESULT (ic));
   while (size--)
@@ -2019,16 +2075,16 @@ genCall (iCode * ic)
       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
        !IFFUNC_ISISR (dtype))
   {
-      swapBanks = TRUE;  
-  } 
-    
+      swapBanks = TRUE;
+  }
+
   /* if caller saves & we have not saved then */
   if (!ic->regsSaved)
       saveRegisters (ic);
 
   if (swapBanks)
   {
-        emitcode ("mov", "psw,#0x%02x", 
+        emitcode ("mov", "psw,#0x%02x",
            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
   }
 
@@ -2039,14 +2095,14 @@ genCall (iCode * ic)
 
   if (swapBanks)
   {
-       emitcode ("mov", "psw,#0x%02x", 
+       emitcode ("mov", "psw,#0x%02x",
           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
   }
 
   /* if we need assign a result value */
   if ((IS_ITEMP (IC_RESULT (ic)) &&
        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
-       OP_SYMBOL (IC_RESULT (ic))->accuse || 
+       OP_SYMBOL (IC_RESULT (ic))->accuse ||
        OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
       IS_TRUE_SYMOP (IC_RESULT (ic)))
     {
@@ -2268,10 +2324,6 @@ genFunction (iCode * ic)
       return;
   }
 
-  /* 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 */
   if (FUNC_REGBANK (ftype) != rbank)
@@ -2548,7 +2600,17 @@ genFunction (iCode * ic)
       emitcode ("add", "a,#0x%02x", ((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 */
+    }
 }
 
 /*-----------------------------------------------------------------*/
@@ -2564,6 +2626,12 @@ genEndFunction (iCode * ic)
       emitcode(";", "naked function: no epilogue.");
       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)
     {
@@ -2688,9 +2756,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)
        {
@@ -2709,9 +2774,6 @@ genEndFunction (iCode * ic)
     }
   else
     {
-      if (IFFUNC_ISCRITICAL (sym->type))
-       emitcode ("setb", "ea");
-
       if (IFFUNC_CALLEESAVES(sym->type))
        {
          int i;
@@ -3130,8 +3192,10 @@ static void
 genPlus (iCode * ic)
 {
   int size, offset = 0;
-  char *add;
+  int skip_bytes = 0;
+  char *add = "add";
   asmop *leftOp, *rightOp;
+  operand * op;
 
   /* special cases :- */
 
@@ -3193,33 +3257,92 @@ genPlus (iCode * ic)
     goto release;
 
   size = getDataSize (IC_RESULT (ic));
-
   leftOp = AOP(IC_LEFT(ic));
   rightOp = AOP(IC_RIGHT(ic));
-  add = "add";
+  op=IC_LEFT(ic);
+
+  /* if this is an add for an array access
+     at a 256 byte boundary */
+  if ( 2 == size
+       && AOP_TYPE (op) == AOP_IMMD
+       && IS_SYMOP (op)
+       && IS_SPEC (OP_SYM_ETYPE (op))
+       && SPEC_ABSA (OP_SYM_ETYPE (op))
+       && (SPEC_ADDR (OP_SYM_ETYPE (op)) & 0xff) == 0
+     )
+    {
+      D(emitcode (";     genPlus aligned array",""));
+      aopPut (AOP (IC_RESULT (ic)),
+             aopGet (rightOp, 0, FALSE, FALSE),
+             0,
+             isOperandVolatile (IC_RESULT (ic), FALSE));
 
-  while (size--)
-    {
-      if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
+      if( 1 == getDataSize (IC_RIGHT (ic)) )
        {
-         emitcode("mov", "b,a");
-         MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
-         emitcode("xch", "a,b");
-         MOVA (aopGet (rightOp, offset, FALSE, TRUE));
-         emitcode (add, "a,b");
+         aopPut (AOP (IC_RESULT (ic)),
+                 aopGet (leftOp, 1, FALSE, FALSE),
+                 1,
+                 isOperandVolatile (IC_RESULT (ic), FALSE));
        }
-      else if (aopGetUsesAcc (leftOp, offset))
-       {
-         MOVA (aopGet (leftOp, offset, FALSE, TRUE));
-         emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
+      else
+        {
+         MOVA (aopGet (AOP (IC_LEFT (ic)), 1, FALSE, FALSE));
+         emitcode ("add", "a,%s", aopGet (rightOp, 1, FALSE, FALSE));
+         aopPut (AOP (IC_RESULT (ic)), "a", 1, isOperandVolatile (IC_RESULT (ic), FALSE));
        }
+      goto release;
+    }
+
+  /* if the lower bytes of a literal are zero skip the addition */
+  if (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT )
+    {
+       while ((0 == ((unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) & (0xff << skip_bytes*8))) &&
+              (skip_bytes+1 < size))
+         {
+           skip_bytes++;
+        }
+       if (skip_bytes)
+         D(emitcode (";     genPlus shortcut",""));
+    }
+
+  while (size--)
+    {
+      if( offset >= skip_bytes )
+        {
+         if (aopGetUsesAcc (leftOp, offset) && aopGetUsesAcc (rightOp, offset))
+           {
+             emitcode("mov", "b,a");
+             MOVA (aopGet (leftOp,  offset, FALSE, TRUE));
+             emitcode("xch", "a,b");
+             MOVA (aopGet (rightOp, offset, FALSE, TRUE));
+             emitcode (add, "a,b");
+           }
+         else if (aopGetUsesAcc (leftOp, offset))
+           {
+             MOVA (aopGet (leftOp, offset, FALSE, TRUE));
+             emitcode (add, "a,%s", aopGet (rightOp, offset, FALSE, TRUE));
+           }
+         else
+           {
+             MOVA (aopGet (rightOp, offset, FALSE, TRUE));
+             emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
+           }
+         aopPut (AOP (IC_RESULT (ic)), "a", offset, isOperandVolatile (IC_RESULT (ic), FALSE));
+         add = "addc";  /* further adds must propagate carry */
+        }
       else
-       {
-         MOVA (aopGet (rightOp, offset, FALSE, TRUE));
-         emitcode (add, "a,%s", aopGet (leftOp, offset, FALSE, TRUE));
+        {
+          if( !sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) || 
+             isOperandVolatile (IC_RESULT (ic), FALSE))
+           {
+             /* just move */
+              aopPut (AOP (IC_RESULT (ic)),
+                     aopGet (leftOp, offset, FALSE, FALSE),
+                     offset,
+                     isOperandVolatile (IC_RESULT (ic), FALSE));
+           }
        }
-      aopPut (AOP (IC_RESULT (ic)), "a", offset++, isOperandVolatile (IC_RESULT (ic), FALSE));
-      add = "addc";  /* further adds must propagate carry */
+      offset++;
     }
 
   adjustArithmeticResult (ic);
@@ -3547,13 +3670,21 @@ genMultOneByte (operand * left,
 
   if (SPEC_USIGN(opetype)
       // ignore the sign of left and right, what else can we do?
-      || (SPEC_USIGN(operandType(left)) && 
+      || (SPEC_USIGN(operandType(left)) &&
          SPEC_USIGN(operandType(right)))) {
     // just an unsigned 8*8=8/16 multiply
     //emitcode (";","unsigned");
     // TODO: check for accumulator clash between left & right aops?
-    emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
-    MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
+  
+    if( AOP_TYPE(right)==AOP_LIT ){
+      // moving to accumulator first helps peepholes 
+      MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
+      emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
+    } else {
+      emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE));
+      MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
+    }
+    
     emitcode ("mul", "ab");
     aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
     if (size==2) {
@@ -3599,7 +3730,7 @@ genMultOneByte (operand * left,
     emitcode ("", "%05d$:", lbl->key+100);
   }
   emitcode ("mul", "ab");
-    
+
   lbl=newiTempLabel(NULL);
   emitcode ("jnb", "F0,%05d$", lbl->key+100);
   // only ONE op was negative, we have to do a 8/16-bit two's complement
@@ -3651,7 +3782,7 @@ genMult (iCode * ic)
 #if 0 // one of them can be a sloc shared with the result
     if (AOP_SIZE (left) == 1 && AOP_SIZE (right) == 1)
 #else
-  if (getSize(operandType(left)) == 1 && 
+  if (getSize(operandType(left)) == 1 &&
       getSize(operandType(right)) == 1)
 #endif
     {
@@ -3665,9 +3796,9 @@ genMult (iCode * ic)
   assert (0);
 
 release:
-  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
-  freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (result, NULL, ic, TRUE);
+  freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
 }
 
 /*-----------------------------------------------------------------*/
@@ -3819,8 +3950,8 @@ genDiv (iCode * ic)
   /* should have been converted to function call */
   assert (0);
 release:
-  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (result, NULL, ic, TRUE);
 }
 
@@ -3964,8 +4095,8 @@ genMod (iCode * ic)
   assert (0);
 
 release:
-  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (result, NULL, ic, TRUE);
 }
 
@@ -4109,8 +4240,8 @@ genCmp (operand * left, operand * right,
     }
 
 release:
-  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
     {
       outBitC (result);
@@ -4201,12 +4332,14 @@ 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;
       right = left;
       left = t;
     }
+  
   if (AOP_TYPE (right) == AOP_LIT)
     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
 
@@ -4230,6 +4363,7 @@ gencjneshort (operand * left, operand * right, symbol * lbl)
   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)))
     {
@@ -4440,8 +4574,8 @@ genCmpEq (iCode * ic, iCode * ifx)
     }
 
 release:
-  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (result, NULL, ic, TRUE);
 }
 
@@ -4540,8 +4674,8 @@ genAndOp (iCode * ic)
       outBitAcc (result);
     }
 
-  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (result, NULL, ic, TRUE);
 }
 
@@ -4582,8 +4716,8 @@ genOrOp (iCode * ic)
       outBitAcc (result);
     }
 
-  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (result, NULL, ic, TRUE);
 }
 
@@ -4829,6 +4963,8 @@ genAnd (iCode * ic, iCode * ifx)
            {
              if (ifx)
                jmpTrueOrFalse (ifx, tlbl);
+              else
+               emitcode ("", "%05d$:", tlbl->key + 100);
              goto release;
            }
        }
@@ -4919,6 +5055,8 @@ genAnd (iCode * ic, iCode * ifx)
            }
          else if (ifx)
            jmpTrueOrFalse (ifx, tlbl);
+          else
+           emitcode ("", "%05d$:", tlbl->key + 100);
        }
       else
        {
@@ -4961,8 +5099,8 @@ genAnd (iCode * ic, iCode * ifx)
     }
 
 release:
-  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (result, NULL, ic, TRUE);
 }
 
@@ -5205,6 +5343,8 @@ genOr (iCode * ic, iCode * ifx)
            }
          else if (ifx)
            jmpTrueOrFalse (ifx, tlbl);
+         else
+           emitcode ("", "%05d$:", tlbl->key + 100);
        }
       else
        for (; (size--); offset++)
@@ -5237,8 +5377,8 @@ genOr (iCode * ic, iCode * ifx)
     }
 
 release:
-  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (result, NULL, ic, TRUE);
 }
 
@@ -5498,8 +5638,8 @@ genXor (iCode * ic, iCode * ifx)
     }
 
 release:
-  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (result, NULL, ic, TRUE);
 }
 
@@ -5686,6 +5826,66 @@ 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);
+  aopOp (result, ic, FALSE);
+  
+  switch (AOP_SIZE (left))
+    {
+    case 1: /* swap nibbles in byte */
+      MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
+      emitcode ("swap", "a");
+      aopPut (AOP (result), "a", 0, isOperandVolatile (result, FALSE));
+      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));
+         aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
+                 0, isOperandVolatile (result, FALSE));
+         aopPut (AOP (result), "a", 1, isOperandVolatile (result, FALSE));
+       }
+      else if (operandsEqu (left, result))
+       {
+          char * reg = "a";
+         MOVA (aopGet (AOP (left), 0, FALSE, FALSE));
+         if (aopGetUsesAcc(AOP (left), 1) || aopGetUsesAcc(AOP (result), 0))
+           {
+             emitcode ("mov", "b,a");
+              reg = "b";
+            }
+         aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
+                 0, isOperandVolatile (result, FALSE));
+         aopPut (AOP (result), reg, 1, isOperandVolatile (result, FALSE));
+       }
+      else
+       {
+         aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE),
+                 0, isOperandVolatile (result, FALSE));
+         aopPut (AOP (result), aopGet (AOP (left), 0, FALSE, FALSE),
+                 1, isOperandVolatile (result, FALSE));
+       }
+      break;
+    default:
+      wassertl(FALSE, "unsupported SWAP operand size");
+    }
+  
+  freeAsmop (left, NULL, ic, TRUE);
+  freeAsmop (result, NULL, ic, TRUE);
+}
+
+    
 /*-----------------------------------------------------------------*/
 /* AccRol - rotate left accumulator by known count                 */
 /*-----------------------------------------------------------------*/
@@ -6528,7 +6728,7 @@ genLeftShiftLiteral (operand * left,
          genlshFour (result, left, shCount);
          break;
        default:
-         werror (E_INTERNAL_ERROR, __FILE__, __LINE__, 
+         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
                  "*** ack! mystery literal shift!\n");
          break;
        }
@@ -6998,7 +7198,7 @@ static void
 genRightShift (iCode * ic)
 {
   operand *right, *left, *result;
-  sym_link *retype;
+  sym_link *letype;
   int size, offset;
   char *l;
   symbol *tlbl, *tlbl1;
@@ -7007,9 +7207,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;
@@ -7113,113 +7313,135 @@ release:
 }
 
 /*-----------------------------------------------------------------*/
-/* 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 = 0;
-  sym_link *etype;
-  int offset = 0;
-  int rsize;
-
-  D(emitcode (";     genUnpackBits",""));
-
-  etype = getSpec (operandType (result));
-  rsize = getSize (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;
     }
+}
 
-  rlen = SPEC_BLEN (etype);
-
-  /* if we have bitdisplacement then it fits   */
-  /* into this byte completely or if length is */
-  /* less than a byte                          */
-  if ((shCnt = SPEC_BSTR (etype)) ||
-      (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);
-
-      emitcode ("anl", "a,#0x%02x",
-               ((unsigned char) -1) >> (8 - SPEC_BLEN (etype)));
-      aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
-      goto finish;
-    }
+    case PPOINTER:
+      MOVA (src);
+      emitcode ("movx", "@%s,a", rname);
+      break;
+      
+    case FPOINTER:
+      MOVA (src);
+      emitcode ("movx", "@dptr,a");
+      break;
 
-  /* bit field did not fit in a byte  */
-  aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
-
-  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;
+    case GPOINTER:
+      MOVA (src);
+      emitcode ("lcall", "__gptrput");
+      break;
+    }
+}
 
-       case CPOINTER:
-         emitcode ("clr", "a");
-         emitcode ("inc", "dptr");
-         emitcode ("movc", "a,@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 GPOINTER:
-         emitcode ("inc", "dptr");
-         emitcode ("lcall", "__gptrget");
-         break;
-       }
+  D(emitcode (";     genUnpackBits",""));
 
-      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,#0x%02x", ((unsigned char) -1) >> (8 - blen));
       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
+      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++, isOperandVolatile (result, FALSE));
+      if (rlen>8)
+        emitcode ("inc", "%s", rname);
     }
 
+  /* Handle the partial byte at the end */
   if (rlen)
     {
+      emitPtrByteGet (rname, ptype, FALSE);
       emitcode ("anl", "a,#0x%02x", ((unsigned char) -1) >> (8-rlen));
       aopPut (AOP (result), "a", offset++, isOperandVolatile (result, FALSE));
     }
@@ -7301,21 +7523,40 @@ genNearPointerGet (operand * left,
       return;
     }
 
 /* if the value is already in a pointer register
+ /* if the value is already in a pointer register
      then don't need anything more */
   if (!AOP_INPREG (AOP (left)))
     {
-      /* otherwise get a free pointer register */
-      aop = newAsmop (0);
-      preg = getFreePtr (ic, &aop, FALSE);
-      emitcode ("mov", "%s,%s",
-               preg->name,
-               aopGet (AOP (left), 0, FALSE, TRUE));
-      rname = preg->name;
+      if (IS_AOP_PREG (left))
+       {
+         // Aha, it is a pointer, just in disguise.
+         rname = aopGet (AOP (left), 0, FALSE, FALSE);
+         if (*rname != '@')
+           {
+             fprintf(stderr, "probable internal error: unexpected rname @ %s:%d\n",
+                     __FILE__, __LINE__);
+           }
+         else
+           {
+             // Expected case.
+             emitcode ("mov", "a%s,%s", rname + 1, rname);
+             rname++;  // skip the '@'.
+           }
+       }
+      else
+       {
+         /* otherwise get a free pointer register */
+         aop = newAsmop (0);
+         preg = getFreePtr (ic, &aop, FALSE);
+         emitcode ("mov", "%s,%s",
+                   preg->name,
+                   aopGet (AOP (left), 0, FALSE, TRUE));
+         rname = preg->name;
+       }
     }
   else
     rname = aopGet (AOP (left), 0, FALSE, FALSE);
-  
+
   //aopOp (result, ic, FALSE);
   aopOp (result, ic, result?TRUE:FALSE);
 
@@ -7353,7 +7594,7 @@ genNearPointerGet (operand * left,
       if (pi) { /* post increment present */
        aopPut(AOP ( left ),rname,0, isOperandVolatile (left, FALSE));
       }
-      freeAsmop (NULL, aop, ic, TRUE);
+      freeAsmop (NULL, aop, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
     }
   else
     {
@@ -7375,8 +7616,8 @@ genNearPointerGet (operand * left,
     }
 
   /* done */
+  freeAsmop (result, NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
   freeAsmop (left, NULL, ic, TRUE);
-  freeAsmop (result, NULL, ic, TRUE);
   if (pi) pi->generated = 1;
 }
 
@@ -7472,6 +7713,66 @@ genPagedPointerGet (operand * left,
 
 }
 
+/*--------------------------------------------------------------------*/
+/* loadDptrFromOperand - load dptr (and optionally B) from operand op */
+/*--------------------------------------------------------------------*/
+static void
+loadDptrFromOperand (operand *op, bool loadBToo)
+{
+  if (AOP_TYPE (op) != AOP_STR)
+    {
+      /* if this is remateriazable */
+      if (AOP_TYPE (op) == AOP_IMMD)
+       {
+         emitcode ("mov", "dptr,%s", aopGet (AOP (op), 0, TRUE, FALSE));
+          if (loadBToo)
+            {
+             if (AOP(op)->aopu.aop_immd.from_cast_remat) 
+               emitcode ("mov", "b,%s",aopGet(AOP (op), AOP_SIZE(op)-1, FALSE, FALSE));
+             else
+                {
+                  wassertl(FALSE, "need pointerCode");
+                  emitcode ("", "; mov b,???");
+                  /* genPointerGet and genPointerSet originally did different
+                  ** things for this case. Both seem wrong.
+                  ** from genPointerGet:
+                 **  emitcode ("mov", "b,#%d", pointerCode (retype));
+                  ** from genPointerSet:
+                 **  emitcode ("mov", "b,%s + 1", aopGet (AOP (result), 0, TRUE, FALSE));
+                  */
+                }
+            }
+       }
+      else if (AOP_TYPE (op) == AOP_DPTR)
+       {
+         if (loadBToo)
+           {
+             MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
+             emitcode ("push", "acc");
+             MOVA (aopGet (AOP (op), 1, FALSE, FALSE));
+             emitcode ("push", "acc");
+             emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
+             emitcode ("pop", "dph");
+             emitcode ("pop", "dpl");
+           }
+         else
+           {
+             MOVA (aopGet (AOP (op), 0, FALSE, FALSE));
+             emitcode ("push", "acc");
+             emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
+             emitcode ("pop", "dpl");
+           }
+       }
+      else
+       {                       /* we need to get it byte by byte */
+         emitcode ("mov", "dpl,%s", aopGet (AOP (op), 0, FALSE, FALSE));
+         emitcode ("mov", "dph,%s", aopGet (AOP (op), 1, FALSE, FALSE));
+         if (loadBToo)
+           emitcode ("mov", "b,%s", aopGet (AOP (op), 2, FALSE, FALSE));
+       }
+    }
+}
+
 /*-----------------------------------------------------------------*/
 /* genFarPointerGet - gget value from far space                    */
 /*-----------------------------------------------------------------*/
@@ -7485,21 +7786,9 @@ genFarPointerGet (operand * left,
   D(emitcode (";     genFarPointerGet",""));
 
   aopOp (left, ic, FALSE);
-
-  /* if the operand is already in dptr
-     then we do nothing else we move the value to dptr */
-  if (AOP_TYPE (left) != AOP_STR)
-    {
-      /* if this is remateriazable */
-      if (AOP_TYPE (left) == AOP_IMMD)
-       emitcode ("mov", "dptr,%s", aopGet (AOP (left), 0, TRUE, FALSE));
-      else
-       {                       /* we need to get it byte by byte */
-         emitcode ("mov", "dpl,%s", aopGet (AOP (left), 0, FALSE, FALSE));
-         emitcode ("mov", "dph,%s", aopGet (AOP (left), 1, FALSE, FALSE));
-       }
-    }
-  /* so dptr know contains the address */
+  loadDptrFromOperand (left, FALSE);
+  
+  /* so dptr now contains the address */
   aopOp (result, ic, FALSE);
 
   /* if bit then unpack */
@@ -7541,21 +7830,9 @@ genCodePointerGet (operand * left,
   D(emitcode (";     genCodePointerGet",""));
 
   aopOp (left, ic, FALSE);
-
-  /* if the operand is already in dptr
-     then we do nothing else we move the value to dptr */
-  if (AOP_TYPE (left) != AOP_STR)
-    {
-      /* if this is remateriazable */
-      if (AOP_TYPE (left) == AOP_IMMD)
-       emitcode ("mov", "dptr,%s", aopGet (AOP (left), 0, TRUE, FALSE));
-      else
-       {                       /* we need to get it byte by byte */
-         emitcode ("mov", "dpl,%s", aopGet (AOP (left), 0, FALSE, FALSE));
-         emitcode ("mov", "dph,%s", aopGet (AOP (left), 1, FALSE, FALSE));
-       }
-    }
-  /* so dptr know contains the address */
+  loadDptrFromOperand (left, FALSE);
+  
+  /* so dptr now contains the address */
   aopOp (result, ic, FALSE);
 
   /* if bit then unpack */
@@ -7606,27 +7883,8 @@ genGenPointerGet (operand * left,
   D(emitcode (";     genGenPointerGet",""));
 
   aopOp (left, ic, FALSE);
-
-  /* if the operand is already in dptr
-     then we do nothing else we move the value to dptr */
-  if (AOP_TYPE (left) != AOP_STR)
-    {
-      /* if this is remateriazable */
-      if (AOP_TYPE (left) == AOP_IMMD)
-       {
-         emitcode ("mov", "dptr,%s", aopGet (AOP (left), 0, TRUE, FALSE));
-         if (AOP(left)->aopu.aop_immd.from_cast_remat) 
-                 emitcode ("mov", "b,%s",aopGet(AOP (left), AOP_SIZE(left)-1, FALSE, FALSE));
-         else
-                 emitcode ("mov", "b,#%d", pointerCode (retype));
-       }
-      else
-       {                       /* we need to get it byte by byte */
-         emitcode ("mov", "dpl,%s", aopGet (AOP (left), 0, FALSE, FALSE));
-         emitcode ("mov", "dph,%s", aopGet (AOP (left), 1, FALSE, FALSE));
-         emitcode ("mov", "b,%s", aopGet (AOP (left), 2, FALSE, FALSE));
-       }
-    }
+  loadDptrFromOperand (left, TRUE);
+  
   /* so dptr know contains the address */
   aopOp (result, ic, FALSE);
 
@@ -7720,6 +7978,8 @@ genPointerGet (iCode * ic, iCode *pi)
 
 }
 
+
+
 /*-----------------------------------------------------------------*/
 /* genPackBits - generates code for packed bit storage             */
 /*-----------------------------------------------------------------*/
@@ -7728,172 +7988,125 @@ genPackBits (sym_link * etype,
             operand * right,
             char *rname, int p_type)
 {
-  int shCount = 0;
-  int offset = 0;
-  int rLen = 0;
-  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);
 
-  l = aopGet (AOP (right), offset++, FALSE, FALSE);
-  MOVA (l);
-
-  /* if the bit lenth is less than or    */
-  /* it exactly fits a byte then         */
-  if (SPEC_BLEN (etype) <= 8)
-    {
-      unsigned char mask = ((unsigned char) (0xFF << (blen + bstr)) |
-                           (unsigned char) (0xFF >> (8 - bstr)));
-      shCount = SPEC_BSTR (etype);
-
-      /* shift left acc */
-      AccLsh (shCount);
-
-      if (SPEC_BLEN (etype) < 8)
-       {                       /* if smaller than a byte */
-
-         emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
-
-         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,#0x%02x", mask);
-         emitcode ("orl", "a,b");
-         if (p_type == GPOINTER)
-           emitcode ("pop", "b");
-       }
-    }
-
-  switch (p_type)
+  /* If the bitfield length is less than a byte */
+  if (blen < 8)
     {
-    case POINTER:
-      emitcode ("mov", "@%s,a", rname);
-      break;
+      mask = ((unsigned char) (0xFF << (blen + bstr)) |
+             (unsigned char) (0xFF >> (8 - bstr)));
 
-    case FPOINTER:
-      emitcode ("movx", "@dptr,a");
-      break;
-
-    case GPOINTER:
-      emitcode ("lcall", "__gptrput");
-      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,#0x%02x", mask);
+          if (litval)
+            emitcode ("orl","a,#0x%02x", 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));
+                  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));
+              /* shift and mask source value */
+              AccLsh (bstr);
+              emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
+
+             /* transfer A to B and get next byte */
+              emitPtrByteGet (rname, p_type, TRUE);
+
+              emitcode ("anl", "a,#0x%02x", mask);
+              emitcode ("orl", "a,b");
+              if (p_type == GPOINTER)
+                emitcode ("pop", "b");
+           }
+        }
+
+      emitPtrByteSet (rname, p_type, "a");
+      return;
     }
 
-  /* 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)
+  /* 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)
     {
-
-      l = aopGet (AOP (right), offset++, FALSE, TRUE);
-
-      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);
+      emitPtrByteSet (rname, p_type, 
+                      aopGet (AOP (right), offset++, FALSE, TRUE) );
+      if (rlen>8)
+        emitcode ("inc", "%s", rname);
     }
 
-  MOVA (l);
-
-  /* last last was not complete */
-  if (rLen)
+  /* If there was a partial byte at the end */
+  if (rlen)
     {
-      emitcode ("anl", "a,#0x%02x",
-                (~(((unsigned char) -1 << rLen) & 0xff)) &0xff);
-
-      /* 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;
+      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,#0x%02x", mask);
+          if (litval)
+            emitcode ("orl","a,#0x%02x", litval);
+        }
+      else
+        {
+          /* Case with partial byte and arbitrary source
+          */
+          MOVA (aopGet (AOP (right), offset++, FALSE, FALSE));
+          emitcode ("anl", "a,#0x%02x", (~mask) & 0xff);
 
-       case GPOINTER:
-         emitcode ("push", "b");
-         emitcode ("push", "acc");
-         emitcode ("lcall", "__gptrget");
-         emitcode ("pop", "b");
-         break;
-       }
+         /* transfer A to B and get next byte */
+          emitPtrByteGet (rname, p_type, TRUE);
 
-      emitcode ("anl", "a,#0x%02x", (((unsigned char) -1 << rLen) & 0xff));
-      emitcode ("orl", "a,b");
+          emitcode ("anl", "a,#0x%02x", 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                 */
 /*-----------------------------------------------------------------*/
@@ -7956,7 +8169,7 @@ genNearPointerSet (operand * right,
       genDataPointerSet (right, result, ic);
       return;
     }
-  
+
   /* if the value is already in a pointer register
      then don't need anything more */
   if (!AOP_INPREG (AOP (result)))
@@ -7976,6 +8189,7 @@ genNearPointerSet (operand * right,
            else
            {
                // Expected case.
+               emitcode ("mov", "a%s,%s", rname + 1, rname);
                rname++;  // skip the '@'.
            }
        }
@@ -7996,7 +8210,7 @@ genNearPointerSet (operand * right,
     }
 
   aopOp (right, ic, FALSE);
-    
+
   /* if bitfield then unpack the bits */
   if (IS_BITVAR (retype) || IS_BITVAR (letype))
     genPackBits ((IS_BITVAR (retype) ? retype : letype), right, rname, POINTER);
@@ -8162,20 +8376,8 @@ genFarPointerSet (operand * right,
   D(emitcode (";     genFarPointerSet",""));
 
   aopOp (result, ic, FALSE);
-
-  /* if the operand is already in dptr
-     then we do nothing else we move the value to dptr */
-  if (AOP_TYPE (result) != AOP_STR)
-    {
-      /* if this is remateriazable */
-      if (AOP_TYPE (result) == AOP_IMMD)
-       emitcode ("mov", "dptr,%s", aopGet (AOP (result), 0, TRUE, FALSE));
-      else
-       {                       /* we need to get it byte by byte */
-         emitcode ("mov", "dpl,%s", aopGet (AOP (result), 0, FALSE, FALSE));
-         emitcode ("mov", "dph,%s", aopGet (AOP (result), 1, FALSE, FALSE));
-       }
-    }
+  loadDptrFromOperand (result, FALSE);
+  
   /* so dptr know contains the address */
   aopOp (right, ic, FALSE);
 
@@ -8219,27 +8421,8 @@ genGenPointerSet (operand * right,
   D(emitcode (";     genGenPointerSet",""));
 
   aopOp (result, ic, FALSE);
-
-  /* if the operand is already in dptr
-     then we do nothing else we move the value to dptr */
-  if (AOP_TYPE (result) != AOP_STR)
-    {
-      /* if this is remateriazable */
-      if (AOP_TYPE (result) == AOP_IMMD)
-       {
-         emitcode ("mov", "dptr,%s", aopGet (AOP (result), 0, TRUE, FALSE));
-         if (AOP(result)->aopu.aop_immd.from_cast_remat) 
-                 emitcode ("mov", "b,%s",aopGet(AOP (result), AOP_SIZE(result)-1, FALSE, FALSE));
-         else 
-                 emitcode ("mov", "b,%s + 1", aopGet (AOP (result), 0, TRUE, FALSE));
-       }
-      else
-       {                       /* we need to get it byte by byte */
-         emitcode ("mov", "dpl,%s", aopGet (AOP (result), 0, FALSE, FALSE));
-         emitcode ("mov", "dph,%s", aopGet (AOP (result), 1, FALSE, FALSE));
-         emitcode ("mov", "b,%s", aopGet (AOP (result), 2, FALSE, FALSE));
-       }
-    }
+  loadDptrFromOperand (result, TRUE);
+  
   /* so dptr know contains the address */
   aopOp (right, ic, FALSE);
 
@@ -8636,7 +8819,9 @@ genCast (iCode * ic)
   aopOp (result, ic, FALSE);
 
   /* if the result is a bit (and not a bitfield) */
-  if (AOP_TYPE (result) == AOP_CRY)
+  // if (AOP_TYPE (result) == AOP_CRY)
+  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 */
@@ -8930,36 +9115,119 @@ genReceive (iCode * ic)
 static void
 genDummyRead (iCode * ic)
 {
-  operand *right;
+  operand *op;
   int size, offset;
 
   D(emitcode(";     genDummyRead",""));
 
-  right = IC_RIGHT (ic);
+  op = IC_RIGHT (ic);
+  if (op && IS_SYMOP (op))
+    {
+      aopOp (op, ic, FALSE);
 
-  aopOp (right, ic, 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));
+           offset++;
+         }
+       }
 
-  /* if the result is a bit */
-  if (AOP_TYPE (right) == AOP_CRY)
-    {
-      emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
-      goto release;
+      freeAsmop (op, NULL, ic, TRUE);
     }
 
-  /* bit variables done */
-  /* general case */
-  size = AOP_SIZE (right);
-  offset = 0;
-  while (size--)
+  op = IC_LEFT (ic);
+  if (op && IS_SYMOP (op))
     {
-      emitcode ("mov", "a,%s", aopGet (AOP (right), offset, FALSE, FALSE));
-      offset++;
+      aopOp (op, ic, 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));
+           offset++;
+         }
+       }
+
+      freeAsmop (op, NULL, ic, TRUE);
     }
+}
 
-release:
-  freeAsmop (right, 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);
+
+  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);
+      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));
+          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");
+    }
 }
 
+
 /*-----------------------------------------------------------------*/
 /* gen51Code - generate code for 8051 based controllers            */
 /*-----------------------------------------------------------------*/
@@ -8994,7 +9262,8 @@ gen51Code (iCode * lic)
 
   for (ic = lic; ic; ic = ic->next)
     {
-
+      _G.current_iCode = ic;
+      
       if (ic->lineno && cln != ic->lineno)
        {
          if (options.debug)
@@ -9217,11 +9486,24 @@ gen51Code (iCode * lic)
          genDummyRead (ic);
          break;
 
+       case CRITICAL:
+         genCritical (ic);
+         break;
+
+       case ENDCRITICAL:
+         genEndCritical (ic);
+         break;
+
+       case SWAP:
+         genSwap (ic);
+         break;
+
        default:
          ic = ic;
        }
     }
 
+  _G.current_iCode = NULL;
 
   /* now we are ready to call the
      peep hole optimizer */