ding, dong, the ack is dead! (fixed the last "Ack!" error)
[fw/sdcc] / src / ds390 / gen.c
index 7685031fb203c8720fdd21d191649479990e1761..c9fff2d325b98fd3ef55083189edcec6f3c88241 100644 (file)
 #ifdef HAVE_SYS_ISA_DEFS_H
 #include <sys/isa_defs.h>
 #else
+#ifdef HAVE_MACHINE_ENDIAN_H
+#include <machine/endian.h>
+#else
 #ifdef HAVE_ENDIAN_H
 #include <endian.h>
 #else
-#if !defined(__BORLANDC__) && !defined(_MSC_VER)
+#if !defined(__BORLANDC__) && !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__CYGWIN__)
 #warning "Cannot determine ENDIANESS of this machine assuming LITTLE_ENDIAN"
 #warning "If you running sdcc on an INTEL 80x86 Platform you are okay"
 #endif
 #endif
 #endif
+#endif
+
+#define BETTER_LITERAL_SHIFT
 
 char *aopLiteral (value * val, int offset);
 
@@ -61,9 +67,15 @@ static char *spname;
 
 #define D(x) x
 
+#define TR_DPTR(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_DPTR1 %s ", s); }
+#define TR_AP(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_AP %s ", s); }
+
 unsigned fReturnSizeDS390 = 5; /* shared with ralloc.c */
-static char *fReturn[] =
+static char *fReturn24[] =
 {"dpl", "dph", "dpx", "b", "a"};
+static char *fReturn16[] =
+{"dpl", "dph", "b", "a"};
+static char **fReturn = fReturn24;
 static char *accUse[] =
 {"a", "b"};
 
@@ -81,7 +93,7 @@ static struct
   }
 _G;
 
-static void saverbank (int, iCode *, bool);
+static void saveRBank (int, iCode *, bool);
 
 #define RESULTONSTACK(x) \
                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
@@ -98,6 +110,10 @@ static void saverbank (int, iCode *, bool);
 #define CLRC    emitcode("clr","c")
 #define SETC    emitcode("setb","c")
 
+// A scratch register which will be used to hold
+// result bytes from operands in far space via DPTR2.
+#define DP2_RESULT_REG "ap"
+
 static lineNode *lineHead = NULL;
 static lineNode *lineCurr = NULL;
 
@@ -120,7 +136,7 @@ static void
 emitcode (char *inst, char *fmt,...)
 {
   va_list ap;
-  char lb[MAX_INLINEASM];
+  char lb[INITIAL_INLINEASM];
   char *lbp = lb;
 
   va_start (ap, fmt);
@@ -162,9 +178,9 @@ getFreePtr (iCode * ic, asmop ** aopp, bool result)
 
   /* first check if r0 & r1 are used by this
      instruction, in which case we are in trouble */
-  if ((r0iu = bitVectBitValue (ic->rUsed, R0_IDX)) &&
-      (r1iu = bitVectBitValue (ic->rUsed, R1_IDX)))
-    {
+  r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
+  r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
+  if (r0iu && r1iu) {
       goto endOfWorld;
     }
 
@@ -233,7 +249,6 @@ endOfWorld:
       return NULL;
     }
 
-  piCode (ic, stdout);
   /* other wise this is true end of the world */
   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
          "getFreePtr should never reach here");
@@ -281,6 +296,7 @@ genSetDPTR (int n)
     }
   else
     {
+      TR_DPTR("#1");
       emitcode ("mov", "dps, #0x01");
     }
 }
@@ -307,7 +323,11 @@ _startLazyDPSEvaluation (void)
 {
   _currentDPS = 0;
   _desiredDPS = 0;
+#ifdef BETTER_LITERAL_SHIFT  
+  _lazyDPS++;
+#else
   _lazyDPS = 1;
+#endif  
 }
 
 /*-----------------------------------------------------------------*/
@@ -346,14 +366,21 @@ _flushLazyDPS (void)
 static void
 _endLazyDPSEvaluation (void)
 {
-  if (_currentDPS)
+#ifdef BETTER_LITERAL_SHIFT  
+  _lazyDPS--;
+#else
+  _lazyDPS = 0;
+#endif    
+  if (!_lazyDPS)
+  {
+    if (_currentDPS)
     {
       genSetDPTR (0);
       _flushLazyDPS ();
     }
-  _lazyDPS = 0;
-  _currentDPS = 0;
-  _desiredDPS = 0;
+    _currentDPS = 0;
+    _desiredDPS = 0;
+  }
 }
 
 
@@ -440,15 +467,16 @@ aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
 
       if (useDP2)
        {
-         /* genSetDPTR(1); */
-         emitcode ("mov", "dpx1,#0x40");
+         if (options.model == MODEL_FLAT24)
+           emitcode ("mov", "dpx1,#0x40");
+   TR_DPTR("#2");
          emitcode ("mov", "dph1,#0x00");
          emitcode ("mov", "dpl1, a");
-         /* genSetDPTR(0); */
        }
       else
        {
-         emitcode ("mov", "dpx,#0x40");
+         if (options.model == MODEL_FLAT24)
+           emitcode ("mov", "dpx,#0x40");
          emitcode ("mov", "dph,#0x00");
          emitcode ("mov", "dpl, a");
        }
@@ -900,7 +928,7 @@ dealloc:
 /*------------------------------------------------------------------*/
 /* aopGet - for fetching value of the aop                           */
 /*                    */
-/* Set canClobberACC if you are aure it is OK to clobber the value  */
+/* Set canClobberACC if you are sure it is OK to clobber the value  */
 /* in the accumulator. Set it FALSE otherwise; FALSE is always safe, */
 /* just less efficient.               */
 /*------------------------------------------------------------------*/
@@ -959,7 +987,8 @@ aopGet (asmop * aop,
          genSetDPTR (1);
          if (!canClobberACC)
            {
-             emitcode ("xch", "a, ap");
+       TR_AP("#1");
+             emitcode ("xch", "a, %s", DP2_RESULT_REG);
            }
        }
 
@@ -993,8 +1022,9 @@ aopGet (asmop * aop,
          genSetDPTR (0);
          if (!canClobberACC)
            {
-             emitcode ("xch", "a, ap");
-             return "ap";
+       TR_AP("#2");
+             emitcode ("xch", "a, %s", DP2_RESULT_REG);
+             return DP2_RESULT_REG;
            }
        }
       return (dname ? "acc" : "a");
@@ -1224,7 +1254,6 @@ aopPut (asmop * aop, char *s, int offset)
                {
                  MOVA (s);
                }
-#if 0 // jwk: I am not 1000% sure
              {
                symbol *lbl = newiTempLabel (NULL);
                emitcode ("clr", "c");
@@ -1233,9 +1262,6 @@ aopPut (asmop * aop, char *s, int offset)
                emitcode ("", "%05d$:", lbl->key + 100);
                emitcode ("mov", "%s,c", aop->aopu.aop_dir);
              }
-#else
-             emitcode ("mov", "%s,acc.0", aop->aopu.aop_dir);
-#endif
            }
        }
       break;
@@ -1374,7 +1400,6 @@ genNotFloat (operand * op, operand * res)
                        offset++, FALSE, FALSE, FALSE));
     }
   _endLazyDPSEvaluation ();
-  tlbl = newiTempLabel (NULL);
 
   tlbl = newiTempLabel (NULL);
   aopPut (res->aop, one, 1);
@@ -1473,8 +1498,9 @@ outBitC (operand * result)
 static void
 toBoolean (operand * oper)
 {
-  int size = AOP_SIZE (oper) - 1;
-  int offset = 1;
+  int  size = AOP_SIZE (oper) - 1;
+  int  offset = 1;
+  bool usedB = FALSE;
 
   /* The generic part of a generic pointer should
    * not participate in it's truth value.
@@ -1489,8 +1515,9 @@ toBoolean (operand * oper)
     }
 
   _startLazyDPSEvaluation ();
-  if (AOP_NEEDSACC (oper))
+  if (AOP_NEEDSACC (oper) && size)
     {
+      usedB = TRUE;
       emitcode ("push", "b");
       emitcode ("mov", "b, %s", aopGet (AOP (oper), 0, FALSE, FALSE, FALSE));
     }
@@ -1500,7 +1527,7 @@ toBoolean (operand * oper)
     }
   while (size--)
     {
-      if (AOP_NEEDSACC (oper))
+      if (usedB)
        {
          emitcode ("orl", "b,%s", aopGet (AOP (oper), offset++, FALSE, FALSE, FALSE));
        }
@@ -1511,7 +1538,7 @@ toBoolean (operand * oper)
     }
   _endLazyDPSEvaluation ();
 
-  if (AOP_NEEDSACC (oper))
+  if (usedB)
     {
       emitcode ("mov", "a,b");
       emitcode ("pop", "b");
@@ -1747,7 +1774,8 @@ saveRegisters (iCode * lic)
 
   /* if the registers have been saved already then
      do nothing */
-  if (ic->regsSaved || (OP_SYMBOL (IC_LEFT (ic))->calleeSave))
+  if (ic->regsSaved || IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type) ||
+      IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))))
     return;
 
   /* find the registers in use at this time
@@ -1781,18 +1809,12 @@ saveRegisters (iCode * lic)
     for (i = 0; i < ds390_nRegs; i++)
       {
        if (bitVectBitValue (rsave, i))
-         emitcode ("push", "%s ;jwk saveRegisters", ds390_regWithIdx (i)->dname);
+         emitcode ("push", "%s", ds390_regWithIdx (i)->dname);
       }
 
   detype = getSpec (operandType (IC_LEFT (ic)));
-  if (detype &&
-      (SPEC_BANK (currFunc->etype) != SPEC_BANK (detype)) &&
-      IS_ISR (currFunc->etype) &&
-      !ic->bankSaved)
-
-    saverbank (SPEC_BANK (detype), ic, TRUE);
-
 }
+
 /*-----------------------------------------------------------------*/
 /* unsaveRegisters - pop the pushed registers                      */
 /*-----------------------------------------------------------------*/
@@ -1830,7 +1852,7 @@ unsaveRegisters (iCode * ic)
     for (i = ds390_nRegs; i >= 0; i--)
       {
        if (bitVectBitValue (rsave, i))
-         emitcode ("pop", "%s ;jwk unsaveRegisters", ds390_regWithIdx (i)->dname);
+         emitcode ("pop", "%s", ds390_regWithIdx (i)->dname);
       }
 
 }
@@ -1952,7 +1974,7 @@ genIpush (iCode * ic)
              MOVA (l);
              l = "acc";
            }
-         emitcode ("push", "%s ;jwk genIpush: !parm", l);
+         emitcode ("push", "%s", l);
        }
       _endLazyDPSEvaluation ();
       return;
@@ -1989,7 +2011,7 @@ genIpush (iCode * ic)
          emitcode ("push", "acc");
        }
       else
-       emitcode ("push", "%s ;jwk genIpush", l);
+       emitcode ("push", "%s", l);
     }
   _endLazyDPSEvaluation ();
 
@@ -2018,7 +2040,7 @@ genIpop (iCode * ic)
   _startLazyDPSEvaluation ();
   while (size--)
     {
-      emitcode ("pop", "%s ;jwk genIpop", aopGet (AOP (IC_LEFT (ic)), offset--,
+      emitcode ("pop", "%s", aopGet (AOP (IC_LEFT (ic)), offset--,
                                     FALSE, TRUE, TRUE));
     }
   _endLazyDPSEvaluation ();
@@ -2027,31 +2049,42 @@ genIpop (iCode * ic)
 }
 
 /*-----------------------------------------------------------------*/
-/* unsaverbank - restores the resgister bank from stack            */
+/* unsaveRBank - restores the resgister bank from stack            */
 /*-----------------------------------------------------------------*/
 static void
-unsaverbank (int bank, iCode * ic, bool popPsw)
+unsaveRBank (int bank, iCode * ic, bool popPsw)
 {
   int i;
-  asmop *aop;
+  asmop *aop = NULL;
   regs *r = NULL;
 
+  if (options.useXstack)
+  {
+      if (!ic)
+      {
+         /* Assume r0 is available for use. */
+         r = ds390_regWithIdx (R0_IDX);;          
+      }        
+      else
+      {
+         aop = newAsmop (0);
+         r = getFreePtr (ic, &aop, FALSE);
+      }
+      emitcode ("mov", "%s,_spx", r->name);      
+  }
+  
   if (popPsw)
     {
       if (options.useXstack)
-       {
-         aop = newAsmop (0);
-         r = getFreePtr (ic, &aop, FALSE);
-
-
-         emitcode ("mov", "%s,_spx", r->name);
+      {
          emitcode ("movx", "a,@%s", r->name);
          emitcode ("mov", "psw,a");
          emitcode ("dec", "%s", r->name);
-
        }
       else
+      {
        emitcode ("pop", "psw");
+      }
     }
 
   for (i = (ds390_nRegs - 1); i >= 0; i--)
@@ -2071,30 +2104,38 @@ unsaverbank (int bank, iCode * ic, bool popPsw)
 
   if (options.useXstack)
     {
-
       emitcode ("mov", "_spx,%s", r->name);
-      freeAsmop (NULL, aop, ic, TRUE);
-
     }
+    
+  if (aop)
+  {
+      freeAsmop (NULL, aop, ic, TRUE);  
+  }    
 }
 
 /*-----------------------------------------------------------------*/
-/* saverbank - saves an entire register bank on the stack          */
+/* saveRBank - saves an entire register bank on the stack          */
 /*-----------------------------------------------------------------*/
 static void
-saverbank (int bank, iCode * ic, bool pushPsw)
+saveRBank (int bank, iCode * ic, bool pushPsw)
 {
   int i;
-  asmop *aop;
+  asmop *aop = NULL;
   regs *r = NULL;
 
   if (options.useXstack)
     {
-
-      aop = newAsmop (0);
-      r = getFreePtr (ic, &aop, FALSE);
-      emitcode ("mov", "%s,_spx", r->name);
-
+        if (!ic)
+        {
+                 /* Assume r0 is available for use. */
+                 r = ds390_regWithIdx (R0_IDX);;
+        }
+        else
+        {
+                 aop = newAsmop (0);
+                 r = getFreePtr (ic, &aop, FALSE);
+        }
+        emitcode ("mov", "%s,_spx", r->name);    
     }
 
   for (i = 0; i < ds390_nRegs; i++)
@@ -2119,16 +2160,24 @@ saverbank (int bank, iCode * ic, bool pushPsw)
          emitcode ("movx", "@%s,a", r->name);
          emitcode ("inc", "%s", r->name);
          emitcode ("mov", "_spx,%s", r->name);
-         freeAsmop (NULL, aop, ic, TRUE);
-
        }
       else
+      {
        emitcode ("push", "psw");
+      }
 
       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0x00ff);
     }
