/** * ####################################################################################### * GAYE Abdoulaye Walsimou, * Copyright(C) 2009 GAYE Abdoulaye walsimou, . All rights reserved. * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License * (Version 2 or later) published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. * ####################################################################################### * * \file portmacro.h * \brief portmacro.h for PIC18 SDCC port as required for FreeRTOS * \brief It is based on existing PIC18 port. * \author GAYE Abdoulaye Walsimou, * \date february 2009 * ####################################################################################### */ #ifndef PORTMACRO_H #define PORTMACRO_H #include #include /*----------------------------------------------------------- * Port specific definitions. * * The settings in this file configure FreeRTOS correctly for the * given hardware and compiler. * * These settings should not be altered. *----------------------------------------------------------- */ /* Type definitions. */ #define portCHAR char #define portFLOAT float #define portDOUBLE double #define portLONG long #define portINT int #define portSHORT short #define portSTACK_TYPE __data unsigned char #define portBASE_TYPE char /* Some memory areas get saved as part of the task context. These memory area's get used by the compiler for temporary storage, especially when performing mathematical operations, or when using 32bit data types. This constant defines the size of memory area which must be saved. */ #define portCOMPILER_MANAGED_MEMORY_SIZE ((unsigned portCHAR)20) #if( configUSE_16_BIT_TICKS == 1 ) typedef unsigned portSHORT portTickType; #define portMAX_DELAY ( portTickType ) 0xffff #else typedef unsigned portLONG portTickType; #define portMAX_DELAY ( portTickType ) 0xffffffff #endif /*-----------------------------------------------------------*/ /* Hardware specifics. */ #define portBYTE_ALIGNMENT 1 #define portGLOBAL_INT_ENABLE_BIT 0x80 #define portSTACK_GROWTH -1 #define portTICK_RATE_MS (1000/configTICK_RATE_HZ) /*-----------------------------------------------------------*/ /* * Critical section management. */ #define portDISABLE_INTERRUPTS() INTCONbits.GIE = 0 #define portENABLE_INTERRUPTS() INTCONbits.GIE = 1 /* Push the INTCON register onto the stack, then disable interrupts. */ #define portENTER_CRITICAL() POSTDEC1 = INTCON; portDISABLE_INTERRUPTS() /* Retrieve the INTCON register from the stack, and enable interrupts if they were saved as being enabled. Don't modify any other bits within the INTCON register as these may have lagitimately have been modified within the critical region. */ #define portEXIT_CRITICAL() \ _asm \ MOVF PREINC1, 1, 0; \ _endasm; \ if(INDF1&portGLOBAL_INT_ENABLE_BIT) \ { \ portENABLE_INTERRUPTS(); \ } /*-----------------------------------------------------------*/ /* Task utilities. */ extern void vPortYield( void ) __naked; #define portYIELD() vPortYield() /*-----------------------------------------------------------*/ /* Task function macros as described on the FreeRTOS.org WEB site. */ #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) /*-----------------------------------------------------------*/ /* Required by the kernel aware debugger. */ #ifdef __DEBUG #define portREMOVE_STATIC_QUALIFIER #endif #define portNOP() Nop() /* * portSAVE_CONTEXT(ucForcedInterruptFlags): * Macro that pushes all the registers that make up the context of a task onto * the stack, then saves the new top of stack into the TCB. * * If this is called from an ISR then the interrupt enable bits must have been * set for the ISR to ever get called. Therefore we want to save the INTCON * register with the enable bits forced to be set - and ucForcedInterruptFlags * must contain these bit settings. This means the interrupts will again be * enabled when the interrupted task is switched back in. * * If this is called from a manual context switch (i.e. from a call to yield), * then we want to save the INTCON so it is restored with its current state, * and ucForcedInterruptFlags must be 0. This allows a yield from within * a critical section. * * The compiler uses some locations at the bottom of the memory for temporary * storage during math and other computations. This is especially true if * 32bit data types are utilised (as they are by the scheduler). The .registers * section have to be stored in there entirety as part of a task context. * This macro stores from data address 0x00 to portCOMPILER_MANAGED_MEMORY_SIZE. * This is sufficient for the demo applications but you should check the map file * for your project to ensure this is sufficient for your needs. * It is not clear whether this size is fixed for all compilations or has the * potential to be program specific. */ #pragma preproc_asm - #define portSAVE_CONTEXT_GLOBAL_REGISTERS() _asm ;Save the status and WREG registers first, as these will get modified ;by the operations below. MOVFF WREG,POSTDEC1 MOVFF STATUS,POSTDEC1 _endasm #pragma preproc_asm + #pragma preproc_asm - #define portSAVE_CONTEXT_HW_REGISTERS() _asm ;Store the necessary hardware registers to the stack. MOVFF BSR,POSTDEC1 MOVFF FSR2L,POSTDEC1 MOVFF FSR2H,POSTDEC1 MOVFF FSR0L,POSTDEC1 MOVFF FSR0H,POSTDEC1 MOVFF TABLAT,POSTDEC1 MOVFF TBLPTRL,POSTDEC1 MOVFF TBLPTRH,POSTDEC1 MOVFF TBLPTRU,POSTDEC1 MOVFF PRODL,POSTDEC1 MOVFF PRODH,POSTDEC1 MOVFF PCLATH,POSTDEC1 MOVFF PCLATU,POSTDEC1 _endasm #pragma preproc_asm + #pragma preproc_asm - #define portSAVE_CONTEXT_DOT_REGISTERS_START() _asm ;Start to store .registers areas as described above. CLRF FSR0L,ACCESS CLRF FSR0H,ACCESS _endasm #pragma preproc_asm + #pragma preproc_asm - #define portSAVE_CONTEXT_DOT_REGISTERS_END() _asm ;End store .registers areas as described above. MOVFF INDF0,POSTDEC1 MOVFF FSR0L,POSTDEC1 MOVFF FSR0H,POSTDEC1 ;Store the hardware stack pointer in a temp register (FSR0L) before we ;modify it. MOVFF STKPTR,FSR0L _endasm #pragma preproc_asm + #pragma preproc_asm - #define portSAVE_CONTEXT_HWSTACK() _asm MOVFF TOSL,POSTDEC1 MOVFF TOSH,POSTDEC1 MOVFF TOSU,POSTDEC1 POP _endasm #pragma preproc_asm + #pragma preproc_asm - #define portSAVE_CONTEXT_END() _asm ;Store the number of addresses on the hardware stack (from the ;temporary register). MOVFF FSR0L,POSTDEC1 ;Save the new top of the software stack in the TCB. MOVFF _pxCurrentTCB,FSR0L MOVFF _pxCurrentTCB+1,FSR0H MOVFF FSR1L,POSTINC0 MOVFF FSR1H,POSTINC0 _endasm #pragma preproc_asm + #define portSAVE_CONTEXT(ucForcedInterruptFlags) \ { \ portSAVE_CONTEXT_GLOBAL_REGISTERS(); \ _asm \ MOVFF INTCON,WREG \ _endasm; \ _asm \ IORLW ucForcedInterruptFlags \ _endasm; \ _asm \ MOVFF WREG,POSTDEC1 \ _endasm; \ portDISABLE_INTERRUPTS(); \ portSAVE_CONTEXT_HW_REGISTERS(); \ portSAVE_CONTEXT_DOT_REGISTERS_START(); \ while(FSR0L<(unsigned portCHAR)(portCOMPILER_MANAGED_MEMORY_SIZE-1)) \ { \ _asm \ MOVFF POSTINC0,POSTDEC1 \ _endasm; \ } \ portSAVE_CONTEXT_DOT_REGISTERS_END(); \ while(STKPTR>(unsigned portCHAR)0) \ { \ portSAVE_CONTEXT_HWSTACK(); \ } \ portSAVE_CONTEXT_END(); \ } /*-----------------------------------------------------------*/ /* * portRESTORE_CONTEXT(): * This is the reverse of portSAVE_CONTEXT. See portSAVE_CONTEXT for more * details. */ #pragma preproc_asm - #define portRESTORE_CONTEXT_GET_PXCURRENTTCB() _asm ;Set FSR0 to point to pxCurrentTCB. MOVFF _pxCurrentTCB,FSR0L MOVFF _pxCurrentTCB+1,FSR0H ;De-reference FSR0 to set the address it holds into FSR1. ;(i.e. pxCurrentTCB->pxTopOfStack) MOVFF POSTINC0,FSR1L MOVFF POSTINC0,FSR1H _endasm #pragma preproc_asm + #pragma preproc_asm - #define portRESTORE_CONTEXT_GET_STACKDEPTH() _asm ;How many return addresses are there on the hardware stack? MOVFF PREINC1, FSR0L ;(Above FSR0L is used as temp register.) _endasm #pragma preproc_asm + #pragma preproc_asm - #define portRESTORE_CONTEXT_FILL_HWSTACK() _asm PUSH MOVF PREINC1,0,ACCESS MOVWF TOSU,ACCESS MOVF PREINC1,0,ACCESS MOVWF TOSH,ACCESS MOVF PREINC1,0,ACCESS MOVWF TOSL,ACCESS _endasm #pragma preproc_asm + #pragma preproc_asm - #define portRESTORE_CONTEXT_DOT_REGISTERS_START() _asm ;Start to restore the .registers section. MOVFF PREINC1,FSR0H MOVFF PREINC1,FSR0L ;Use WREG as temp register CLRF FSR2L,ACCESS _endasm #pragma preproc_asm + #pragma preproc_asm - #define portRESTORE_CONTEXT_DOT_REGISTERS_END() _asm ;End to restore the .registers section. MOVFF PREINC1,INDF0 _endasm #pragma preproc_asm + #pragma preproc_asm - #define portRESTORE_CONTEXT_HW_REGISTERS() _asm ;Restore the other registers forming the tasks context. MOVFF PREINC1, PCLATU MOVFF PREINC1, PCLATH MOVFF PREINC1, PRODH MOVFF PREINC1, PRODL MOVFF PREINC1, TBLPTRU MOVFF PREINC1, TBLPTRH MOVFF PREINC1, TBLPTRL MOVFF PREINC1, TABLAT MOVFF PREINC1, FSR0H MOVFF PREINC1, FSR0L MOVFF PREINC1, FSR2H MOVFF PREINC1, FSR2L MOVFF PREINC1, BSR ;The next byte is the INTCON register. Read this into WREG as some ;manipulation is required. MOVFF PREINC1, WREG _endasm #pragma preproc_asm + #pragma preproc_asm - #define portRESTORE_CONTEXT_RETFIE() _asm ;From the INTCON register, only the interrupt enable bits form part ;of the tasks context. It is perfectly legitimate for another task to ;have modified any other bits. We therefore only restore the top two bits. MOVFF PREINC1, STATUS MOVFF PREINC1, WREG ;Return enabling interrupts. RETFIE 0 _endasm #pragma preproc_asm + #pragma preproc_asm - #define portRESTORE_CONTEXT_RETURN() _asm MOVFF PREINC1, STATUS MOVFF PREINC1, W ;Return without effecting interrupts. The context may have ;been saved from a critical region. RETURN 0 _endasm #pragma preproc_asm + #define portRESTORE_CONTEXT() \ { \ portRESTORE_CONTEXT_GET_PXCURRENTTCB(); \ portRESTORE_CONTEXT_GET_STACKDEPTH(); \ STKPTR = 0; \ while( STKPTR < FSR0L) \ { \ portRESTORE_CONTEXT_FILL_HWSTACK(); \ } \ portRESTORE_CONTEXT_DOT_REGISTERS_START(); \ while(FSR2L<(unsigned portCHAR)(portCOMPILER_MANAGED_MEMORY_SIZE-1)) \ { \ _asm \ MOVFF PREINC1,POSTDEC0 \ _endasm; \ _asm \ INCF FSR2L,F,ACCESS \ _endasm; \ } \ portRESTORE_CONTEXT_DOT_REGISTERS_END(); \ portRESTORE_CONTEXT_HW_REGISTERS(); \ if(WREG & portGLOBAL_INTERRUPT_FLAG) \ { \ portRESTORE_CONTEXT_RETFIE(); \ } \ else \ { \ portRESTORE_CONTEXT_RETURN(); \ } \ } #endif /*PORTMACRO_H*/