fix combination of --xstack & ISRs using non-zero banks
[fw/sdcc] / src / mcs51 / gen.c
index 6ad7a2a2d98917dbd8593bfc60559dc989df45a8..2d70a6af55b5b93cd6599ed7bfdd0ad03dd065b3 100644 (file)
@@ -1,4 +1,3 @@
-void CatchMe() {}
 /*-------------------------------------------------------------------------
   SDCCgen51.c - source file for code generation for 8051
 
@@ -1619,7 +1618,6 @@ genIpush (iCode * ic)
   int size, offset = 0;
   char *l;
 
-  CatchMe();
   /* if this is not a parm push : ie. it is spill push
      and spill push is always done on the local stack */
   if (!ic->parmPush)
@@ -1712,25 +1710,36 @@ static void
 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 = mcs51_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 = (mcs51_nRegs - 1); i >= 0; i--)
@@ -1750,11 +1759,13 @@ 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);  
+  }    
 }
 
 /*-----------------------------------------------------------------*/
@@ -1764,16 +1775,22 @@ static void
 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);
+      if (!ic)
+      {
+         /* Assume r0 is available for use. */
+         r = mcs51_regWithIdx (R0_IDX);;
+      }
+      else
+      {
+         aop = newAsmop (0);
+         r = getFreePtr (ic, &aop, FALSE);
+      }
       emitcode ("mov", "%s,_spx", r->name);
-
     }
 
   for (i = 0; i < mcs51_nRegs; i++)
@@ -1798,16 +1815,25 @@ 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;
+  }
 }
 
 /*-----------------------------------------------------------------*/
@@ -1817,6 +1843,8 @@ static void
 genCall (iCode * ic)
 {
   sym_link *detype;
+  bool restoreBank = FALSE;
+  bool swapBanks = FALSE;
 
   /* if send set is not empty the assign */
   if (_G.sendSet)
@@ -1850,13 +1878,27 @@ genCall (iCode * ic)
   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);
-  } else /* no need to save if we just saved the whole bank */ {
-    /* if caller saves & we have not saved then */
-    if (!ic->regsSaved)
+      IS_ISR (currFunc->etype))
+  {
+      if (!ic->bankSaved) 
+      {
+           /* This is unexpected; the bank should have been saved in
+            * genFunction.
+            */
+          saveRBank (SPEC_BANK (detype), ic, FALSE);
+          restoreBank = TRUE;
+      }
+      swapBanks = TRUE;  
+  } 
+    
+  /* if caller saves & we have not saved then */
+  if (!ic->regsSaved)
       saveRegisters (ic);
+
+  if (swapBanks)
+  {
+        emitcode ("mov", "psw,#0x%02x", 
+           ((SPEC_BANK(detype)) << 3) & 0xff);
   }
 
   /* make the call */
@@ -1864,6 +1906,12 @@ genCall (iCode * ic)
                            OP_SYMBOL (IC_LEFT (ic))->rname :
                            OP_SYMBOL (IC_LEFT (ic))->name));
 
+  if (swapBanks)
+  {
+       emitcode ("mov", "psw,#0x%02x", 
+          ((SPEC_BANK(currFunc->etype)) << 3) & 0xff);
+  }
+
   /* if we need assign a result value */
   if ((IS_ITEMP (IC_RESULT (ic)) &&
        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
@@ -1894,18 +1942,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))
     unsaveRegisters (ic);
 
-
+  /* if register bank was saved then pop them */
+  if (restoreBank)
+    unsaveRBank (SPEC_BANK (detype), ic, FALSE);
 }
 
 /*-----------------------------------------------------------------*/
@@ -2075,6 +2120,7 @@ genFunction (iCode * ic)
 {
   symbol *sym;
   sym_link *fetype;
+  bool   switchedPSW = FALSE;
 
   _G.nRegsSaved = 0;
   /* create the function header */
@@ -2157,6 +2203,95 @@ genFunction (iCode * ic)
              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 (sym->hasFcall)
+           {
+
+#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 *detype;
+                       
+                       detype = getSpec(operandType (IC_LEFT(i)));
+                       if (detype 
+                        && SPEC_BANK(detype) != SPEC_BANK(sym->etype))
+                       {
+                            /* Mark this bank for saving. */
+                            if (SPEC_BANK(detype) >= MAX_REGISTER_BANKS)
+                            {
+                                werror(E_NO_SUCH_BANK, SPEC_BANK(detype));
+                            }
+                            else
+                            {
+                                banksToSave |= (1 << SPEC_BANK(detype));
+                            }
+                            
+                            /* 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", 
+                             (SPEC_BANK (sym->etype) << 3) & 0x00ff);
+                   switchedPSW = TRUE;
+               }
+               
+               for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
+               {
+                    if (banksToSave & (1 << ix))
+                    {
+                        saveRBank(ix, NULL, FALSE);
+                    }
+               }
+           }
+           SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
+       }
     }
   else
     {
@@ -2184,7 +2319,8 @@ genFunction (iCode * ic)
     }
 
   /* set the register bank to the desired value */
-  if (SPEC_BANK (sym->etype) || IS_ISR (sym->etype))
+  if ((SPEC_BANK (sym->etype) || IS_ISR (sym->etype))
+   && !switchedPSW)
     {
       emitcode ("push", "psw");
       emitcode ("mov", "psw,#0x%02x", (SPEC_BANK (sym->etype) << 3) & 0x00ff);
@@ -2280,7 +2416,16 @@ genEndFunction (iCode * ic)
 
   /* restore the register bank  */
   if (SPEC_BANK (sym->etype) || IS_ISR (sym->etype))
-    emitcode ("pop", "psw");
+  {
+    if (!SPEC_BANK (sym->etype) || !IS_ISR (sym->etype)
+     || !options.useXstack)
+    {
+        /* Special case of ISR using non-zero bank with useXstack
+         * is handled below.
+         */
+        emitcode ("pop", "psw");
+    }
+  }
 
   if (IS_ISR (sym->etype))
     {
@@ -2291,7 +2436,6 @@ genEndFunction (iCode * ic)
          registers :-) */
       if (!SPEC_BANK (sym->etype))
        {
-
          /* if this function does not call any other
             function then we can be economical and
             save only those registers that are used */
@@ -2320,6 +2464,32 @@ genEndFunction (iCode * ic)
              unsaveRBank (0, ic, FALSE);
            }
        }
+       else
+       {
+           /* This ISR uses a non-zero bank.
+            *
+            * Restore any register banks saved by genFunction
+            * in reverse order.
+            */
+           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");
+           }
+       }
 
       if (!inExcludeList ("dph"))
        emitcode ("pop", "dph");
@@ -4992,7 +5162,6 @@ release:
 /*-----------------------------------------------------------------*/
 /* genInline - write the inline code out                           */
 /*-----------------------------------------------------------------*/
-char *johan;
 static void
 genInline (iCode * ic)
 {
@@ -5009,7 +5178,6 @@ genInline (iCode * ic)
       if (*bp == '\n')
        {
          *bp++ = '\0';
-         johan=bp;
          emitcode (bp1, "");
          bp1 = bp;
        }
@@ -5020,7 +5188,6 @@ genInline (iCode * ic)
              bp++;
              *bp = '\0';
              bp++;
-             johan=bp;
              emitcode (bp1, "");
              bp1 = bp;
            }