-  ic->bankSaved = 1;
-
+  
+  if (aop)
+  {
+       freeAsmop (NULL, aop, ic, TRUE);
+  }    
+    
+  if (ic)
+  {  
+      ic->bankSaved = 1;
+  }
 }
 
 /*-----------------------------------------------------------------*/
@@ -2137,27 +2186,41 @@ saverbank (int bank, iCode * ic, bool pushPsw)
 static void
 genCall (iCode * ic)
 {
-  sym_link *detype;
-
-  D (emitcode (";", "genCall ");
-    );
+  sym_link *dtype;
+  bool restoreBank = FALSE;
+  bool swapBanks = FALSE;
 
-  /* if caller saves & we have not saved then */
-  if (!ic->regsSaved)
-    saveRegisters (ic);
+  D (emitcode (";", "genCall "););
 
-  /* if we are calling a function that is not using
+  /* if we are calling a not _naked function that is not using
      the same register bank then we need to save the
      destination registers on the stack */
-  detype = getSpec (operandType (IC_LEFT (ic)));
-  if (detype &&
-      (SPEC_BANK (currFunc->etype) != SPEC_BANK (detype)) &&
-      IS_ISR (currFunc->etype) &&
-      !ic->bankSaved)
-
-    saverbank (SPEC_BANK (detype), ic, TRUE);
-
+  dtype = operandType (IC_LEFT (ic));
+  if (dtype && !IFFUNC_ISNAKED(dtype) &&
+      (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
+      IFFUNC_ISISR (currFunc->type))
+  {
+      if (!ic->bankSaved) 
+      {
+           /* This is unexpected; the bank should have been saved in
+            * genFunction.
+            */
+          saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
+          restoreBank = TRUE;
+      }
+      swapBanks = TRUE;
+  }
+  
+    /* if caller saves & we have not saved then */
+    if (!ic->regsSaved)
+      saveRegisters (ic);
+  
   /* if send set is not empty the assign */
+  /* We've saved all the registers we care about;
+  * therefore, we may clobber any register not used
+  * in the calling convention (i.e. anything not in
+  * fReturn.
+  */
   if (_G.sendSet)
     {
       iCode *sic;
@@ -2167,33 +2230,63 @@ genCall (iCode * ic)
        {
          int size, offset = 0;
 
-         aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
+         aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
          size = AOP_SIZE (IC_LEFT (sic));
 
          _startLazyDPSEvaluation ();
          while (size--)
            {
-             char *l = aopGet (AOP (IC_LEFT (sic)), offset,
+             char *l = aopGet (AOP(IC_LEFT(sic)), offset,
                                FALSE, FALSE, TRUE);
-             if (strcmp (l, fReturn[offset])) {
-               genSetDPTR(0);
-               _flushLazyDPS();
-               emitcode ("mov", "%s,%s ;jwk lazy genCall",
-                         fReturn[offset],
-                         l);
-             }
+               if ((AOP_TYPE(IC_LEFT(sic)) == AOP_DPTR) && size)
+               {
+                   emitcode("mov", "%s,%s", regs390[offset].name, l);
+               }
+               else if (strcmp (l, fReturn[offset]))
+               {
+                   emitcode ("mov", "%s,%s",
+                             fReturn[offset],
+                             l);
+               }
              offset++;
            }
          _endLazyDPSEvaluation ();
+         if (AOP_TYPE(IC_LEFT(sic)) == AOP_DPTR)
+         {
+             size = AOP_SIZE (IC_LEFT (sic));
+             if (size)
+             {
+                size--;
+             }
+             while (size)
+             {
+                  size--;
+                  emitcode("mov", "%s,%s",
+                                   fReturn[size], regs390[size].name);
+             }
+         }
          freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
        }
       _G.sendSet = NULL;
-    }
+    }  
+    
+  if (swapBanks)
+  {
+        emitcode ("mov", "psw,#0x%02x", 
+           ((FUNC_REGBANK(dtype)) << 3) & 0xff);
+  }
+
   /* make the call */
   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
                            OP_SYMBOL (IC_LEFT (ic))->rname :
                            OP_SYMBOL (IC_LEFT (ic))->name));
 
+  if (swapBanks)
+  {
+       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 ||
@@ -2206,8 +2299,6 @@ genCall (iCode * ic)
          int size = getSize (operandType (IC_RESULT (ic)));
 
          /* Special case for 1 or 2 byte return in far space. */
-         emitcode (";", "Kevin function call abuse #1");
-
          MOVA (fReturn[0]);
          if (size > 1)
            {
@@ -2249,18 +2340,15 @@ genCall (iCode * ic)
       else
        for (i = 0; i < ic->parmBytes; i++)
          emitcode ("dec", "%s", spname);
-
     }
 
-  /* if register bank was saved then pop them */
-  if (ic->bankSaved)
-    unsaverbank (SPEC_BANK (detype), ic, TRUE);
-
   /* if we hade saved some registers then unsave them */
-  if (ic->regsSaved && !(OP_SYMBOL (IC_LEFT (ic))->calleeSave))
+  if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
     unsaveRegisters (ic);
 
-
+  /* if register bank was saved then pop them */
+  if (restoreBank)
+    unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
 }
 
 /*-----------------------------------------------------------------*/
@@ -2269,7 +2357,7 @@ genCall (iCode * ic)
 static void
 genPcall (iCode * ic)
 {
-  sym_link *detype;
+  sym_link *dtype;
   symbol *rlbl = newiTempLabel (NULL);
 
   D (emitcode (";", "genPcall ");
@@ -2283,11 +2371,11 @@ genPcall (iCode * ic)
   /* if we are calling a function that is not using
      the same register bank then we need to save the
      destination registers on the stack */
-  detype = getSpec (operandType (IC_LEFT (ic)));
-  if (detype &&
-      IS_ISR (currFunc->etype) &&
-      (SPEC_BANK (currFunc->etype) != SPEC_BANK (detype)))
-    saverbank (SPEC_BANK (detype), ic, TRUE);
+  dtype = operandType (IC_LEFT (ic));
+  if (dtype &&
+      IFFUNC_ISISR (currFunc->type) &&
+      (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)))
+    saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
 
 
   /* push the return address on to the stack */
@@ -2378,10 +2466,10 @@ genPcall (iCode * ic)
     }
 
   /* if register bank was saved then unsave them */
-  if (detype &&
-      (SPEC_BANK (currFunc->etype) !=
-       SPEC_BANK (detype)))
-    unsaverbank (SPEC_BANK (detype), ic, TRUE);
+  if (dtype &&
+      (FUNC_REGBANK (currFunc->type) !=
+       FUNC_REGBANK (dtype)))
+    unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
 
   /* if we hade saved some registers then
      unsave them */
