A simple RTOS for microcontrollers based upon concepts of FreeRTOS

This file is part of SimpleRTOS2

by Isaac Marino Bavaresco

This is file "SimpleRTOS\PortPIC24dsPIC-C.c"

/*============================================================================*/
/*
SimpleRTOS - Very simple RTOS for Microcontrollers - PIC24/dsPIC port
v2.00 (2014-01-21)
isaacbavaresco@yahoo.com.br
*/
/*============================================================================*/
/*
 Copyright (c) 2007-2014, Isaac Marino Bavaresco
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
     * Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.
     * Neither the name of the author nor the
       names of its contributors may be used to endorse or promote products
       derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY
 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*============================================================================*/
#if         defined __XC16__
/*============================================================================*/
#include <string.h>
#include "PortPIC24dsPIC.h"
#include "SimpleRTOSInternals.h"
/*============================================================================*/
void TickHook( void );
/*============================================================================*/
static void Switch( void )
    {
    IFS0bits.T1IF   = 0;    /* clear the interrupt flag */

    SystemTick++;

    CheckDelayList();

    /* The current task ran for at least one full time slice... */
    if( AlreadySwitched == 0 && CurrentTask->Priority == HighestReadyPriority )
        /* ... it doesn't deserve an additional time slice. */
        ReadyTasks[HighestReadyPriority]
            = ReadyTasks[HighestReadyPriority]->Next;

    CurrentTask         = ReadyTasks[HighestReadyPriority];

    /*
    The upcoming task will run from the very beginning of its time slice,
    at the end of this slice it will be switched off.
    */
    AlreadySwitched     = 0;

    TickHook();
    }
/*============================================================================*/
void ContextInit( context_t *Context, unsigned char *Stack, unsigned long StackSize, void *Parameter, void (*TaskFunc)( void* ), unsigned int Priority )
    {
    unsigned long   FuncAddress;

    memset( Context, 0x00, sizeof( context_t ));

    FuncAddress         = (unsigned short)TaskFunc;

    Context->W0         = (unsigned short)Parameter;
    Context->W15        = (unsigned short)Stack;

    Context->SR         = 0x0000;

    /*
    The IPL bits must be zero for the interrupts to be enabled when the
    task starts.
    */
    Context->SR_IPL3_PC = (( 0 /*SR*/    <<  8 ) & 0xff00 ) |
                          (( CORCON      <<  4 ) & 0x0080 ) |
                          (( FuncAddress >> 16 ) & 0x007f );

    /*
    The SFA bit must be zero on function entry because a call instrustion always
    clears it.
    */
    Context->PC_SFA                 = ( FuncAddress & 0xfffe ) | (( 0 /*CORCON*/ >> 2 ) & 0x0001 );

    Context->SPLIM                  = (unsigned short)Stack + StackSize - 2;
    Context->TBLPAG                 = TBLPAG;

    /*
    The RCOUNT register must be zero on function entry.
    */
    Context->RCOUNT                 = 0;
    Context->CORCON                 = CORCON;


#if         defined __PIC24H__ || defined __PIC24F__ || defined __PIC24FK__

    Context->PSVPAG                 = PSVPAG;

#elif       defined __PIC24E__

    Context->DSRPAG                 = DSRPAG;
    Context->DSWPAG                 = DSWPAG;

#endif  /*  defined __PIC24H__ || defined __PIC24F__ || defined __PIC24FK__ */

    Context->Priority               = Priority;
    Context->TDelay                 = 0;
    Context->PreviousDelayedTask    = 0;
    Context->NextDelayedTask        = 0;
    Context->DelayList              = 0;

    #ifdef      USE_SLICE_LENGTH
        Context->SliceLength        = 0;
    #endif  /*  USE_SLICE_LENGTH */

    Context->Previous               = 0;
    Context->Next                   = 0;
    Context->List                   = 0;
    }
