port.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /*
  2. * FreeRTOS Kernel <DEVELOPMENT BRANCH>
  3. * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  4. *
  5. * SPDX-License-Identifier: MIT
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  8. * this software and associated documentation files (the "Software"), to deal in
  9. * the Software without restriction, including without limitation the rights to
  10. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  11. * the Software, and to permit persons to whom the Software is furnished to do so,
  12. * subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in all
  15. * copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  19. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  20. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  21. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  22. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. *
  24. * https://www.FreeRTOS.org
  25. * https://github.com/FreeRTOS
  26. *
  27. */
  28. /*-----------------------------------------------------------
  29. * Implementation of functions defined in portable.h for the MicroBlaze port.
  30. *----------------------------------------------------------*/
  31. /* Scheduler includes. */
  32. #include "FreeRTOS.h"
  33. #include "task.h"
  34. /* Standard includes. */
  35. #include <string.h>
  36. /* Hardware includes. */
  37. #include <xintc.h>
  38. #include <xintc_i.h>
  39. #include <xtmrctr.h>
  40. #if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
  41. #error configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 to use this port.
  42. #endif
  43. /* Tasks are started with interrupts enabled. */
  44. #define portINITIAL_MSR_STATE ( ( StackType_t ) 0x02 )
  45. /* Tasks are started with a critical section nesting of 0 - however prior
  46. * to the scheduler being commenced we don't want the critical nesting level
  47. * to reach zero, so it is initialised to a high value. */
  48. #define portINITIAL_NESTING_VALUE ( 0xff )
  49. /* Our hardware setup only uses one counter. */
  50. #define portCOUNTER_0 0
  51. /* The stack used by the ISR is filled with a known value to assist in
  52. * debugging. */
  53. #define portISR_STACK_FILL_VALUE 0x55555555
  54. /* Counts the nesting depth of calls to portENTER_CRITICAL(). Each task
  55. * maintains it's own count, so this variable is saved as part of the task
  56. * context. */
  57. volatile UBaseType_t uxCriticalNesting = portINITIAL_NESTING_VALUE;
  58. /* To limit the amount of stack required by each task, this port uses a
  59. * separate stack for interrupts. */
  60. uint32_t * pulISRStack;
  61. /*-----------------------------------------------------------*/
  62. /*
  63. * Sets up the periodic ISR used for the RTOS tick. This uses timer 0, but
  64. * could have alternatively used the watchdog timer or timer 1.
  65. */
  66. static void prvSetupTimerInterrupt( void );
  67. /*-----------------------------------------------------------*/
  68. /*
  69. * Initialise the stack of a task to look exactly as if a call to
  70. * portSAVE_CONTEXT had been made.
  71. *
  72. * See the header file portable.h.
  73. */
  74. StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
  75. TaskFunction_t pxCode,
  76. void * pvParameters )
  77. {
  78. extern void * _SDA2_BASE_;
  79. extern void * _SDA_BASE_;
  80. const uint32_t ulR2 = ( uint32_t ) &_SDA2_BASE_;
  81. const uint32_t ulR13 = ( uint32_t ) &_SDA_BASE_;
  82. /* Place a few bytes of known values on the bottom of the stack.
  83. * This is essential for the Microblaze port and these lines must
  84. * not be omitted. The parameter value will overwrite the
  85. * 0x22222222 value during the function prologue. */
  86. *pxTopOfStack = ( StackType_t ) 0x11111111;
  87. pxTopOfStack--;
  88. *pxTopOfStack = ( StackType_t ) 0x22222222;
  89. pxTopOfStack--;
  90. *pxTopOfStack = ( StackType_t ) 0x33333333;
  91. pxTopOfStack--;
  92. /* First stack an initial value for the critical section nesting. This
  93. * is initialised to zero as tasks are started with interrupts enabled. */
  94. *pxTopOfStack = ( StackType_t ) 0x00; /* R0. */
  95. /* Place an initial value for all the general purpose registers. */
  96. pxTopOfStack--;
  97. *pxTopOfStack = ( StackType_t ) ulR2; /* R2 - small data area. */
  98. pxTopOfStack--;
  99. *pxTopOfStack = ( StackType_t ) 0x03; /* R3. */
  100. pxTopOfStack--;
  101. *pxTopOfStack = ( StackType_t ) 0x04; /* R4. */
  102. pxTopOfStack--;
  103. *pxTopOfStack = ( StackType_t ) pvParameters; /* R5 contains the function call parameters. */
  104. pxTopOfStack--;
  105. *pxTopOfStack = ( StackType_t ) 0x06; /* R6. */
  106. pxTopOfStack--;
  107. *pxTopOfStack = ( StackType_t ) 0x07; /* R7. */
  108. pxTopOfStack--;
  109. *pxTopOfStack = ( StackType_t ) 0x08; /* R8. */
  110. pxTopOfStack--;
  111. *pxTopOfStack = ( StackType_t ) 0x09; /* R9. */
  112. pxTopOfStack--;
  113. *pxTopOfStack = ( StackType_t ) 0x0a; /* R10. */
  114. pxTopOfStack--;
  115. *pxTopOfStack = ( StackType_t ) 0x0b; /* R11. */
  116. pxTopOfStack--;
  117. *pxTopOfStack = ( StackType_t ) 0x0c; /* R12. */
  118. pxTopOfStack--;
  119. *pxTopOfStack = ( StackType_t ) ulR13; /* R13 - small data read write area. */
  120. pxTopOfStack--;
  121. *pxTopOfStack = ( StackType_t ) pxCode; /* R14. */
  122. pxTopOfStack--;
  123. *pxTopOfStack = ( StackType_t ) 0x0f; /* R15. */
  124. pxTopOfStack--;
  125. *pxTopOfStack = ( StackType_t ) 0x10; /* R16. */
  126. pxTopOfStack--;
  127. *pxTopOfStack = ( StackType_t ) 0x11; /* R17. */
  128. pxTopOfStack--;
  129. *pxTopOfStack = ( StackType_t ) 0x12; /* R18. */
  130. pxTopOfStack--;
  131. *pxTopOfStack = ( StackType_t ) 0x13; /* R19. */
  132. pxTopOfStack--;
  133. *pxTopOfStack = ( StackType_t ) 0x14; /* R20. */
  134. pxTopOfStack--;
  135. *pxTopOfStack = ( StackType_t ) 0x15; /* R21. */
  136. pxTopOfStack--;
  137. *pxTopOfStack = ( StackType_t ) 0x16; /* R22. */
  138. pxTopOfStack--;
  139. *pxTopOfStack = ( StackType_t ) 0x17; /* R23. */
  140. pxTopOfStack--;
  141. *pxTopOfStack = ( StackType_t ) 0x18; /* R24. */
  142. pxTopOfStack--;
  143. *pxTopOfStack = ( StackType_t ) 0x19; /* R25. */
  144. pxTopOfStack--;
  145. *pxTopOfStack = ( StackType_t ) 0x1a; /* R26. */
  146. pxTopOfStack--;
  147. *pxTopOfStack = ( StackType_t ) 0x1b; /* R27. */
  148. pxTopOfStack--;
  149. *pxTopOfStack = ( StackType_t ) 0x1c; /* R28. */
  150. pxTopOfStack--;
  151. *pxTopOfStack = ( StackType_t ) 0x1d; /* R29. */
  152. pxTopOfStack--;
  153. *pxTopOfStack = ( StackType_t ) 0x1e; /* R30. */
  154. pxTopOfStack--;
  155. /* The MSR is stacked between R30 and R31. */
  156. *pxTopOfStack = portINITIAL_MSR_STATE;
  157. pxTopOfStack--;
  158. *pxTopOfStack = ( StackType_t ) 0x1f; /* R31. */
  159. pxTopOfStack--;
  160. /* Return a pointer to the top of the stack we have generated so this can
  161. * be stored in the task control block for the task. */
  162. return pxTopOfStack;
  163. }
  164. /*-----------------------------------------------------------*/
  165. BaseType_t xPortStartScheduler( void )
  166. {
  167. extern void( __FreeRTOS_interrupt_Handler )( void );
  168. extern void( vStartFirstTask )( void );
  169. /* Setup the FreeRTOS interrupt handler. Code copied from crt0.s. */
  170. asm volatile ( "la r6, r0, __FreeRTOS_interrupt_handler \n\t" \
  171. "sw r6, r1, r0 \n\t" \
  172. "lhu r7, r1, r0 \n\t" \
  173. "shi r7, r0, 0x12 \n\t" \
  174. "shi r6, r0, 0x16 " );
  175. /* Setup the hardware to generate the tick. Interrupts are disabled when
  176. * this function is called. */
  177. prvSetupTimerInterrupt();
  178. /* Allocate the stack to be used by the interrupt handler. */
  179. pulISRStack = ( uint32_t * ) pvPortMalloc( configMINIMAL_STACK_SIZE * sizeof( StackType_t ) );
  180. /* Restore the context of the first task that is going to run. */
  181. if( pulISRStack != NULL )
  182. {
  183. /* Fill the ISR stack with a known value to facilitate debugging. */
  184. memset( pulISRStack, portISR_STACK_FILL_VALUE, configMINIMAL_STACK_SIZE * sizeof( StackType_t ) );
  185. pulISRStack += ( configMINIMAL_STACK_SIZE - 1 );
  186. /* Kick off the first task. */
  187. vStartFirstTask();
  188. }
  189. /* Should not get here as the tasks are now running! */
  190. return pdFALSE;
  191. }
  192. /*-----------------------------------------------------------*/
  193. void vPortEndScheduler( void )
  194. {
  195. /* Not implemented. */
  196. }
  197. /*-----------------------------------------------------------*/
  198. /*
  199. * Manual context switch called by portYIELD or taskYIELD.
  200. */
  201. void vPortYield( void )
  202. {
  203. extern void VPortYieldASM( void );
  204. /* Perform the context switch in a critical section to assure it is
  205. * not interrupted by the tick ISR. It is not a problem to do this as
  206. * each task maintains it's own interrupt status. */
  207. portENTER_CRITICAL();
  208. /* Jump directly to the yield function to ensure there is no
  209. * compiler generated prologue code. */
  210. asm volatile ( "bralid r14, VPortYieldASM \n\t" \
  211. "or r0, r0, r0 \n\t" );
  212. portEXIT_CRITICAL();
  213. }
  214. /*-----------------------------------------------------------*/
  215. /*
  216. * Hardware initialisation to generate the RTOS tick.
  217. */
  218. static void prvSetupTimerInterrupt( void )
  219. {
  220. XTmrCtr xTimer;
  221. const uint32_t ulCounterValue = configCPU_CLOCK_HZ / configTICK_RATE_HZ;
  222. UBaseType_t uxMask;
  223. /* The OPB timer1 is used to generate the tick. Use the provided library
  224. * functions to enable the timer and set the tick frequency. */
  225. XTmrCtr_mDisable( XPAR_OPB_TIMER_1_BASEADDR, XPAR_OPB_TIMER_1_DEVICE_ID );
  226. XTmrCtr_Initialize( &xTimer, XPAR_OPB_TIMER_1_DEVICE_ID );
  227. XTmrCtr_mSetLoadReg( XPAR_OPB_TIMER_1_BASEADDR, portCOUNTER_0, ulCounterValue );
  228. XTmrCtr_mSetControlStatusReg( XPAR_OPB_TIMER_1_BASEADDR, portCOUNTER_0, XTC_CSR_LOAD_MASK | XTC_CSR_INT_occurred_MASK );
  229. /* Set the timer interrupt enable bit while maintaining the other bit
  230. * states. */
  231. uxMask = XIntc_In32( ( XPAR_OPB_INTC_0_BASEADDR + XIN_IER_OFFSET ) );
  232. uxMask |= XPAR_OPB_TIMER_1_INTERRUPT_MASK;
  233. XIntc_Out32( ( XPAR_OPB_INTC_0_BASEADDR + XIN_IER_OFFSET ), ( uxMask ) );
  234. XTmrCtr_Start( &xTimer, XPAR_OPB_TIMER_1_DEVICE_ID );
  235. XTmrCtr_mSetControlStatusReg( XPAR_OPB_TIMER_1_BASEADDR, portCOUNTER_0, XTC_CSR_ENABLE_TMR_MASK | XTC_CSR_ENABLE_INT_MASK | XTC_CSR_AUTO_RELOAD_MASK | XTC_CSR_DOWN_COUNT_MASK | XTC_CSR_INT_occurred_MASK );
  236. XIntc_mAckIntr( XPAR_INTC_SINGLE_BASEADDR, 1 );
  237. }
  238. /*-----------------------------------------------------------*/
  239. /*
  240. * The interrupt handler placed in the interrupt vector when the scheduler is
  241. * started. The task context has already been saved when this is called.
  242. * This handler determines the interrupt source and calls the relevant
  243. * peripheral handler.
  244. */
  245. void vTaskISRHandler( void )
  246. {
  247. static uint32_t ulPending;
  248. /* Which interrupts are pending? */
  249. ulPending = XIntc_In32( ( XPAR_INTC_SINGLE_BASEADDR + XIN_IVR_OFFSET ) );
  250. if( ulPending < XPAR_INTC_MAX_NUM_INTR_INPUTS )
  251. {
  252. static XIntc_VectorTableEntry * pxTablePtr;
  253. static XIntc_Config * pxConfig;
  254. static uint32_t ulInterruptMask;
  255. ulInterruptMask = ( uint32_t ) 1 << ulPending;
  256. /* Get the configuration data using the device ID */
  257. pxConfig = &XIntc_ConfigTable[ ( uint32_t ) XPAR_INTC_SINGLE_DEVICE_ID ];
  258. pxTablePtr = &( pxConfig->HandlerTable[ ulPending ] );
  259. if( pxConfig->AckBeforeService & ( ulInterruptMask ) )
  260. {
  261. XIntc_mAckIntr( pxConfig->BaseAddress, ulInterruptMask );
  262. pxTablePtr->Handler( pxTablePtr->CallBackRef );
  263. }
  264. else
  265. {
  266. pxTablePtr->Handler( pxTablePtr->CallBackRef );
  267. XIntc_mAckIntr( pxConfig->BaseAddress, ulInterruptMask );
  268. }
  269. }
  270. }
  271. /*-----------------------------------------------------------*/
  272. /*
  273. * Handler for the timer interrupt.
  274. */
  275. void vTickISR( void * pvBaseAddress )
  276. {
  277. uint32_t ulCSR;
  278. /* Increment the RTOS tick - this might cause a task to unblock. */
  279. if( xTaskIncrementTick() != pdFALSE )
  280. {
  281. vTaskSwitchContext();
  282. }
  283. /* Clear the timer interrupt */
  284. ulCSR = XTmrCtr_mGetControlStatusReg( XPAR_OPB_TIMER_1_BASEADDR, 0 );
  285. XTmrCtr_mSetControlStatusReg( XPAR_OPB_TIMER_1_BASEADDR, portCOUNTER_0, ulCSR );
  286. }
  287. /*-----------------------------------------------------------*/