@@ -2443,10 +2531,10 @@ static void
 genFunction (iCode * ic)
 {
   symbol *sym;
-  sym_link *fetype;
+  sym_link *ftype;
+  bool   switchedPSW = FALSE;
 
-  D (emitcode (";", "genFunction ");
-    );
+  D (emitcode (";", "genFunction "););
 
   _G.nRegsSaved = 0;
   /* create the function header */
@@ -2455,19 +2543,25 @@ genFunction (iCode * ic)
   emitcode (";", "-----------------------------------------");
 
   emitcode ("", "%s:", sym->rname);
-  fetype = getSpec (operandType (IC_LEFT (ic)));
+  ftype = operandType (IC_LEFT (ic));
+
+  if (IFFUNC_ISNAKED(ftype))
+  {
+      emitcode(";", "naked function: no prologue.");
+      return;
+  }
 
   /* if critical function then turn interrupts off */
-  if (SPEC_CRTCL (fetype))
+  if (IFFUNC_ISCRITICAL (ftype))
     emitcode ("clr", "ea");
 
   /* here we need to generate the equates for the
      register bank if required */
-  if (SPEC_BANK (fetype) != rbank)
+  if (FUNC_REGBANK (ftype) != rbank)
     {
       int i;
 
-      rbank = SPEC_BANK (fetype);
+      rbank = FUNC_REGBANK (ftype);
       for (i = 0; i < ds390_nRegs; i++)
        {
          if (strcmp (regs390[i].base, "0") == 0)
@@ -2484,7 +2578,7 @@ genFunction (iCode * ic)
 
   /* if this is an interrupt service routine then
      save acc, b, dpl, dph  */
-  if (IS_ISR (sym->etype))
+  if (IFFUNC_ISISR (sym->type))
     {
 
       if (!inExcludeList ("acc"))
@@ -2507,19 +2601,19 @@ genFunction (iCode * ic)
              emitcode ("push", "dpl1");
              emitcode ("push", "dph1");
              emitcode ("push", "dpx1");
-             emitcode ("push", "ap");
+             emitcode ("push",  DP2_RESULT_REG);
            }
        }
       /* if this isr has no bank i.e. is going to
          run with bank 0 , then we need to save more
          registers :-) */
-      if (!SPEC_BANK (sym->etype))
+      if (!FUNC_REGBANK (sym->type))
        {
 
          /* if this function does not call any other
             function then we can be economical and
             save only those registers that are used */
-         if (!sym->hasFcall)
+         if (!IFFUNC_HASFCALL(sym->type))
            {
              int i;
 
@@ -2539,17 +2633,107 @@ genFunction (iCode * ic)
          else
            {
              /* this function has  a function call cannot
-                determines register usage so we will have the
+                determines register usage so we will have to push the
                 entire bank */
-             saverbank (0, ic, FALSE);
+             saveRBank (0, ic, FALSE);
+           }
+       }
+       else
+       {
+           /* This ISR uses a non-zero bank.
+            *
+            * We assume that the bank is available for our
+            * exclusive use.
+            *
+            * However, if this ISR calls a function which uses some
+            * other bank, we must save that bank entirely.
+            */
+           unsigned long banksToSave = 0;
+           
+           if (IFFUNC_HASFCALL(sym->type))
+           {
+
+#define MAX_REGISTER_BANKS 4
+
+               iCode *i;
+               int ix;
+
+               for (i = ic; i; i = i->next)
+               {
+                   if (i->op == ENDFUNCTION)
+                   {
+                       /* we got to the end OK. */
+                       break;
+                   }
+                   
+                   if (i->op == CALL)
+                   {
+                       sym_link *dtype;
+                       
+                       dtype = operandType (IC_LEFT(i));
+                       if (dtype 
+                        && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
+                       {
+                            /* Mark this bank for saving. */
+                            if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
+                            {
+                                werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
+                            }
+                            else
+                            {
+                                banksToSave |= (1 << FUNC_REGBANK(dtype));
+                            }
+                            
+                            /* And note that we don't need to do it in 
+                             * genCall.
+                             */
+                            i->bankSaved = 1;
+                       }
+                   }
+                   if (i->op == PCALL)
+                   {
+                       /* This is a mess; we have no idea what
+                        * register bank the called function might
+                        * use.
+                        *
+                        * The only thing I can think of to do is
+                        * throw a warning and hope.
+                        */
+                       werror(W_FUNCPTR_IN_USING_ISR);   
+                   }
+               }
+
+               if (banksToSave && options.useXstack)
+               {
+                   /* Since we aren't passing it an ic, 
+                    * saveRBank will assume r0 is available to abuse.
+                    *
+                    * So switch to our (trashable) bank now, so
+                    * the caller's R0 isn't trashed.
+                    */
+                   emitcode ("push", "psw");
+                   emitcode ("mov", "psw,#0x%02x", 
+                             (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
+                   switchedPSW = TRUE;
+               }
+               
+               for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
+               {
+                    if (banksToSave & (1 << ix))
+                    {
+                        saveRBank(ix, NULL, FALSE);
+                    }
+               }
            }
+           // jwk: this needs a closer look
+           SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
        }
     }
   else
     {
       /* if callee-save to be used for this function
          then save the registers being used in this function */
-      if (sym->calleeSave)
+      if (IFFUNC_CALLEESAVES(sym->type))
        {
          int i;
 
@@ -2571,13 +2755,14 @@ genFunction (iCode * ic)
     }
 
   /* set the register bank to the desired value */
-  if (SPEC_BANK (sym->etype) || IS_ISR (sym->etype))
+  if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
+   && !switchedPSW)
     {
       emitcode ("push", "psw");
-      emitcode ("mov", "psw,#0x%02x", (SPEC_BANK (sym->etype) << 3) & 0x00ff);
+      emitcode ("mov", "psw,#0x%02x", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
     }
 
-  if (IS_RENT (sym->etype) || options.stackAuto)
+  if (IFFUNC_ISREENT (sym->type) || options.stackAuto)
     {
 
       if (options.useXstack)
@@ -2634,10 +2819,15 @@ genEndFunction (iCode * ic)
 {
   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
 
-  D (emitcode (";", "genEndFunction ");
-    );
+  D (emitcode (";", "genEndFunction "););
+
+  if (IFFUNC_ISNAKED(sym->type))
+  {
+      emitcode(";", "naked function: no epilogue.");
+      return;
+  }
 
-  if (IS_RENT (sym->etype) || options.stackAuto)
+  if (IFFUNC_ISREENT (sym->type) || options.stackAuto)
     {
       emitcode ("mov", "%s,_bp", spname);
     }
@@ -2653,7 +2843,7 @@ genEndFunction (iCode * ic)
     }
 
 
-  if ((IS_RENT (sym->etype) || options.stackAuto))
+  if ((IFFUNC_ISREENT (sym->type) || options.stackAuto))
     {
       if (options.useXstack)
        {
@@ -2669,23 +2859,31 @@ genEndFunction (iCode * ic)
     }
 
   /* restore the register bank  */
-  if (SPEC_BANK (sym->etype) || IS_ISR (sym->etype))
-    emitcode ("pop", "psw");
+  if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
+  {
+    if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
+     || !options.useXstack)
+    {
+        /* Special case of ISR using non-zero bank with useXstack
+         * is handled below.
+         */
+        emitcode ("pop", "psw");
+    }
+  }
 
-  if (IS_ISR (sym->etype))
+  if (IFFUNC_ISISR (sym->type))
     {
 
       /* now we need to restore the registers */
       /* if this isr has no bank i.e. is going to
          run with bank 0 , then we need to save more
          registers :-) */
-      if (!SPEC_BANK (sym->etype))
+      if (!FUNC_REGBANK (sym->type))
        {
-
          /* if this function does not call any other
             function then we can be economical and
             save only those registers that are used */
-         if (!sym->hasFcall)
+         if (!IFFUNC_HASFCALL(sym->type))
            {
              int i;
 
@@ -2705,9 +2903,36 @@ genEndFunction (iCode * ic)
          else
            {
              /* this function has  a function call cannot
-                determines register usage so we will have the
+                determines register usage so we will have to pop the
                 entire bank */
-             unsaverbank (0, ic, FALSE);
+             unsaveRBank (0, ic, FALSE);
+           }
+       }
+       else
+       {
+           /* This ISR uses a non-zero bank.
+            *
+            * Restore any register banks saved by genFunction
+            * in reverse order.
+            */
+         // jwk: this needs a closer look
+           unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
+           int ix;
+         
+           for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
+           {
+               if (savedBanks & (1 << ix))
+               {
+                   unsaveRBank(ix, NULL, FALSE);
+               }
+           }
+           
+           if (options.useXstack)
+           {
+               /* Restore bank AFTER calling unsaveRBank,
+                * since it can trash r0.
+                */
+               emitcode ("pop", "psw");
            }
        }
 
@@ -2715,7 +2940,7 @@ genEndFunction (iCode * ic)
        {
          if (options.stack10bit)
            {
-             emitcode ("pop", "ap");
+             emitcode ("pop", DP2_RESULT_REG);
              emitcode ("pop", "dpx1");
              emitcode ("pop", "dph1");
              emitcode ("pop", "dpl1");
@@ -2732,13 +2957,11 @@ genEndFunction (iCode * ic)
       if (!inExcludeList ("acc"))
        emitcode ("pop", "acc");
 
-      if (SPEC_CRTCL (sym->etype))
+      if (IFFUNC_ISCRITICAL (sym->type))
        emitcode ("setb", "ea");
 
       /* if debug then send end of function */
-/*  if (options.debug && currFunc) { */
-      if (currFunc)
-       {
+      if (options.debug && currFunc) {
          _G.debugLine = 1;
          emitcode ("", "C$%s$%d$%d$%d ==.",
                    FileBaseName (ic->filename), currFunc->lastLine,
@@ -2754,10 +2977,10 @@ genEndFunction (iCode * ic)
     }
   else
     {
-      if (SPEC_CRTCL (sym->etype))
+      if (IFFUNC_ISCRITICAL (sym->type))
        emitcode ("setb", "ea");
 
-      if (sym->calleeSave)
+      if (IFFUNC_CALLEESAVES(sym->type))
        {
          int i;
 
@@ -2776,7 +2999,7 @@ genEndFunction (iCode * ic)
        }
 
       /* if debug then send end of function */
-      if (currFunc)
+      if (options.debug && currFunc)
        {
          _G.debugLine = 1;
          emitcode ("", "C$%s$%d$%d$%d ==.",
@@ -2828,8 +3051,11 @@ genRet (iCode * ic)
        }
       else
        {
+         /* Since A is the last element of fReturn,
+          * is is OK to clobber it in the aopGet.
+          */
          l = aopGet (AOP (IC_LEFT (ic)), offset,
-                     FALSE, FALSE, FALSE);
+                     FALSE, FALSE, TRUE);
          if (strcmp (fReturn[offset], l))
            emitcode ("mov", "%s,%s", fReturn[offset++], l);
        }
@@ -3132,6 +3358,10 @@ adjustArithmeticResult (iCode * ic)
     }
 }
 
+#if 0 // AOP_OP_3 is deprecated; nobody likes Ack errors.
+      // Please don't bring it back without a really good reason.
+// Macro to aopOp all three operands of an ic. Will fatal if this cannot be done
+// (because all three operands are in far space).
 #define AOP_OP_3(ic) \
     aopOp (IC_RIGHT(ic),ic,FALSE, FALSE); \
     aopOp (IC_LEFT(ic),ic,FALSE, (AOP_TYPE(IC_RIGHT(ic)) == AOP_DPTR)); \
@@ -3144,7 +3374,12 @@ adjustArithmeticResult (iCode * ic)
         fprintf(stderr,                                  \
                "Ack: three operands in far space! (%s:%d %s:%d)\n", __FILE__, __LINE__, ic->filename, ic->lineno);   \
     }
+#endif
 
+// Macro to aopOp all three operands of an ic. If this cannot be done, 
+// the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
+// will be set TRUE. The caller must then handle the case specially, noting
+// that the IC_RESULT operand is not aopOp'd.
 #define AOP_OP_3_NOFATAL(ic, rc) \
     aopOp (IC_RIGHT(ic),ic,FALSE, FALSE); \
     aopOp (IC_LEFT(ic),ic,FALSE, (AOP_TYPE(IC_RIGHT(ic)) == AOP_DPTR)); \
@@ -3168,15 +3403,48 @@ adjustArithmeticResult (iCode * ic)
        } \
     }
 
+// aopOp the left & right operands of an ic.
 #define AOP_OP_2(ic) \
     aopOp (IC_RIGHT(ic),ic,FALSE, FALSE); \
     aopOp (IC_LEFT(ic),ic,FALSE, (AOP_TYPE(IC_RIGHT(ic)) == AOP_DPTR));
 
+// convienience macro.
 #define AOP_SET_LOCALS(ic) \
     left = IC_LEFT(ic); \
     right = IC_RIGHT(ic); \
     result = IC_RESULT(ic);
 
+
+// Given an integer value of pushedSize bytes on the stack,
+// adjust it to be resultSize bytes, either by discarding
+// the most significant bytes or by zero-padding.
+//
+// On exit from this macro, pushedSize will have been adjusted to
+// equal resultSize, and ACC may be trashed.
+#define ADJUST_PUSHED_RESULT(pushedSize, resultSize)           \
+      /* If the pushed data is bigger than the result,         \
+       * simply discard unused bytes. Icky, but works.         \
+       */                                                      \
+      while (pushedSize > resultSize)                          \
+      {                                                                \
+         D (emitcode (";", "discarding unused result byte."););\
+         emitcode ("pop", "acc");                              \
+         pushedSize--;                                         \
+      }                                                                \
+      if (pushedSize < resultSize)                             \
+      {                                                                \
+         emitcode ("clr", "a");                                \
+         /* Conversly, we haven't pushed enough here.          \
+          * just zero-pad, and all is well.                    \
+          */                                                   \
+         while (pushedSize < resultSize)                       \
+         {                                                     \
+             emitcode("push", "acc");                          \
+             pushedSize++;                                     \
+         }                                                     \
+      }                                                                \
+      assert(pushedSize == resultSize);
+
 /*-----------------------------------------------------------------*/
 /* genPlus - generates code for addition                           */
 /*-----------------------------------------------------------------*/
@@ -3187,16 +3455,14 @@ genPlus (iCode * ic)
   bool pushResult = FALSE;
   int rSize;
 
-  D (emitcode (";", "genPlus ");
-    );
+  D (emitcode (";", "genPlus "););
 
   /* special cases :- */
 
   AOP_OP_3_NOFATAL (ic, pushResult);
   if (pushResult)
     {
-      D (emitcode (";", "genPlus: must push result: 3 ops in far space");
-       );
+      D (emitcode (";", "genPlus: must push result: 3 ops in far space"););
     }
 
   if (!pushResult)
@@ -3264,7 +3530,7 @@ genPlus (iCode * ic)
   _startLazyDPSEvaluation ();
   while (size--)
     {
-      if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
+      if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
        {
          MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, TRUE));
          if (offset == 0)
@@ -3276,13 +3542,35 @@ genPlus (iCode * ic)
        }
       else
        {
+         if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
+         {
+             /* right is going to use ACC or we would have taken the
+              * above branch.
+              */
+             assert(AOP_NEEDSACC(IC_RIGHT(ic)));
+       TR_AP("#3");
+             D(emitcode(";", "+ AOP_ACC special case."););
+             emitcode("xch", "a, %s", DP2_RESULT_REG);
+         }
          MOVA (aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, TRUE));
          if (offset == 0)
-           emitcode ("add", "a,%s",
-                 aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, FALSE));
+         {
+           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
+           {
+         TR_AP("#4");
+               emitcode("add", "a, %s", DP2_RESULT_REG); 
+           }
+           else
+           {
+               emitcode ("add", "a,%s",
+                       aopGet (AOP(IC_LEFT(ic)), offset, FALSE, FALSE, FALSE));
+           }
+          }
          else
+         {
            emitcode ("addc", "a,%s",
                  aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, FALSE));
+         }
        }
       if (!pushResult)
        {
@@ -3303,38 +3591,13 @@ genPlus (iCode * ic)
       size = getDataSize (IC_LEFT (ic));
       rSize = getDataSize (IC_RESULT (ic));
 
-      /* If the pushed data is bigger than the result,
-       * simply discard unused bytes. Icky, but works.
-       *
-       * Should we throw a warning here? We're losing data...
-       */
-      while (size > rSize)
-       {
-         D (emitcode (";", "discarding unused result byte.");
-           );
-         emitcode ("pop", "acc");
-         size--;
-         offset--;
-       }
-      if (size < rSize)
-       {
-         emitcode ("clr", "a");
-         /* Conversly, we haven't pushed enough here.
-          * just zero-pad, and all is well.
-          */
-         while (size < rSize)
-           {
-             emitcode ("push", "acc");
-             size++;
-             offset++;
-           }
-       }
+      ADJUST_PUSHED_RESULT(size, rSize);
 
       _startLazyDPSEvaluation ();
       while (size--)
        {
          emitcode ("pop", "acc");
-         aopPut (AOP (IC_RESULT (ic)), "a", --offset);
+         aopPut (AOP (IC_RESULT (ic)), "a", size);
        }
       _endLazyDPSEvaluation ();
     }
@@ -3486,16 +3749,24 @@ addSign (operand * result, int offset, int sign)
   int size = (getDataSize (result) - offset);
   if (size > 0)
     {
+      _startLazyDPSEvaluation();
       if (sign)
        {
          emitcode ("rlc", "a");
          emitcode ("subb", "a,acc");
          while (size--)
+         {
            aopPut (AOP (result), "a", offset++);
+         }
        }
       else
+      {
        while (size--)
+       {
          aopPut (AOP (result), zero, offset++);
+       }
+      }
+      _endLazyDPSEvaluation();
     }
 }
 
@@ -3507,8 +3778,7 @@ genMinusBits (iCode * ic)
 {
   symbol *lbl = newiTempLabel (NULL);
 
-  D (emitcode (";", "genMinusBits ");
-    );
+  D (emitcode (";", "genMinusBits "););
 
   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
     {
@@ -3541,8 +3811,7 @@ genMinus (iCode * ic)
   unsigned long lit = 0L;
   bool pushResult = FALSE;
 
-  D (emitcode (";", "genMinus ");
-    );
+  D (emitcode (";", "genMinus "););
 
   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
   aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
@@ -3595,12 +3864,17 @@ genMinus (iCode * ic)
       else
        {
          /* first add without previous c */
-         if (!offset)
-           emitcode ("add", "a,#0x%02x",
-                     (unsigned int) (lit & 0x0FFL));
-         else
+         if (!offset) {
+           if (!size && lit==-1) {
+             emitcode ("dec", "a");
+           } else {
+             emitcode ("add", "a,#0x%02x",
+                       (unsigned int) (lit & 0x0FFL));
+           }
+         } else {
            emitcode ("addc", "a,#0x%02x",
                      (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
+         }
        }
 
       if (pushResult)
@@ -3622,37 +3896,15 @@ genMinus (iCode * ic)
       size = getDataSize (IC_LEFT (ic));
       rSize = getDataSize (IC_RESULT (ic));
 
-      /* If the pushed data is bigger than the result,
-       * simply discard unused bytes. Icky, but works.
-       *
-       * Should we throw a warning here? We're losing data...
-       */
-      while (size > getDataSize (IC_RESULT (ic)))
-       {
-         emitcode (";", "discarding unused result byte.");
-         emitcode ("pop", "acc");
-         size--;
-         offset--;
-       }
-      if (size < rSize)
-       {
-         emitcode ("clr", "a");
-         /* Conversly, we haven't pushed enough here.
-          * just zero-pad, and all is well.
-          */
-         while (size < rSize)
-           {
-             emitcode ("push", "acc");
-             size++;
-             offset++;
-           }
-       }
+      ADJUST_PUSHED_RESULT(size, rSize);
 
+      _startLazyDPSEvaluation ();
       while (size--)
        {
          emitcode ("pop", "acc");
-         aopPut (AOP (IC_RESULT (ic)), "a", --offset);
+         aopPut (AOP (IC_RESULT (ic)), "a", size);
        }
+      _endLazyDPSEvaluation ();
     }
 
   adjustArithmeticResult (ic);
@@ -3670,10 +3922,12 @@ release:
 static void
 genMultbits (operand * left,
             operand * right,
-            operand * result)
+            operand * result,
+            iCode   * ic)
 {
   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
+  aopOp(result, ic, TRUE, FALSE);
   outBitC (result);
 }
 
@@ -3684,19 +3938,12 @@ genMultbits (operand * left,
 static void
 genMultOneByte (operand * left,
                operand * right,
-               operand * result)
+               operand * result,
+               iCode   * ic)
 {
   sym_link *opetype = operandType (result);
   symbol *lbl;
-  int size=AOP_SIZE(result);
 
-  emitcode (";",__FUNCTION__);
-  if (size<1 || size>2) {
-    // this should never happen
-      fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n", 
-              AOP_SIZE(result), __FUNCTION__, lineno);
-      exit (1);
-  }
 
   /* (if two literals: the value is computed before) */
   /* if one literal, literal on the right */
@@ -3717,8 +3964,22 @@ genMultOneByte (operand * left,
     emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, TRUE));
     MOVA (aopGet (AOP (left), 0, FALSE, FALSE, TRUE));
     emitcode ("mul", "ab");
+   
+    _G.accInUse++;
+    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);
-    if (size==2) {
+    _G.accInUse--;
+    if (AOP_SIZE(result)==2) 
+    {
       aopPut (AOP (result), "b", 1);
     }
     return;
@@ -3728,7 +3989,6 @@ genMultOneByte (operand * left,
 
   emitcode (";", "signed");
   emitcode ("clr", "F0"); // reset sign flag
-  emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, TRUE));
   MOVA (aopGet (AOP (left), 0, FALSE, FALSE, TRUE));
 
   lbl=newiTempLabel(NULL);
@@ -3739,33 +3999,46 @@ genMultOneByte (operand * left,
   emitcode ("inc", "a");
 
   emitcode ("", "%05d$:", lbl->key+100);
-  emitcode ("xch", "a,b");
 
   /* if literal */
   if (AOP_TYPE(right)==AOP_LIT) {
+    signed char val=floatFromVal (AOP (right)->aopu.aop_lit);
     /* AND literal negative */
-    if ((int) floatFromVal (AOP (right)->aopu.aop_lit) < 0) {
-      // two's complement for literal<0
-      emitcode ("xrl", "PSW,#0x20"); // xrl sign flag
-      emitcode ("cpl", "a");
-      emitcode ("inc", "a");
+    if ((int) val < 0) {
+      emitcode ("cpl", "F0"); // complement sign flag
+      emitcode ("mov", "b,#0x%02x", -val);
+    } else {
+      emitcode ("mov", "b,#0x%02x", val);
     }
   } else {
     lbl=newiTempLabel(NULL);
+    emitcode ("mov", "b,a");
+    emitcode ("mov", "a,%s", aopGet (AOP (right), 0, FALSE, FALSE, TRUE));
     emitcode ("jnb", "acc.7,%05d$", lbl->key+100);
     // right side is negative, 8-bit two's complement
-    emitcode ("xrl", "PSW,#0x20"); // xrl sign flag
+    emitcode ("cpl", "F0"); // complement sign flag
     emitcode ("cpl", "a");
     emitcode ("inc", "a");
     emitcode ("", "%05d$:", lbl->key+100);
   }
   emitcode ("mul", "ab");
     
+  _G.accInUse++;
+  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,%05d$", lbl->key+100);
   // only ONE op was negative, we have to do a 8/16-bit two's complement
   emitcode ("cpl", "a"); // lsb
-  if (size==1) {
+  if (AOP_SIZE(result)==1) {
     emitcode ("inc", "a");
   } else {
     emitcode ("add", "a,#1");
@@ -3777,7 +4050,8 @@ genMultOneByte (operand * left,
 
   emitcode ("", "%05d$:", lbl->key+100);
   aopPut (AOP (result), "a", 0);
-  if (size==2) {
+  _G.accInUse--;
+  if (AOP_SIZE(result)==2) {
     aopPut (AOP (result), "b", 1);
   }
 }
@@ -3792,18 +4066,17 @@ genMult (iCode * ic)
   operand *right = IC_RIGHT (ic);
   operand *result = IC_RESULT (ic);
 
-  D (emitcode (";", "genMult ");
-    );
+  D (emitcode (";", "genMult "););
 
   /* assign the amsops */
-  AOP_OP_3 (ic);
+  AOP_OP_2 (ic);
 
   /* special cases first */
   /* both are bits */
   if (AOP_TYPE (left) == AOP_CRY &&
       AOP_TYPE (right) == AOP_CRY)
     {
-      genMultbits (left, right, result);
+      genMultbits (left, right, result, ic);
       goto release;
     }
 
@@ -3811,7 +4084,7 @@ genMult (iCode * ic)
   if (AOP_SIZE (left) == 1 &&
       AOP_SIZE (right) == 1)
     {
-      genMultOneByte (left, right, result);
+      genMultOneByte (left, right, result, ic);
       goto release;
     }
 
@@ -3830,7 +4103,8 @@ release:
 static void
 genDivbits (operand * left,
            operand * right,
-           operand * result)
+           operand * result,
+           iCode   * ic)
 {
 
   char *l;
@@ -3839,6 +4113,8 @@ genDivbits (operand * left,
   LOAD_AB_FOR_DIV (left, right, l);
   emitcode ("div", "ab");
   emitcode ("rrc", "a");
+  aopOp(result, ic, TRUE, FALSE);
+    
   aopPut (AOP (result), "c", 0);
 }
 
@@ -3848,24 +4124,33 @@ genDivbits (operand * left,
 static void
 genDivOneByte (operand * left,
               operand * right,
-              operand * result)
+              operand * result,
+              iCode   * ic)
 {
   sym_link *opetype = operandType (result);
   char *l;
   symbol *lbl;
   int size, offset;
 
-  size = AOP_SIZE (result) - 1;
   offset = 1;
   /* signed or unsigned */
   if (SPEC_USIGN (opetype))
     {
-      /* unsigned is easy */
-      LOAD_AB_FOR_DIV (left, right, l);
-      emitcode ("div", "ab");
-      aopPut (AOP (result), "a", 0);
-      while (size--)
-       aopPut (AOP (result), zero, offset++);
+       /* 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--;
+
+       size = AOP_SIZE (result) - 1;
+       
+       while (size--)
+       {
+           aopPut (AOP (result), zero, offset++);
+       }
       return;
     }
 
@@ -3916,14 +4201,23 @@ genDivOneByte (operand * left,
   emitcode ("", "%05d$:", (lbl->key + 100));
 
   /* now we are done */
-  aopPut (AOP (result), "b", 0);
-  if (size > 0)
+    _G.accInUse++;
+    aopOp(result, ic, TRUE, FALSE);
+    
+    aopPut (AOP (result), "b", 0);
+    
+    size = AOP_SIZE (result) - 1;
+    
+    if (size > 0)
     {
       emitcode ("mov", "c,b.7");
       emitcode ("subb", "a,acc");
     }
-  while (size--)
-    aopPut (AOP (result), "a", offset++);
+    while (size--)
+    {
+       aopPut (AOP (result), "a", offset++);
+    }
+    _G.accInUse--;
 
 }
 
@@ -3937,18 +4231,17 @@ genDiv (iCode * ic)
   operand *right = IC_RIGHT (ic);
   operand *result = IC_RESULT (ic);
 
-  D (emitcode (";", "genDiv ");
-    );
+  D (emitcode (";", "genDiv "););
 
   /* assign the amsops */
-  AOP_OP_3 (ic);
+  AOP_OP_2 (ic);
 
   /* special cases first */
   /* both are bits */
   if (AOP_TYPE (left) == AOP_CRY &&
       AOP_TYPE (right) == AOP_CRY)
     {
-      genDivbits (left, right, result);
+      genDivbits (left, right, result, ic);
       goto release;
     }
 
@@ -3956,7 +4249,7 @@ genDiv (iCode * ic)
   if (AOP_SIZE (left) == 1 &&
       AOP_SIZE (right) == 1)
     {
-      genDivOneByte (left, right, result);
+      genDivOneByte (left, right, result, ic);
       goto release;
     }
 
@@ -3974,7 +4267,8 @@ release:
 static void
 genModbits (operand * left,
            operand * right,
-           operand * result)
+           operand * result,
+           iCode   * ic)
 {
 
   char *l;
@@ -3984,6 +4278,7 @@ genModbits (operand * left,
   emitcode ("div", "ab");
   emitcode ("mov", "a,b");
   emitcode ("rrc", "a");
+  aopOp(result, ic, TRUE, FALSE);
   aopPut (AOP (result), "c", 0);
 }
 
@@ -3993,7 +4288,8 @@ genModbits (operand * left,
 static void
 genModOneByte (operand * left,
               operand * right,
-              operand * result)
+              operand * result,
+              iCode   * ic)
 {
   sym_link *opetype = operandType (result);
   char *l;
@@ -4005,6 +4301,7 @@ genModOneByte (operand * left,
       /* unsigned is easy */
       LOAD_AB_FOR_DIV (left, right, l);
       emitcode ("div", "ab");
+      aopOp(result, ic, TRUE, FALSE);  
       aopPut (AOP (result), "b", 0);
       return;
     }
@@ -4057,6 +4354,7 @@ genModOneByte (operand * left,
   emitcode ("", "%05d$:", (lbl->key + 100));
 
   /* now we are done */
+  aopOp(result, ic, TRUE, FALSE);    
   aopPut (AOP (result), "b", 0);
 
 }
@@ -4071,18 +4369,17 @@ genMod (iCode * ic)
   operand *right = IC_RIGHT (ic);
   operand *result = IC_RESULT (ic);
 
-  D (emitcode (";", "genMod ");
-    );
+  D (emitcode (";", "genMod "); );
 
   /* assign the amsops */
-  AOP_OP_3 (ic);
+  AOP_OP_2 (ic);
 
   /* special cases first */
   /* both are bits */
   if (AOP_TYPE (left) == AOP_CRY &&
       AOP_TYPE (right) == AOP_CRY)
     {
-      genModbits (left, right, result);
+      genModbits (left, right, result, ic);
       goto release;
     }
 
@@ -4090,7 +4387,7 @@ genMod (iCode * ic)
   if (AOP_SIZE (left) == 1 &&
       AOP_SIZE (right) == 1)
     {
-      genModOneByte (left, right, result);
+      genModOneByte (left, right, result, ic);
       goto release;
     }
 
@@ -4347,8 +4644,7 @@ genCmpLt (iCode * ic, iCode * ifx)
   sym_link *letype, *retype;
   int sign;
 
-  D (emitcode (";", "genCmpLt ");
-    );
+  D (emitcode (";", "genCmpLt "););
 
   left = IC_LEFT (ic);
   right = IC_RIGHT (ic);
@@ -4683,13 +4979,12 @@ genAndOp (iCode * ic)
   operand *left, *right, *result;
   symbol *tlbl;
 
-  D (emitcode (";", "genAndOp ");
-    );
+  D (emitcode (";", "genAndOp "););
 
   /* note here that && operations that are in an
      if statement are taken away by backPatchLabels
      only those used in arthmetic operations remain */
-  AOP_OP_3 (ic);
+  AOP_OP_2 (ic);
   AOP_SET_LOCALS (ic);
 
   /* if both are bit variables */
@@ -4698,6 +4993,10 @@ genAndOp (iCode * ic)
     {
       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
+      freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+      freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+  
+      aopOp (result,ic,FALSE, FALSE);
       outBitC (result);
     }
   else
@@ -4707,12 +5006,13 @@ genAndOp (iCode * ic)
       emitcode ("jz", "%05d$", tlbl->key + 100);
       toBoolean (right);
       emitcode ("", "%05d$:", tlbl->key + 100);
+      freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+      freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+  
+      aopOp (result,ic,FALSE, FALSE);
       outBitAcc (result);
     }
-
-  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
-  freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
-  freeAsmop (result, NULL, ic, TRUE);
+    freeAsmop (result, NULL, ic, TRUE);
 }
 
 
@@ -4725,13 +5025,12 @@ genOrOp (iCode * ic)
   operand *left, *right, *result;
   symbol *tlbl;
 
-  D (emitcode (";", "genOrOp ");
-    );
+  D (emitcode (";", "genOrOp "););
 
   /* note here that || operations that are in an
      if statement are taken away by backPatchLabels
      only those used in arthmetic operations remain */
-  AOP_OP_3 (ic);
+  AOP_OP_2 (ic);
   AOP_SET_LOCALS (ic);
 
   /* if both are bit variables */
@@ -4740,6 +5039,11 @@ genOrOp (iCode * ic)
     {
       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
+      freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+      freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+  
+      aopOp (result,ic,FALSE, FALSE);
+      
       outBitC (result);
     }
   else
@@ -4749,11 +5053,14 @@ genOrOp (iCode * ic)
       emitcode ("jnz", "%05d$", tlbl->key + 100);
       toBoolean (right);
       emitcode ("", "%05d$:", tlbl->key + 100);
+      freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+      freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
+  
+      aopOp (result,ic,FALSE, FALSE);
+      
       outBitAcc (result);
     }
 
-  freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
-  freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
   freeAsmop (result, NULL, ic, TRUE);
 }
 
@@ -4824,9 +5131,56 @@ jmpTrueOrFalse (iCode * ic, symbol * tlbl)
   ic->generated = 1;
 }
 
-/*-----------------------------------------------------------------*/
-/* genAnd  - code for and                                          */
-/*-----------------------------------------------------------------*/
+// Generate code to perform a bit-wise logic operation
+// on two operands in far space (assumed to already have been 
+// aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
+// in far space. This requires pushing the result on the stack
+// then popping it into the result.
+static void
+genFarFarLogicOp(iCode *ic, char *logicOp)
+{
+      int size, resultSize, compSize;
+      int offset = 0;
+      
+      TR_AP("#5");
+      D(emitcode(";", "%s special case for 3 far operands.", logicOp););
+      compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ? 
+                 AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
+      
+      _startLazyDPSEvaluation();
+      for (size = compSize; (size--); offset++)
+      {
+         MOVA (aopGet (AOP (IC_LEFT(ic)), offset, FALSE, FALSE, TRUE));
+         emitcode ("mov", "%s, acc", DP2_RESULT_REG);
+         MOVA (aopGet (AOP (IC_RIGHT(ic)), offset, FALSE, FALSE, TRUE));
+         
+         emitcode (logicOp, "a,%s", DP2_RESULT_REG);
+         emitcode ("push", "acc");
+      }
+      _endLazyDPSEvaluation();
+     
+      freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
+      freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
+      aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
+     
+      resultSize = AOP_SIZE(IC_RESULT(ic));
+
+      ADJUST_PUSHED_RESULT(compSize, resultSize);
+
+      _startLazyDPSEvaluation();
+      while (compSize--)
+      {
+         emitcode ("pop", "acc");
+         aopPut (AOP (IC_RESULT (ic)), "a", compSize);
+      }
+      _endLazyDPSEvaluation();
+      freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
+}
+
+
+/*-----------------------------------------------------------------*/
+/* genAnd  - code for and                                          */
+/*-----------------------------------------------------------------*/
 static void
 genAnd (iCode * ic, iCode * ifx)
 {
@@ -4835,13 +5189,19 @@ genAnd (iCode * ic, iCode * ifx)
   unsigned long lit = 0L;
   int bytelit = 0;
   char buffer[10];
+  bool pushResult;
 
-  D (emitcode (";", "genAnd ");
-    );
+  D (emitcode (";", "genAnd "););
 
-  AOP_OP_3 (ic);
+  AOP_OP_3_NOFATAL (ic, pushResult);
   AOP_SET_LOCALS (ic);
 
+  if (pushResult)
+  {
+      genFarFarLogicOp(ic, "anl");
+      return;
+  }  
+
 #ifdef DEBUG_TYPE
   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
            AOP_TYPE (result),
@@ -5062,9 +5422,20 @@ genAnd (iCode * ic, iCode * ifx)
            emitcode ("setb", "c");
          while (sizer--)
            {
-             MOVA (aopGet (AOP (right), offset, FALSE, FALSE, TRUE));
-             emitcode ("anl", "a,%s",
-                       aopGet (AOP (left), offset, FALSE, FALSE, FALSE));
+             if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
+               emitcode ("anl", "a,%s",
+                         aopGet (AOP (right), offset, FALSE, FALSE, FALSE));
+             } else {
+               if (AOP_TYPE(left)==AOP_ACC) {
+                 emitcode("mov", "b,a");
+                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE, TRUE));
+                 emitcode("anl", "a,b");
+               }else {
+                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE, TRUE));
+                 emitcode ("anl", "a,%s",
+                           aopGet (AOP (left), offset, FALSE, FALSE, FALSE));
+               }
+             }
              emitcode ("jnz", "%05d$", tlbl->key + 100);
              offset++;
            }
@@ -5131,6 +5502,7 @@ release:
   freeAsmop (result, NULL, ic, TRUE);
 }
 
+
 /*-----------------------------------------------------------------*/
 /* genOr  - code for or                                            */
 /*-----------------------------------------------------------------*/
@@ -5140,13 +5512,20 @@ genOr (iCode * ic, iCode * ifx)
   operand *left, *right, *result;
   int size, offset = 0;
   unsigned long lit = 0L;
+  bool            pushResult;
 
-  D (emitcode (";", "genOr ");
-    );
+  D (emitcode (";", "genOr "););
 
-  AOP_OP_3 (ic);
+  AOP_OP_3_NOFATAL (ic, pushResult);
   AOP_SET_LOCALS (ic);
 
+  if (pushResult)
+  {
+      genFarFarLogicOp(ic, "orl");
+      return;
+  }
+
+
 #ifdef DEBUG_TYPE
   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
            AOP_TYPE (result),
@@ -5356,9 +5735,14 @@ genOr (iCode * ic, iCode * ifx)
            emitcode ("setb", "c");
          while (sizer--)
            {
-             MOVA (aopGet (AOP (right), offset, FALSE, FALSE, TRUE));
-             emitcode ("orl", "a,%s",
-                       aopGet (AOP (left), offset, FALSE, FALSE, FALSE));
+             if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
+               emitcode ("orl", "a,%s",
+                         aopGet (AOP (right), offset, FALSE, FALSE, FALSE));
+             } else {
+               MOVA (aopGet (AOP (right), offset, FALSE, FALSE, TRUE));
+               emitcode ("orl", "a,%s",
+                         aopGet (AOP (left), offset, FALSE, FALSE, FALSE));
+             }
              emitcode ("jnz", "%05d$", tlbl->key + 100);
              offset++;
            }