/*============================================================================*/
void InitRTOS( context_t *ctxts, int Number )
    {
    unsigned int i;

    /* No contexts to be initialized... The RTOS is useless.*/
    if( ctxts == NULL || Number == 0 )
        {
        FreeContexts        = NULL;
        return;
        }

    CurrentTask     = ctxts;

    for( i = 0; i < MAX_PRIORITIES; i++ )
        ReadyTasks[i]   = NULL;

    /*------------------------------------------------------------------------*/
    /* Initialize all contexts and link them to the free contexts list.*/
    FreeContexts        = ctxts;
    for( i = 0; i < Number - 1; i++, ctxts++ )
        {
        ctxts->Next = ctxts + 1;
        ctxts->List = &FreeContexts;
        }
    ctxts->Next     = NULL;
    ctxts->List     = &FreeContexts;

    /*------------------------------------------------------------------------*/
    }
/*============================================================================*/
static void __attribute__((naked)) SaveContext( void )
    {
    /*------------------------------------------------------------------------*/
    asm volatile(
        "push.w     W4                  \n"
        "mov.w      _CurrentTask,W4     \n"
        "mov.w      W0,[W4+0]           \n"
        "pop.w      W0                  \n"
        "mov.w      W0,[W4+8]           \n"

        "mov.w      W1,[W4+2]           \n"
        "mov.w      W2,[W4+4]           \n"
        "mov.w      W3,[W4+6]           \n"

        "mov.w      W5,[W4+10]          \n"
        "mov.w      W6,[W4+12]          \n"
        "mov.w      W7,[W4+14]          \n"
        "mov.w      W8,[W4+16]          \n"
        "mov.w      W9,[W4+18]          \n"
        "mov.w      W10,[W4+20]         \n"
        "mov.w      W11,[W4+22]         \n"
        "mov.w      W12,[W4+24]         \n"
        "mov.w      W13,[W4+26]         \n"
        "mov.w      W14,[W4+28]         \n"

        "mov.w      SR,W0               \n"
        "mov.w      W0,[W4+32]          \n"
        );

    asm volatile(
        "pop.s                          \n"
        "mov.w      W0,[W4+34]          \n"
        "mov.w      W1,[W4+36]          \n"
        "mov.w      W2,[W4+38]          \n"
        "mov.w      W3,[W4+40]          \n"
        "mov.w      SR,W0               \n"
        "mov.w      W0,[W4+42]          \n"
        );

    asm volatile(
        "mov.w      [W15-6],W0          \n"
        "mov.w      W0,[W4+44]          \n"
        "mov.w      [W15-8],W0          \n"
        "mov.w      W0,[W4+46]          \n"

        "sub.w      W15,#8,W0           \n"
        "mov.w      W0,[W4+30]          \n"

        "mov.w      SPLIM,W0            \n"
        "mov.w      W0,[W4+48]          \n"
        "mov.w      TBLPAG,W0           \n"
        "mov.w      W0,[W4+50]          \n"
        "mov.w      RCOUNT,W0           \n"
        "mov.w      W0,[W4+52]          \n"
        "mov.w      CORCON,W0           \n"
        "mov.w      W0,[W4+54]          \n"
        );

        /*--------------------------------------------------------------------*/

#if         defined __dsPIC30F__ || defined __dsPIC33F__
    asm volatile(
        "mov.w      PSVPAG,W0           \n"
        "mov.w      W0,[W4+56]          \n"
        );
#elif       defined __dsPIC33E__
    asm volatile(
        "mov.w      DSRPAG,W0           \n"
        "mov.w      W0,[W4+56]          \n"
        "mov.w      DSWPAG,W0           \n"
        "mov.w      W0,[W4+58]          \n"
        );
#endif  /*  defined __dsPIC30F__ || defined __dsPIC33F__ */

        /*--------------------------------------------------------------------*/
        /* Específicos dsPIC                                                  */
        /*--------------------------------------------------------------------*/

#if         defined __dsPIC30F__ || defined __dsPIC33F__ || defined __dsPIC33E__

    asm volatile(

        "mov.w      ACCAL,W0            \n"
        "mov.w      W0,[W4+60]          \n"
        "mov.w      ACCAH,W0            \n"
        "mov.w      W0,[W4+62]          \n"
        "mov.w      ACCAU,W0            \n"
        "mov.w      W0,[W4+64]          \n"
        "mov.w      ACCBL,W0            \n"
        "mov.w      W0,[W4+66]          \n"
        "mov.w      ACCBH,W0            \n"
        "mov.w      W0,[W4+68]          \n"
        "mov.w      ACCBU,W0            \n"
        "mov.w      W0,[W4+70]          \n"
        );

    asm volatile(

    /* Save DO vars */
        "mov.w      DCOUNT,W0           \n"
        "mov.w      W0,[W4+72]          \n"
        "mov.w      DOENDL,W0           \n"
        "mov.w      W0,[W4+74]          \n"
        "mov.w      DOENDH,W0           \n"
        "mov.w      W0,[W4+76]          \n"
        "mov.w      DOSTARTL,W0         \n"
        "mov.w      W0,[W4+78]          \n"
        "mov.w      DOSTARTH,W0         \n"
        "mov.w      W0,[W4+80]          \n"

    /* DL > 0 ? */
        "mov.b      [W4+55],W2          \n"
        "and.w      #7,W2               \n"
        "bra        z,JumpX             \n"
        );

    asm volatile(

    /* Abort DO */
        "mov.w      #tbloffset(Label1),W0   \n"
        "mov.w      W0,DOSTARTL             \n"
        "mov.w      #tblpage(Label1),W0     \n"
        "mov.w      W0,DOSTARTH             \n"
        "mov.w      #tbloffset(Label2),W0   \n"
        "mov.w      W0,DOENDL               \n"
        "mov.w      #tblpage(Label2),W0     \n"
        "mov.w      W0,DOENDH               \n"

        "mov.w      #1,W2                   \n"

"Label1:                                    \n"
        "mov.w      W2,DCOUNT               \n"
        "bset.w     CORCON,#11              \n"
"Label2: nop                                \n"

    /* DL > 0 ? */
        "btss.w     SR,#9                   \n"
        "bra        JumpX                   \n"
        );

    /* Save DO shadows */
    asm volatile(
        "mov.w      DCOUNT,W0           \n"
        "mov.w      W0,[W4+82]          \n"
        "mov.w      DOENDL,W0           \n"
        "mov.w      W0,[W4+84]          \n"
        "mov.w      DOENDH,W0           \n"
        "mov.w      W0,[W4+86]          \n"
        "mov.w      DOSTARTL,W0         \n"
        "mov.w      W0,[W4+88]          \n"
        "mov.w      DOSTARTH,W0         \n"
        "mov.w      W0,[W4+90]          \n"

    /* Abort DO */
        "bset.w     CORCON,#11          \n"
"JumpX:                                 \n"
        );

#endif  /*  defined __dsPIC30F__ || defined __dsPIC33F__ || defined __dsPIC33E__ */
        /*--------------------------------------------------------------------*/
    }
