femtoos_source/femtoos_port.c

Go to the documentation of this file.
00001 /*
00002  * Femto OS v 0.91 - Copyright (C) 2008-2009 Ruud Vlaming
00003  *
00004  * This file is part of the Femto OS distribution.
00005  *
00006  * This program is free software: you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation, version 3 of the License.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017  *
00018  * Please note that, due to the GPLv3 license, for application of this
00019  * work and/or combined work in embedded systems special obligations apply.
00020  * If these are not to you liking, please know the Femto OS is dual
00021  * licensed. A commercial license and support are available.
00022  * See http://www.femtoos.org/ for details.
00023  */
00024 
00025 #include "femtoos_core.h"
00026 #include "femtoos_shared.h"
00027 
00028 
00029 #if (cfgCheckReset == cfgTrue) || (defCheckReportingError == cfgTrue)
00030 
00034   static void portShortDelay(Tuint08 uiLoops);
00035 #endif
00036 
00037 
00038 #if (defSysGCCstartup != cfgReplace)
00039 
00040 void portInit(void)
00041 { /* Switch to the highest internal clock frequency (8MHz) Note that the need of this action
00042    * depends on the setting of the fuse CKDIV8. If that is unprogrammed (i.e. set to 1) these
00043    * instructions are not needed. However, the device is shipped with a programmed fuse. */
00044   #if (devCLKPCE != cfgUndefined)
00045     /* Not all hardware has prescalers but if it does, set the values here. We set it to
00046      * the highest clock frequency. This may not be what you want because of the power
00047      * consumption. Set an other value if needed. */
00048     devCLKPR = preBitSet1(0x00,devCLKPCE);
00049     devCLKPR = defClockPrescaleBits;
00050   #endif
00051   /* If we use low power sleep we disable watchdog, only works in  safety level 1
00052    * (in safety level 2 fuses need to be reset). Please note that it may be necessary
00053    * to perform this steps on devices that where switched off during sleep, and are
00054    * now used for other purposes. */
00055   #if (cfgUseLowPowerSleep == cfgTrue) || (includeGenReboot == cfgTrue)
00056     /* Disable the watchdog, since WDRF overrides the WDE, we must clear it first.
00057      * Furthermore, we clear all other flags, since we have no interest in them.
00058      * If you do, alter the code here to preserver the flags. */
00059     devMCUSR  =  preBitClr4(0x00,devWDRF,devBORF,devEXTRF,devPORF);
00060     /* Enable configuration change. */
00061     devWDTCR  =  preBitSet2(0x00,devWDCE,devWDE);
00062     /* Disable Watchdog, do NOT write any other bits! */
00063     devWDTCR  =  preBitClr1(0x00,devWDCE);
00064   #endif
00065   /* If we make use of tracing, we must configure it at the very beginning. Note we use
00066    * bitbanging because this is the most portable. */
00067   #if (cfgCheckTrace == cfgTrue)
00068     /* Set the data pin to output, we use it to transport the bits. */
00069     devTraceComDRR = preBitSet1(devTraceComDRR,devTraceDataPin);
00070     /* Set the ready pin to output, we use it to signal the data is available. */
00071     devTraceComDRR = preBitSet1(devTraceComDRR,devTraceReadyPin);
00072     /* Set the acknowledge pin to output, we use it see if the data has been read. */
00073     devTraceComDRR = preBitClr1(devTraceComDRR,devTraceAckPin);
00074   #endif
00075   /* Done */ }
00076 
00077 #endif
00078 
00079 
00080 
00081 #if (cfgCheckTrace == cfgTrue)
00082 
00083 void portTrace(Tuint08 uiEvent)
00084 { /* This routine shifts one byte through an handshaked bitbanging protocol. */
00085   Tuint08 uiBitLoc = 0x80;
00086   /* uiBitLoc indicates the bit location of the bit from uiEvent that is about to be send. The loop
00087    * runs until all bits have been send. Since this is a full handshake protocol, make sure your
00088    * data collector is quick enough, otherwise timing errors may occur. */
00089   while (uiBitLoc != 0)
00090   { /* If the bit is set, set the output pin, otherwise clear it. */
00091     if ((uiEvent & uiBitLoc) != 0x00)
00092     { devTraceComPORT = preBitSet1(devTraceComPORT,devTraceDataPin); }
00093     else
00094     { devTraceComPORT = preBitClr1(devTraceComPORT,devTraceDataPin); }
00095     /* Send the listener that the data is ready. */
00096     devTraceComPORT = preBitSet1(devTraceComPORT,devTraceReadyPin);
00097     /* Wait until the data has been read and the listener told so. */
00098     while (preBitIsClr(devTraceComPIN,devTraceAckPin));
00099     /* Go to the next bit */
00100     uiBitLoc >>= 1;
00101     /* If the bit is set, set the output pin, otherwise clear it. */
00102     if ((uiEvent & uiBitLoc) != 0x00)
00103     { devTraceComPORT = preBitSet1(devTraceComPORT,devTraceDataPin); }
00104     else
00105     { devTraceComPORT = preBitClr1(devTraceComPORT,devTraceDataPin); }
00106     /* Send the listener that the data is ready. */
00107     devTraceComPORT = preBitClr1(devTraceComPORT,devTraceReadyPin);
00108     /* Wait until the data has been read and the listener told so. */
00109     while (preBitIsSet(devTraceComPIN,devTraceAckPin));
00110     /* Go to the next bit */
00111     uiBitLoc>>= 1; }
00112   /* Done. Note that if the transmission of even one bit fails, this protocol hangs for ever, so
00113    * keep your lines short. */ }
00114 
00115 #endif
00116 
00117 
00118 
00119 #if (defCheckReportingError == cfgTrue)
00120 
00121 void portShowError(Tuint08 uiMessage, Tuint08 uiCallId, Tuint08 uiInfoTask)
00122 { /* We display the error code on devErrorComPORT. If you use the stk500 with eight leds, this can be
00123    * seen quite nicely. Specify that we want the message to be repeated 16 times. We arrive here
00124    * with disabled tick and global interrupts. */
00125   Tuint08 uiCount = 16;
00126   /* The error Port must be configured as output on all pins. We do not bother to store its original
00127    * value, since we must solve the error first. */
00128   devErrorComDDR = 0xFF;
00129   /* Send the error message several times. In order to make them catch the eye we have a special
00130    * blinking scheme. */
00131   while (uiCount--)
00132   { /* Draw the attention of the user by running a led. This also marks the beginning
00133      * of the sequence of information. */
00134     Tuint08 uiRun = 0x80;
00135     do
00136     { devErrorComPORT = ~uiRun;
00137       portShortDelay(0x02);
00138       uiRun >>= 1; }
00139     while (uiRun);
00140     /* Display the message. */
00141     devErrorComPORT = ~uiMessage;
00142     /* wait a little while */
00143     portShortDelay(0x20);
00144     /* Display the caller. */
00145     devErrorComPORT = ~uiCallId;
00146     /* wait a little while */
00147     portShortDelay(0x20);
00148     /* Display extra information. */
00149     devErrorComPORT = ~uiInfoTask;
00150     /* wait a somewhat longer */
00151     portShortDelay(0x20); }
00152   /* Done, we return, if the error was fatal, this method will be called again automatically. */ }
00153 
00154 #endif
00155 
00156 
00157 #if (cfgCheckReset == cfgTrue) || (defCheckReportingError == cfgTrue)
00158 
00159 static void portShortDelay(Tuint08 uiLoops)
00160 { /* Disable all timer interrupts. Since we use this routine to display some (error) information
00161    * we do not want to disturbed by other sources. We only make it explicit for timer 0.
00162    * Note that other timer bits may be destroyed here. */
00163   devTIMSK = preBitClr2(0x00,devOCIE,devTOIE);
00164   /* Set the timer in normal 8 bit mode and activate the timer with the chosen prescaler.
00165    * Now, on some devices these bits are located on the same register, and on other they
00166    * are not. We must separate. Furthermore, it is assumed it is OK to clear the other
00167    * bits in the register.  */
00168   if (preEqualMacros(devTCCRB,devTCCRA))
00169   { devTCCRA = preBitClr1(0x00,devWGM) | defDelayPrescaleBits; }
00170   else
00171   { devTCCRA = preBitClr1(0x00,devWGM);
00172     devTCCRB = defDelayPrescaleBits; }
00173   /* operate in the standard 8 bit timer mode (some devices do not have a 16 bit mode.
00174    *  Note we use the same timer as the tick interrupt does. */
00175   /* reset the timer */
00176   devTCNT = 0x00;
00177   /* clear the overflow flag, so that we start with a clean timer. */
00178   devTIFR = preBitSet1(0x00,devTOV);
00179   /* If you use the simulator of Atmel, it cannot simulate the timer at this point
00180    * so just skip it. */
00181   #if (cfgSysDebug == cfgFalse)
00182     /* wait until the time is done. Note we do not use an interrupt, since that routine
00183      * is not at our disposal, but there is no need either. */
00184     while (uiLoops!=0)
00185     {  /* Wait until the timer overflows. */
00186        while (preBitIsClr(devTIFR,devTOV));
00187        /* Reset the overflow flag */
00188        devTIFR = preBitSet1(0x00,devTOV);
00189        /* Every overflow counts as one loop. */
00190        uiLoops--; }
00191   #endif
00192  /* Done, we have spend some time in this method. */ }
00193 
00194 #endif
00195 
00196 #if (cfgCheckReset == cfgTrue)
00197 
00198 void portShowReset(void)
00199 { /* We blink all leds rapidly on portA. If you use the stk500 with eight leds, this can be
00200    * seen quite nicely. Specify that we want the message to be repeated 5 times. */
00201   Tuint08 uiCount = 5;
00202   /* Port A must be configured as output on all pins. */
00203   devErrorComDDR = 0xFF;
00204   /* Show the reset message a number of times. */
00205   while (uiCount--)
00206   { /* all leds on */
00207     devErrorComPORT = 0x00;
00208     /* wait a little while */
00209     portShortDelay(0x01);
00210     /* all leds off */
00211     devErrorComPORT = 0xFF;
00212     /* wait a little while */
00213     portShortDelay(0x01); }
00214  /* Done */ }
00215 
00216 #endif
00217 
00218 
00219 #if (cfgUseLowPowerSleep == cfgTrue) && ((cfgUseLowPowerOnDelay == cfgFalse) || !defined(devSigWatchdogTimeout))
00220 
00221 void portSleep(Tuint08 uiTickBlockMinDelay)
00222 { /* We will go to sleep until we are woken by a kiss of the prins (i.e.
00223    * an external interrupt.) The parameter uiTickBlockMinDelay has no
00224    * relevance. Set the sleep mode to power down. This is needed,
00225    * since normally the sleep mode is different during the idle task.
00226    * Make sure we leave the other bits alone. */
00227   devSMCR = preBitClr2(preBitSet2(devSMCR,devSE,devSM1),devSM0,devSM2);
00228   /* Start sleeping, since we arrive here with interrupts disabled, they must be enabled again
00229    * just before sleeping, to make sure we actually go to sleep before an interrupt comes.
00230    * To make sure we only have one waking up interrupt we must immediately switch off
00231    * interrupts after wakeup. That way we can reliably determine which was the cause
00232    * of the awakening. */
00233   asm volatile (
00234    "sei        \n\t"   /* We reactivate the global interrupt just before we go to sleep so we know for      */
00235    "sleep      \n\t"   /* sure the sleep will indeed start off. In that way we do not miss an interrupt.    */
00236    "cli        \n\t"   /* And then we immediately disable them again so there cannot be an extra interrupt  */
00237     ::);               /* just after the first interrupt.                                                   */
00238   /* We woke up, first disable the sleep so we do not accidently fall asleep again. */
00239   devSMCR = preBitClr1(devSMCR,devSE);
00240   /* Cinderella has no idea how long she has slept, so it makes no sense to
00241    * correct the tick counter. We are done sleeping and may return to the OS
00242    * Note we must return with interrupts still switched off! */ }
00243 
00244 #endif
00245 
00246 
00247 #if (cfgUseLowPowerSleep == cfgTrue) && (cfgUseLowPowerOnDelay == cfgTrue)
00248 
00249 void portSleep(Tuint08 uiTickBlockMinDelay)
00250 { /* We will go to sleep in periods given by cfgNumSleepPeriod and rounded to an allowed value
00251    * for this device. Global and timer interrupts are disabled at this moment, so we are
00252    * responsible for activating the interrupts on the right moment. Timer interrupts must
00253    * stay disabled. uiTickBlockMinDelay denotes the time we can sleep safely without
00254    * having the risk to wake up any delayed tasks. If uiTickBlockMinDelay is defSleepInfinite
00255    * (0xFF) there are no delayed tasks and we may sleep up to the moment an external interrupt
00256    * arrives. Of course we may sleep longer as uiTickBlockMinDelay but then you must activate
00257    * cfgUseLowPowerDelayRelease or face incorrect wakeup of delayed tasks. For infinite
00258    * sleep this does not matter, since there are no delays in that case and keeping the
00259    * tick counter does not make much sense. */
00260   /* Calculate how much blocks in terms of the watchdog we may sleep. Please note this generates
00261    * the shortest code when defSleepDivider is a power of two. See the discussion at its
00262    * definition.*/
00263   Tuint08 uiBlocksToSleep = (uiTickBlockMinDelay / defSleepDivider);
00264   /* The watchdog will be used to wake up, thus enable it (note that is does not seem
00265    * necessary to set the WDCE bit for changing the prescaler bits, contrary to what the manual
00266    * on page 45 states: "Bit 4 – WDCE: Watchdog Change Enable: .... This bit must also be set
00267    * when changing the prescaler bits") It seems this only is required at disabling the watchdog,
00268    * but i never got this to work as described. */
00269   /* Enable configuration change. */
00270   devWDTCR = preBitSet2(0x00,devWDCE,devWDE);
00271   devWDTCR = preBitSet4(0x00,devWDIF,devWDIE,devWDP2,devWDP1) | preBitClr4(0x00,devWDP3,devWDCE,devWDE,devWDP0);
00272   /* At this moment we have a fixed mode for sleeping which is the powerdown. Change it to your
00273    *  liking if needed. So, set the sleep mode to power down. This is needed, since normally
00274    * the sleep mode is different during the idle task. Make sure we leave the other bits alone. */
00275   devSMCR = preBitClr2(preBitSet2(devSMCR,devSE,devSM1),devSM0,devSM2);
00276   /* We use a counter to keep track of how many blocks we have slept, this in order to
00277    * correct the clock later on. */
00278   Tuint08 uiBlocksSleepCount = 0;
00279   /* Start sleeping. Because there are two sources of wakeup, i.e. the watchdog and some other
00280    * interrupt we must distinguish between the two. We do so by setting a sleepbit (we can use
00281    * the devAuxSysRegBit bit since within the sleep - wake loop no other use is made of it.) in
00282    * the devAuxSysReg. This bit is cleared by the watchdog and cleared just before sleep. If at
00283    * wakeup the bit is not set we know an other interrupt source was present and we must
00284    * break of sleeping at once. Otherwise we may continue if we are not done yet. So first
00285    * set the sleepBit to pass the first while loop.*/
00286   #if (cfgSysSqueezeState == cfgFalse)
00287   devAuxSysReg = preBitSet1(devAuxSysReg,devAuxSysRegBit);
00288   /* You may continue the loop when not all blocks are slept yet and we came from a watchdog interrupt */
00289   while ( ((uiBlocksSleepCount != uiBlocksToSleep)) && preBitIsSet(devAuxSysReg,devAuxSysRegBit) )
00290   { /* Clear the sleepbit, so it can be set by the watchdog interrupt */
00291     devAuxSysReg = preBitClr1(devAuxSysReg,devAuxSysRegBit);
00292     asm volatile (
00293      "sei        \n\t"   /* We reactivate the global interrupt just before we go to sleep so we know for      */
00294      "sleep      \n\t"   /* sure the sleep will indeed start off. In that way we do not miss an interrupt.    */
00295      "cli        \n\t"   /* And then we immideately disable them again so there cannot be an extra interrupt  */
00296      ::);                /* just after the first interrupt.                                                   */
00297     /* If we may sleep for ever we simple forbid sleepcounting so the loop will never reach its limit. Still other
00298      * interrupts may break the loop.*/
00299     if ((uiTickBlockMinDelay != defSleepInfinite)) uiBlocksSleepCount++;
00300     /* If a sleephook was installed it is called at every wakeup. */
00301     #if (callAppTickSleep == cfgTrue)
00302       appTickSleep();
00303     #endif
00304     /* Done, if we leave the loop here, the device has woken up */ }
00305   #else
00306     /* The code below does exactly the same as above, but now for the T bit instead of the AuxRegBit. Since
00307      * i don't know an efficient way to use the T bit in C code directly, i coded it in assembly. Save's two bytes
00308      * compared to what the gcc compiler makes of the code above, and six push/pop instructions, due to efficient
00309      * register use.
00310      * Note that you onw interrupt should not set the T bit on entry. Usually that does not happen since interrupts
00311      * should preserve the status register. And this has T bit cleared.  */
00312     asm volatile (
00313      "set                       \n\t"  /* The T bit functions as flag to detect if we come from an watchdog interrupt    */
00314      "76:                       \n\t"  /* or from an other interrupt. When it is set, we assume coming from a watchdog   */
00315      "cp %[_Count_],%[_Sleep_]  \n\t"  /* So start with the flag set. Now we compare the sleep counter with the number   */
00316      "breq 78f                  \n\t"  /* of blocks we must sleep. When equal, we are done, jump to the end.             */
00317      "brtc 78f                  \n\t"  /* Subsequently we check if the T bit is still set. If not, we had an non watch   */
00318      "clt                       \n\t"  /* dog interrupt and we may stop. Then, we start sleeping with T bit reset.       */
00319      "sei                       \n\t"  /* We reactivate the global interrupt just before we go to sleep so we know for   */
00320      "sleep                     \n\t"  /* sure the sleep will indeed start off. In that way we do not miss an interrupt. */
00321      "cli                       \n\t"  /* And then we immediately disable them again so there cannot be an extra inter-  */
00322      "cpi %[_Delay_],%[_Inf_]   \n\t"  /* rupt after the first interrupt. Then increase the sleep counter by one if      */
00323      "breq 77f                  \n\t"  /* sleep time is limited and otherwise keeping the counter constant will induce   */
00324      "subi %[_Count_],0xFF      \n\t"  /* Infinite looping.                                                               */
00325      "77:                       \n\t"  /*  */
00326     #if (callAppTickSleep == cfgTrue)  /* If we defined a hook on the heartbeat of sleeping call it.                     */
00327      defCALL " appTickSleep     \n\t"  /* Make use if defCall because we do not know how far we must go                  */
00328     #endif                             /*  */
00329      "rjmp 76b                  \n\t"  /*  Go for an other round of sleep.                                               */
00330      "78:                       \n\t"
00331      :
00332      [_Count_]    "=r" (uiBlocksSleepCount):
00333      "[_Count_]"       (uiBlocksSleepCount),
00334      [_Sleep_]    "r" (uiBlocksToSleep),
00335      [_Delay_]    "r" (uiTickBlockMinDelay),
00336      [_Inf_]      "i" (defSleepInfinite));
00337 
00338 #endif
00339   /* To prevent accidentally falling asleep, clear the sleep enable bit. */
00340   devSMCR = preBitClr1(devSMCR,devSE);
00341   /* The watchdog must be disabled, since it may interrupt the OS with disastrous consequences.
00342    * Enable a configuration change. (There is no need now to clear the WDRF, we do not come here
00343    * after a reset. If we did not set the watchdog, there is nothing to clear here.  */
00344   devWDTCR  =  preBitSet2(0x00,devWDCE,devWDE);
00345   /* Disable Watchdog, do NOT write any other bits! Setting the prescaler seems not to be allowed
00346    * on this moment. Why, is unclear to me, but we do not need it here. */
00347   devWDTCR  =  preBitClr1(0x00,devWDCE);
00348   /* If we want to correct the tick counter ... */
00349   #if (includeGenAddtoTickCount == cfgTrue)
00350     /* Calculate the time slept by approximation. It does not make sense to adjust the clock
00351      * when we where allowed to sleep indefinitely. */
00352     if (uiTickBlockMinDelay != defSleepInfinite)
00353     { /* The number of sleepblocks slept have been counted, so it is relatively easy to calculate
00354        * the number of extra ticks. First each sleepblock accounts for defSleepDivider tickblocks,
00355        * and each tickblock is 256 ticks. */
00356       Tuint16 uiTicksSlept = (uiBlocksSleepCount * defSleepDivider << 8);
00357       /* And pass it on to the Femto OS */
00358       genAddtoTickCount(uiTicksSlept); }
00359   #endif
00360   /* We are done sleeping and may return to the OS
00361    * Note we must return with interrupts still switched off! */ }
00362 
00363 #endif
00364 
00365 
00366 #if (includeGenReboot == cfgTrue)
00367 
00368 void portReboot(void)
00369 { /* These are the device specific instructions to reboot. Unfortunately there is no
00370    * way to reset the device directly. Depending on your situation you could jump to
00371    * __init, but that does not reset the registers, and your __init may even rely upon
00372    * the inital values of them, so the interrupts may not be cleared at the start!!
00373    * Hmm, it seems we must misuse the
00374    * watchdog for this. Make sure you disable the watchdog upon re-entry, set it to
00375    * the reset mode, and the shortest interval. (16ms)
00376    * TODO: test if the reset time is really 16ms, even if we have slept some other time
00377    * before. The point is, we do not set WDCE, although is should have been done
00378    * account. Page 45 of the manual, Bit 4 -WDCE: Watchdog Change Enable.
00379    * Found: for the attiny861 this is works also without, but for other devices it does not. */
00380   devWDTCR  =  preBitSet2(0x00,devWDCE,devWDE);
00381   devWDTCR  =  preBitSet1(0x00,devWDE) | preBitClr5(0x00,devWDIE,devWDP3,devWDP2,devWDP1,devWDP0);
00382   /* Now, wait on the reset, for we may not return. */
00383   while (true); }
00384 
00385 #endif
00386 
00387 
00388 void portIdle(void)
00389 { /* If we arrive here it is because there are no tasks that can be run. This is the idle
00390    * task. We must stay here until the next timer interrupt. */
00391   #if cfgSysDebug == cfgTrue
00392     /* If you use the simulator of Atmel, it cannot simulate the timer at this point
00393      * so we manually simulate it. */
00394     devSigTimerCompare();
00395   #else
00396     /* It is the responsibility of the portIdle implementation to activate the timer
00397      * interrupts, since there are no references with regard to timer activation/
00398      * deactivation inside the femto OS core. You may assume you arrive here with
00399      * timer interrupts switched off. */
00400     devTIMSK = preBitSet1(devTIMSK,devOCIE);
00401     /* the avr tiny has and idle state that we will utilize, this is the sleep idle mode,
00402      * enable it */
00403     devSMCR = preBitClr3(preBitSet1(devSMCR,devSE),devSM2,devSM1,devSM0);
00404     /* and start sleeping. An (timer) interrupt will wake the device */
00405     asm volatile ("sleep" :: );
00406     /* If we are woken by some other interrupt we return here after the interrupt is
00407      * done. However, we may not return, therefore we will just wait for the next
00408      * timer interrupt. */
00409     while (true);
00410   #endif
00411 }
00412 
00413 #ifndef portInitContext
00414 /* Only include the code below if portInitContext is not defined, i.e. if we do not reroute a call to
00415  * portInitContext to privInitContext. The implementation below is identical to the one in the core.c */
00416 Taddress portInitContext(Taddress pTaskStart, Taddress pStackTop, Tuint08 uiRegisterCount, Tuint08 uiInterruptStart)
00417 { /* In case you cannot make use of the privInitContext defined inside the Femto OS you can define your
00418    * own. This method does not contain any assembler, but the order in which status register and regular registers
00419    * are save is tightly coupled to the organization of portSaveContext and portRestorContext.
00420    * Note that the code below is identical to the code inside Femto OS and is not used in reality. See
00421    * port.h how to activate this (or your substitute) code. */
00422   Tuint16 uiStartAddress = (Tuint16) pTaskStart;
00423   /* At the bottom of the artificial stack the start address of each task is defined. This is a pointer
00424    * to your Loop code. */
00425   *(pStackTop--) = (Tuint08) uiStartAddress;
00426   *(pStackTop--) = (Tuint08) (uiStartAddress >> 8);
00427   /* If we have a program counter of more than 16 bit, call instructions push three bytes
00428    * into the stack. We must take that into account. Unfortunately, i believe, gcc is not
00429    * able to handle pointer larger as 64K words in the current setting. Thus this will
00430    * effectively be zero, thus although you need something like
00431    *   *(pStackTop--) = (Tuint08) (pTaskStart >> 16);
00432    * we will use: */
00433   #if (defThreeByteAddress == cfgTrue)
00434     *(pStackTop--) = 0;
00435   #endif
00436   /* DISCUSSION
00437    * You can if you wish fill the register space with other bytes. This is the place to do so,
00438    * otherwise these have the value of the defStackInitByte, which is usually set to zero. */
00439   #if (0)
00440     /* Clean the stack actively in case that we are reinitializing, or want to fill it with something else as 0.
00441      * Note that this also fill r1 since the option cfgSysClearUnusedR1 operates before the registers are restored. */
00442     while (uiRegisterCount--) { *(pStackTop--) = defYourRegisterInitByte; }
00443   #else
00444     /* We rely upon register cleaning done by the Femto OS, or the precleaning done by privTaskInit(). */
00445     pStackTop -= uiRegisterCount;
00446   #endif
00447   /* The way the status register is setup depends on the state of the interrupts. These can be specified per task
00448    * or (easier, and shorter) in general. Note that the optimization is not needed in a strict sense, the variable
00449    * uiInterruptStart constrains the interrupt start information, even if this is constant for all tasks. But, of course,
00450    * the lower part generates shorter code. */
00451   #if (defInterruptStartConstant == cfgFalse)
00452     /* If we specify the CPU status register per task, we need to prepare them per task. uiInterruptStart contains
00453      * the information about which interrupts must be activated. The other bits of the status register cannot be
00454      * set individually (there is no need in general) */
00455     Tuint08 uiInitCPUStatusRegister = defInitCPUStatusRegister | (0 << portInitModeInterruptLoc);
00456     /* Test if global interrupts must be activated at the start, if so set the specified bit. */
00457     #if (cfgIntGlobalOnly ==  cfgTrue)
00458       /* In case we have a mapping from tick interrupts on global interrupts, we require both interrupts
00459        * to be activated before activating the global interrupt. */
00460       if ((uiInterruptStart & ((cfgGlobSet | cfgTickSet) & defInitialInterruptGetMask)) == ((cfgGlobSet | cfgTickSet) & defInitialInterruptGetMask)) { uiInitCPUStatusRegister |= (1 << portInitGlobalInterruptLoc); }
00461     #else
00462       /* Otherwise we just test the global interrupt setting. */
00463       if ((uiInterruptStart & (cfgGlobSet & defInitialInterruptGetMask)) != defInitialInterruptAbsent) { uiInitCPUStatusRegister |= (1 << portInitGlobalInterruptLoc); }
00464     #endif
00465     /* Test if tick interrupts must be activated at the start, if so set the specified bit. */
00466     #if (cfgIntTickTrack == cfgTrue)
00467       if ((uiInterruptStart & (cfgTickSet & defInitialInterruptGetMask)) != defInitialInterruptAbsent) { uiInitCPUStatusRegister |= (1 << portInitTickInterruptLoc); }
00468     #endif
00469     /* The status register is put at the end of the stack. (See portSaveContext for the reason why) */
00470     *(pStackTop--) = uiInitCPUStatusRegister;
00471   #else
00472     /* Set up the status register with the initial interrupt states: global set and tick set */
00473     #if (((defInterruptStartFixed) & cfgGlobSet) == cfgGlobSet) && (((defInterruptStartFixed) & cfgTickSet) == cfgTickSet)
00474       *(pStackTop--) = defInitCPUStatusRegister | (0 << portInitModeInterruptLoc) | (1 << portInitGlobalInterruptLoc) | (1 << portInitTickInterruptLoc);
00475     /* Set up the status register with the initial interrupt states: global set and tick clear */
00476     #elif (((defInterruptStartFixed) & cfgGlobSet) == cfgGlobSet) && (((defInterruptStartFixed) & cfgTickClear) == cfgTickClear)
00477       #if (cfgIntGlobalOnly == cfgTrue)
00478         /* In case we have a mapping from tick interrupts on global interrupts, global interrupts cannot be activated if tick interrupts are not activated */
00479         *(pStackTop--) = defInitCPUStatusRegister | (0 << portInitModeInterruptLoc) | (0 << portInitGlobalInterruptLoc) | (0 << portInitTickInterruptLoc);
00480       #else
00481         /* Default situation. */
00482         *(pStackTop--) = defInitCPUStatusRegister | (0 << portInitModeInterruptLoc) | (1 << portInitGlobalInterruptLoc) | (0 << portInitTickInterruptLoc);
00483       #endif
00484     /* Set up the status register with the initial interrupt states: global clear and tick set */
00485     #elif (((defInterruptStartFixed) & cfgGlobClear) == cfgGlobClear) && (((defInterruptStartFixed) & cfgTickSet) == cfgTickSet)
00486       *(pStackTop--) = defInitCPUStatusRegister | (0 << portInitModeInterruptLoc) | (0 << portInitGlobalInterruptLoc) | (1 << portInitTickInterruptLoc);
00487     /* Set up the status register with the initial interrupt states: global clear and tick clear */
00488     #elif (((defInterruptStartFixed) & cfgGlobClear) == cfgGlobClear) && (((defInterruptStartFixed) & cfgTickClear) == cfgTickClear)
00489       *(pStackTop--) = defInitCPUStatusRegister | (0 << portInitModeInterruptLoc) | (0 << portInitGlobalInterruptLoc) | (0 << portInitTickInterruptLoc);
00490     #elif (defNumberOfTasks == 0)
00491       /* without tasks there is nothing to set. */
00492     #else
00493       /* well, we never come here. */
00494       #error "Parameter 'defInterruptStartFixed' is misspeld or incorrect (You should not arrive here)."
00495     #endif
00496   #endif
00497   /* Done, let the caller know where the stack ended. */
00498   return pStackTop; }
00499 #endif
00500 
00501 
00502 void portSetupTimerInterrupt(void)
00503 { /* We use a 8 bit timer to generate the tick. Note that it is not really possible to 'calculate' the
00504    * maximum value of the timer for general values of the tick frequency, this depends heavily on the
00505    * possibilities of the hardware. Therefore we work with a limited set of allowed values of the
00506    * prescaler, present in most devices.
00507    * Reset the prescaler, Set the largest  divider */
00508    /* In case of equidistant ticks we make use of the automatic cleaning of the subtick counter
00509     * If your hardware does not have such a mode, it must be coded by hand in the tick interrupt. */
00510    #if (cfgUseEquidistantTicks == cfgTrue)
00511      /* Use the 8 bit CTC mode */
00512      if (preEqualMacros(devTCCRB,devTCCRA))
00513      { devTCCRA = preBitSet1(0x00,devWGM) | defTimerPrescaleBits; }
00514      else
00515      { devTCCRA = preBitSet1(0x00,devWGM);
00516        devTCCRB = defTimerPrescaleBits; }
00517      /* Set the time at which the tick interrupt should take place. */
00518      devOCR = cfgSysSubTicksPerFullTick;
00519    #else
00520      /* Use a normal counting mode in case of variable time slices, clear is done through the call
00521       * portReadAndResetTimer */
00522      if (preEqualMacros(devTCCRB,devTCCRA))
00523      { devTCCRA = preBitClr1(0x00,devWGM) | defTimerPrescaleBits; }
00524      else
00525      { devTCCRA = preBitClr1(0x00,devWGM);
00526        devTCCRB = defTimerPrescaleBits; }
00527   #endif
00528   /* To be able to check for overflowing timers we must enable the overflow interrupt. */
00529   #if ((cfgUseEquidistantTicks == cfgFalse) && (cfgCheckTiming == cfgTrue))
00530     /* We  must make sure a overflow interrupt is not immediately generated, so reset the timer. */
00531     devTCNT = 0x00;
00532     /* Set the TOIE0  bit (enables the overflow interrupt). */
00533     devTIMSK = preBitSet1(devTIMSK,devTOIE);
00534   #endif
00535  /* Do not enable the tick interrupt itself. The OS is started with tick interrupts disabled. */ }
00536 
00537 
00538 #if ((cfgUseEquidistantTicks == cfgTrue) && ((cfgCheckTiming == cfgTrue) || (cfgUseLoadMonitor == cfgTrue))) || ((cfgUseLoadMonitor == cfgTrue) && (cfgIntUserDefined == cfgTrue))
00539 
00540 Tuint08 portReadTimer(void)
00541 {  /* The intent of this method is to read the current value of the subtick timer. */
00542   #if cfgSysDebug == cfgTrue
00543     /* If you use the simulator of Atmel, it cannot simulate the timer at this point
00544      * so we manually simulate it, let's just return some fictitious value. */
00545     Tuint08 uiResult = cfgSysSubTicksPerFullTick / 8;
00546   #else
00547     /* We must have deactivated timer interrupts to get an reliable measurement. However, we do not
00548      * need to do that here, since the portReadTimer is only called from the OS (timer interrupts
00549      * are switched off, or from an isr (global interrupts switched off). */
00550     Tuint08 uiResult = devTCNT;
00551     /* if there is an unhandled interrupt, the read value must be increased with cfgSysSubTicksPerFullTick
00552      * since there is no way we could otherwise obtain this information. The only problem is that the
00553      * interrupt flag could become set in between the instruction above and the one below. That would lead to
00554      * a way to large value of the result. Now, since there is no atomic way to gain the information about the
00555      * subtick timer and the interrupt flag, we must check if adding cfgSysSubTicksPerFullTick makes sense. */
00556     if ( preBitIsSet(devTIFR,devOCF)  && (uiResult < cfgSysSubTicksPerFullTick/2) ) uiResult+=cfgSysSubTicksPerFullTick;
00557   #endif
00558   return uiResult; }
00559 #endif
00560 
00561 
00562 #if (cfgUseEquidistantTicks == cfgTrue) && (cfgIntManualTicks == cfgTrue)
00563 
00564 Tbool portCheckTimer(void)
00565 { /* Check if the timer interrupt is due to fire. If so return true and release the trigger, otherwise
00566    * return false. This is used in situations where all tasks are cooperative and the timer never gets
00567    * a chance to fire. */
00568   Tbool bResult = false;
00569   /* Test the value of the timer interrupt flag. If set, reset it by writing a one to its position
00570    * and utilize the none zero result as true value. Note that we do NOT change the value of the timer,
00571    * we merely reset the timer flag, which is replaced by a manual tick inside the core code. */
00572   if (preBitIsSet(devTIFR,devOCF))  { devTIFR = bResult = preBitSet1(0x00,devOCF); }
00573   /* Done, return the result. */
00574   return bResult; }
00575 
00576 #endif
00577 
00578 
00579 #if (cfgUseEquidistantTicks == cfgFalse)
00580 
00581 Tuint08 portReadAndResetTimer(Tuint08 uiSubTickInterrupt)
00582 { /* The intent of this method is to read the current value of the subtick timer and
00583    * reset it at the same time. Unfortunately this cannot be done in one instruction,
00584    * thus we make a systematic timing error here. If needed this timer can be implemented
00585    * as a 16 bit timer which would enhance the accuracy of the timer. In practice we never
00586    * measure real time through this mechanism so approximate values are sufficient here.
00587    * This method is called with tick interrupts disabled. */
00588   #if cfgSysDebug == cfgTrue
00589     /* If you use the simulator of Atmel, it cannot simulate the timer at this point
00590      * so we manually simulate it, let's just return some fictitious value. */
00591     Tuint08 uiResult = cfgSysSubTicksPerFullTick / 2;
00592   #else
00593     /* If we have OS protection, global interrupts are disabled, but otherwise ... */
00594     #if (cfgIntOsProtected == cfgFalse)
00595       /* ... if an other interrupt comes in between these two instructions, that will disturb the
00596        * timing even more. This can be prevented by conditionally disabling the interrupts
00597        * around these instructions. */
00598       privDisableGlobalInterrupts();
00599     #endif
00600       /* Read the value of the current sub tick timer (timer 0 on this device) */
00601       Tuint08 uiResult = devTCNT;
00602       /* reset the timer. This timer could be increased during the time needed to execute
00603        * the the former instruction. This results in a systematic loss of accuracy, for
00604        * which there is no real (short) cure. It is absolutely essential that no interrupts occur
00605        * between there two instructions.*/
00606       devTCNT = 0x00;
00607       /* Set the new value of the alarm, this determines the time the next task has. */
00608       devOCR = uiSubTickInterrupt;
00609       /* We clear the interrupt compare flag, to make sure the new task has the full
00610        * slice, if we would skip this, there could be the situation that that a previous
00611        * unhandled tick cases an unintended interrupt. */
00612       devTIFR = preBitSet1(0x00,devOCF);
00613     #if (cfgIntOsProtected == cfgFalse)
00614       /* From this point on interrupts are allowed again. */
00615       privEnableGlobalInterrupts();
00616     #endif
00617   #endif
00618   /* Done, let he caller know the previous time spend. */
00619   return uiResult; }
00620 
00621 #endif
00622 
00623 
00624 #if defined(devSigWatchdogTimeout) && (defSysGCCstartup != cfgReplace) && (cfgUseLowPowerSleep == cfgTrue) && (cfgUseLowPowerOnDelay == cfgTrue)
00625 
00626 void devSigWatchdogTimeout(void)
00627 { /* We must signal the receiver we come from the watchdog interrupt. Unfortunately the device flag
00628    * is cleared because of this handeling. We have to implement some handling however, otherwise
00629    * the interrupt cannot wake up the device. */
00630 #if (cfgSysSqueezeState == cfgFalse)
00631 
00632   asm volatile (
00633    "sbi  %[_ASR_],%[_ARB_] \n\t"  /* Set the WD bit to indicate a watchdog timeout occurred.                */
00634    "ret                    \n\t"  /* Get back to the sleepmethod, there is no need to set the interrupts.   */
00635    "" ::
00636    [_ARB_]  "i" (devAuxSysRegBit),
00637    [_ASR_]  "i" (_SFR_IO_ADDR(devAuxSysReg))
00638    );
00639 
00640 #else
00641   /* Here we use the T bit to transmit we hit the watchdog. The H bit is less suitable since its state
00642    * may be destroyed (set) in the handling of alternative interrupts. It is easier to restrict the
00643    * use of the T-bit. */
00644   asm volatile (
00645    "set  \n\t" /* Set the T bit to indicate a watchdog timeout occurred.                 */
00646    "ret  \n\t" /* Get back to the sleep method, there is no need to set the interrupts.   */
00647    "" :: );
00648 #endif
00649 }
00650 
00651 #endif
00652 
00653 
00654 #if (defSysGCCstartup != cfgReplace) && (cfgUseEquidistantTicks == cfgFalse) && (cfgCheckTiming == cfgTrue)
00655 
00656 void devSigTimerOverflow(void)
00657 { /* Let the OS know the subtick timer overflowed. This only makes sense when cfgUseEquidistantTicks == cfgFalse
00658   * since in the other case the timer cannot overflow. */
00659   portJump(privSubtickOverflow); }
00660 
00661 #endif
00662 
00663 
00664 #if (defSysGCCstartup != cfgReplace)
00665 
00666 void devSigTimerCompare(void)
00667 { /* If your hardware does not support automatic reset of the sub tick counter, you must do so here,
00668    * but only if (cfgUseEquidistantTicks == cfgTrue). */
00669   /* Let the OS know the sub tick timer reached its interrupt level and it is
00670    * time to switch the task. */
00671   portJump(privTickYield); }
00672 
00673 #endif
00674 
00675 /* Define the most optimal handling for the TIMSK register, depending on its location.  */
00676 #if (defTIMSKinIO == cfgTrue)
00677   #define LoadTIMSK(rx)   "in   " #rx ", %[_TIMSKio_]    \n\t"
00678   #define StoreTIMSK(rx)  "out  %[_TIMSKio_], " #rx "    \n\t"
00679 #else
00680   #define LoadTIMSK(rx)   "lds   " #rx ", %[_TIMSKmem_]  \n\t"
00681   #define StoreTIMSK(rx)  "sts  %[_TIMSKmem_], " #rx "   \n\t"
00682 #endif
00683 
00684 
00685 #if (cfgUseFileSystem == cfgTrue) && (cfgUseFileSystemEconomyMode == cfgFalse)
00686 /* If you arrive here the OS did already check writing is allowed via portFSWriteBusy, there
00687  * is not need to check it again. Make sure you erase the bytes if needed Global interrupts may
00688  * be activated, so save the state.*/
00689 void portFSWriteByte(Taddress pAddress, Tbyte bValue)
00690 { /* We perfrom the actual writing in assembly code for optimization reasons. */
00691   asm volatile (
00692    "com %[_VAL_]             \n\t" /* The byte that we write is actually the inverse,                                                  */
00693   #if (devEEPROMsize > 0x0100U)
00694    "out %[_EEARH_],%B[_ADR_] \n\t" /* Fill the registers EEARH and EEARL with the location of the byte to be written. Since we are     */
00695   #endif
00696    "out %[_EEARL_],%A[_ADR_] \n\t" /* the only task that may write (and thus use these registers), we don't need to disable irq's yet. */
00697    "clr r26                  \n\t" /* Make one register 0 (we could have used r1, but i am not absolutely certain it is zero always.   */
00698    "out %[_EECR_], r26       \n\t" /* Set the erase/Write mode (0<<EEPM1)|(0<<EEPM0), clear interrupt mode,                            */
00699    "out %[_EEDR_], %[_VAL_]  \n\t" /* Put the data at the location for writing.                                                        */
00700    "in  r26, __SREG__        \n\t" /* At this point we must disable interrupts, since the two instructions that follow, must be        */
00701    "cli                      \n\t" /* executed within 4 clockcyles of each other.                                                      */
00702    "sbi %[_EECR_],%[_EEMPE_] \n\t" /* Enable writing, and (in next instruction ) commence writing. Note the writing is still busy when */
00703    "sbi %[_EECR_],%[_EEPE_]  \n\t" /* this function completes. That is OK, we call portFSWriteReady() before next writing.             */
00704    "out __SREG__, r26        \n\t" /* Restore the interrupt state and we are done.                                                     */
00705    "" ::
00706    [_ADR_]   "r" (pAddress),
00707    [_VAL_]   "r" (bValue),
00708    [_EECR_]  "i" (_SFR_IO_ADDR(devEECR)),
00709    [_EEDR_]  "i" (_SFR_IO_ADDR(devEEDR)),
00710    [_EEARL_] "i" (_SFR_IO_ADDR(devEEARL)),
00711   #if (devEEPROMsize > 0x0100U)
00712    [_EEARH_] "i" (_SFR_IO_ADDR(devEEARH)),
00713   #endif
00714    [_EERE_]  "i" (devEERE),
00715    [_EEPE_]  "i" (devEEPE),
00716    [_EEMPE_] "i" (devEEMPE):
00717    "r26" ); }
00718 
00719 #endif
00720 
00721 /* DISCUSSION
00722  *
00723  * Because we make use of -mint8 we cannot make use of the instruction cbr Rd,K. This
00724  * is because gcc emits signed integers as operands and thus something like
00725  *   cbr r24, 0xF0
00726  * generates
00727  *   cbr r24, -128
00728  * this can then not be translated into opcodes, for internally the operation
00729  * (0xFF - -128) cannot be performed. Imho this is a bug in the compiler.
00730  * The workaround is:
00731  *   andi r24, ~0xFO
00732  */
00733 
00734 #if (cfgUseFileSystem == cfgTrue) && (cfgUseFileSystemEconomyMode == cfgTrue)
00735 /* First make sure the device has features for split-byte programming, if not,
00736  * you should not call this (test is done in check.h)
00737  * If you arrive here the OS did already check writing is allowed via portFSWriteBusy, there
00738  * is not need to check it again. Make sure you erase the bytes if needed Global interrupts may
00739  * be activated, so save the state. This method implements a more careful way of writing bytes,
00740  * making use of the split erase / write mode of the device. In fact, we only need to erase if
00741  * there are some bits to be set and only need to write if there are some bits to be cleared
00742  * in the byte to be written. We read first to inspect the situation. Off course this introduces
00743  * overhead, but extends the lifetime of the eeprom. Also, on average, the call completes more
00744  * quickly compared to the standard implementation. */
00745 void portFSWriteByte(Taddress pAddress, Tbyte bValue)
00746 { asm volatile (
00747   #if (devEEPROMsize > 0x0100U)
00748    "out %[_EEARH_],%B[_ADR_] \n\t" /* Fill the registers EEARH and EEARL with the location of the byte to be written. Since we are    */
00749   #endif
00750    "out %[_EEARL_],%A[_ADR_] \n\t" /* the only task that may write (and thus use these registers), we don't need to disable irqs yet. */
00751    "sbi %[_EECR_],%[_EERE_]  \n\t" /* Start reading, we need the information of the byte present to sort out what to do.              */
00752    "in  r24, %[_EEDR_]       \n\t" /* Fetch the data.                                                                                 */
00753    "ldi r23, %[_EECOMb_]     \n\t" /* EEPM1,EEPM0, EEMPE set 0x34                                                                     */
00754    "mov r25,24               \n\t" /* Copy the data (data is retained for later use)                                                  */
00755    "or  r25,%[_VAL_]         \n\t" /* r25=d|m (determines which positions must be set                                                 */
00756    "cpi r25,0xFF             \n\t" /* d|m ?= 0xFF If that results equals 'all set' we don't need to erase                             */
00757    "breq 2f                  \n\t" /* Skip to the next test                                                                           */
00758    "andi r23, %[_nEEPM1b_]   \n\t" /* Activate the erase bit in the action register r23 (bit _EEPM1_)                                 */
00759    "ldi r24,0xFF             \n\t" /* d=0xFF  replace the data byte by 0xFF                                                           */
00760    "2:                       \n\t" /* Continue operations here is there is nothing to erase.                                          */
00761    "and r24,%[_VAL_]         \n\t" /* r24=d&m (determines which positions remain cleared.                                             */
00762    "cpi r24,0x00             \n\t" /* d&m ?= 0 If all positions remain cleared, there is noting to write                              */
00763    "breq 3f                  \n\t" /* Skip to the next action                                                                         */
00764    "andi r23, %[_nEEPM0b_]   \n\t" /* Activate the write bit in the action register r23 (bit _EEPM0_)                                 */
00765    "3:                       \n\t" /* Continue operations here is there is nothing to write.                                          */
00766    "cpi r23, %[_EECOMb_]     \n\t" /* Now, check if there are any actions to take.                                                    */
00767    "breq 4f                  \n\t" /* If not, there is nothing to do and we are done.                                                 */
00768    "com %[_VAL_]             \n\t" /* The byte that we write is actually the inverse, this is to save write operations.               */
00769    "out %[_EEDR_],%[_VAL_]   \n\t" /* Put the byte in the correct location for writing.                                               */
00770    "in   r24, __SREG__       \n\t" /* Writing (and/or erasing) must be prepared whitout the risk of an interrupt, so copy the status  */
00771    "cli                      \n\t" /* register, and clear the interrupts.                                                             */
00772    "out %[_EECR_],r23        \n\t" /* Enable writing (and set write/erase mode according to action register at the same time!), and   */
00773    "sbi %[_EECR_],%[_EEPE_]  \n\t" /* commence writing. Note the writing is still busy when this function completes. That is ok, we   */
00774    "out __SREG__, r24        \n\t" /* call portFSWriteReady() before next writing. Restore the interrupt state and we are done.       */
00775    "4:                       \n\t"
00776    "" ::
00777    [_ADR_]     "r" (pAddress),
00778    [_VAL_]     "r" (bValue),
00779    [_EECR_]    "i" (_SFR_IO_ADDR(devEECR)),
00780    [_EEDR_]    "i" (_SFR_IO_ADDR(devEEDR)),
00781    [_EEARL_]   "i" (_SFR_IO_ADDR(devEEARL)),
00782   #if (devEEPROMsize > 0x0100U)
00783    [_EEARH_]   "i" (_SFR_IO_ADDR(devEEARH)),
00784   #endif
00785    [_EERE_]    "i" (devEERE),
00786    [_EEPE_]    "i" (devEEPE),
00787    [_EEMPE_]   "i" (devEEMPE),
00788    [_EEPM0_]   "i" (devEEPM0),
00789    [_EEPM1_]   "i" (devEEPM1),
00790    [_nEEPM0b_] "i" (preBitClr1(0xFF,devEEPM0)),
00791    [_nEEPM1b_] "i" (preBitClr1(0xFF,devEEPM1)),
00792    [_EECOMb_]  "i" (preBitSet3(0x00,devEEPM1,devEEPM0,devEEMPE)):
00793    "r23");
00794  }
00795 
00796 #endif
00797 
00798 #if (cfgUseFileSystem == cfgTrue)
00799 /* Reading is allowed with interrupts on. */
00800 Tbyte portFSReadByte(Taddress pAddress)
00801 { Tuint08 result;
00802    /* We perform the actual reading in assembly code for optimization reasons. */
00803   asm volatile (
00804    "in  r26, __SREG__        \n\t" /* Copy the status register as quickly as possible and disable interrupts, even if it was cleared  */
00805    "cli                      \n\t" /* already. Although the read operation in itself is allowed to be interrupted, we cannot allow    */
00806   #if (devEEPROMsize > 0x0100U)
00807    "out %[_EEARH_],%B[_ADR_] \n\t" /* the registers EEARH and EEARL to be destroyed by an other task. Load the EEARH and EEARL        */
00808   #endif
00809    "out %[_EEARL_],%A[_ADR_] \n\t" /* registers.                                                                                      */
00810    "sbi %[_EECR_],%[_EERE_]  \n\t" /* Start reading                                                                                   */
00811    "in  %A[_RES_],%[_EEDR_]  \n\t" /* Fetch the data read.                                                                            */
00812    "out __SREG__, r26        \n\t" /* Done.                                                                                           */
00813    "" :
00814    [_RES_]   "=r" (result):
00815    [_ADR_]   "0" (pAddress),
00816    [_EECR_]  "i" (_SFR_IO_ADDR(devEECR)),
00817    [_EEDR_]  "i" (_SFR_IO_ADDR(devEEDR)),
00818    [_EEARL_] "i" (_SFR_IO_ADDR(devEEARL)),
00819   #if (devEEPROMsize > 0x0100U)
00820    [_EEARH_] "i" (_SFR_IO_ADDR(devEEARH)),
00821   #endif
00822    [_EERE_]  "i" (devEERE),
00823    [_EEPE_]  "i" (devEEPE),
00824    [_EEMPE_] "i" (devEEMPE),
00825    [_EEPM0_] "i" (devEEPM0),
00826    [_EEPM1_] "i" (devEEPM1):
00827    "r26" );
00828   /* Note we invert the result. All bytes are stored inverted, so that a completely erased eerprom
00829    * appears to be filled with zero's */
00830   return ~result; }
00831 
00832 #endif
00833 
00834 
00835 /* DISCUSSION
00836  * The port(Enter/Exit)(Global/Tick)Interrupts methods must temporarily store
00837  * the value of the interrupt state and restore it when needed. These methods
00838  * are only called from within the Femto OS and are never nested, and you should not
00839  * call them yourself. (other functions are available). Since we did not want to make
00840  * inserts (although you can still do so, by turning them into defines)
00841  * because that takes a lot of extra bytes (a call is shorter) we cannot store
00842  * the status on the stack. Thus we decided to use, for example a general purpose
00843  * I/O register (devAuxSysReg) of the AVR tiny as temporary variable. This is used in
00844  * portSave- and portRestore Context also, but since we know we will never call a context
00845  * switch from within one of these Enter/Exit constructions, there is no risk
00846  * of double use. (Remember, you should not use these functions, the results
00847  * can be bizarre!)
00848  * Furthermore we make use of one bit of devAuxSysReg to catch the state of the current
00849  * global interrupt when a context switch occurs. Therefore, when running a task that
00850  * bit must always be zero; it is set if global interrupts are set on context switch.
00851  * Note that the functions portEnterGlobalInterrupts/portExitGlobalInterrupts
00852  * cannot rely on bit 7 being zero since these functions are used in isr's also.
00853  * This has been corrected by clearing this bit in the PortSaveContext.
00854  * From this it follows that it is forbidden to activate global or tick interrupts
00855  * in their respective critical sections by hand. It is not a very logical thing
00856  * to do either.
00857  * An other point of attention is the interrupt nesting due to external interrupts.
00858  * We do not allow interrupt nesting in principle, so you may not activate interrupts
00859  * inside an isr. If we have not protected the OS from outside interrupts, you may
00860  * not call genXXX methods, and if we do EnterSysCritical translates to global
00861  * interrupt management. Thus we can use for both portEnterGlobalInterrupts/portExit-
00862  * GlobalInterrupts and portEnterTickInterrupts/portExitTickInterrupts the same
00863  * storage room for the interrupt state since they can never be nested.
00864  * Remember for user critical nesting there are other facilities. The former are
00865  * solely for the OS and are meant to be as brief as possible.
00866  */
00867 
00868 #if (defNonSwitchingCallPresent == cfgTrue)
00869 
00870 #if (cfgSysSqueezeState == cfgFalse)
00871 
00872 void portEnterGlobalInterrupts(void)
00873 { /* We make use of the fact that devAuxSysRegBit must equal zero upon entry. */
00874   asm volatile (
00875    "brid 41f               \n\t"  /* We rely upon devAuxSysRegBit being zero. Thus we test if global interrupts are activated.   */
00876    "cli                    \n\t"  /* If not we skip, since there is nothing to do. If so, directly clear them, and set the bit   */
00877    "sbi %[_ASR_],%[_ARB_]  \n\t"  /* in devAuxSysRegBit to one, indicating the interrupts where activated. If we skip, the       */
00878    "41:                    \n\t"  /* value in devAuxSysRegBit is already correct.                                                */
00879    "ret     " ::                  /* Return to caller.                                                                           */
00880    [_ARB_]  "i" (devAuxSysRegBit),
00881    [_ASR_]  "i" (_SFR_IO_ADDR(devAuxSysReg))); }
00882 
00883 #else
00884 
00885 void portEnterGlobalInterrupts(void)
00886 { /* We keep the state of the interrupt in the Tbit. This is perfectly save since we know code in between
00887    * portEnterGlobalInterrupts and portExitGlobalInterrupts is Femto OS code only, which is verified to
00888    * use no T bit. */
00889   asm volatile (
00890    "clt                    \n\t"  /* We cannot rely upon T bit being zero, so clean that first. We do not have to preserve T     */
00891    "brid 41f               \n\t"  /* since we came here manually. Now test  if global interrupts are activated.                  */
00892    "cli                    \n\t"  /* If not we skip, since there is nothing to do. If so, directly clear them, and set the T bit */
00893    "set                    \n\t"  /* to one, indicating the interrupts where activated. If we skip, the T bit remains zero       */
00894    "41:                    \n\t"  /* which is correct.                                                                           */
00895    "ret     " ::
00896    [_Tb_]   "i" (preBitSet1(0x00,SREG_T)) ); }
00897 
00898 #endif
00899 
00900 #endif
00901 
00902 
00903 #if (defNonSwitchingCallPresent == cfgTrue)
00904 
00905 #if (cfgSysSqueezeState == cfgFalse)
00906 
00907 void portExitGlobalInterrupts(void)
00908 { asm volatile (
00909    "sbis %[_ASR_],%[_ARB_] \n\t" /* If devAuxSysRegBit is zero global interrupts where disabled on enter, nothing to do            */
00910    "ret                    \n\t" /* So we can just return                                                                          */
00911    "cbi  %[_ASR_],%[_ARB_] \n\t" /* Otherwise, devAuxSysRegBit of must be zero before e.g. a portSaveContext occurs, so clear it   */
00912    "reti                   \n\t" /* And since it was set we must activate interrupts upon return                                   */
00913    "" ::
00914    [_ARB_]  "i" (devAuxSysRegBit) ,
00915    [_ASR_]  "i" (_SFR_IO_ADDR(devAuxSysReg))
00916    ); }
00917 
00918 #else
00919 
00920 void portExitGlobalInterrupts(void)
00921 { /* We keep the state of the interrupt in the Tbit. This is perfectly save since we know code in between
00922    * portEnterGlobalInterrupts and portExitGlobalInterrupts is Femto OS code only, which is verified to
00923    * use no T bit. */
00924   asm volatile (
00925    "brts 40f               \n\t" /* The previous state of the interrupt was stored in the T bit, test if it was set, if so return  */
00926    "ret                    \n\t" /* with a reti, otherwise no interrupt was set and return with a ret.                             */
00927    "40:                    \n\t" /*                                                                                                */
00928    "reti                   \n\t" /*                                                                                                */
00929    "" ::
00930    [_Tb_]       "i" (preBitSet1(0x00,SREG_T)) ); }
00931 
00932 #endif
00933 
00934 #endif
00935 
00936 
00937 /* DISCUSSION
00938  * We don not need the portEnterTickInterrupts when we only allow for global interrupts. Switched on
00939  * tick interrupts are then replaced by global interrupts. If not these calls are used by Femto OS
00940  * to protect the internals of the API methods. They are only used when cfgIntOsProtected == cfgFalse.
00941  * In that case interrupts from outside may interrupt these methods. Note that, because of this,
00942  * it is never possible that the Enter/Exit Tick Interrupts get nested, for when they are allowed,
00943  * user defined interrupts may not yield, but must return to the point of interrupt. Therefore we
00944  * do not need to save the the state of tick interrupt itself, we can simply switch it off and on,
00945  * if there is no tick interrupt tracking. In the latter case we save the previous state of the
00946  * tick interrupt on some save place, to restore it later on.
00947  * Of course, we must keep the other bits in the TIMSK, so when changing the bit, global interrupts
00948  * must be switched off.
00949  */
00950 
00951 
00952 #if (defNonSwitchingCallPresent == cfgTrue) && (cfgIntGlobalOnly == cfgFalse) && (cfgIntOsProtected == cfgFalse)
00953 
00954 void portEnterTickInterrupts(void)
00955 { /* Since these calls are not nested, we can simply switch off / switch on the tick interrupts. Only if
00956    * we make use of tick tracking we must store the previous value and restore it upon return. */
00957   asm volatile (
00958    "in   r25, __SREG__      \n\t" /* Copy the status register as quickly as possible and disable interrupts, even if it was cleared  */
00959    "cli                     \n\t" /* already. This is needed for a tick may intervene and alter other bits of the TIMSK register.    */
00960    LoadTIMSK(r24)                 /* Load the TIMSK register, holding the state of the tick interrupt on bit OCIE0A,                 */
00961   #if (cfgIntTickTrack == cfgTrue)      /* If we make use of tick tracking we must store the value of the tick interrupt somewhere   */
00962    #if (cfgSysSqueezeState == cfgTrue)  /* At squeezing, we want spare our registers, so we utilize the T bit for storage, as with   */
00963    "bst r24, %[_OCIE0A_]    \n\t" /* the global interrupts, the T bit is not used, neither is it combined with the global enter      */
00964    #else                          /* Thus, copy the value of the tick interrupt bit into the T bit. In case we do not want to use    */
00965    "sbrc r24, %[_OCIE0A_]   \n\t" /* the status register at all, we use our devAuxSysRegBit to store the value. This is always       */
00966    "sbi %[_ASR_],%[_ARB_]   \n\t" /* cleared upon entry, so we only need to set it when the tick interrupt is set.                   */
00967    #endif
00968   #endif
00969    "andi r24, %[_nOCIE0Ab_] \n\t" /* Reset the timer0 interrupt enable bit                                                           */
00970    StoreTIMSK(r24)                /* Rewrite the TIMSK register, so interrupts are disabled after this instruction                   */
00971    "out  __SREG__, r25      \n\t" /* Restore the state of the global interrupts.                                                     */
00972    "ret                     \n\t" /* Done.                                                                                           */
00973    "" ::
00974    [_ARB_]       "i" (devAuxSysRegBit),
00975    [_ASR_]       "i" (_SFR_IO_ADDR(devAuxSysReg)),
00976    [_TIMSKio_]   "i" (_SFR_IO_ADDR(devTIMSK)),
00977    [_TIMSKmem_]  "i" (_SFR_MEM_ADDR(devTIMSK)),
00978    [_OCIE0A_]    "i" (devOCIE),
00979    [_nOCIE0Ab_]  "i" (preBitClr1(0xFF,devOCIE)):
00980    "r24","r25" ); }
00981 
00982 #endif
00983 
00984 
00985 #if (defNonSwitchingCallPresent == cfgTrue) && (cfgIntGlobalOnly == cfgFalse) && (cfgIntOsProtected == cfgFalse)
00986 
00987 void portExitTickInterrupts(void)
00988 { /* Since these calls are not nested, we can simply switch off / switch on the tick interrupts. At entrance the tick interrupts
00989    * are switched of, so if we make use of tick tracking, and the restore state is switched off interrupts, there is
00990    * nothing to do */
00991   asm volatile (
00992   #if (cfgIntTickTrack == cfgTrue)      /* If we make use of tick tracking we must restore the value of the tick interrupt         */
00993    #if (cfgSysSqueezeState == cfgTrue)  /* At squeezing, it was stored in the T bit, so we ask if the T bit is set, if not we are  */
00994    "brtc  1f               \n\t" /*  done since the value of the tick interrupt bit is already zero which it must stay.            */
00995    #else                         /* Otherwise, the last value was stored in devAuxSysRegBit, and we must test if that bit was set  */
00996    "sbis %[_ASR_],%[_ARB_] \n\t" /* If not, we are done too, and we do not even need to clean the devAuxSysRegBit bit because it   */
00997    "rjmp 1f                \n\t" /* is already zero. (Any interrupt that might become after this is not allowed to change that)    */
00998    "cbi  %[_ASR_],%[_ARB_] \n\t" /* Since we know now that devAuxSysRegBit is set, we must clear it for use after this routine     */
00999    #endif                        /* And there are, at this point, not interrupts possible that may rely on the fact of             */
01000   #endif                         /* devAuxSysRegBit being zero [no context switch, no enter global, no switching isr etc]          */
01001    "in   r25, __SREG__    \n\t" /* Copy the status register as quickly as possible and disable interrupts, even if it was cleared  */
01002    "cli                   \n\t" /* already. This is needed for an other interrupt may intervene and alter other bits of the TIMSK  */
01003    LoadTIMSK(r24)               /* Load the TIMSK register, holding the state of the tick interrupt on bit OCIE0A,                 */
01004    "sbr r24, %[_OCIE0Ab_] \n\t" /* Set the timer0 interrupt enable bit                                                             */
01005    StoreTIMSK(r24)              /* Rewrite the TIMSK register, so interrupts are enabled after this instruction                    */
01006    "out  __SREG__, r25    \n\t" /* Restore the state of the global interrupts.                                                     */
01007    "1:                    \n\t" /* We jump to this point if there is nothing to do.                                                */
01008    "ret                   \n\t" /* Done.                                                                                           */
01009    "" ::
01010    [_ARB_]       "i" (devAuxSysRegBit),
01011    [_ASR_]       "i" (_SFR_IO_ADDR(devAuxSysReg)),
01012    [_TIMSKio_]   "i" (_SFR_IO_ADDR(devTIMSK)),
01013    [_TIMSKmem_]  "i" (_SFR_MEM_ADDR(devTIMSK)),
01014    [_OCIE0A_]    "i" (devOCIE),
01015    [_OCIE0Ab_]   "i" (preBitSet1(0x00,devOCIE)):
01016    "r24","r25" ); }
01017 
01018 #endif
01019 
01020 
01021 #if ((cfgIntGlobalOnly == cfgFalse) && (cfgIntTickTrack == cfgTrue)) || (defCheckReportingError == cfgTrue)
01022 
01023 void portDisableTickInterrupts(void)
01024 { /* This simply disables the tick interrupts. Nothing more. The call is not used by the OS itself, (portEnterTickInterrupts /
01025    * portExitTickInterrupts is used to that end), with the exception of being called from the error handling. */
01026   asm volatile (
01027    "in   r25, __SREG__      \n\t" /* Copy the status register as quickly as possible and disable interrupts, even if it was cleared  */
01028    "cli                     \n\t" /* already. This is needed for a tick may intervene and alter other bits of the TIMSK register.    */
01029    LoadTIMSK(r24)                 /* Load the TIMSK register, holding the state of the tick interrupt on bit OCIE0A,                 */
01030    "andi r24, %[_nOCIE0Ab_] \n\t" /* Reset the timer0 interrupt enable bit                                                           */
01031    StoreTIMSK(r24)                /* Rewrite the TIMSK register, so interrupts are disabled after this instruction                   */
01032    "out  __SREG__, r25      \n\t" /* Restore the state of the global interrupts.                                                     */
01033    "ret                     \n\t" /* Done.                                                                                           */
01034    "" ::
01035    [_TIMSKio_]   "i" (_SFR_IO_ADDR(devTIMSK)),
01036    [_TIMSKmem_]  "i" (_SFR_MEM_ADDR(devTIMSK)),
01037    [_OCIE0A_]    "i" (devOCIE),
01038    [_nOCIE0Ab_]  "i" (preBitClr1(0xFF,devOCIE)):
01039    "r24","r25" ); }
01040 
01041 #endif
01042 
01043 
01044 #if (cfgIntGlobalOnly == cfgFalse) && (cfgIntTickTrack == cfgTrue)
01045 
01046 void portEnableTickInterrupts(void)
01047 { /* This simply enables the tick interrupts. Nothing more. The call is not used by the OS itself, (portEnterTickInterrupts /
01048    * portExitTickInterrupts is used to that end). */
01049   asm volatile (
01050    "in   r25, __SREG__    \n\t" /* Copy the status register as quickly as possible and disable interrupts, even if it was cleared  */
01051    "cli                   \n\t" /* already. This is needed for an other interrupt may intervene and alter other bits of the TIMSK  */
01052    LoadTIMSK(r24)               /* Load the TIMSK register, holding the state of the tick interrupt on bit OCIE0A,                 */
01053    "sbr r24, %[_OCIE0Ab_] \n\t" /* Set the timer0 interrupt enable bit                                                             */
01054    StoreTIMSK(r24)              /* Rewrite the TIMSK register, so interrupts are enabled after this instruction                    */
01055    "out  __SREG__, r25    \n\t" /* Restore the state of the global interrupts.                                                     */
01056    "ret                   \n\t" /* Done.                                                                                           */
01057    "" ::
01058    [_TIMSKio_]  "i" (_SFR_IO_ADDR(devTIMSK)),
01059    [_TIMSKmem_] "i" (_SFR_MEM_ADDR(devTIMSK)),
01060    [_OCIE0A_]   "i" (devOCIE),
01061    [_OCIE0Ab_]  "i" (preBitSet1(0x00,devOCIE)):
01062    "r24","r25" ); }
01063 
01064 #endif
01065 
01066 
01067 #if (cfgSysClearUnusedR1 == cfgTrue)
01068   /* Checking on r1 is special since gcc always assumes the register to be zero. */
01069   #define CheckRegisterR1 "cpse r1,r30 \n\t" /* Thus we compare not to r2 but to r31 which contains zero at the place this is inserted */
01070   #define ClearRegisterR1 "clr  r1     \n\t" /* If we make use of the gcc we are save by always clearing r1                            */
01071   #define FillRegisterR1  ""                 /* The register is not filled with r2 which contains some magic byte to check with.       */
01072 #else
01073   /* Not using gcc r1 is just like other registers */
01074   #define CheckRegisterR1 "cpse r1,r29 \n\t" /* r1 is now compared with the magic check byte just like the other registers             */
01075   #define ClearRegisterR1 ""                 /* r1 is not cleared.                                                                     */
01076   #define FillRegisterR1  "mov  r1,r2  \n\t" /* r1 is now filled with the magic check byte just like the other registers               */
01077 #endif
01078 
01079 
01080 /* The return value is placed in r24, the standard register used by gcc. */
01081 #if (cfgUseSynchronization != cfgSyncNon) && (defUseBoolReturns == cfgTrue)
01082   #define ReturnState(arg) \
01083    "lds  r16," #arg "           \n\t" /* Now load the return value in r16, which is still free for use               */\
01084    "sbrs r16,%[_RET1_]          \n\t" /* If the bit 1 is set, we don't copy the return value              ...        */\
01085    "mov  r24, r16               \n\t" /* load the result.                                                            */
01086   /* This contains the value that must be returned (false, non-false) */
01087   #define ReturnField           &xOS.pxSave.uiReturn
01088 #else
01089   #define ReturnState(arg)      ""
01090   #define ReturnField           0
01091 #endif
01092 
01093 
01094 /* If we protect the OS from interruptions, we allow for call to the operating system
01095  * from isr. We must have some mechanism to detect that we are calling from an isr.
01096  * Thus we replace the uiOSstatus by a value which indicates that we are in an
01097  * isr, but we must restore the original status as we leave the isr. Note that we
01098  * may replace since we may never call functions from within the OS which need the
01099  * other bits. Note, this code may not corrupt the status register. The uiOSstatus is
01100  * temporarily saved in an unused background variable, and (thus) we may never call this
01101  * when we want to execute an isr in OS space with an OS stack.
01102  */
01103 #if (cfgIntOsProtected == cfgTrue)
01104   /* Replace the uiOSstatus with the key that indicates we are in the isr context */
01105   #define SaveOsStatus(stat,save,key)  \
01106    "lds  r31," #stat "   \n\t" /* Load the uiOSstatus                                                                            */\
01107    "sts  " #save ", r31  \n\t" /* Save that value in r31 background variable.                                                    */\
01108    "ldi  r31," #key "    \n\t" /* Load the defContextStateIsr key                                                                */\
01109    "sts  " #stat ", r31  \n\t" /* Store that key in the uiOSstatus. Destruction of other bits is allowed.                        */
01110   /* Repair the uiOSstatus */
01111   #define RestoreOsStatus(stat,save)   \
01112    "lds  r31," #save "   \n\t" /* Recall the original value of the uiOSstatus                                                    */\
01113    "sts  " #stat ", r31  \n\t" /* Restore that Status                                                                            */
01114 #else
01115   #define SaveOsStatus(stat,save,key)   ""
01116   #define RestoreOsStatus(stat,save)    ""
01117 #endif
01118 
01119 
01120 #if (cfgIntUserDefined == cfgTrue) && (cfgIntOsProtected == cfgTrue) && (includeIsrEnter == cfgTrue) &&  (cfgIntSwitchUsesOSstack == cfgFalse)
01121 
01122 void portEnterISR(void)
01123 /* Enters the isr with the isrStack, thus performs a stack switch and an update of the uiOSstatus. The return address is
01124  * remembered so we will return to the code implementing the isr when the stack switch is over. Since we replace the
01125  * stack pointer, global interrupts must be switched off. (Note that defContextStateIsr must be 0xb11000000.)
01126  * Note that for up-growing stacks this code is quite different, and not implemented yet
01127  */
01128 { asm volatile (
01129    "pop  r24                 \n\t" /* Get the first byte of the return address, which is on top of the current stack.                */
01130    "sts  %[_ISR1_], r24      \n\t" /* Place it on the new isr stack in the correct position.                                         */
01131    "pop  r24                 \n\t" /* Get the second byte of the return address, which is now on top of the current stack.           */
01132    "sts  %[_ISR2_], r24      \n\t" /* Place it on the new isr stack in the correct position.                                         */
01133   #if (defThreeByteAddress == cfgTrue)
01134    "pop  r24                 \n\t" /* Get the third byte of the return address, which is now on top of the current stack.            */
01135    "sts  %[_ISR3_], r24      \n\t" /* Place it on the new isr stack in the correct position.                                         */
01136   #endif
01137    "lds  r24,%[_Status_]     \n\t" /* Load the uiOSstatus, now indicating we are running something else.                             */
01138    "ori  r24,%[_ConIsr_]     \n\t" /* Place the key bits in place (do not overwrite the other bits, we do not save the uiOSstatus!)  */
01139    "sts  %[_Status_], r24    \n\t" /* Replace the uiOSstatus register with bits adapted.                                             */
01140    "ldi  r24,lo8(%[_ISRst_]) \n\t" /* Now load the low byte of the new (isr) stack                                                   */
01141    "out  __SP_L__,r24        \n\t" /* Replace the stack pointer                                                                      */
01142   #if (defStackSpaceExceedsOneByte == cfgTrue)
01143    "ldi  r24,hi8(%[_ISRst_]) \n\t" /* Now load the high byte of the new (isr) stack                                                  */
01144    "out  __SP_H__,r24        \n\t" /* Replace the stack pointer                                                                      */
01145   #endif
01146    "ret                      \n\t" /* Done, return to the isr with a brand new stack.                                                */
01147    "" ::
01148    [_ISR1_]    "i" (&StackISR[ISRstackFirstByte]),
01149    [_ISR2_]    "i" (&StackISR[ISRstackSecondByte]),
01150    [_ISR3_]    "i" (&StackISR[ISRstackThirdByte]),
01151    [_ISRst_]   "i" (&StackISR[ISRstackStart]),
01152    [_ConIsr_]  "i" (defContextStateIsr),
01153    [_Status_]  "i" (&uiOsStatus) )
01154    ; }
01155 
01156 #endif
01157 
01158 
01159 #if (cfgIntUserDefined == cfgTrue) && (cfgIntOsProtected == cfgTrue) && (includeIsrEnter == cfgTrue) &&  (cfgIntSwitchUsesOSstack == cfgTrue)
01160 
01161 void portEnterISR(void)
01162 /* Enters the isr with the OsStack. Since this is performed after a context switch we are already in
01163  * Os Space. so no stack transplant needed. What remains is changing the OsStatus. (Note that defContextStateIsr
01164  * must be 0xb11000000.)
01165  */
01166 { asm volatile (
01167    "lds  r24,%[_Status_]     \n\t" /* Load the uiOSstatus, now indicating we are running something else.                             */
01168    "ori  r24,%[_ConIsr_]     \n\t" /* Place the key bits in place (do not overwrite the other bits, we do not save the uiOSstatus!)  */
01169    "sts  %[_Status_], r24    \n\t" /* Replace the uiOSstatus register with bits adapted.                                             */
01170    "ret                      \n\t" /* Done, return to the isr with a brand new stack.                                                */
01171    "" ::
01172    [_ConIsr_]  "i" (defContextStateIsr),
01173    [_Status_]  "i" (&uiOsStatus) )
01174    ; }
01175 
01176 #endif
01177 
01178 
01179 
01180 #if (defUseIsrStack == cfgTrue) && (includeIsrBegin == cfgTrue)
01181 
01182 void portBeginISR(void)
01183 /* Call this if you want to start an isr directly, thus without a context switch first. It may even interrupt
01184  * the OS. The stack must be switched but the registers and the status must not be effected. It is up to the
01185  * user to save these.  Of course, this routine may only be called with interrupts switched off. */
01186 { asm volatile (
01187    "sts  %[_ISRlst_], r31    \n\t" /* Save the current value of register r31 (Note, not in the background r31, this is not free!)    */
01188    "pop  r31                 \n\t" /* Get the first byte of the return address, which is on top of the current stack.                */
01189    "sts  %[_ISR1_], r31      \n\t" /* Place it on the new isr stack in the correct position.                                         */
01190    "pop  r31                 \n\t" /* Get the second byte of the return address, which is now on top of the current stack.           */
01191    "sts  %[_ISR2_], r31      \n\t" /* Place it on the new isr stack in the correct position.                                         */
01192   #if (defThreeByteAddress == cfgTrue)
01193    "pop  r31                 \n\t" /* Get the third byte of the return address, which is now on top of the current stack.            */
01194    "sts  %[_ISR3_], r31      \n\t" /* Place it on the new isr stack in the correct position.                                         */
01195   #endif
01196    "in   r31,__SP_L__        \n\t" /* The current stack pointer must be rescued, its value is put below(!) the return address of the */
01197    "sts  %[_ISRspl_], r31    \n\t" /* isr stack. (Normally these values are not used for anything else)                              */
01198   #if (defStackSpaceExceedsOneByte == cfgTrue)
01199    "in   r31,__SP_H__        \n\t" /* Get the high byte of the current stack pointer                                                 */
01200    "sts  %[_ISRsph_], r31    \n\t" /* Save it.                                                                                       */
01201   #endif
01202    "ldi  r31,lo8(%[_ISRst_]) \n\t" /* Now make the stack switch, Load the pointer at which we want to start (above the return        */
01203    "out  __SP_L__,r31        \n\t" /* address) and store it in the low and high byte respectively.                                   */
01204   #if (defStackSpaceExceedsOneByte == cfgTrue)
01205    "ldi  r31,hi8(%[_ISRst_]) \n\t" /* Get the high byte of the new                                                                   */
01206    "out  __SP_H__,r31        \n\t" /* Save it.                                                                                       */
01207   #endif
01208     SaveOsStatus(%[_Status_],%[_s31_],%[_ConISR_])  /* If we have OS protection, we may perform genXXX calls, inform the system      */
01209    "lds  r31,%[_ISRlst_]     \n\t" /* Restore the value of r31                                                                       */
01210    "ret                      \n\t" /* Return with the registers and stack intact                                                     */
01211    "" ::
01212    [_ISRspl_]  "i" (&StackISR[ISRstackSPL]),
01213    [_ISRsph_]  "i" (&StackISR[ISRstackSPH]),
01214    [_ISR1_]    "i" (&StackISR[ISRstackFirstByte]),
01215    [_ISR2_]    "i" (&StackISR[ISRstackSecondByte]),
01216    [_ISR3_]    "i" (&StackISR[ISRstackThirdByte]),
01217    [_ISRlst_]  "i" (&StackISR[ISRstackLastByte]),
01218    [_s31_]     "i" (&xOS.pxSave.r31),
01219    [_ISRst_]   "i" (&StackISR[ISRstackStart]),
01220    [_ConISR_]  "i" (defContextStateIsr),
01221    [_Status_]  "i" (&uiOsStatus) )
01222    ; }
01223 
01224 #endif
01225 
01226 
01227 #if (defUseIsrStack == cfgTrue) && (includeIsrEndReturn == cfgTrue)
01228 
01229 void portReturnISR(void)
01230 /* Call this to end you isr. Do not call reti from your isr, the return is performed by this method. It restores the
01231  * stack and, if needed the OS stack. You are responsible for the registers and the status. Interrupts must (still)
01232  * be disabled when calling this routine. */
01233 { asm volatile (
01234    "sts  %[_ISRlst_], r31            \n\t" /* Save the current value of register r31 (Note, not in the background r31, this is not free!)    */
01235     RestoreOsStatus(%[_Status_],%[_s31_])  /* If we have OS protection, we have replaced the uiOSstatus, which must be repaired              */
01236    "lds  r31,%[_ISRspl_]             \n\t" /* Load the old low byte stack pointer                                                            */
01237    "out  __SP_L__,r31                \n\t" /* Restore it                                                                                     */
01238   #if (defStackSpaceExceedsOneByte == cfgTrue)
01239    "lds  r31,%[_ISRsph_]             \n\t" /* Load the old high byte stack pointer                                                           */
01240    "out  __SP_H__,r31                \n\t" /* Restore it                                                                                     */
01241   #endif
01242    "lds  r31,%[_ISRlst_]             \n\t" /* Restore the value of r31                                                                       */
01243    "reti                             \n\t" /* Return to the interrupted code with interrupts activated.                                      */
01244    "" ::
01245    [_ISRspl_]  "i" (&StackISR[ISRstackSPL]),
01246    [_ISRsph_]  "i" (&StackISR[ISRstackSPH]),
01247    [_s31_]     "i" (&xOS.pxSave.r31),
01248    [_ISRlst_]  "i" (&StackISR[ISRstackLastByte]),
01249    [_Status_]  "i" (&uiOsStatus) )
01250    ; }
01251 
01252 #endif
01253 
01254 
01255 #if (defUseIsrStack == cfgTrue) && (cfgIntOsProtected == cfgTrue) && (includeIsrEndYield == cfgTrue) && (includeTaskYield == cfgTrue)
01256 
01257 void portYieldISR(void)
01258 /* Identical functionality as portReturnISR but does not return to the original point of interrupt, but directly
01259  * performs a context switch, possibly to activate a resumed task. Of course this functionality is only available
01260  * when a task is interrupted thus when we have OS protection on. */
01261 { asm volatile (
01262    "sts  %[_ISRlst_], r31            \n\t" /* Save the current value of register r31 (Note, not in the background r31, this is not free!)    */
01263     RestoreOsStatus(%[_Status_],%[_s31_])  /* If we have OS protection, we have replaced the uiOSstatus, which must be repaired              */
01264    "lds  r31,%[_ISRspl_]             \n\t" /* Load the old low byte stack pointer                                                            */
01265    "out  __SP_L__,r31                \n\t" /* Restore it                                                                                     */
01266   #if (defStackSpaceExceedsOneByte == cfgTrue)
01267    "lds  r31,%[_ISRsph_]             \n\t" /* Load the old high byte stack pointer                                                           */
01268    "out  __SP_H__,r31                \n\t" /* Restore it                                                                                     */
01269   #endif
01270    "lds  r31,%[_ISRlst_]             \n\t" /* Restore the value of r31                                                                       */
01271    "" ::
01272    [_ISRspl_]  "i" (&StackISR[ISRstackSPL]),
01273    [_ISRsph_]  "i" (&StackISR[ISRstackSPH]),
01274    [_s31_]     "i" (&xOS.pxSave.r31),
01275    [_ISRlst_]  "i" (&StackISR[ISRstackLastByte]),
01276    [_Status_]  "i" (&uiOsStatus) );
01277   /* Don't return but directly perform a context switch, use a portJump because the jump may
01278    * not be possible with the rjmp. */
01279    portJump(taskYield); }
01280 
01281 #endif
01282 
01283 
01284 /* DISCUSSION
01285  * Below you will find the portSave and portRestore context. The code in these routines is build on the settings
01286  * of the configuration parameters of the different tasks. First, we distinguish to main blocks, of which only
01287  * one is compiled depending on the setting of cfgCheckRegisters, cfgCheckTaskStack, cfgCheckWatermarks. If one of
01288  * these is cfgTrue, checks are performed on the use of the registers or stack, i.e. this is protected context switching.
01289  * For every group of registers it is
01290  * decided separately if check or save/restore actions are needed. In general this is the approach:
01291  * (1) Registers that are used in all tasks are always saved/restored, and no code is added to test if
01292  *     these actions should be skipped, since there is no need.
01293  * (2) Registers that are used in some tasks are conditionally saved/restored.
01294  * (3) Registers that are used in none of the tasks are completely left out of save/restore.
01295  * The same kind of scheme holds with respect to register use checking, since this may be specified separately,
01296  * but now for filling with the check byte and checking against the check byte.
01297  * Of course this code is all AVR specific.
01298  */
01299 
01300 /* Save registers r28r29r30r31 if they are used, in any of the tasks. */
01301 #if ((defRegisterUseCollect & r28r29r30r31) == r28r29r30r31)
01302   /* This define is for protected context switching. */
01303   #define SaveGroup7b \
01304    "lds  r28,%[_r28_]    \n\t" /* Load original value of register r28     */ \
01305    "push r28             \n\t" /* Push it on the right place on the stack */ \
01306    "lds  r28,%[_r29_]    \n\t" /* Load original value of register r29     */ \
01307    "push r28             \n\t" /* Push it on the right place on the stack */ \
01308    "lds  r28,%[_r30_]    \n\t" /* Load original value of register r30     */ \
01309    "push r28             \n\t" /* Push it on the right place on the stack */ \
01310    "lds  r28,%[_r31_]    \n\t" /* Load original value of register r31     */ \
01311    "push r28             \n\t" /* Push it on the right place on the stack */
01312 
01313   /* This define is for standard context switching. */
01314   #define SaveGroup7a \
01315    "lds  r31,%[_r31_]    \n\t" \
01316    "push r28             \n\t" \
01317    "push r29             \n\t" \
01318    "push r30             \n\t" \
01319    "push r31             \n\t"
01320 #else
01321   #define SaveGroup7a  ""
01322   #define SaveGroup7b  ""
01323 #endif
01324 
01325 /* Save registers r24r25r26r27 if they are used, in any of the tasks. */
01326 #if ((defRegisterUseCollect & r24r25r26r27) == r24r25r26r27)
01327   #define SaveGroup6 \
01328    "push r24             \n\t" \
01329    "push r25             \n\t" \
01330    "push r26             \n\t" \
01331    "push r27             \n\t"
01332 #else
01333   #define SaveGroup6  ""
01334 #endif
01335 
01336 /* Save registers r20r21r22r23 if they are used, in any of the tasks. */
01337 #if ((defRegisterUseCollect & r20r21r22r23) == r20r21r22r23)
01338   #define SaveGroup5 \
01339    "push r20             \n\t" \
01340    "push r21             \n\t" \
01341    "push r22             \n\t" \
01342    "push r23             \n\t"
01343 #else
01344   #define SaveGroup5  ""
01345 #endif
01346 
01347 /* Save registers r16r17r18r19 if they are used, in any of the tasks. */
01348 #if ((defRegisterUseCollect & r16r17r18r19) == r16r17r18r19)
01349   #define SaveGroup4 \
01350    "push r16             \n\t" \
01351    "push r17             \n\t" \
01352    "push r18             \n\t" \
01353    "push r19             \n\t"
01354 #else
01355   #define SaveGroup4  ""
01356 #endif
01357 
01358 /* Save registers r12r13r14r15 if they are used, in any of the tasks. */
01359 #if ((defRegisterUseCollect & r12r13r14r15) == r12r13r14r15)
01360   #define SaveGroup3 \
01361    "push r12             \n\t" \
01362    "push r13             \n\t" \
01363    "push r14             \n\t" \
01364    "push r15             \n\t"
01365 #else
01366   #define SaveGroup3  ""
01367 #endif
01368 
01369 /* Save registers r08r09r10r11 if they are used, in any of the tasks. */
01370 #if ((defRegisterUseCollect & r08r09r10r11) == r08r09r10r11)
01371   #define SaveGroup2 \
01372    "push r8              \n\t" \
01373    "push r9              \n\t" \
01374    "push r10             \n\t" \
01375    "push r11             \n\t"
01376 #else
01377   #define SaveGroup2  ""
01378 #endif
01379 
01380 /* Save registers r04r05r06r07 if they are used, in any of the tasks. */
01381 #if ((defRegisterUseCollect & r04r05r06r07) == r04r05r06r07)
01382   #define SaveGroup1 \
01383    "push r4              \n\t" \
01384    "push r5              \n\t" \
01385    "push r6              \n\t" \
01386    "push r7              \n\t"
01387 #else
01388   #define SaveGroup1  ""
01389 #endif
01390 
01391 /* Save registers r00r01r02r03 if they are used, in any of the tasks. */
01392 #if ((defRegisterUseCollect & r00r01r02r03) == r00r01r02r03)
01393   #define SaveGroup0 \
01394    "push r0              \n\t" \
01395    "push r1              \n\t" \
01396    "push r2              \n\t" \
01397    "push r3              \n\t"
01398 #else
01399   #define SaveGroup0  ""
01400 #endif
01401 
01402 
01403 /* Test if the registergroup r28r29r30r31 must be saved for the current task */
01404 #if ((defRegisterUseVariable & r28r29r30r31) == r28r29r30r31)
01405   #define TestSaveGroup7 \
01406    "sbrs r31, 7          \n\t" \
01407    "rjmp 7f              \n\t"
01408 #else
01409   #define TestSaveGroup7  ""
01410 #endif
01411 
01412 /* Test if the registergroup r24r25r26r27 must be saved for the current task */
01413 #if ((defRegisterUseVariable & r24r25r26r27) == r24r25r26r27)
01414   #define TestSaveGroup6 \
01415    "sbrs r31, 6          \n\t" \
01416    "rjmp 6f              \n\t"
01417 #else
01418   #define TestSaveGroup6  ""
01419 #endif
01420 
01421 /* Test if the registergroup r00r01r02r03 must be saved for the current task */
01422 #if ((defRegisterUseVariable & r20r21r22r23) == r20r21r22r23)
01423   #define TestSaveGroup5 \
01424    "sbrs r31, 5          \n\t" \
01425    "rjmp 5f              \n\t"
01426 #else
01427   #define TestSaveGroup5  ""
01428 #endif
01429 
01430 /* Test if the registergroup r16r17r18r19 must be saved for the current task */
01431 #if ((defRegisterUseVariable & r16r17r18r19) == r16r17r18r19)
01432   #define TestSaveGroup4 \
01433    "sbrs r31, 4          \n\t" \
01434    "rjmp 4f              \n\t"
01435 #else
01436   #define TestSaveGroup4  ""
01437 #endif
01438 
01439 /* Test if the registergroup r00r01r02r03 must be saved for the current task */
01440 #if ((defRegisterUseVariable & r12r13r14r15) == r12r13r14r15)
01441   #define TestSaveGroup3 \
01442    "sbrs r31, 3          \n\t" \
01443    "rjmp 3f              \n\t"
01444 #else
01445   #define TestSaveGroup3  ""
01446 #endif
01447 
01448 /* Test if the registergroup r08r09r10r11 must be saved for the current task */
01449 #if ((defRegisterUseVariable & r08r09r10r11) == r08r09r10r11)
01450   #define TestSaveGroup2 \
01451    "sbrs r31, 2          \n\t" \
01452    "rjmp 2f              \n\t"
01453 #else
01454   #define TestSaveGroup2  ""
01455 #endif
01456 
01457 /* Test if the registergroup r04r05r06r07 must be saved for the current task */
01458 #if ((defRegisterUseVariable & r04r05r06r07) == r04r05r06r07)
01459   #define TestSaveGroup1 \
01460    "sbrs r31, 1          \n\t" \
01461    "rjmp 1f              \n\t"
01462 #else
01463   #define TestSaveGroup1  ""
01464 #endif
01465 
01466 /* Test if the registergroup r00r01r02r03 must be saved for the current task */
01467 #if ((defRegisterUseVariable & r00r01r02r03) == r00r01r02r03)
01468   #define TestSaveGroup0 \
01469    "sbrs r31, 0          \n\t" \
01470    "rjmp 0f              \n\t"
01471 #else
01472   #define TestSaveGroup0  ""
01473 #endif
01474 
01475 
01476 /* Check the content of registergroup r28r29r30r31. */
01477 #if ((defRegisterCheckCollect & r28r29r30r31) == r28r29r30r31)
01478   #define CheckGroup7 \
01479    "lds  r28,%[_r28_]    \n\t" \
01480    "cpse r28,r29         \n\t" \
01481    "sbr  r30,0x80        \n\t" \
01482    "lds  r28,%[_r29_]    \n\t" \
01483    "cpse r28,r29         \n\t" \
01484    "sbr  r30,0x80        \n\t" \
01485    "lds  r28,%[_r30_]    \n\t" \
01486    "cpse r28,r29         \n\t" \
01487    "sbr  r30,0x80        \n\t" \
01488    "lds  r28,%[_r31_]    \n\t" \
01489    "cpse r28,r29         \n\t" \
01490    "sbr  r30,0x80        \n\t"
01491 #else
01492   #define CheckGroup7  ""
01493 #endif
01494 
01495 /* Check the content of registergroup r24r25r26r27. */
01496 #if ((defRegisterCheckCollect & r24r25r26r27) == r24r25r26r27)
01497   #define CheckGroup6 \
01498    "cpse r24,r29         \n\t" \
01499    "sbr  r30,0x40        \n\t" \
01500    "cpse r25,r29         \n\t" \
01501    "sbr  r30,0x40        \n\t" \
01502    "cpse r26,r29         \n\t" \
01503    "sbr  r30,0x40        \n\t" \
01504    "cpse r27,r29         \n\t" \
01505    "sbr  r30,0x40        \n\t"
01506 #else
01507   #define CheckGroup6  ""
01508 #endif
01509 
01510 /* Check the content of registergroup r20r21r22r23. */
01511 #if ((defRegisterCheckCollect & r20r21r22r23) == r20r21r22r23)
01512   #define CheckGroup5 \
01513    "cpse r20,r29         \n\t" \
01514    "sbr  r30,0x20        \n\t" \
01515    "cpse r21,r29         \n\t" \
01516    "sbr  r30,0x20        \n\t" \
01517    "cpse r22,r29         \n\t" \
01518    "sbr  r30,0x20        \n\t" \
01519    "cpse r23,r29         \n\t" \
01520    "sbr  r30,0x20        \n\t"
01521 #else
01522   #define CheckGroup5  ""
01523 #endif
01524 
01525 /* Check the content of registergroup r16r17r18r19. */
01526 #if ((defRegisterCheckCollect & r16r17r18r19) == r16r17r18r19)
01527   #define CheckGroup4 \
01528    "cpse r16,r29         \n\t" \
01529    "sbr  r30,0x10        \n\t" \
01530    "cpse r17,r29         \n\t" \
01531    "sbr  r30,0x10        \n\t" \
01532    "cpse r18,r29         \n\t" \
01533    "sbr  r30,0x10        \n\t" \
01534    "cpse r19,r29         \n\t" \
01535    "sbr  r30,0x10        \n\t"
01536 #else
01537   #define CheckGroup4  ""
01538 #endif
01539 
01540 /* Check the content of registergroup r12r13r14r15. */
01541 #if ((defRegisterCheckCollect & r12r13r14r15) == r12r13r14r15)
01542   #define CheckGroup3 \
01543    "cpse r12,r29         \n\t" \
01544    "sbr  r30,0x08        \n\t" \
01545    "cpse r13,r29         \n\t" \
01546    "sbr  r30,0x08        \n\t" \
01547    "cpse r14,r29         \n\t" \
01548    "sbr  r30,0x08        \n\t" \
01549    "cpse r15,r29         \n\t" \
01550    "sbr  r30,0x08        \n\t"
01551 #else
01552   #define CheckGroup3  ""
01553 #endif
01554 
01555 /* Check the content of registergroup r08r09r10r11. */
01556 #if ((defRegisterCheckCollect & r08r09r10r11) == r08r09r10r11)
01557   #define CheckGroup2 \
01558    "cpse r8,r29          \n\t" \
01559    "sbr  r30,0x04        \n\t" \
01560    "cpse r9,r29          \n\t" \
01561    "sbr  r30,0x04        \n\t" \
01562    "cpse r10,r29         \n\t" \
01563    "sbr  r30,0x04        \n\t" \
01564    "cpse r11,r29         \n\t" \
01565    "sbr  r30,0x04        \n\t"
01566 #else
01567   #define CheckGroup2  ""
01568 #endif
01569 
01570 /* Check the content of registergroup r04r05r06r07. */
01571 #if ((defRegisterCheckCollect & r04r05r06r07) == r04r05r06r07)
01572   #define CheckGroup1 \
01573    "cpse r4,r29          \n\t" \
01574    "sbr  r30,0x02        \n\t" \
01575    "cpse r5,r29          \n\t" \
01576    "sbr  r30,0x02        \n\t" \
01577    "cpse r6,r29          \n\t" \
01578    "sbr  r30,0x02        \n\t" \
01579    "cpse r7,r29          \n\t" \
01580    "sbr  r30,0x02        \n\t"
01581 #else
01582   #define CheckGroup1  ""
01583 #endif
01584 
01585 /* Check the content of registergroup r00r01r02r03. */
01586 #if ((defRegisterCheckCollect & r00r01r02r03) == r00r01r02r03)
01587   #define CheckGroup0 \
01588     CheckRegisterR1 \
01589    "sbr  r30,0x01        \n\t" \
01590    "cpse r0,r29          \n\t" \
01591    "sbr  r30,0x01        \n\t" \
01592    "cpse r2,r29          \n\t" \
01593    "sbr  r30,0x01        \n\t" \
01594    "cpse r3,r29          \n\t" \
01595    "sbr  r30,0x01        \n\t"
01596 #else
01597   #define CheckGroup0  ""
01598 #endif
01599 
01600 
01601 void portSaveContext(void)
01602 { /* PortSaveContext must do what it promises, thus save all used registers for  the current task
01603    * on the stack, and save the device status register too. Furthermore, it must switch from task
01604    * stack to OS stack, store if global interrupt was enabled on the moment
01605    * we left the task, disable the tick interrupt, and if requested, check if the stack will
01606    * not overflow (it must not save the context if the stack will overflow) and check if
01607    * no registers are changed which the task promised not to use. And all this must be done while
01608    * leaving ALL registers unchanged, since they may contain parameters for some OS function that
01609    * was called. The device status register must be left unchanged, until it is saved, which is
01610    * at the end of the the routine, i.e. the status is saved last. The latter seems highly unpractical
01611    * but the reason is that, if we save the status first, we must restore it last, after all registers
01612    * are restored. At that time we do have any registers to work with left. This can be circumvented
01613    * off course, but this costs extra code, and the current implementation does not.
01614    * Note that, since the stack changes in this method global interrupts must be switched off.
01615    */
01616 
01617 #if (cfgCheckRegisters == cfgTrue) || (cfgCheckTaskStack == cfgTrue) || (cfgCheckWatermarks == cfgTrue)
01618 
01619   /* This is the code for protected context saving. */
01620   asm volatile (
01621    "sts  %[_r31_], r31       \n\t" /* We need quite some space to work, so we start of by saving the registers r31,r30,r29,r28.      */
01622    "sts  %[_r30_], r30       \n\t" /* These are placed at a special reserved place on the OS stack, since that space is not used at  */
01623    "sts  %[_r29_], r29       \n\t" /* the moment.                                                                                    */
01624    "sts  %[_r28_], r28       \n\t" /*                                                                                                */
01625    "pop  r31                 \n\t" /* Now we must save the return address. The top address of the stack is the address which called  */
01626    "sts  %[_OS1_], r31       \n\t" /* portSaveContext, and this is the place where we must return to. Since we change stack at the   */
01627    "pop  r31                 \n\t" /* end we displace this address to the OS stack. After this, the top address on the current stack */
01628    "sts  %[_OS2_], r31       \n\t" /* is the address at which the task must be restarted after the portRestoreContext.               */
01629   #if (defThreeByteAddress == cfgTrue)
01630    "pop  r31                 \n\t" /* Get the third byte of the return address, which is now on top of the current stack.            */
01631    "sts  %[_OS3_], r31       \n\t" /* Place it on the OS stack in the correct position.                                              */
01632   #endif
01633    "lds  r31,%[_Status_]     \n\t" /* Now we check from which place we are coming. If this is not a task, but the idle task (info    */
01634    "sbrc r31,%[_ConBit_]     \n\t" /* is in the uiOSstatus) we can skip this, since there is nothing to be saved or checked. Jump in */
01635    "rjmp 41f                 \n\t" /* that case directly to the place where timer interrupt is disabled and the stack is changed.    */
01636    "in   r28, __SREG__       \n\t" /* Make a copy of the device status register, cause we must do some calculus below, preserve r28  */
01637    "in   r30,__SP_L__        \n\t" /* Now we will check if the stack call sustain all registers that must be pushed onto it. If not, */
01638    "lds  r29,(%[_StLim_])    \n\t" /* we will not even try, thereby rescuing the system from a crash, but we will simply inform the  */
01639    "sub  r30,r29             \n\t" /* OS that we did not succeed. The OS will stop the current task, so it is not rescheduled.       */
01640    "ldi  r30,0x00            \n\t" /* Load the StackPointer and the precalculated stack limit, contained in %[_StLim_],and calculate */
01641   #if (defStackSpaceExceedsOneByte == cfgTrue)  /* difference. We are not interested in the actual value, only the carry. We need r30*/
01642    "in   r31,__SP_H__        \n\t" /* to be zero below. If we make use of large stacks, We must repeat the subtraction for the       */
01643    "lds  r29,(%[_StLim_])+1  \n\t" /* high byte. Continue the subtraction with sbc. If we have a small stack, we need not to take    */
01644    "sbc  r31,r29             \n\t" /*  into account the high byte SP_H (which still may be present though)                           */
01645   #endif
01646    "brcc 20f                 \n\t" /* and skip if the stack will fit the space                                                       */
01647    "sbr  r30,%[_STKBITb_]    \n\t" /* if not, indicate the error in uiStackTCheck (this is why r30 needed to be clean)               */
01648    "20:                      \n\t"
01649    "sts  %[_StChk_],r30      \n\t" /* save the result in the uiStackTCheck                                                           */
01650    "ldi  r31,0x00            \n\t" /* Clear r31 to compare with and to collect the register test if we may continue, only if the     */
01651    "cpse r30,r31             \n\t" /* value of uiStackTCheck == 0, if not zero (r31!=r30), we do not save the stack (but do calcu-   */
01652    "rjmp 8f                  \n\t" /* late the new stack level), the task will be terminated, registers saved and not checked.       */
01653    "21:                      \n\t" /* Now we are ready to save and check the registers. (btw we know r30==0 since r30==r31)          */
01654    "lds  r31,%[_RegUse_]     \n\t" /* Load the parameter that describes which registers must be saved.                               */
01655    "ldi  r29,%[_RegByt_]     \n\t" /* Load the parameter that describes which registers must be checked.                             */
01656     CheckGroup0                    /* Check if register group r00r01r03r03 must be checked (if included), collect result in r30      */
01657     TestSaveGroup0                 /* Check if register group r00r01r03r03 must be saved (if included), use r31 for that info        */
01658     SaveGroup0                     /* Save register group r00r01r03r03 (if included).                                                */
01659    "0:                       \n\t" /* Copy the contents of the status register to a save place, freeing r28 for other use. We can    */
01660    "mov r1,r28               \n\t" /* use r1 for this purpose, since it is cleared afterwards and never used for parameters.         */
01661     CheckGroup1                    /* Same as handling of Group0                                                                     */
01662     TestSaveGroup1                 /* */
01663     SaveGroup1                     /* */
01664    "1:                       \n\t" /* */
01665     CheckGroup2                    /* Same as handling of Group0                                                                     */
01666     TestSaveGroup2                 /* */
01667     SaveGroup2                     /* */
01668    "2:                       \n\t" /* */
01669     CheckGroup3                    /* Same as handling of Group0                                                                     */
01670     TestSaveGroup3                 /* */
01671     SaveGroup3                     /* */
01672    "3:                       \n\t" /* */
01673     CheckGroup4                    /* Same as handling of Group0                                                                     */
01674     TestSaveGroup4                 /* */
01675     SaveGroup4                     /* */
01676    "4:                       \n\t" /* */
01677     CheckGroup5                    /* Same as handling of Group0                                                                     */
01678     TestSaveGroup5                 /* */
01679     SaveGroup5                     /* */
01680    "5:                       \n\t" /* */
01681     CheckGroup6                    /* Same as handling of Group0                                                                     */
01682     TestSaveGroup6                 /* */
01683     SaveGroup6                     /* */
01684    "6:                       \n\t" /* */
01685     CheckGroup7                    /* The last instructions are a bit different since we must now check the registers we are using   */
01686     TestSaveGroup7                 /* */
01687     SaveGroup7b                    /* */
01688    "7:                       \n\t" /* All registers are saved, r30 contains the result of the check.                                 */
01689    "mov   r31, r1            \n\t" /* Now we start storing the status register. Move it to r31 for bit maintenance and storage ...   */
01690   #if (cfgSysSqueezeState == cfgTrue) /* We must distinguish between several situations. First in case we have a squeezed state      */
01691    #if (cfgIntTickTrack == cfgTrue)/* If we have tracking of the timer interrupts we must store the actual value. We are ordered to  */
01692    LoadTIMSK(r29)                  /* squeeze it into the status register. The only bit not used by gcc except for the H flag are I  */
01693    "bst r29, %[_OCIE0A_]     \n\t" /* and V flag (overflow), thus copy the value of the tick bit unto the I flag (which is not used) */
01694    "bld r31, %[_I_]          \n\t" /* at the moment loading it in T and replacing it on the correct position.                        */
01695    #endif                          /* The previous interrupt state is contained in the H bit, and that has already been set.         */
01696   #else                            /* If we do not squeeze, we have the state of the global interrupt at the moment the context      */
01697    #if (cfgIntTickTrack == cfgTrue)/* switch stored in devAuxSysRegBit. Now we must see if we must store the tick interrupts as well */
01698    "sbr  r31,%[_Ib_]         \n\t" /* This is very hard since we lack the space. The trick is to store the mode (preemptive, equals  */
01699     LoadTIMSK(r29)                 /* both interrupts active as bit set in I, and cooperative as bit zero in I. In the coop mode the */
01700    "bst r29, %[_OCIE0A_]     \n\t" /* the status register is of no importance, thus may be used to store whatever you like. Thus     */
01701    "clh                      \n\t" /* first copy the tick interrupt state to the T-flag and the global interrupt state to the H-flag */
01702    "sbic %[_ASR_],%[_ARB_]   \n\t" /* Then we must determine in what mode we were when we arrived here. If one of the interrupts is  */
01703    "seh                      \n\t" /* reset we must be in the cooperative mode (tick interrupt not possible, and the secret route    */
01704    "brtc 50f                 \n\t" /* via an user interrupt and context switching is not possible when TickTrack is active. Other-   */
01705    "brhs 51f                 \n\t" /* wise we could be (but not need to be) in the preemptive mode. Former, we save both interrupts. */
01706    "50:                      \n\t" /* We arrive here if one of the interrupts is switched off, thus we store the current manipulated */
01707    "in r31, __SREG__         \n\t" /* status register where T and H represent the Tick and Global interrupt states, otherwise we     */
01708    "51:                      \n\t" /* store the original status register with I location bit set, indicating preemptive mode.        */
01709    #else                           /* If not we only need to store the global interrupt, which can best be done on its place holder  */
01710    "sbic %[_ASR_],%[_ARB_]   \n\t" /* Get the state of the interrupt at the moment the context switch occurred and set the I bit     */
01711    "sbr  r31,%[_Ib_]         \n\t" /* to one if the interrupts where set. Per default that bit is zero                               */
01712    #endif
01713   #endif
01714    "push r31                 \n\t" /* The status register is the last register that is pushed (for the reason, see above)            */
01715    "lds  r28,%[_RegChk_]     \n\t" /* uiRegisterCheck contains the registers we want to check, others may be used but are ignored    */
01716    "and  r30,r28             \n\t" /* deliberately, thus we calculate an and between the registers found to be used (in r30) and the */
01717    "sts  %[_RegChk_],r30     \n\t" /* ones we are interested in. Save the result at the same place.                                  */
01718    "8:                       \n\t" /* We calculate the new stack level below.                                                        */
01719    "lds  r1,%[_StOff_]       \n\t" /* First load the stack offset, then load the low stack pointer. The difference is the new        */
01720    "in   r31,__SP_L__        \n\t" /* stack level. This even holds true over an page border. Standard: 0x31-0x21 = 0x10 and over a   */
01721    "sub  r1,r31              \n\t" /* page border: 0x0101 - 0x00F1 = 0x0010 becomes 0x01 - 0xF1 = 0x10                               */
01722    "lds  r30,%[_StLev_]      \n\t" /* Load the address of the stack level.                                                           */
01723    "lds  r31,(%[_StLev_])+1  \n\t" /* in the Z register for indirect storage.                                                        */
01724    "st   Z,r1                \n\t" /* Store the stack level, directly the right place.                                               */
01725   #if (defStackSizeExceedsOneByte == cfgTrue)
01726    "lds  r1,(%[_StOff_])+1   \n\t" /* In case we have two byte stack level, we must also process the high byte. Load the stack high  */
01727    "in   r31,__SP_H__        \n\t" /* byte of the offset, and the high byte of the stack pointer. The difference is the high byte of */
01728    "sbc  r1,r31              \n\t" /* the stack level, provided we take the carry of the previous subtraction into account. Reload   */
01729    "lds  r31,(%[_StLev_])+1  \n\t" /* r31 (r30 is preserved) and take care to store the high byte stack level result at the correct  */
01730    "std   Z+1,r1             \n\t" /* location, which is one further as the base address. (We may only work with r1,r30,r31 here)    */
01731   #endif                           /* Btw, if the StackSize exceeds one byte so must the StackSpace do, so we do not test for it     */
01732    "41:                      \n\t" /* Below we switch of the tick interrupts. We do that here since we may skip the part at label 7. */
01733     LoadTIMSK(r30)                 /* Load the TIMSK in a register                                                                   */
01734    "andi  r30, %[_nOCIE0Ab_] \n\t" /* Clear the tick interrupt bit (timer 0)                                                         */
01735     StoreTIMSK(r30)                /* write the new state to the timer register, disabling tick interrupts                           */
01736    "ldi  r31,lo8(%[_OSst_])  \n\t" /* Load the low byte of the OS stack.                                                             */
01737    "out  __SP_L__,r31        \n\t" /* Save it.                                                                                       */
01738   #if (defStackSpaceExceedsOneByte == cfgTrue)
01739    "ldi  r31,hi8(%[_OSst_])  \n\t" /* Load the high byte of the OS stack.                                                            */
01740    "out  __SP_H__,r31        \n\t" /* Save it.                                                                                       */
01741   #endif
01742    "lds  r30,%[_r30_]        \n\t" /* Now we restore r30 and r31. Registers r28 and r29 do not need to be restored since if they we  */
01743    "lds  r31,%[_r31_]        \n\t" /* used by the task they where restored in SaveGroup7b, and if not they where already checked and */
01744   #if (cfgSysSqueezeState == cfgFalse)
01745    "cbi %[_ASR_],%[_ARB_]    \n\t" /* Make sure the portSaveContext is left with zero devAuxSysRegBit for interrupt routines that    */
01746   #endif                           /* may make use of genXXX routines. */
01747    "clr  r1                  \n\t" /* the contents should not be important any more. Clear r1 since gcc generated code expects it.   */
01748    "ret                      \n\t" /* Done, return without enabling the global interrupt, that is done inside the OS if needed.      */
01749    "" ::\
01750    [_OS1_]      "i" (&xOS.StackOS[OSstackFirstByte]),
01751    [_OS2_]      "i" (&xOS.StackOS[OSstackSecondByte]),
01752    [_OS3_]      "i" (&xOS.StackOS[OSstackThirdByte]),
01753    [_OSst_]     "i" (&xOS.StackOS[OSstackStart]),
01754    [_r31_]      "i" (&xOS.pxSave.r31),
01755    [_r30_]      "i" (&xOS.pxSave.r30),
01756    [_r29_]      "i" (&xOS.pxSave.r29),
01757    [_r28_]      "i" (&xOS.pxSave.r28),
01758    [_RegByt_]   "i" (cfgSysRegisterCheckByte),
01759    [_RegUse_]   "i" (&xOS.pxSave.uiRegisterUse),
01760    [_RegChk_]   "i" (&xOS.pxSave.uiRegisterCheck),
01761    [_StOff_]    "i" (&xOS.pxSave.pcStackOffset),
01762    [_StLev_]    "i" (&xOS.pxSave.pcStackLevel),
01763    [_StLim_]    "i" (&xOS.pxSave.pcStackLimit),
01764    [_StChk_]    "i" (&xOS.pxSave.uiStackTCheck),
01765    [_ConBit_]   "i" (defContextStateSaveBit),
01766    [_Status_]   "i" (&uiOsStatus),
01767    [_I_]        "i" (SREG_I),
01768    [_Ib_]       "i" (preBitSet1(0x00,SREG_I)),
01769    [_Tb_]       "i" (preBitSet1(0x00,SREG_T)),
01770    [_STKBIT_]   "i" (defCheckStackBit),
01771    [_STKBITb_]  "i" (preBitSet1(0x00,defCheckStackBit)),
01772    [_TIMSKio_]  "i" (_SFR_IO_ADDR(devTIMSK)),
01773    [_TIMSKmem_] "i" (_SFR_MEM_ADDR(devTIMSK)),
01774    [_OCIE0A_]   "i" (devOCIE),
01775    [_nOCIE0Ab_] "i" (preBitClr1(0xFF,devOCIE)),
01776    [_ARB_]      "i" (devAuxSysRegBit),
01777    [_ASR_]      "i" (_SFR_IO_ADDR(devAuxSysReg)));
01778 
01779 #else
01780 
01781   /* This is the code standard context saving. */
01782   asm volatile (
01783    "sts  %[_r31_], r31      \n\t" /* We need some space to work, so we start of by saving the registers r31,r30.                    */
01784    "sts  %[_r30_], r30      \n\t" /* These are placed at a special reserved place on the OS stack, not used at this moment          */
01785    "pop  r31                \n\t" /* Now we must save the return address. The top address of the stack is the address which called  */
01786    "sts  %[_OS1_], r31      \n\t" /* portSaveContext, and this is the place where we must return to. Since we change stack at the   */
01787    "pop  r31                \n\t" /* end we displace this address to the OS stack. After this, the top address on the current stack */
01788    "sts  %[_OS2_], r31      \n\t" /* is the address at which the task must be restarted after the portRestoreContext.               */
01789   #if (defThreeByteAddress == cfgTrue)
01790    "pop  r31                \n\t" /* Get the third byte of the return address, which is now on top of the current stack.           */
01791    "sts  %[_OS3_], r31      \n\t" /* Place it on the OS stack in the correct position.                                         */
01792   #endif
01793    "lds  r31,%[_Status_]    \n\t" /* Now we check from which place we are coming. If this is not a task, but the idle task (info    */
01794    "sbrc r31,%[_ConBit_]    \n\t" /* is in the uiOSstatus) we can skip this, since there is nothing to be saved or checked. Jump in */
01795    "rjmp 41f                \n\t" /* that case directly to the place where timer interrupt is disabled and the stack is changed.    */
01796    "lds  r31,%[_RegUse_]    \n\t" /* Load the parameter that describes which registers must be saved.                               */
01797     TestSaveGroup0                /* Check if registergroup r00r01r03r03 must be saved (if included).                               */
01798     SaveGroup0                    /* Save registergroup r00r01r03r03 (if included).                                                 */
01799    "0:                      \n\t" /* */
01800     TestSaveGroup1                /* Same as handling of Group0                                                                     */
01801     SaveGroup1                    /* */
01802    "1:                      \n\t" /* */
01803     TestSaveGroup2                /* Same as handling of Group0                                                                     */
01804     SaveGroup2                    /* */
01805    "2:                      \n\t" /* */
01806     TestSaveGroup3                /* Same as handling of Group0                                                                     */
01807     SaveGroup3                    /* */
01808    "3:                      \n\t" /* */
01809     TestSaveGroup4                /* Same as handling of Group0                                                                     */
01810     SaveGroup4                    /* */
01811    "4:                      \n\t" /* */
01812     TestSaveGroup5                /* Same as handling of Group0                                                                     */
01813     SaveGroup5                    /* */
01814    "5:                      \n\t" /* */
01815     TestSaveGroup6                /* Same as handling of Group0                                                                     */
01816     SaveGroup6                    /* */
01817    "6:                      \n\t" /* */
01818     TestSaveGroup7                /* Same as handling of Group0                                                                     */
01819     SaveGroup7a                   /* */
01820    "7:                      \n\t" /* */
01821    "in   r31, __SREG__      \n\t" /* Until this point the status register must be unchanged, now is the time to save it.            */
01822   #if (cfgSysSqueezeState == cfgTrue) /* We must distinguish between several situations. First in case we have a squeezed state      */
01823    #if (cfgIntTickTrack == cfgTrue)/* If we have tracking of the timer interrupts we must store the actual value. We are ordered to  */
01824    LoadTIMSK(r30)                  /* squeeze it into the status register. The only bit not used by gcc except for the H flag are I  */
01825    "bst r30, %[_OCIE0A_]     \n\t" /* and V flag (overflow), thus copy the value of the tick bit unto the I flag (which is not used) */
01826    "bld r31, %[_I_]          \n\t" /* at the moment loading it in T and replacing it on the correct position.                                      */
01827    #endif                          /* The previous interrupt state is contained in the H bit, and that has already been set.         */
01828   #else                            /* If we do not squeeze, we have the state of the global interrupt at the moment the context      */
01829    #if (cfgIntTickTrack == cfgTrue)/* switch stored in devAuxSysRegBit. Now we must see if we must store the tick interrupts as well */
01830    "sbr  r31,%[_Ib_]         \n\t" /* This is very hard since we lack the space. The trick is to store the mode (preemptive, equals  */
01831     LoadTIMSK(r30)                 /* both interrupts active as bit set in I, and cooperative as bit zero in I. In the coop mode the */
01832    "bst r30, %[_OCIE0A_]     \n\t" /* the status register is of no importance, thus may be used to store whatever you like. Thus     */
01833    "clh                      \n\t" /* first copy the tick interrupt state to the T-flag and the global interrupt state to the H-flag */
01834    "sbic %[_ASR_],%[_ARB_]   \n\t" /* Then we must determine in what mode we were when we arrived here. If one of the interrupts is  */
01835    "seh                      \n\t" /* reset we must be in the cooperative mode (tick interrupt not possible, and the secret route    */
01836    "brtc 50f                 \n\t" /* via an user interrupt and context switching is not possible when TickTrack is active. Other-   */
01837    "brhs 51f                 \n\t" /* wise we could be (but not need to be) in the preemptive mode. Former, we save both interrupts. */
01838    "50:                      \n\t" /* We arrive here if one of the interrupts is switched off, thus we store the current manipulated */
01839    "in r31, __SREG__         \n\t" /* status register where T and H represent the Tick and Global interrupt states, otherwise we     */
01840    "51:                      \n\t" /* store the original status register with I location bit set, indicating preemptive mode.         */
01841    #else                           /* If not we only need to store the global interrupt, which can best be done on its place holder  */
01842    "sbic %[_ASR_],%[_ARB_]   \n\t" /* Get the state of the interrupt at the moment the context switch occurred and set the I bit     */
01843    "sbr  r31,%[_Ib_]         \n\t" /* to one if the interrupts where set. Per default that bit is zero                               */
01844    #endif
01845   #endif
01846    "push r31                \n\t" /* The status register is the last register that is pushed (for the reason, see above)            */
01847    "lds  r1,%[_StOff_]      \n\t" /* First load the stack offset, then load the low stack pointer. The difference is the new        */
01848    "in   r31,__SP_L__       \n\t" /* stack level. This even holds true over an page border. Standard: 0x31-0x21 = 0x10 and over a   */
01849    "sub  r1,r31             \n\t" /* page border: 0x0101 - 0x00F1 = 0x0010 becomes 0x01 - 0xF1 = 0x10                               */
01850    "lds  r30,%[_StLev_]     \n\t" /* Load the address of the stack level.                                                           */
01851    "lds  r31,(%[_StLev_])+1 \n\t" /* in the Z register for indirect storage.                                                        */
01852    "st   Z,r1               \n\t" /* Store the stack level, directly the right place.                                               */
01853   #if (defStackSizeExceedsOneByte == cfgTrue)
01854    "lds  r1,(%[_StOff_])+1  \n\t" /* In case we have two byte stack level, we must also process the high byte. Load the stack high  */
01855    "in   r31,__SP_H__       \n\t" /* byte of the offset, and the high byte of the stack pointer. The difference is the high byte of */
01856    "sbc  r1,r31             \n\t" /* the stack level, provided we take the carry of the previous subtraction into account. Reload   */
01857    "lds  r31,(%[_StLev_])+1 \n\t" /* r31 (r30 is preserved) and take care to store the high byte stack level result at the correct  */
01858    "std   Z+1,r1            \n\t" /* location, which is one further as the base address. (We may only work with r1,r30,r31 here)    */
01859   #endif                          /* Btw, if the StackSize exceeds one byte so must the StackSpace do, so we do not test for it     */
01860    "41:                     \n\t" /* Below we switch off the tick interrupts. We do that here since we may skip the part at label 7.*/
01861     LoadTIMSK(r30)                /* Load the TIMSK in a register                                                                   */
01862    "andi  r30, %[_nOCIE0Ab_]\n\t" /* Clear the tick interrupt bit (timer 0)                                                         */
01863     StoreTIMSK(r30)               /* write the new state to the timer register, disabling tick interrupts                           */
01864    "ldi  r31,lo8(%[_OSst_]) \n\t" /* Load the low byte of the OS stack.                                                             */
01865    "out  __SP_L__,r31       \n\t" /* Save it.                                                                                       */
01866   #if (defStackSpaceExceedsOneByte == cfgTrue)
01867    "ldi  r31,hi8(%[_OSst_]) \n\t" /* Load the high byte of the OS stack.                                                            */
01868    "out  __SP_H__,r31       \n\t" /* Save it.                                                                                       */
01869   #endif
01870    "lds  r30,%[_r30_]       \n\t" /* Now we restore r30 and r31.                                                                    */
01871    "lds  r31,%[_r31_]       \n\t" /* */
01872   #if (cfgSysSqueezeState == cfgFalse)
01873    "cbi %[_ASR_],%[_ARB_]   \n\t" /* Make sure the portSaveContext is left with zero devAuxSysRegBit for interrupt routines that    */
01874   #endif                          /* may make use of genXXX routines. */
01875    "clr  r1                 \n\t" /* Clear r1 since gcc generated code expects it.                                                  */
01876    "ret                     \n\t" /* Done, return without enabling the global interrupt, that is done inside the OS if needed.      */
01877    "" ::
01878    [_OS1_]      "i" (&xOS.StackOS[OSstackFirstByte]),
01879    [_OS2_]      "i" (&xOS.StackOS[OSstackSecondByte]),
01880    [_OS3_]      "i" (&xOS.StackOS[OSstackThirdByte]),
01881    [_OSst_]     "i" (&xOS.StackOS[OSstackStart]),
01882    [_r31_]      "i" (&xOS.pxSave.r31),
01883    [_r30_]      "i" (&xOS.pxSave.r30),
01884    [_RegUse_]   "i" (&xOS.pxSave.uiRegisterUse),
01885    [_StOff_]    "i" (&xOS.pxSave.pcStackOffset),
01886    [_StLev_]    "i" (&xOS.pxSave.pcStackLevel),
01887    [_ConBit_]   "i" (defContextStateSaveBit),
01888    [_Status_]   "i" (&uiOsStatus),
01889    [_I_]        "i" (SREG_I),
01890    [_Ib_]       "i" (preBitSet1(0x00,SREG_I)),
01891    [_Tb_]       "i" (preBitSet1(0x00,SREG_T)),
01892    [_Vb_]       "i" (preBitSet1(0x00,SREG_V)),
01893    [_STKBIT_]   "i" (defCheckStackBit),
01894    [_STKBITb_]  "i" (preBitSet1(0x00,defCheckStackBit)),
01895    [_TIMSKio_]  "i" (_SFR_IO_ADDR(devTIMSK)),
01896    [_TIMSKmem_] "i" (_SFR_MEM_ADDR(devTIMSK)),
01897    [_OCIE0A_]   "i" (devOCIE),
01898    [_nOCIE0Ab_] "i" (preBitClr1(0xFF,devOCIE)),
01899    [_ARB_]      "i" (devAuxSysRegBit),
01900    [_ASR_]      "i" (_SFR_IO_ADDR(devAuxSysReg)));
01901 
01902 #endif
01903 }
01904 
01905 /* DISCUSSION
01906  * One might wonder why there is so much work on the Save Context. Would porting not be
01907  * a lot simpler if we just saved the registers and the status, and left stack switching
01908  * and interrupt capture to the OS? Well, yes but there is a problem too. Some of the
01909  * OS function calls are switching, which means that as the application calls the function
01910  * a task switch must be performed also. Standard OS implementation perform function handling
01911  * in task space, issuing a copy of all OS handling on every stack. We use the OS stack so
01912  * we must switch stack and save the interrupts while leaving ALL registers in unchanged since
01913  * they might contain parameters of the calling function. GCC is not capable of generating
01914  * such code, so it must be done by hand.
01915  */
01916 
01917 /* Restore registers r28r29r30r31 if they are used, in any of the tasks. */
01918 #if ((defRegisterUseCollect & r28r29r30r31) == r28r29r30r31)
01919   #define RestoreGroup7 \
01920    "pop  r31             \n\t" \
01921    "pop  r30             \n\t" \
01922    "pop  r29             \n\t" \
01923    "pop  r28             \n\t"
01924 #else
01925   #define RestoreGroup7  ""
01926 #endif
01927 
01928 /* Restore registers r24r25r26r27 if they are used, in any of the tasks. */
01929 #if ((defRegisterUseCollect & r24r25r26r27) == r24r25r26r27)
01930   #define RestoreGroup6 \
01931    "pop  r27             \n\t" \
01932    "pop  r26             \n\t" \
01933    "pop  r25             \n\t" \
01934    "pop  r24             \n\t"
01935 #else
01936   #define RestoreGroup6  ""
01937 #endif
01938 
01939 /* Restore registers r20r21r22r23 if they are used, in any of the tasks. */
01940 #if ((defRegisterUseCollect & r20r21r22r23) == r20r21r22r23)
01941   #define RestoreGroup5 \
01942    "pop  r23             \n\t" \
01943    "pop  r22             \n\t" \
01944    "pop  r21             \n\t" \
01945    "pop  r20             \n\t"
01946 #else
01947   #define RestoreGroup5  ""
01948 #endif
01949 
01950 /* Restore registers r16r17r18r19 if they are used, in any of the tasks. */
01951 #if ((defRegisterUseCollect & r16r17r18r19) == r16r17r18r19)
01952   #define RestoreGroup4 \
01953    "pop  r19             \n\t" \
01954    "pop  r18             \n\t" \
01955    "pop  r17             \n\t" \
01956    "pop  r16             \n\t"
01957 #else
01958   #define RestoreGroup4  ""
01959 #endif
01960 
01961 /* Restore registers r12r13r14r15 if they are used, in any of the tasks. */
01962 #if ((defRegisterUseCollect & r12r13r14r15) == r12r13r14r15)
01963   #define RestoreGroup3 \
01964    "pop  r15             \n\t" \
01965    "pop  r14             \n\t" \
01966    "pop  r13             \n\t" \
01967    "pop  r12             \n\t"
01968 #else
01969   #define RestoreGroup3  ""
01970 #endif
01971 
01972 /* Restore registers r08r09r10r11 if they are used, in any of the tasks. */
01973 #if ((defRegisterUseCollect & r08r09r10r11) == r08r09r10r11)
01974   #define RestoreGroup2 \
01975    "pop  r11             \n\t" \
01976    "pop  r10             \n\t" \
01977    "pop  r9              \n\t" \
01978    "pop  r8              \n\t"
01979 #else
01980   #define RestoreGroup2  ""
01981 #endif
01982 
01983 /* Restore registers r04r05r06r07 if they are used, in any of the tasks. */
01984 #if ((defRegisterUseCollect & r04r05r06r07) == r04r05r06r07)
01985   #define RestoreGroup1 \
01986    "pop  r7              \n\t" \
01987    "pop  r6              \n\t" \
01988    "pop  r5              \n\t" \
01989    "pop  r4              \n\t"
01990 #else
01991   #define RestoreGroup1  ""
01992 #endif
01993 
01994 /* Restore registers r00r01r02r03 if they are used, in any of the tasks. */
01995 #if ((defRegisterUseCollect & r00r01r02r03) == r00r01r02r03)
01996   #define RestoreGroup0 \
01997    "pop  r3              \n\t" \
01998    "pop  r2              \n\t" \
01999    "pop  r1              \n\t" \
02000    "pop  r0              \n\t"
02001 #else
02002   #define RestoreGroup0  ""
02003 #endif
02004 
02005 /* Test if the registergroup r28r29r30r31 must be restored for the current task */
02006 #if ((defRegisterUseVariable & r28r29r30r31) == r28r29r30r31)
02007   #define TestRestoreGroup7 \
02008    "sbrs r0, 7           \n\t" \
02009    "rjmp 7f              \n\t"
02010 #else
02011   #define TestRestoreGroup7  ""
02012 #endif
02013 
02014 /* Test if the registergroup r24r25r26r27 must be restored for the current task */
02015 #if ((defRegisterUseVariable & r24r25r26r27) == r24r25r26r27)
02016   #define TestRestoreGroup6 \
02017    "sbrs r0, 6           \n\t" \
02018    "rjmp 6f              \n\t"
02019 #else
02020   #define TestRestoreGroup6  ""
02021 #endif
02022 
02023 /* Test if the registergroup r20r21r22r23 must be restored for the current task */
02024 #if ((defRegisterUseVariable & r20r21r22r23) == r20r21r22r23)
02025   #define TestRestoreGroup5 \
02026    "sbrs r0, 5           \n\t" \
02027    "rjmp 5f              \n\t"
02028 #else
02029   #define TestRestoreGroup5  ""
02030 #endif
02031 
02032 /* Test if the registergroup r16r17r18r19 must be restored for the current task */
02033 #if ((defRegisterUseVariable & r16r17r18r19) == r16r17r18r19)
02034   #define TestRestoreGroup4 \
02035    "sbrs r0, 4           \n\t" \
02036    "rjmp 4f              \n\t"
02037 #else
02038   #define TestRestoreGroup4  ""
02039 #endif
02040 
02041 /* Test if the registergroup r12r13r14r15 must be restored for the current task */
02042 #if ((defRegisterUseVariable & r12r13r14r15) == r12r13r14r15)
02043   #define TestRestoreGroup3 \
02044    "sbrs r0, 3           \n\t" \
02045    "rjmp 3f              \n\t"
02046 #else
02047   #define TestRestoreGroup3  ""
02048 #endif
02049 
02050 /* Test if the registergroup r08r09r10r11 must be restored for the current task */
02051 #if ((defRegisterUseVariable & r08r09r10r11) == r08r09r10r11)
02052   #define TestRestoreGroup2 \
02053    "sbrs r0, 2           \n\t" \
02054    "rjmp 2f              \n\t"
02055 #else
02056   #define TestRestoreGroup2  ""
02057 #endif
02058 
02059 /* Test if the registergroup r04r05r06r07 must be restored for the current task */
02060 #if ((defRegisterUseVariable & r04r05r06r07) == r04r05r06r07)
02061   #define TestRestoreGroup1 \
02062    "sbrs r0, 1           \n\t" \
02063    "rjmp 1f              \n\t"
02064 #else
02065   #define TestRestoreGroup1  ""
02066 #endif
02067 
02068 /* Test if the registergroup r00r01r02r03 must be restored for the current task */
02069 #if ((defRegisterUseVariable & r00r01r02r03) == r00r01r02r03)
02070   #define TestRestoreGroup0 \
02071    "sbrs r0, 0           \n\t" \
02072    "rjmp 0f              \n\t"
02073   #define SkipFillGroup0 \
02074    "rjmp 10f             \n\t"
02075 #else
02076   #define TestRestoreGroup0 ""
02077   #define SkipFillGroup0    ""
02078 #endif
02079 
02080 /* Test if the registergroup r00r01r02r03 must be filled for the current task */
02081 #if ((defRegisterUseVariable & r00r01r02r03) == r00r01r02r03)
02082   #define TestFillGroup0 \
02083    "sbrc r0, 0           \n\t" \
02084    "rjmp 0f              \n\t"
02085   #define SkipRestoreGroup0 \
02086    "rjmp 10f             \n\t"
02087 #else
02088   #define TestFillGroup0     ""
02089   #define SkipRestoreGroup0  ""
02090 #endif
02091 
02092 /* Fill registergroup r28r29r30r31 with the check byte */
02093 #if ((defRegisterCheckCollect & r28r29r30r31) == r28r29r30r31)
02094   #define FillGroup7 \
02095    "mov  r30,r2          \n\t" \
02096    "mov  r29,r2          \n\t" \
02097    "mov  r28,r2          \n\t"
02098 #else
02099   #define FillGroup7  ""
02100 #endif
02101 
02102 /* Fill registergroup r24r25r26r27 with the check byte */
02103 #if ((defRegisterCheckCollect & r24r25r26r27) == r24r25r26r27)
02104   #define FillGroup6 \
02105    "mov  r27,r2          \n\t" \
02106    "mov  r26,r2          \n\t" \
02107    "mov  r25,r2          \n\t" \
02108    "mov  r24,r2          \n\t"
02109 #else
02110   #define FillGroup6  ""
02111 #endif
02112 
02113 /* Fill registergroup r20r21r22r23 with the check byte */
02114 #if ((defRegisterCheckCollect & r20r21r22r23) == r20r21r22r23)
02115   #define FillGroup5 \
02116    "mov  r23,r2          \n\t" \
02117    "mov  r22,r2          \n\t" \
02118    "mov  r21,r2          \n\t" \
02119    "mov  r20,r2          \n\t"
02120 #else
02121   #define FillGroup5  ""
02122 #endif
02123 
02124 /* Fill registergroup r16r17r18r19 with the check byte */
02125 #if ((defRegisterCheckCollect & r16r17r18r19) == r16r17r18r19)
02126   #define FillGroup4 \
02127    "mov  r19,r2          \n\t" \
02128    "mov  r18,r2          \n\t" \
02129    "mov  r17,r2          \n\t" \
02130    "mov  r16,r2          \n\t"
02131 #else
02132   #define FillGroup4  ""
02133 #endif
02134 
02135 /* Fill registergroup r12r13r14r15 with the check byte */
02136 #if ((defRegisterCheckCollect & r12r13r14r15) == r12r13r14r15)
02137   #define FillGroup3 \
02138    "mov  r15,r2          \n\t" \
02139    "mov  r14,r2          \n\t" \
02140    "mov  r13,r2          \n\t" \
02141    "mov  r12,r2          \n\t"
02142 #else
02143   #define FillGroup3  ""
02144 #endif
02145 
02146 /* Fill registergroup r20r21r22r23 with the check byte */
02147 #if ((defRegisterCheckCollect & r08r09r10r11) == r08r09r10r11)
02148   #define FillGroup2 \
02149    "mov  r11,r2          \n\t" \
02150    "mov  r10,r2          \n\t" \
02151    "mov  r9,r2           \n\t" \
02152    "mov  r8,r2           \n\t"
02153 #else
02154   #define FillGroup2  ""
02155 #endif
02156 
02157 /* Fill registergroup r04r05r06r07 with the check byte */
02158 #if ((defRegisterCheckCollect & r04r05r06r07) == r04r05r06r07)
02159   #define FillGroup1 \
02160    "mov  r7,r2           \n\t" \
02161    "mov  r6,r2           \n\t" \
02162    "mov  r5,r2           \n\t" \
02163    "mov  r4,r2           \n\t"
02164 #else
02165   #define FillGroup1  ""
02166 #endif
02167 
02168 /* Fill registergroup r00r01r02r03 with the check byte */
02169 #if ((defRegisterCheckCollect & r00r01r02r03) == r00r01r02r03)
02170   #define FillGroup0 \
02171    "mov  r3,r2           \n\t" \
02172     FillRegisterR1             \
02173    "mov  r0,r2           \n\t"
02174 #else
02175   #define FillGroup0        ""
02176 #endif
02177 
02178 
02179 void portRestoreContext(void)
02180 {
02181 
02182 #if (cfgCheckRegisters == cfgTrue) || (cfgCheckTaskStack == cfgTrue) || (cfgCheckWatermarks == cfgTrue)
02183 
02184   /* This is the code for protected context restoring. */
02185   asm volatile (
02186     ClearRegisterR1                /* GCC generated code expects r1 to be zero, clear it if the option cfgSysClearUnusedR1 is set   */
02187     LoadTIMSK(r30)                 /* We must restore the status register as well as set the tick interrupt correctly. Load the     */
02188    "pop  r31                \n\t"  /* latter into r30 and the first into r31 for manipulation. Then sort out if we squeeze or not.  */
02189   #if (cfgSysSqueezeState == cfgTrue) /* If we have a squeezed state, the global interrupt was stored at the H bit location. Done   */
02190    #if (cfgIntTickTrack == cfgTrue)/* If we keep track of tick interrupts, the information was stored at the I bit location.        */
02191    "bst  r31, %[_I_]         \n\t" /* Copy the value of the I bit location to the the place where the timer interrupt is situated   */
02192    "bld  r30, %[_OCIE0A_]    \n\t" /* by moving it through the T bit (shortest method).                                             */
02193    "andi r31,%[_nIb_]        \n\t" /* Don't forget to clear its location, we do not want to activate global interrupts.             */
02194    #else                           /* If we do not track tick interrupts the tick interrupt is not saved, restore global only       */
02195    "sbr  r30,%[_OCIE0Ab_]   \n\t"  /* If we do not keep track of tick interrupts we must set the timer interrupt per default        */
02196    #endif
02197   #else                            /* If we not squeeze, the information is packed differently, (see save context also).            */
02198    #if (cfgIntTickTrack == cfgTrue) /* If we keep track of the tick interrupt state, we must sort out if we were in the preemptive  */
02199    "sbr  r30,%[_OCIE0Ab_]   \n\t"  /* mode or not. If so we need to activate both global and tick interrupts, do so here by default */
02200    "sbi  %[_ASR_],%[_ARB_]  \n\t"  /* by setting the bit locations on their registers.                                              */
02201    "sbrc r31,%[_I_]         \n\t"  /* Now look if the preemptive mode was set (I bit location set)                                  */
02202    "rjmp 52f                \n\t"  /* If so, we are almost done skip the following                                                  */
02203    "sbrs r31,%[_T_]         \n\t"  /* If not we must reset the tick interrupt if the T-flag was not set, test if it was set         */
02204    "andi r30,%[_nOCIE0Ab_]  \n\t"  /* if not, reset that bit otherwise just skip, since it was set already.                         */
02205    "sbrs r31,%[_H_]         \n\t"  /* Also test the H-flag indicating the new state of the global interrupt, test if it was set     */
02206    "cbi  %[_ASR_],%[_ARB_]  \n\t"  /* if not, reset that bit otherwise just skip, since it was set already.                         */
02207    "52:                     \n\t"  /* Arrive here when place holders of tick and global interrupt are setup correctly               */
02208    "andi  r31,%[_nIb_]      \n\t" /* Make sure we do not activate the global interrupt just yet.                                    */
02209    #else                          /* If we do not track tick interrupts the tick interrupt is not saved, restore global only        */
02210    "cbi  %[_ASR_],%[_ARB_]  \n\t" /* We want to temporarily save the status of the global interrupt in the devAuxSysRegBit, clear   */
02211    "sbrc r31,%[_I_]         \n\t" /* that bit first, then check the value of the position of the I bit, if it is set, then          */
02212    "sbi  %[_ASR_],%[_ARB_]  \n\t" /* set the devAuxSysRegBit, if not we can leave it cleared.                                       */
02213    "andi r31,%[_nIb_]       \n\t" /* Make sure the I bit is cleared. (we do not want to activate global interrupts here).           */
02214    "sbr  r30,%[_OCIE0Ab_]   \n\t" /* If we do not keep track of tick interrupts we must set the timer interrupt per default         */
02215    #endif
02216   #endif
02217    "out  __SREG__, r31      \n\t" /* Restore the status register.                                                                  */
02218     StoreTIMSK(r30)               /* Restore the TIMSK register holding the tick interrupt                                         */
02219    "lds  r0,%[_RegUse_]     \n\t" /* Load the parameter describing which register are used, in order to restore them.               */
02220    "ldi  r31,%[_RegByt_]    \n\t" /* Load the byte we use to fill unused register in under to check if they are misused.            */
02221    "mov  r2,r31             \n\t" /* Since we need to restore higher number register first, copy that value to r2                   */
02222     FillGroup7                    /* Fill the register group with checkbytes (if used)                                              */
02223     TestRestoreGroup7             /* Check if the register group must be restored (if used)                                         */
02224     RestoreGroup7                 /* Restore the register group (if used)                                                           */
02225    "7:                      \n\t" /* */
02226     FillGroup6                    /* Same handling as group 7                                                                       */
02227     TestRestoreGroup6             /* */
02228     RestoreGroup6                 /* */
02229    "6:                      \n\t" /* */
02230     ReturnState(%[_RetPar_])      /* Now r24 is restored we can fill it with a return value when needed, plenty of registers free   */
02231     FillGroup5                    /* Same handling as group 7                                                                       */
02232     TestRestoreGroup5             /* */
02233     RestoreGroup5                 /* */
02234    "5:                      \n\t" /* */
02235     FillGroup4                    /* Same handling as group 7                                                                       */
02236     TestRestoreGroup4             /* */
02237     RestoreGroup4                 /* */
02238    "4:                      \n\t" 
02239     FillGroup3                    /* Same handling as group 7                                                                       */
02240     TestRestoreGroup3             /* */
02241     RestoreGroup3                 /* */
02242    "3:                      \n\t" /* */
02243     FillGroup2                    /* Same handling as group 7                                                                       */
02244     TestRestoreGroup2             /* */
02245     RestoreGroup2                 /* */
02246    "2:                      \n\t" /* */
02247     FillGroup1                    /* Same handling as group 7                                                                       */
02248     TestRestoreGroup1             /* */
02249     RestoreGroup1                 /* */
02250    "1:                      \n\t" /* */
02251     TestFillGroup0                /* Since we must test if we need to restore (and this uses register r0, and at the same time fill */
02252     FillGroup0                    /* r0, we have a problem. Since we cannot fill and overwrite, thus we must skip, if the Test was  */
02253     SkipRestoreGroup0             /* was present. Otherwise there is nothing to skip.                                               */
02254    "0:                      \n\t" /* */
02255     RestoreGroup0                 /* */
02256    "10:                     \n\t" /* */
02257   #if (cfgSysSqueezeState == cfgFalse)
02258    "sbis %[_ASR_],%[_ARB_]  \n\t" /* devAuxSysReg contains a copy of the status register, test for the global interrupt bit         */
02259    "ret                     \n\t" /* if it is not set return normally (interrupt keeps deactivated) otherwise reti                  */
02260    "cbi %[_ASR_],%[_ARB_]   \n\t" /* bit ARB of must be zero before a portSaveContext occurs.                                       */
02261    "reti                    \n\t" /* */
02262   #else
02263    "brhs 13f                \n\t" /* The H bit contains the interrupt state, so if it is not set                                    */
02264    "ret                     \n\t" /* return without interrupts activated, and otherwise                                             */
02265    "13:                     \n\t" /* */
02266    "reti                    \n\t" /* set the interrupts while returning.                                                            */
02267   #endif
02268    "" ::
02269    [_RegUse_]   "i" (&xOS.pxSave.uiRegisterUse),
02270    [_RegByt_]   "i" (cfgSysRegisterCheckByte),
02271    [_RetPar_]   "i" (ReturnField),
02272    [_I_]        "i" (SREG_I),
02273    [_H_]        "i" (SREG_H),
02274    [_T_]        "i" (SREG_T),
02275    [_Ib_]       "i" (preBitSet1(0x00,SREG_I)),
02276    [_Tb_]       "i" (preBitSet1(0x00,SREG_T)),
02277    [_nITb_]     "i" (preBitClr2(0xFF,SREG_I,SREG_T)),
02278    [_nIb_]      "i" (preBitClr1(0xFF,SREG_I)),
02279    [_RET0_]     "i" (defRet0),
02280    [_RET1_]     "i" (defRet1),
02281    [_STKBIT_]   "i" (defCheckStackBit),
02282    [_STKBITb_]  "i" (preBitSet1(0x00,defCheckStackBit)),
02283    [_TIMSKio_]  "i" (_SFR_IO_ADDR(devTIMSK)),
02284    [_TIMSKmem_] "i" (_SFR_MEM_ADDR(devTIMSK)),
02285    [_OCIE0A_]   "i" (devOCIE),
02286    [_OCIE0Ab_]  "i" (preBitSet1(0x00,devOCIE)),
02287    [_nOCIE0Ab_] "i" (preBitClr1(0xFF,devOCIE)),
02288    [_ARB_]      "i" (devAuxSysRegBit),
02289    [_ASR_]      "i" (_SFR_IO_ADDR(devAuxSysReg)));
02290 
02291 #else
02292 
02293   /* This is the code standard context restoring. */
02294   asm volatile (
02295     ClearRegisterR1               /* GCC generated code expects r1 to be zero, clear it if the option cfgSysClearUnusedR1 is set    */
02296     LoadTIMSK(r30)                 /* We must restore the status register as well as set the tick interrupt correctly. Load the     */
02297    "pop  r31                \n\t"  /* latter into r30 and the first into r31 for manipulation. Then sort out if we squeeze or not.  */
02298   #if (cfgSysSqueezeState == cfgTrue) /* If we have a squeezed state, the global interrupt was stored at the H bit location. Done   */
02299    #if (cfgIntTickTrack == cfgTrue)/* If we keep track of tick interrupts, the information was stored at the I bit location.        */
02300    "bst  r31, %[_I_]         \n\t" /* Copy the value of the I bit location to the the place where the timer interrupt is situated   */
02301    "bld  r30, %[_OCIE0A_]    \n\t" /* by moving it through the T bit (shortest method).                                             */
02302    "andi r31,%[_nIb_]        \n\t" /* Don't forget to clear its location, we do not want to activate global interrupts.             */
02303    #else                           /* If we do not track tick interrupts the tick interrupt is not saved, restore global only       */
02304    "sbr  r30,%[_OCIE0Ab_]   \n\t"  /* If we do not keep track of tick interrupts we must set the timer interrupt per default        */
02305    #endif
02306   #else                            /* If we not squeeze, the information is packed differently, (see save context also).            */
02307    #if (cfgIntTickTrack == cfgTrue) /* If we keep track of the tick interrupt state, we must sort out if we were in the preemptive  */
02308    "sbr  r30,%[_OCIE0Ab_]   \n\t"  /* mode or not. If so we need to activate both global and tick interrupts, do so here by default */
02309    "sbi  %[_ASR_],%[_ARB_]  \n\t"  /* by setting the bit locations on their registers.                                              */
02310    "sbrc r31,%[_I_]         \n\t"  /* Now look if the preemptive mode was set (I bit location set)                                  */
02311    "rjmp 52f                \n\t"  /* If so, we are almost done skip the following                                                  */
02312    "sbrs r31,%[_T_]         \n\t"  /* If not we must reset the tick interrupt if the T-flag was not set, test if it was set         */
02313    "andi r30,%[_nOCIE0Ab_]  \n\t"  /* if not, reset that bit otherwise just skip, since it was set already.                         */
02314    "sbrs r31,%[_H_]         \n\t"  /* Also test the H-flag indicating the new state of the global interrupt, test if it was set     */
02315    "cbi  %[_ASR_],%[_ARB_]  \n\t"  /* if not, reset that bit otherwise just skip, since it was set already.                         */
02316    "52:                     \n\t"  /* Arrive here when place holders of tick and global interrupt are setup correctly               */
02317    "andi r31,%[_nIb_]       \n\t" /* Make sure we do not activate the global interrupt just yet.                                   */
02318    #else                           /* If we do not track tick interrupts the tick interrupt is not saved, restore global only       */
02319    "cbi  %[_ASR_],%[_ARB_]  \n\t" /* We want to temporarily save the status of the global interrupt in the devAuxSysRegBit, clear   */
02320    "sbrc r31,%[_I_]         \n\t" /* that bit first, then check the value of the position of the I bit, if it is set, then          */
02321    "sbi  %[_ASR_],%[_ARB_]  \n\t" /* set the devAuxSysRegBit, if not we can leave it cleared.                                       */
02322    "andi r31,%[_nIb_]       \n\t" /* Make sure the I bit is cleared. (we do not want to activate global interrupts here).           */
02323    "sbr  r30,%[_OCIE0Ab_]   \n\t" /* If we do not keep track of tick interrupts we must set the timer interrupt per default        */
02324    #endif
02325   #endif
02326    "out  __SREG__, r31      \n\t" /* Restore the status register.                                                                  */
02327     StoreTIMSK(r30)               /* Restore the TIMSK register holding the tick interrupt                                         */
02328    "lds  r0,%[_RegUse_]     \n\t" /* Load the parameter describing which register are used, in order to restore them.               */
02329     TestRestoreGroup7             /* Check if the registergroup must be restored (if used)                                          */
02330     RestoreGroup7                 /* Restore the registergroup (if used)                                                            */
02331    "7:                      \n\t" /* */
02332     TestRestoreGroup6             /* Same handling as group 7                                                                       */
02333     RestoreGroup6                 /* */
02334    "6:                      \n\t" /* */
02335     ReturnState(%[_RetPar_])         /* Now r24 is restored we can fill it with a return value when needed, plenty of registers free   */
02336     TestRestoreGroup5             /* Same handling as group 7                                                                       */
02337     RestoreGroup5                 /* */
02338    "5:                      \n\t" /* */
02339     TestRestoreGroup4             /* Same handling as group 7                                                                       */
02340     RestoreGroup4                 /* */
02341    "4:                      \n\t" /* */
02342     TestRestoreGroup3             /* Same handling as group 7                                                                       */
02343     RestoreGroup3                 /* */
02344    "3:                      \n\t" /* */
02345     TestRestoreGroup2             /* Same handling as group 7                                                                       */
02346     RestoreGroup2                 /* */
02347    "2:                      \n\t" /* */
02348     TestRestoreGroup1             /* Same handling as group 7                                                                       */
02349     RestoreGroup1                 /* */
02350    "1:                      \n\t" /* */
02351     TestRestoreGroup0             /* Same handling as group 7                                                                       */
02352     RestoreGroup0                 /* */
02353    "0:                      \n\t" /* */
02354   #if (cfgSysSqueezeState == cfgFalse)
02355    "sbis %[_ASR_],%[_ARB_]  \n\t" /* devAuxSysReg contains a copy of the status register, test for the global interrupt bit         */
02356    "ret                     \n\t" /* if it is not set return normally (interrupt keeps deactivated) otherwise reti                  */
02357    "cbi %[_ASR_],%[_ARB_]   \n\t" /* bit ARB of must be zero before a portSaveContext occurs.                                       */
02358    "reti                    \n\t" /* */
02359   #else
02360    "brhs 13f                \n\t" /* The H bit contains the interrupt state, so if it is not set                                    */
02361    "ret                     \n\t" /* return without interrupts activated, and otherwise                                             */
02362    "13:                     \n\t" /* */
02363    "reti                    \n\t" /* set the interrupts while returning.                                                            */
02364   #endif
02365    "" ::
02366    [_RegUse_]   "i" (&xOS.pxSave.uiRegisterUse),
02367    [_RetPar_]   "i" (ReturnField),
02368    [_I_]        "i" (SREG_I),
02369    [_H_]        "i" (SREG_H),
02370    [_T_]        "i" (SREG_T),
02371    [_Ib_]       "i" (preBitSet1(0x00,SREG_I)),
02372    [_Tb_]       "i" (preBitSet1(0x00,SREG_T)),
02373    [_nITb_]     "i" (preBitClr2(0xFF,SREG_I,SREG_T)),
02374    [_nIb_]      "i" (preBitClr1(0xFF,SREG_I)),
02375    [_RET0_]     "i" (defRet0),
02376    [_RET1_]     "i" (defRet1),
02377    [_STKBIT_]   "i" (defCheckStackBit),
02378    [_STKBITb_]  "i" (preBitSet1(0x00,defCheckStackBit)),
02379    [_TIMSKio_]  "i" (_SFR_IO_ADDR(devTIMSK)),
02380    [_TIMSKmem_] "i" (_SFR_MEM_ADDR(devTIMSK)),
02381    [_OCIE0A_]   "i" (devOCIE),
02382    [_OCIE0Ab_]  "i" (preBitSet1(0x00,devOCIE)),
02383    [_nOCIE0Ab_] "i" (preBitClr1(0xFF,devOCIE)),
02384    [_ARB_]      "i" (devAuxSysRegBit),
02385    [_ASR_]      "i" (_SFR_IO_ADDR(devAuxSysReg)));
02386 
02387  #endif
02388 }

Generated on Fri Oct 16 00:05:21 2009 for FemtoOS by  doxygen 1.5.2