@@ -5429,13 +5813,19 @@ genXor (iCode * ic, iCode * ifx)
   operand *left, *right, *result;
   int size, offset = 0;
   unsigned long lit = 0L;
+  bool pushResult;
 
-  D (emitcode (";", "genXor ");
-    );
+  D (emitcode (";", "genXor "););
 
-  AOP_OP_3 (ic);
+  AOP_OP_3_NOFATAL (ic, pushResult);
   AOP_SET_LOCALS (ic);
 
+  if (pushResult)
+  {
+      genFarFarLogicOp(ic, "xrl");
+      return;
+  }  
+
 #ifdef DEBUG_TYPE
   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
            AOP_TYPE (result),
@@ -5624,9 +6014,14 @@ genXor (iCode * ic, iCode * ifx)
                }
              else
                {
-                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE, TRUE));
-                 emitcode ("xrl", "a,%s",
-                         aopGet (AOP (left), offset, FALSE, FALSE, FALSE));
+                 if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
+                   emitcode ("xrl", "a,%s",
+                             aopGet (AOP (right), offset, FALSE, FALSE, FALSE));
+                 } else {
+                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, TRUE));
+                   emitcode ("xrl", "a,%s",
+                             aopGet (AOP (left), offset, FALSE, FALSE, FALSE));
+                 }
                }
              emitcode ("jnz", "%05d$", tlbl->key + 100);
              offset++;