/*============================================================================*/
static void __attribute__((naked)) RestoreContext( void )
    {
    asm volatile(
        "mov.w      _CurrentTask,W4     \n"
        );

        /*--------------------------------------------------------------------*/
        /* Específicos dsPIC                                                  */
        /*--------------------------------------------------------------------*/

#if         defined __dsPIC30F__ || defined __dsPIC33F__ || defined __dsPIC33E__

    asm volatile(

    /* DL > 0 ? */
        "mov.b      [W4+45],W2          \n"
        "and.w      #7,W2               \n"
        "bra        z,JumpA             \n"

    /* DL > 1 ? */
        "dec.w      W2,W0               \n"
        "bra        z,JumpB             \n"

    /* Start DO */
        "do         #1,Label0           \n"

    /* DL = DL - 1 */
        "dec.w      W2,W2               \n"
        );

    /* Restore DO shadows */
    asm volatile(
        "mov.w      [W4+90],W0          \n"
        "mov.w      W0,DOSTARTH         \n"
        "mov.w      [W4+88],W0          \n"
        "mov.w      W0,DOSTARTL         \n"
        "mov.w      [W4+86],W0          \n"
        "mov.w      W0,DOENDH           \n"
        "mov.w      [W4+84],W0          \n"
        "mov.w      W0,DOENDL           \n"
        "mov.w      [W4+82],W0          \n"
        "mov.w      W0,DCOUNT           \n"
        );

    asm volatile(

"JumpB:                                 \n"

    /* Start DO */
        "do         #1,Label0           \n"

    /* DL = DL - 1 */
        "dec.w      W2,W2               \n"

    /* DL > 0 ? */
        "bra        nz,JumpB            \n"

"JumpA:                                 \n"
    /* Restore DO vars */

        "mov.w      [W4+80],W0          \n"
        "mov.w      W0,DOSTARTH         \n"
        "mov.w      [W4+78],W0          \n"
        "mov.w      W0,DOSTARTL         \n"
        "mov.w      [W4+76],W0          \n"
        "mov.w      W0,DOENDH           \n"
        "mov.w      [W4+74],W0          \n"
        "mov.w      W0,DOENDL           \n"
        "mov.w      [W4+72],W0          \n"
"Label0: mov.w      W0,DCOUNT           \n"
        );

    /* Restore DSP accumulators */
    asm volatile(
        "mov.w      [W4+70],W0          \n"
        "mov.w      W0,ACCBU            \n"
        "mov.w      [W4+68],W0          \n"
        "mov.w      W0,ACCBH            \n"
        "mov.w      [W4+66],W0          \n"
        "mov.w      W0,ACCBL            \n"
        "mov.w      [W4+64],W0          \n"
        "mov.w      W0,ACCAU            \n"
        "mov.w      [W4+62],W0          \n"
        "mov.w      W0,ACCAH            \n"
        "mov.w      [W4+60],W0          \n"
        "mov.w      W0,ACCAL            \n"
        );

#endif  /*  defined __dsPIC30F__ || defined __dsPIC33F__ || defined __dsPIC33E__ */

        /*--------------------------------------------------------------------*/

        /* Restore program space visibility registers */

#if         defined __dsPIC30F__ || defined __dsPIC33F__

    asm volatile(
        "mov.w      [W4+56],W0          \n"
        "mov.w      W0,PSVPAG           \n"
        );

#elif       defined __dsPIC33E__

    asm volatile(
        "mov.w      [W4+58],W0          \n"
        "mov.w      W0,DSWPAG           \n"
        "mov.w      [W4+56],W0          \n"
        "mov.w      W0,DSRPAG           \n"
        );

#endif  /*  defined __dsPIC30F__ || defined __dsPIC33F__ */

        /*--------------------------------------------------------------------*/

    /* Restore core control registers */
    asm volatile(
        "mov.w      [W4+54],W0          \n"
        "mov.w      W0,CORCON           \n"
        "mov.w      [W4+52],W0          \n"
        "mov.w      W0,RCOUNT           \n"
        "mov.w      [W4+50],W0          \n"
        "mov.w      W0,TBLPAG           \n"
        "mov.w      [W4+48],W0          \n"
        "mov.w      W0,SPLIM            \n"

        "mov.w      [W4+30],W15         \n"

        "mov.w      [W4+46],W0          \n"
        "push.w     W0                  \n"
        "mov.w      [W4+44],W0          \n"
        "push.w     W0                  \n"
        );

    /* Restore shadow registers */
    asm volatile(
        "mov.w      [W4+42],W0          \n"
        "mov.w      W0,SR               \n"
        "mov.w      [W4+40],W3          \n"
        "mov.w      [W4+38],W2          \n"
        "mov.w      [W4+36],W1          \n"
        "mov.w      [W4+34],W0          \n"
        "push.s                         \n"
        );

    /* Restore main registers */
    asm volatile(
        "mov.b      [W4+33],W0          \n"
        "mov.b      WREG,0x0043         \n"

        "mov.w      [W4+28],W14         \n"
        "mov.w      [W4+26],W13         \n"
        "mov.w      [W4+24],W12         \n"
        "mov.w      [W4+22],W11         \n"
        "mov.w      [W4+20],W10         \n"
        "mov.w      [W4+18],W9          \n"
        "mov.w      [W4+16],W8          \n"
        "mov.w      [W4+14],W7          \n"
        "mov.w      [W4+12],W6          \n"
        "mov.w      [W4+10],W5          \n"

        "mov.w      [W4+6],W3           \n"
        "mov.w      [W4+4],W2           \n"
        "mov.w      [W4+2],W1           \n"

        "mov.w      [W4+0],W0           \n"
        "mov.w      [W4+8],W4           \n"

        "retfie                         \n"
        );
    }