@@ -5692,14 +6087,14 @@ release:
 static void
 genInline (iCode * ic)
 {
-  char buffer[MAX_INLINEASM];
-  char *bp = buffer;
-  char *bp1 = buffer;
+  char *buffer, *bp, *bp1;
 
   D (emitcode (";", "genInline ");
     );
 
   _G.inLine += (!options.asmpeep);
+
+  buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
   strcpy (buffer, IC_INLINE (ic));
 
   /* emit each line as a code */
@@ -5957,8 +6352,7 @@ AccRsh (int shCount)
     }
 }
 
-#if 0
-//REMOVE ME!!!
+#ifdef BETTER_LITERAL_SHIFT
 /*-----------------------------------------------------------------*/
 /* AccSRsh - signed right shift accumulator by known count                 */
 /*-----------------------------------------------------------------*/
@@ -5996,8 +6390,7 @@ AccSRsh (int shCount)
 }
 #endif
 
-#if 0
-//REMOVE ME!!!
+#ifdef BETTER_LITERAL_SHIFT
 /*-----------------------------------------------------------------*/
 /* shiftR1Left2Result - shift right one byte from left to result   */
 /*-----------------------------------------------------------------*/
@@ -6016,8 +6409,7 @@ shiftR1Left2Result (operand * left, int offl,
 }
 #endif
 
-#if 0
-//REMOVE ME!!!
+#ifdef BETTER_LITERAL_SHIFT
 /*-----------------------------------------------------------------*/
 /* shiftL1Left2Result - shift left one byte from left to result    */
 /*-----------------------------------------------------------------*/
@@ -6025,17 +6417,14 @@ static void
 shiftL1Left2Result (operand * left, int offl,
                    operand * result, int offr, int shCount)
 {
-  char *l;
-  l = aopGet (AOP (left), offl, FALSE, FALSE, TRUE);
-  MOVA (l);
+  MOVA(aopGet (AOP (left), offl, FALSE, FALSE, TRUE));
   /* shift left accumulator */
   AccLsh (shCount);
   aopPut (AOP (result), "a", offr);
 }
 #endif
 
-#if 0
-//REMOVE ME!!!
+#ifdef BETTER_LITERAL_SHIFT
 /*-----------------------------------------------------------------*/
 /* movLeft2Result - move byte from left to result                  */
 /*-----------------------------------------------------------------*/
@@ -6045,18 +6434,20 @@ movLeft2Result (operand * left, int offl,
 {
   char *l;
   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
-    {
-      l = aopGet (AOP (left), offl, FALSE, FALSE, FALSE);
+  {
+      l = aopGet (AOP (left), offl, FALSE, FALSE, TRUE);
 
       if (*l == '@' && (IS_AOP_PREG (result)))
-       {
+      {
          emitcode ("mov", "a,%s", l);
          aopPut (AOP (result), "a", offr);
-       }
+      }
       else
-       {
+      {
          if (!sign)
+         {
            aopPut (AOP (result), l, offr);
+         }
          else
            {
              /* MSB sign in acc.7 ! */
@@ -6066,13 +6457,12 @@ movLeft2Result (operand * left, int offl,
                  aopPut (AOP (result), "a", offr);
                }
            }
-       }
-    }
+      }
+  }
 }
 #endif
 
-#if 0
-//REMOVE ME!!!
+#ifdef BETTER_LITERAL_SHIFT
 /*-----------------------------------------------------------------*/
 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
 /*-----------------------------------------------------------------*/
@@ -6086,7 +6476,7 @@ AccAXRrl1 (char *x)
 }
 #endif
 
-#if 0
+#ifdef BETTER_LITERAL_SHIFT
 //REMOVE ME!!!
 /*-----------------------------------------------------------------*/
 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
@@ -6101,8 +6491,7 @@ AccAXLrl1 (char *x)
 }
 #endif
 
-#if 0
-//REMOVE ME!!!
+#ifdef BETTER_LITERAL_SHIFT
 /*-----------------------------------------------------------------*/
 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
 /*-----------------------------------------------------------------*/
@@ -6116,8 +6505,7 @@ AccAXLsh1 (char *x)
 }
 #endif
 
-#if 0
-//REMOVE ME!!!
+#ifdef BETTER_LITERAL_SHIFT
 /*-----------------------------------------------------------------*/
 /* AccAXLsh - left shift a:x by known count (0..7)                 */
 /*-----------------------------------------------------------------*/
@@ -6201,7 +6589,7 @@ AccAXLsh (char *x, int shCount)
 }
 #endif
 
-#if 0
+#ifdef BETTER_LITERAL_SHIFT
 //REMOVE ME!!!
 /*-----------------------------------------------------------------*/
 /* AccAXRsh - right shift a:x known count (0..7)                   */
@@ -6284,8 +6672,7 @@ AccAXRsh (char *x, int shCount)
 }
 #endif
 
-#if 0
-//REMOVE ME!!!
+#ifdef BETTER_LITERAL_SHIFT
 /*-----------------------------------------------------------------*/
 /* AccAXRshS - right shift signed a:x known count (0..7)           */
 /*-----------------------------------------------------------------*/
@@ -6387,8 +6774,94 @@ AccAXRshS (char *x, int shCount)
 }
 #endif
 
-#if 0
-//REMOVE ME!!!
+#ifdef BETTER_LITERAL_SHIFT
+static void
+_loadLeftIntoAx(char   **lsb, 
+               operand *left, 
+               operand *result,
+               int     offl,
+               int     offr)
+{
+  // Get the initial value from left into a pair of registers.
+  // MSB must be in A, LSB can be any register.
+  //
+  // If the result is held in registers, it is an optimization
+  // if the LSB can be held in the register which will hold the,
+  // result LSB since this saves us from having to copy it into
+  // the result following AccAXLsh.
+  //
+  // If the result is addressed indirectly, this is not a gain.
+  if (AOP_NEEDSACC(result))
+  {
+       char *leftByte;
+       
+       _startLazyDPSEvaluation();
+      if (AOP_TYPE(left) == AOP_DPTR2)
+       {
+           // Get MSB in A.
+                  MOVA(aopGet(AOP(left), offl + MSB16, FALSE, FALSE, TRUE));
+                  // get LSB in DP2_RESULT_REG.
+                  leftByte = aopGet(AOP(left), offl, FALSE, FALSE, FALSE);
+                  assert(!strcmp(leftByte, DP2_RESULT_REG));
+       }
+       else
+       {
+           // get LSB into DP2_RESULT_REG
+                  leftByte = aopGet (AOP(left), offl, FALSE, FALSE, TRUE);
+           if (strcmp(leftByte, DP2_RESULT_REG))
+           {
+               TR_AP("#7");
+               emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
+                  }
+                  // And MSB in A.
+                  leftByte = aopGet(AOP(left), offl + MSB16, FALSE, FALSE, TRUE);
+                  assert(strcmp(leftByte, DP2_RESULT_REG));
+                  MOVA(leftByte);
+       }
+       _endLazyDPSEvaluation();
+       *lsb = DP2_RESULT_REG;
+  }
+  else
+  {
+      if (sameRegs (AOP (result), AOP (left)) &&
+       ((offl + MSB16) == offr))
+      {
+         /* don't crash result[offr] */
+         MOVA(aopGet(AOP(left), offl, FALSE, FALSE, TRUE));
+         emitcode ("xch", "a,%s", 
+                   aopGet(AOP(left), offl + MSB16, FALSE, FALSE, FALSE));
+      }
+      else
+      {
+         movLeft2Result (left, offl, result, offr, 0);
+         MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE, TRUE));
+      }
+      *lsb = aopGet(AOP (result), offr, FALSE, FALSE, FALSE);
+      assert(strcmp(*lsb,"a"));      
+  }
+}
+
+static void
+_storeAxResults(char   *lsb,
+               operand *result,
+               int     offr)
+{
+  _startLazyDPSEvaluation();
+  if (AOP_NEEDSACC(result))
+  {
+      /* We have to explicitly update the result LSB.
+       */
+      emitcode("xch","a,%s", lsb);
+      aopPut(AOP(result), "a", offr);
+      emitcode("mov","a,%s", lsb);
+  }
+  if (getDataSize (result) > 1)
+  {
+      aopPut (AOP (result), "a", offr + MSB16);
+  }
+  _endLazyDPSEvaluation();
+}
+
 /*-----------------------------------------------------------------*/
 /* shiftL2Left2Result - shift left two bytes from left to result   */
 /*-----------------------------------------------------------------*/
@@ -6396,26 +6869,17 @@ static void
 shiftL2Left2Result (operand * left, int offl,
                    operand * result, int offr, int shCount)
 {
-  if (sameRegs (AOP (result), AOP (left)) &&
-      ((offl + MSB16) == offr))
-    {
-      /* don't crash result[offr] */
-      MOVA (aopGet (AOP (left), offl, FALSE, FALSE, TRUE));
-      emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE, FALSE));
-    }
-  else
-    {
-      movLeft2Result (left, offl, result, offr, 0);
-      MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE, TRUE));
-    }
-  /* ax << shCount (x = lsb(result)) */
-  AccAXLsh (aopGet (AOP (result), offr, FALSE, FALSE, FALSE), shCount);
-  aopPut (AOP (result), "a", offr + MSB16);
+  char *lsb;
+
+  _loadLeftIntoAx(&lsb, left, result, offl, offr);
+  
+  AccAXLsh (lsb, shCount);
+  
+  _storeAxResults(lsb, result, offr);
 }
 #endif
 
-#if 0
-//REMOVE ME!!!
+#ifdef BETTER_LITERAL_SHIFT
 /*-----------------------------------------------------------------*/
 /* shiftR2Left2Result - shift right two bytes from left to result  */
 /*-----------------------------------------------------------------*/
@@ -6424,25 +6888,21 @@ shiftR2Left2Result (operand * left, int offl,
                    operand * result, int offr,
                    int shCount, int sign)
 {
-  if (sameRegs (AOP (result), AOP (left)) &&
-      ((offl + MSB16) == offr))
-    {
-      /* don't crash result[offr] */
-      MOVA (aopGet (AOP (left), offl, FALSE, FALSE, TRUE));
-      emitcode ("xch", "a,%s", aopGet (AOP (left), offl + MSB16, FALSE, FALSE, FALSE));
-    }
-  else
-    {
-      movLeft2Result (left, offl, result, offr, 0);
-      MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE, TRUE));
-    }
+  char *lsb;
+  
+  _loadLeftIntoAx(&lsb, left, result, offl, offr);
+  
   /* a:x >> shCount (x = lsb(result)) */
   if (sign)
-    AccAXRshS (aopGet (AOP (result), offr, FALSE, FALSE, FALSE), shCount);
+  {
+     AccAXRshS(lsb, shCount);
+  }
   else
-    AccAXRsh (aopGet (AOP (result), offr, FALSE, FALSE, FALSE), shCount);
-  if (getDataSize (result) > 1)
-    aopPut (AOP (result), "a", offr + MSB16);
+  {
+    AccAXRsh(lsb, shCount);
+  }
+  
+  _storeAxResults(lsb, result, offr);
 }
 #endif
 
@@ -6484,22 +6944,19 @@ shiftRLeftOrResult (operand * left, int offl,
 }
 #endif
 
-#if 0
-//REMOVE ME!!!
+#ifdef BETTER_LITERAL_SHIFT
 /*-----------------------------------------------------------------*/
 /* genlshOne - left shift a one byte quantity by known count       */
 /*-----------------------------------------------------------------*/
 static void
 genlshOne (operand * result, operand * left, int shCount)
 {
-  D (emitcode (";", "genlshOne ");
-    );
+  D (emitcode (";", "genlshOne "););
   shiftL1Left2Result (left, LSB, result, LSB, shCount);
 }
 #endif
 
-#if 0
-//REMOVE ME!!!
+#ifdef BETTER_LITERAL_SHIFT
 /*-----------------------------------------------------------------*/
 /* genlshTwo - left shift two bytes by known amount != 0           */
 /*-----------------------------------------------------------------*/
@@ -6508,33 +6965,50 @@ genlshTwo (operand * result, operand * left, int shCount)
 {
   int size;
 
-  D (emitcode (";", "genlshTwo ");
-    );
+  D (emitcode (";", "genlshTwo "););
 
   size = getDataSize (result);
 
   /* if shCount >= 8 */
   if (shCount >= 8)
-    {
+  {
       shCount -= 8;
 
+      _startLazyDPSEvaluation();
+
       if (size > 1)
        {
          if (shCount)
+         {
+           _endLazyDPSEvaluation();
            shiftL1Left2Result (left, LSB, result, MSB16, shCount);
+           aopPut (AOP (result), zero, LSB);       
+         }
          else
+         {
            movLeft2Result (left, LSB, result, MSB16, 0);
+           aopPut (AOP (result), zero, LSB);
+           _endLazyDPSEvaluation();
+         }
        }
-      aopPut (AOP (result), zero, LSB);
-    }
+       else
+       {
+         aopPut (AOP (result), zero, LSB);
+         _endLazyDPSEvaluation();
+       }
+  }
 
   /*  1 <= shCount <= 7 */
   else
     {
       if (size == 1)
+      {
        shiftL1Left2Result (left, LSB, result, LSB, shCount);
+      }
       else
+      {
        shiftL2Left2Result (left, LSB, result, LSB, shCount);
+      }
     }
 }
 #endif
@@ -6638,7 +7112,7 @@ genlshFour (operand * result, operand * left, int shCount)
        movLeft2Result (left, LSB, result, MSB32, 0);
       aopPut (AOP (result), zero, LSB);
       aopPut (AOP (result), zero, MSB16);
-      aopPut (AOP (result), zero, MSB32);
+      aopPut (AOP (result), zero, MSB24);
       return;
     }
 
@@ -6710,12 +7184,11 @@ genlshFour (operand * result, operand * left, int shCount)
 }
 #endif
 
-#if 0
-//REMOVE ME!!!
+#ifdef BETTER_LITERAL_SHIFT
 /*-----------------------------------------------------------------*/
 /* genLeftShiftLiteral - left shifting by known count              */
 /*-----------------------------------------------------------------*/
-static void
+static bool
 genLeftShiftLiteral (operand * left,
                     operand * right,
                     operand * result,
@@ -6724,16 +7197,44 @@ genLeftShiftLiteral (operand * left,
   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
   int size;
 
-  D (emitcode (";", "genLeftShiftLiteral (%d)", shCount);
-    );
+  size = getSize (operandType (result));
 
-  freeAsmop (right, NULL, ic, TRUE);
+  D(emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
 
-  aopOp (left, ic, FALSE, FALSE);
-  aopOp (result, ic, FALSE, TRUE);
+  /* We only handle certain easy cases so far. */
+  if ((shCount != 0)
+   && (shCount < (size * 8))
+   && (size != 1)
+   && (size != 2))
+  {
+      D(emitcode (";", "genLeftShiftLiteral wimping out"););   
+      return FALSE;
+  }
 
-  size = getSize (operandType (result));
+  freeAsmop (right, NULL, ic, TRUE);
 
+  aopOp(left, ic, FALSE, FALSE);
+  aopOp(result, ic, FALSE, (AOP_TYPE(left) == AOP_DPTR));
+
+#if 1 // debug spew
+  if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
+  {
+       emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
+       if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
+       {
+          emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
+       }
+  }
+  if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
+  {
+       emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
+       if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
+       {
+          emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
+       }       
+  }  
+#endif
+  
 #if VIEW_SIZE
   emitcode ("; shift left ", "result %d, left %d", size,
            AOP_SIZE (left));
@@ -6741,18 +7242,25 @@ genLeftShiftLiteral (operand * left,
 
   /* I suppose that the left size >= result size */
   if (shCount == 0)
-    {
-      while (size--)
+  {
+       _startLazyDPSEvaluation();
+       while (size--)
        {
          movLeft2Result (left, size, result, size, 0);
        }
-    }
-
+       _endLazyDPSEvaluation();
+  }
   else if (shCount >= (size * 8))
+  {
+    _startLazyDPSEvaluation();
     while (size--)
+    {
       aopPut (AOP (result), zero, size);
+    }
+    _endLazyDPSEvaluation();
+  }
   else
-    {
+  {
       switch (size)
        {
        case 1:
@@ -6760,17 +7268,21 @@ genLeftShiftLiteral (operand * left,
          break;
 
        case 2:
-       case 3:         /* bug: this is for generic pointers, I bet. */
          genlshTwo (result, left, shCount);
          break;
-
+#if 0
        case 4:
          genlshFour (result, left, shCount);
          break;
+#endif
+       default:
+         fprintf(stderr, "*** ack! mystery literal shift!\n");   
+         break;
        }
     }
   freeAsmop (left, NULL, ic, TRUE);
   freeAsmop (result, NULL, ic, TRUE);
+  return TRUE;
 }
 #endif
 
@@ -6785,8 +7297,7 @@ genLeftShift (iCode * ic)
   char *l;
   symbol *tlbl, *tlbl1;
 
-  D (emitcode (";", "genLeftShift ");
-    );
+  D (emitcode (";", "genLeftShift "););
 
   right = IC_RIGHT (ic);
   left = IC_LEFT (ic);
@@ -6794,13 +7305,16 @@ genLeftShift (iCode * ic)
 
   aopOp (right, ic, FALSE, FALSE);
 
-#if 0
+
+#ifdef BETTER_LITERAL_SHIFT
   /* if the shift count is known then do it
      as efficiently as possible */
   if (AOP_TYPE (right) == AOP_LIT)
     {
-      genLeftShiftLiteral (left, right, result, ic);
-      return;
+      if (genLeftShiftLiteral (left, right, result, ic))
+      {
+       return;
+      }
     }
 #endif
 
@@ -6810,8 +7324,20 @@ genLeftShift (iCode * ic)
      more that 32 bits make no sense anyway, ( the
      largest size of an object can be only 32 bits ) */
 
-  emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, FALSE));
-  emitcode ("inc", "b");
+  if (AOP_TYPE (right) == AOP_LIT)
+  {
+      /* Really should be handled by genLeftShiftLiteral,
+       * but since I'm too lazy to fix that today, at least we can make
+       * some small improvement.
+       */
+       emitcode("mov", "b,#0x%02x",
+                       ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
+  }
+  else
+  {
+       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, FALSE));
+       emitcode ("inc", "b");
+  }
   freeAsmop (right, NULL, ic, TRUE);
   aopOp (left, ic, FALSE, FALSE);
   aopOp (result, ic, FALSE, AOP_TYPE (left) == AOP_DPTR);
@@ -6888,8 +7414,7 @@ release:
   freeAsmop (result, NULL, ic, TRUE);
 }
 
-#if 0
-//REMOVE ME!!!
+#ifdef BETTER_LITERAL_SHIFT
 /*-----------------------------------------------------------------*/
 /* genrshOne - right shift a one byte quantity by known count      */
 /*-----------------------------------------------------------------*/
@@ -6897,14 +7422,12 @@ static void
 genrshOne (operand * result, operand * left,
           int shCount, int sign)
 {
-  D (emitcode (";", "genrshOne");
-    );
+  D (emitcode (";", "genrshOne"););
   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
 }
 #endif
 
-#if 0
-//REMOVE ME!!!
+#ifdef BETTER_LITERAL_SHIFT
 /*-----------------------------------------------------------------*/
 /* genrshTwo - right shift two bytes by known amount != 0          */
 /*-----------------------------------------------------------------*/
@@ -6912,24 +7435,31 @@ static void
 genrshTwo (operand * result, operand * left,
           int shCount, int sign)
 {
-  D (emitcode (";", "genrshTwo");
-    );
+  D (emitcode (";", "genrshTwo"););
 
   /* if shCount >= 8 */
   if (shCount >= 8)
     {
       shCount -= 8;
+      _startLazyDPSEvaluation();
       if (shCount)
+      {
        shiftR1Left2Result (left, MSB16, result, LSB,
                            shCount, sign);
+      }                            
       else
+      {
        movLeft2Result (left, MSB16, result, LSB, sign);
+      }
       addSign (result, MSB16, sign);
+      _endLazyDPSEvaluation();
     }
 
   /*  1 <= shCount <= 7 */
   else
+  {
     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
+  }
 }
 #endif
 
@@ -6943,28 +7473,54 @@ static void
 shiftRLong (operand * left, int offl,
            operand * result, int sign)
 {
-  if (!sign)
+  int isSameRegs=sameRegs(AOP(left),AOP(result));
+
+  if (isSameRegs && offl>1) {
+    // we are in big trouble, but this shouldn't happen
+    werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
+  }
+
+  MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE));
+  
+  if (offl==MSB16) {
+    // shift is > 8
+    if (sign) {
+      emitcode ("rlc", "a");
+      emitcode ("subb", "a,acc");
+      emitcode ("xch", "a,%s", aopGet(AOP(left), MSB32, FALSE, FALSE));
+    } else {
+      aopPut (AOP(result), zero, MSB32);
+    }
+  }
+
+  if (!sign) {
     emitcode ("clr", "c");
-  MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE, TRUE));
-  if (sign)
+  } else {
     emitcode ("mov", "c,acc.7");
-  emitcode ("rrc", "a");
-  aopPut (AOP (result), "a", MSB32 - offl);
-  if (offl == MSB16)
-    /* add sign of "a" */
-    addSign (result, MSB32, sign);
+  }
 