/*============================================================================*/
void __attribute__((noreturn)) StartRTOS( tickcount_t TickPeriod )
    {
    SystemTick      = 0;
    CurrentTask     = ReadyTasks[HighestReadyPriority];

    PR1             = TickPeriod;
    TMR1            = 0;
    T1CON           = 0x8000;

    IFS0bits.T1IF   = 0;
    IEC0bits.T1IE   = 1;

    SR             |= 0x00e0;

    INTCON1         = 0x0000;
    INTCON2         = 0x8000;

    RestoreContext();

    while( 1 )
        {}
    }
/*============================================================================*/
void __attribute__((interrupt,naked,auto_psv)) _T1Interrupt( void )
    {
    /*------------------------------------------------------------------------*/
    SaveContext();

    Switch();

    /*
    Doing it this way to save stack and also because some dsPICs and PIC24 execute
    'bra' and 'goto' faster than 'call' or 'rcall'. We are not returnig from here
    anyway.
    */
    asm volatile(
        "bra        _RestoreContext \n"
         );
    /*------------------------------------------------------------------------*/
    }
/*============================================================================*/
#if         defined __DEBUG

void T2Handler( void );

void __attribute__((interrupt,naked,auto_psv)) _T2Interrupt( void )
    {
    /*------------------------------------------------------------------------*/
    SaveContext();

    T2Handler();

    /*
    Doing it this way to save stack and also because some dsPICs and PIC24 execute
    'bra' and 'goto' faster than 'call' or 'rcall'. We are not returnig from here
    anyway.
    */
    asm volatile(
        "bra        _RestoreContext \n"
         );
    /*------------------------------------------------------------------------*/
    }