-  MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE, TRUE));
   emitcode ("rrc", "a");
-  aopPut (AOP (result), "a", MSB24 - offl);
 
-  MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE, TRUE));
+  if (isSameRegs && offl==MSB16) {
+    emitcode ("xch", "a,%s",aopGet (AOP (left), MSB24, FALSE, FALSE));
+  } else {
+    aopPut (AOP (result), "a", MSB32);
+    MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE));
+  }
+
+  emitcode ("rrc", "a");
+  if (isSameRegs && offl==1) {
+    emitcode ("xch", "a,%s",aopGet (AOP (left), MSB16, FALSE, FALSE));
+  } else {
+    aopPut (AOP (result), "a", MSB24);
+    MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE));
+  }
   emitcode ("rrc", "a");
   aopPut (AOP (result), "a", MSB16 - offl);
 
   if (offl == LSB)
     {
-      MOVA (aopGet (AOP (left), LSB, FALSE, FALSE, TRUE));
+      MOVA (aopGet (AOP (left), LSB, FALSE, FALSE));
       emitcode ("rrc", "a");
       aopPut (AOP (result), "a", LSB);
     }
@@ -7044,12 +7600,11 @@ genrshFour (operand * result, operand * left,
 }
 #endif
 
-#if 0
-//REMOVE ME!!!
+#ifdef BETTER_LITERAL_SHIFT
 /*-----------------------------------------------------------------*/
 /* genRightShiftLiteral - right shifting by known count            */
 /*-----------------------------------------------------------------*/
-static void
+static bool
 genRightShiftLiteral (operand * left,
                      operand * right,
                      operand * result,
@@ -7059,8 +7614,19 @@ genRightShiftLiteral (operand * left,
   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
   int size;
 
-  D (emitcode (";", "genRightShiftLiteral");
-    );
+  size = getSize (operandType (result));
+
+  D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
+
+  /* We only handle certain easy cases so far. */
+  if ((shCount != 0)
+   && (shCount < (size * 8))
+   && (size != 1)
+   && (size != 2))
+  {
+      D(emitcode (";", "genRightShiftLiteral wimping out"););  
+      return FALSE;
+  }
 
   freeAsmop (right, NULL, ic, TRUE);
 
@@ -7072,22 +7638,26 @@ genRightShiftLiteral (operand * left,
            AOP_SIZE (left));
 #endif
 
-  size = getDataSize (left);
   /* test the LEFT size !!! */
 
   /* I suppose that the left size >= result size */
   if (shCount == 0)
-    {
+  {
       size = getDataSize (result);
+      _startLazyDPSEvaluation();
       while (size--)
+      {
        movLeft2Result (left, size, result, size, 0);
-    }
-
+      }
+      _endLazyDPSEvaluation();
+  }
   else if (shCount >= (size * 8))
     {
       if (sign)
+      {
        /* get sign in acc.7 */
        MOVA (aopGet (AOP (left), size - 1, FALSE, FALSE, TRUE));
+      }
       addSign (result, LSB, sign);
     }
   else
@@ -7101,10 +7671,11 @@ genRightShiftLiteral (operand * left,
        case 2:
          genrshTwo (result, left, shCount, sign);
          break;
-
+#if 0
        case 4:
          genrshFour (result, left, shCount, sign);
          break;
+#endif   
        default:
          break;
        }
@@ -7112,6 +7683,7 @@ genRightShiftLiteral (operand * left,
       freeAsmop (left, NULL, ic, TRUE);
       freeAsmop (result, NULL, ic, TRUE);
     }
+    return TRUE;
 }
 #endif
 
@@ -7126,8 +7698,7 @@ genSignedRightShift (iCode * ic)
   char *l;
   symbol *tlbl, *tlbl1;
 
-  D (emitcode (";", "genSignedRightShift ");
-    );
+  D (emitcode (";", "genSignedRightShift "););
 
   /* we do it the hard way put the shift count in b
      and loop thru preserving the sign */
@@ -7138,11 +7709,13 @@ genSignedRightShift (iCode * ic)
 
   aopOp (right, ic, FALSE, FALSE);
 
-#if 0
+#ifdef BETTER_LITERAL_SHIFT
   if (AOP_TYPE (right) == AOP_LIT)
     {
-      genRightShiftLiteral (left, right, result, ic, 1);
-      return;
+      if (genRightShiftLiteral (left, right, result, ic, 1))
+      {
+       return;
+      }
     }
 #endif
   /* shift count is unknown then we have to form
@@ -7151,8 +7724,20 @@ genSignedRightShift (iCode * ic)
      more that 32 bits make no sense anyway, ( the
      largest size of an object can be only 32 bits ) */
 
-  emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, FALSE));
-  emitcode ("inc", "b");
+  if (AOP_TYPE (right) == AOP_LIT)
+  {
+      /* Really should be handled by genRightShiftLiteral,
+       * but since I'm too lazy to fix that today, at least we can make
+       * some small improvement.
+       */
+       emitcode("mov", "b,#0x%02x",
+                       ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
+  }
+  else
+  {
+       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, FALSE));
+       emitcode ("inc", "b");
+  }
   freeAsmop (right, NULL, ic, TRUE);
   aopOp (left, ic, FALSE, FALSE);
   aopOp (result, ic, FALSE, AOP_TYPE (left) == AOP_DPTR);
@@ -7240,8 +7825,7 @@ genRightShift (iCode * ic)
   char *l;
   symbol *tlbl, *tlbl1;
 
-  D (emitcode (";", "genRightShift ");
-    );
+  D (emitcode (";", "genRightShift "););
 
   /* if signed then we do it the hard way preserve the
      sign bit moving it inwards */
@@ -7266,13 +7850,15 @@ genRightShift (iCode * ic)
 
   aopOp (right, ic, FALSE, FALSE);
 
-#if 0
+#ifdef BETTER_LITERAL_SHIFT
   /* if the shift count is known then do it
      as efficiently as possible */
   if (AOP_TYPE (right) == AOP_LIT)
     {
-      genRightShiftLiteral (left, right, result, ic, 0);
-      return;
+      if (genRightShiftLiteral (left, right, result, ic, 0))
+      {
+       return;
+      }
     }
 #endif
 
@@ -7281,9 +7867,21 @@ genRightShift (iCode * ic)
      only the lower order byte since shifting
      more that 32 bits make no sense anyway, ( the
      largest size of an object can be only 32 bits ) */
-
-  emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, FALSE));
-  emitcode ("inc", "b");
+  
+  if (AOP_TYPE (right) == AOP_LIT)
+  {
+      /* Really should be handled by genRightShiftLiteral,
+       * but since I'm too lazy to fix that today, at least we can make
+       * some small improvement.
+       */
+       emitcode("mov", "b,#0x%02x",
+                       ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
+  }
+  else
+  {
+       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, FALSE));
+       emitcode ("inc", "b");
+  }
   freeAsmop (right, NULL, ic, TRUE);
   aopOp (left, ic, FALSE, FALSE);
   aopOp (result, ic, FALSE, AOP_TYPE (left) == AOP_DPTR);
@@ -7391,7 +7989,7 @@ genUnpackBits (operand * result, char *rname, int ptype)
 
     case CPOINTER:
       emitcode ("clr", "a");
-      emitcode ("movc", "a", "@a+dptr");
+      emitcode ("movc", "a,@a+dptr");
       break;
 
     case GPOINTER:
@@ -7443,7 +8041,7 @@ genUnpackBits (operand * result, char *rname, int ptype)
        case CPOINTER:
          emitcode ("clr", "a");
          emitcode ("inc", "dptr");
-         emitcode ("movc", "a", "@a+dptr");
+         emitcode ("movc", "a,@a+dptr");
          break;
 
        case GPOINTER:
@@ -7731,7 +8329,8 @@ genFarPointerGet (operand * left,
            {
              emitcode ("mov", "dpl,%s", aopGet (AOP (left), 0, FALSE, FALSE, TRUE));
              emitcode ("mov", "dph,%s", aopGet (AOP (left), 1, FALSE, FALSE, TRUE));
-             emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, TRUE));
+             if (options.model == MODEL_FLAT24)
+               emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, TRUE));
            }
          else
            {
@@ -7740,7 +8339,8 @@ genFarPointerGet (operand * left,
                );
              emitcode ("push", "%s", aopGet (AOP (left), 0, FALSE, TRUE, TRUE));
              emitcode ("push", "%s", aopGet (AOP (left), 1, FALSE, TRUE, TRUE));
-             emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, TRUE));
+             if (options.model == MODEL_FLAT24)
+               emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, TRUE));
              emitcode ("pop", "dph");
              emitcode ("pop", "dpl");
            }
@@ -7806,7 +8406,8 @@ emitcodePointerGet (operand * left,
            {
              emitcode ("mov", "dpl,%s", aopGet (AOP (left), 0, FALSE, FALSE, TRUE));
              emitcode ("mov", "dph,%s", aopGet (AOP (left), 1, FALSE, FALSE, TRUE));
-             emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, TRUE));
+             if (options.model == MODEL_FLAT24)
+               emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, TRUE));
            }
          else
            {
@@ -7815,7 +8416,8 @@ emitcodePointerGet (operand * left,
                );
              emitcode ("push", "%s", aopGet (AOP (left), 0, FALSE, TRUE, TRUE));
              emitcode ("push", "%s", aopGet (AOP (left), 1, FALSE, TRUE, TRUE));
-             emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, TRUE));
+             if (options.model == MODEL_FLAT24)
+               emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, TRUE));
              emitcode ("pop", "dph");
              emitcode ("pop", "dpl");
            }
@@ -7885,21 +8487,29 @@ genGenPointerGet (operand * left,
            l=aopGet(AOP(left),0,FALSE,FALSE,TRUE);
            genSetDPTR(0);
            _flushLazyDPS();
-           emitcode ("mov", "dpl,%s ;jwk lazy genGenPointerGet", l);
+           emitcode ("mov", "dpl,%s", l);
            l=aopGet(AOP(left),1,FALSE,FALSE,TRUE);
            genSetDPTR(0);
            _flushLazyDPS();
-           emitcode ("mov", "dph,%s ;jwk lazy genGenPointerGet", l);
-           l=aopGet(AOP(left),2,FALSE,FALSE,TRUE);
-           genSetDPTR(0);
-           _flushLazyDPS();
-           emitcode ("mov", "dpx,%s ;jwk lazy genGenPointerGet", l);
-           emitcode ("mov", "b,%s", aopGet (AOP(left),3,FALSE,FALSE,TRUE));
+           emitcode ("mov", "dph,%s", l);
+           if (options.model == MODEL_FLAT24) {
+             l=aopGet(AOP(left),2,FALSE,FALSE,TRUE);
+             genSetDPTR(0);
+             _flushLazyDPS();
+             emitcode ("mov", "dpx,%s", l);
+             emitcode ("mov", "b,%s", aopGet (AOP(left),3,FALSE,FALSE,TRUE));
+           } else {
+             emitcode ("mov", "b,%s", aopGet (AOP(left),2,FALSE,FALSE,TRUE));
+           }
          } else {
            emitcode ("mov", "dpl,%s", aopGet (AOP(left),0,FALSE,FALSE,TRUE));
            emitcode ("mov", "dph,%s", aopGet (AOP(left),1,FALSE,FALSE,TRUE));
-           emitcode ("mov", "dpx,%s", aopGet (AOP(left),2,FALSE,FALSE,TRUE));
-           emitcode ("mov", "b,%s", aopGet (AOP(left),3,FALSE,FALSE,TRUE));
+           if (options.model == MODEL_FLAT24) {
+             emitcode ("mov", "dpx,%s", aopGet (AOP(left),2,FALSE,FALSE,TRUE));
+             emitcode ("mov", "b,%s", aopGet (AOP(left),3,FALSE,FALSE,TRUE));
+           } else {
+             emitcode ("mov", "b,%s", aopGet (AOP(left),2,FALSE,FALSE,TRUE));
+           }
          }
          _endLazyDPSEvaluation ();
        }