#endif  /*  defined __DEBUG */
/*============================================================================*/
void __attribute__((naked)) ForceYield( void )
    {
    /*------------------------------------------------------------------------*/
    /*
    Transform the return address to a form suitable for
    a 'retfie' instruction.
    */
    asm volatile(
        "mov.b      SR,WREG             \n"
        "mov.b      W0,[W15-1]          \n"
        );

    SaveContext();

    CurrentTask = ReadyTasks[HighestReadyPriority];

    /*
    Doing it this way to save stack and also because some dsPICs and PIC24 execute
    'bra' and 'goto' faster than 'call' or 'rcall'. We are not returnig from here
    anyway.
    */
    asm volatile(
        "bra        _RestoreContext \n"
         );
    /*------------------------------------------------------------------------*/
    }
/*============================================================================*/
void __attribute__((naked)) HigherPriorityAwakened( void )
    {
    CurrentTask = ReadyTasks[HighestReadyPriority];

    /*
    Doing it this way to save stack and also because some dsPICs and PIC24 execute
    'bra' and 'goto' faster than 'call' or 'rcall'. We are not returnig from here
    anyway.
    */
    asm volatile(
        "bra        _RestoreContext \n"
         );
    }
/*============================================================================*/
#endif  /*  defined __XC16__ */
/*============================================================================*/

void dummy( void );