@@ -8403,7 +9013,8 @@ genFarPointerSet (operand * right,
            {
              emitcode ("mov", "dpl,%s", aopGet (AOP (result), 0, FALSE, FALSE, TRUE));
              emitcode ("mov", "dph,%s", aopGet (AOP (result), 1, FALSE, FALSE, TRUE));
-             emitcode ("mov", "dpx,%s", aopGet (AOP (result), 2, FALSE, FALSE, TRUE));
+             if (options.model == MODEL_FLAT24)
+               emitcode ("mov", "dpx,%s", aopGet (AOP (result), 2, FALSE, FALSE, TRUE));
            }
          else
            {
@@ -8412,7 +9023,8 @@ genFarPointerSet (operand * right,
                );
              emitcode ("push", "%s", aopGet (AOP (result), 0, FALSE, TRUE, TRUE));
              emitcode ("push", "%s", aopGet (AOP (result), 1, FALSE, TRUE, TRUE));
-             emitcode ("mov", "dpx,%s", aopGet (AOP (result), 2, FALSE, FALSE, TRUE));
+             if (options.model == MODEL_FLAT24)
+               emitcode ("mov", "dpx,%s", aopGet (AOP (result), 2, FALSE, FALSE, TRUE));
              emitcode ("pop", "dph");
              emitcode ("pop", "dpl");
            }
@@ -8478,8 +9090,12 @@ genGenPointerSet (operand * right,
        {                       /* we need to get it byte by byte */
          emitcode ("mov", "dpl,%s", aopGet (AOP (result), 0, FALSE, FALSE, TRUE));
          emitcode ("mov", "dph,%s", aopGet (AOP (result), 1, FALSE, FALSE, TRUE));
-         emitcode ("mov", "dpx,%s", aopGet (AOP (result), 2, FALSE, FALSE, TRUE));
-         emitcode ("mov", "b,%s", aopGet (AOP (result), 3, FALSE, FALSE, TRUE));
+         if (options.model == MODEL_FLAT24) {
+           emitcode ("mov", "dpx,%s", aopGet (AOP (result), 2, FALSE, FALSE, TRUE));
+           emitcode ("mov", "b,%s", aopGet (AOP (result), 3, FALSE, FALSE, TRUE));
+         } else {
+           emitcode ("mov", "b,%s", aopGet (AOP (result), 2, FALSE, FALSE, TRUE));
+         }
        }
       _endLazyDPSEvaluation ();
     }
@@ -8579,8 +9195,7 @@ genIfx (iCode * ic, iCode * popIc)
   operand *cond = IC_COND (ic);
   int isbit = 0;
 
-  D (emitcode (";", "genIfx ");
-    );
+  D (emitcode (";", "genIfx "););
 
   aopOp (cond, ic, FALSE, FALSE);
 
@@ -8688,6 +9303,115 @@ release:
 
 }
 
+/*-----------------------------------------------------------------*/
+/* genArrayInit - generates code for address of                       */
+/*-----------------------------------------------------------------*/
+static void
+genArrayInit (iCode * ic)
+{
+    literalList *iLoop;
+    int         ix, count;
+    int         elementSize = 0, eIndex;
+    unsigned    val, lastVal;
+    sym_link    *type;
+    operand     *left=IC_LEFT(ic);
+    
+    D (emitcode (";", "genArrayInit "););
+
+    aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
+    
+    if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
+    {
+       // Load immediate value into DPTR.
+       emitcode("mov", "dptr, %s",
+            aopGet(AOP(IC_LEFT(ic)), 0, TRUE, FALSE, TRUE));
+    }
+    else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
+    {
+#if 0
+      werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
+             "Unexpected operand to genArrayInit.\n");
+      exit(1);
+#else
+      // a regression because of SDCCcse.c:1.52
+      emitcode ("mov", "dpl,%s", aopGet (AOP (left), 0, FALSE, FALSE, TRUE));
+      emitcode ("mov", "dph,%s", aopGet (AOP (left), 1, FALSE, FALSE, TRUE));
+      if (options.model == MODEL_FLAT24)
+       emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, TRUE));
+#endif
+    }
+    
+    type = operandType(IC_LEFT(ic));
+    
+    if (type && type->next)
+    {
+       elementSize = getSize(type->next);
+    }
+    else
+    {
+       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
+                               "can't determine element size in genArrayInit.\n");
+       exit(1);
+    }
+    
+    iLoop = IC_ARRAYILIST(ic);
+    lastVal = 0xffff;
+    
+    while (iLoop)
+    {
+       bool firstpass = TRUE;
+       
+       emitcode(";", "store %d x 0x%x to DPTR (element size %d)", 
+                iLoop->count, (int)iLoop->literalValue, elementSize);
+       
+       ix = iLoop->count;
+       
+       while (ix)
+       {
+           symbol *tlbl = NULL;
+           
+           count = ix > 256 ? 256 : ix;
+           
+           if (count > 1)
+           {
+               tlbl = newiTempLabel (NULL);
+               if (firstpass || (count & 0xff))
+               {
+                   emitcode("mov", "b, #0x%x", count & 0xff);
+               }
+               
+               emitcode ("", "%05d$:", tlbl->key + 100);
+           }
+           
+           firstpass = FALSE;
+               
+           for (eIndex = 0; eIndex < elementSize; eIndex++)
+           {
+               val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
+               if (val != lastVal)
+               {
+                   emitcode("mov", "a, #0x%x", val);
+                   lastVal = val;
+               }
+               
+               emitcode("movx", "@dptr, a");
+               emitcode("inc", "dptr");
+           }
+           
+           if (count > 1)
+           {
+               emitcode("djnz", "b, %05d$", tlbl->key + 100);
+           }
+           
+           ix -= count;
+       }
+       
+       iLoop = iLoop->next;
+    }
+    
+    freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
+}
+
 /*-----------------------------------------------------------------*/
 /* genFarFarAssign - assignment when both are in far space         */
 /*-----------------------------------------------------------------*/
@@ -8696,19 +9420,86 @@ genFarFarAssign (operand * result, operand * right, iCode * ic)
 {
   int size = AOP_SIZE (right);
   int offset = 0;
-  char *l;
-
-  if (size > 1)
-    {
-      /* This is a net loss for size == 1, but a big gain
-       * otherwise.
-       */
-      D (emitcode (";", "genFarFarAssign (improved)");
-       );
+  symbol *rSym = NULL;
 
+  if (size == 1)
+  {
+      /* quick & easy case. */
+      D(emitcode(";","genFarFarAssign (1 byte case)"););      
+      MOVA(aopGet(AOP(right), 0, FALSE, FALSE, TRUE));
+      freeAsmop (right, NULL, ic, FALSE);
+      /* now assign DPTR to result */
+      _G.accInUse++;
+      aopOp(result, ic, FALSE, FALSE);
+      _G.accInUse--;
+      aopPut(AOP(result), "a", 0);
+      freeAsmop(result, NULL, ic, FALSE);
+      return;
+  }
+  
+  /* See if we've got an underlying symbol to abuse. */
+  if (IS_SYMOP(result) && OP_SYMBOL(result))
+  {
+      if (IS_TRUE_SYMOP(result))
+      {
+         rSym = OP_SYMBOL(result);
+      }
+      else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
+      {
+         rSym = OP_SYMBOL(result)->usl.spillLoc;
+      }
+  }
+            
+  if (size > 1 && rSym && rSym->rname && !rSym->onStack)
+  {
+      /* We can use the '390 auto-toggle feature to good effect here. */
+      
+      D(emitcode(";","genFarFarAssign (390 auto-toggle fun)"););
+      emitcode("mov", "dps, #0x21");   /* Select DPTR2 & auto-toggle. */
+      emitcode ("mov", "dptr,#%s", rSym->rname); 
+      /* DP2 = result, DP1 = right, DP1 is current. */
+      while (size)
+      {
+          emitcode("movx", "a,@dptr");
+          emitcode("movx", "@dptr,a");
+          if (--size)
+          {
+               emitcode("inc", "dptr");
+               emitcode("inc", "dptr");
+          }
+      }
+      emitcode("mov", "dps, #0");
+      freeAsmop (right, NULL, ic, FALSE);
+#if 0
+some alternative code for processors without auto-toggle
+no time to test now, so later well put in...kpb
+        D(emitcode(";","genFarFarAssign (dual-dptr fun)"););
+        emitcode("mov", "dps, #0x01");         /* Select DPTR2. */
+        emitcode ("mov", "dptr,#%s", rSym->rname); 
+        /* DP2 = result, DP1 = right, DP1 is current. */
+        while (size)
+        {
+          --size;
+          emitcode("movx", "a,@dptr");
+          if (size)
+            emitcode("inc", "dptr");
+          emitcode("inc", "dps");
+          emitcode("movx", "@dptr,a");
+          if (size)
+            emitcode("inc", "dptr");
+          emitcode("inc", "dps");
+        }
+        emitcode("mov", "dps, #0");
+        freeAsmop (right, NULL, ic, FALSE);
+#endif
+  }
+  else
+  {
+      D (emitcode (";", "genFarFarAssign"););
       aopOp (result, ic, TRUE, TRUE);
 
       _startLazyDPSEvaluation ();
+      
       while (size--)
        {
          aopPut (AOP (result),
@@ -8718,33 +9509,7 @@ genFarFarAssign (operand * result, operand * right, iCode * ic)
       _endLazyDPSEvaluation ();
       freeAsmop (result, NULL, ic, FALSE);
       freeAsmop (right, NULL, ic, FALSE);
-    }
-  else
-    {
-      D (emitcode (";", "genFarFarAssign ");
-       );
-
-      /* first push the right side on to the stack */
-      _startLazyDPSEvaluation ();
-      while (size--)
-       {
-         l = aopGet (AOP (right), offset++, FALSE, FALSE, TRUE);
-         MOVA (l);
-         emitcode ("push", "acc");
-       }
-
-      freeAsmop (right, NULL, ic, FALSE);
-      /* now assign DPTR to result */
-      aopOp (result, ic, FALSE, FALSE);
-      size = AOP_SIZE (result);
-      while (size--)
-       {
-         emitcode ("pop", "acc");
-         aopPut (AOP (result), "a", --offset);
-       }
-      freeAsmop (result, NULL, ic, FALSE);
-      _endLazyDPSEvaluation ();
-    }
+  }
 }
 
 /*-----------------------------------------------------------------*/
@@ -8790,9 +9555,8 @@ genAssign (iCode * ic)
     goto release;
 
   /* if the result is a bit */
-  if (AOP_TYPE (result) == AOP_CRY)
+  if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
     {
-
       /* if the right size is a literal then
          we know what the value is */
       if (AOP_TYPE (right) == AOP_LIT)
@@ -8830,8 +9594,6 @@ genAssign (iCode * ic)
       (AOP_TYPE (right) == AOP_LIT) &&
       !IS_FLOAT (operandType (right)))
     {
-      D (emitcode (";", "Kevin's better literal load code");
-       );
       _startLazyDPSEvaluation ();
       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
        {
@@ -8925,7 +9687,8 @@ genCast (iCode * ic)
   aopOp (result, ic, FALSE, AOP_TYPE (right) == AOP_DPTR);
 
   /* if the result is a bit */
-  if (AOP_TYPE (result) == AOP_CRY)
+  // if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
+  if (IS_BITVAR(OP_SYMBOL(result)->type))
     {
       /* if the right size is a literal then
          we know what the value is */
@@ -9167,12 +9930,37 @@ genDjnz (iCode * ic, iCode * ifx)
     return 0;
 
   /* otherwise we can save BIG */
+  D(emitcode(";", "genDjnz"););
+
   lbl = newiTempLabel (NULL);
   lbl1 = newiTempLabel (NULL);
 
   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
 
-  if (IS_AOP_PREG (IC_RESULT (ic)))
+  if (AOP_NEEDSACC(IC_RESULT(ic)))
+  {
+      /* If the result is accessed indirectly via
+       * the accumulator, we must explicitly write
+       * it back after the decrement.
+       */
+      char *rByte = aopGet(AOP(IC_RESULT(ic)), 0, FALSE, FALSE, TRUE);
+      
+      if (strcmp(rByte, "a"))
+      {
+           /* Something is hopelessly wrong */
+           fprintf(stderr, "*** warning: internal error at %s:%d\n",
+                  __FILE__, __LINE__);
+           /* We can just give up; the generated code will be inefficient,
+            * but what the hey.
+            */
+           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
+           return 0;
+      }
+      emitcode ("dec", "%s", rByte);
+      aopPut(AOP(IC_RESULT(ic)), rByte, 0);
+      emitcode ("jnz", "%05d$", lbl->key + 100);
+  }
+  else if (IS_AOP_PREG (IC_RESULT (ic)))
     {
       emitcode ("dec", "%s",
                aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE, FALSE));
@@ -9181,7 +9969,7 @@ genDjnz (iCode * ic, iCode * ifx)
     }
   else
     {
-      emitcode ("djnz", "%s,%05d$", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE, FALSE),
+      emitcode ("djnz", "%s,%05d$", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, TRUE, FALSE),
                lbl->key + 100);
     }
   emitcode ("sjmp", "%05d$", lbl1->key + 100);
@@ -9248,6 +10036,14 @@ gen390Code (iCode * lic)
 
   lineHead = lineCurr = NULL;
 
+  if (options.model == MODEL_FLAT24) {
+    fReturnSizeDS390 = 5;
+    fReturn = fReturn24;
+  } else {
+    fReturnSizeDS390 = 4;
+    fReturn = fReturn16;
+    options.stack10bit=0;
+  }
 #if 0
   //REMOVE ME!!!
   /* print the allocation information */
@@ -9479,10 +10275,12 @@ gen390Code (iCode * lic)
          addSet (&_G.sendSet, ic);
          break;
 
+       case ARRAYINIT:
+           genArrayInit(ic);
+           break;
+           
        default:
          ic = ic;
-         /*      piCode(ic,stdout); */
-
        }
     }