| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- #include <stdio.h>
- #include "ucos_ii.h"
- #include "nuclei_sdk_soc.h"
- #include "os_cpu_port.h"
- //#define ENABLE_KERNEL_DEBUG
- #ifdef ENABLE_KERNEL_DEBUG
- #define UCOSII_PORT_DEBUG(...) printf(__VA_ARGS__)
- #else
- #define UCOSII_PORT_DEBUG(...)
- #endif
- #ifndef configASSERT
- #define configASSERT( x )
- #define configASSERT_DEFINED 0
- #else
- #define configASSERT_DEFINED 1
- #endif
- #ifndef configSYSTICK_CLOCK_HZ
- #define configSYSTICK_CLOCK_HZ SOC_TIMER_FREQ
- #endif
- #ifndef configKERNEL_INTERRUPT_PRIORITY
- #define configKERNEL_INTERRUPT_PRIORITY 0
- #endif
- #define SYSTICK_TICK_CONST (configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ)
- /* Constants required to set up the initial stack. */
- #define portINITIAL_MSTATUS ( MSTATUS_MPP | MSTATUS_MPIE | MSTATUS_FS_INITIAL | MSTATUS_VS_INITIAL)
- #define portINITIAL_EXC_RETURN ( 0xfffffffd )
- /* Let the user override the pre-loading of the initial LR with the address of
- prvTaskExitError() in case it messes up unwinding of the stack in the
- debugger. */
- #ifdef configTASK_RETURN_ADDRESS
- #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
- #else
- #define portTASK_RETURN_ADDRESS prvTaskExitError
- #endif
- /*
- * Setup the timer to generate the tick interrupts. The implementation in this
- * file is weak to allow application writers to change the timer used to
- * generate the tick interrupt.
- */
- void vPortSetupTimerInterrupt(void);
- /*
- * Exception handlers.
- */
- #define xPortSysTickHandler irqc_mtip_handler
- /*
- * Start first task is a separate function so it can be tested in isolation.
- */
- extern void prvPortStartFirstTask(void) __attribute__((naked));
- /*
- * Used to catch tasks that attempt to return from their implementing function.
- */
- static void prvTaskExitError(void);
- /*-----------------------------------------------------------*/
- /* Each task maintains its own interrupt status in the critical nesting
- variable. */
- static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
- /*
- * Record the real MTH calculated by the configMAX_SYSCALL_INTERRUPT_PRIORITY
- * The configMAX_SYSCALL_INTERRUPT_PRIORITY is not the left-aligned level value,
- * See equations below:
- * Level Bits number: lvlbits = min(nlbits, CLICINTCTLBITS)
- * Left align Bits number: lfabits = 8-lvlbits
- * 0 < configMAX_SYSCALL_INTERRUPT_PRIORITY <= (2^lvlbits-1)
- * uxMaxSysCallMTH = (configMAX_SYSCALL_INTERRUPT_PRIORITY << lfabits) | ((2^lfabits)-1)
- * If nlbits = 3, CLICINTCTLBITS=3, then lvlbits = 3, lfabits = 5
- * Set configMAX_SYSCALL_INTERRUPT_PRIORITY to 6
- * Then uxMaxSysCallMTH = (6<<5) | (2^5 - 1) = 223
- *
- * See function prvCheckMaxSysCallPrio and prvCalcMaxSysCallMTH
- */
- uint8_t uxMaxSysCallMTH = 255;
- /*-----------------------------------------------------------*/
- /*
- *********************************************************************************************************
- * INITIALIZE A TASK'S STACK
- *
- * Description: This function is called by either OSTaskCreate() or OSTaskCreateExt() to initialize the
- * stack frame of the task being created. This function is highly processor specific.
- *
- * Arguments : task is a pointer to the task code
- *
- * p_arg is a pointer to a user supplied data area that will be passed to the task
- * when the task first executes.
- *
- * p_tos is a pointer to the top of stack. It is assumed that 'ptos' points to
- * a 'free' entry on the task stack. If OS_STK_GROWTH is set to 1 then
- * 'ptos' will contain the HIGHEST valid address of the stack. Similarly, if
- * OS_STK_GROWTH is set to 0, the 'ptos' will contains the LOWEST valid address
- * of the stack.
- *
- * opt specifies options that can be used to alter the behavior of OSTaskStkInit().
- * (see uCOS_II.H for OS_TASK_OPT_xxx).
- *
- * Returns : Always returns the location of the new top-of-stack once the processor registers have
- * been placed on the stack in the proper order.
- *
- * Note(s) : (1) Interrupts are enabled when task starts executing.
- *
- * (2) There is no need to save register x0 since it is a hard-wired zero.
- *
- * (3) RISC-V calling convention register usage:
- *
- * +-------------+-------------+----------------------------------+
- * | Register | ABI Name | Description |
- * +-------------+-------------+----------------------------------+
- * | x31 - x28 | t6 - t3 | Temporaries |
- * +-------------+-------------+----------------------------------+
- * | x27 - x18 | s11 - s2 | Saved registers |
- * +-------------+-------------+----------------------------------+
- * | x17 - x12 | a7 - a2 | Function arguments |
- * +-------------+-------------+----------------------------------+
- * | x11 - x10 | a1 - a0 | Function arguments/return values |
- * +-------------+-------------+----------------------------------+
- * | x9 | s1 | Saved register |
- * +-------------+-------------+----------------------------------+
- * | x8 | s0/fp | Saved register/frame pointer |
- * +-------------+-------------+----------------------------------+
- * | x7 - x5 | t2 - t0 | Temporaries |
- * +-------------+-------------+----------------------------------+
- * | x4 | tp | Thread pointer |
- * +-------------+-------------+----------------------------------+
- * | x3 | gp | Global pointer |
- * +-------------+-------------+----------------------------------+
- * | x2 | sp | Stack pointer |
- * +-------------+-------------+----------------------------------+
- * | x1 | ra | return address |
- * +-------------+-------------+----------------------------------+
- * | x0 | zero | Hard-wired zero |
- * +-------------+-------------+----------------------------------+
- *
- * As per the standard RISC-V ABI pxTopcOfStack is passed in in a0, pxCode in
- * a1, and pvParameters in a2. The new top of stack is passed out in a0.
- *
- * The RISC-V context is saved rtos tasks in the following stack frame,
- * where the global and thread pointers are currently assumed to be constant so
- * are not saved:
- *
- * mstatus
- * #ifndef __riscv_32e
- * rsv1
- * rsv0
- * x31
- * x30
- * x29
- * x28
- * x27
- * x26
- * x25
- * x24
- * x23
- * x22
- * x21
- * x20
- * x19
- * x18
- * x17
- * x16
- * #endif
- * x15
- * x14
- * x13
- * x12
- * x11
- * pvParameters
- * x9
- * x8
- * x7
- * x6
- * x5
- * portTASK_RETURN_ADDRESS
- * pxCode
- */
- OS_STK* OSTaskStkInit(void (*task)(void* pd), void* pdata, OS_STK* ptos, INT16U opt)
- {
- /* Simulate the stack frame as it would be created by a context switch
- interrupt. */
- // Force stack 8byte align for double floating point case
- OS_STK* pxTopOfStack = (OS_STK*)(((unsigned long)ptos) & (~(unsigned long)(portBYTE_ALIGNMENT - 1)));
- /* Offset added to account for the way the MCU uses the stack on entry/exit
- of interrupts, and to ensure alignment. */
- pxTopOfStack--;
- *pxTopOfStack = portINITIAL_MSTATUS; /* MSTATUS */
- /* Save code space by skipping register initialisation. */
- #ifndef __riscv_32e
- pxTopOfStack -= 24; /* X11 - X31. + 2 reserved */
- #else
- pxTopOfStack -= 6; /* X11 - X15. */
- #endif
- *pxTopOfStack = (StackType_t) pdata; /* X10/A0 */
- pxTopOfStack -= 6; /* X5 - X9 */
- *pxTopOfStack = (StackType_t) portTASK_RETURN_ADDRESS; /* RA, X1 */
- pxTopOfStack --;
- *pxTopOfStack = ((StackType_t) task) ; /* PC */
- return pxTopOfStack;
- }
- static void prvTaskExitError(void)
- {
- volatile uint32_t ulDummy = 0;
- /* A function that implements a task must not exit or attempt to return to
- its caller as there is nothing to return to. If a task wants to exit it
- should instead call vTaskDelete( NULL ).
- Artificially force an assert() to be triggered if configASSERT() is
- defined, then stop here so application writers can catch the error. */
- configASSERT(uxCriticalNesting == ~0UL);
- portDISABLE_INTERRUPTS();
- while (ulDummy == 0) {
- /* This file calls prvTaskExitError() after the scheduler has been
- started to remove a compiler warning about the function being defined
- but never called. ulDummy is used purely to quieten other warnings
- about code appearing after this function is called - making ulDummy
- volatile makes the compiler think the function could return and
- therefore not output an 'unreachable code' warning for code that appears
- after it. */
- /* Sleep and wait for interrupt */
- __WFI();
- }
- }
- /*
- * See header file for description.
- */
- void OSStartHighRdy(void)
- {
- __disable_irq();
- /* Start the timer that generates the tick ISR. Interrupts are disabled
- here already. */
- vPortSetupTimerInterrupt();
- /* Initialise the critical nesting count ready for the first task. */
- uxCriticalNesting = 0;
- /* Mark OSRunning to True */
- OSRunning = OS_TRUE;
- #if (OS_CPU_HOOKS_EN > 0) && (OS_TASK_SW_HOOK_EN > 0)
- /* Call OSTaskSwHook */
- OSTaskSwHook();
- #endif
- /* Start the first task. */
- prvPortStartFirstTask();
- /* Should never get here as the tasks will now be executing! Call the task
- exit error function to prevent compiler warnings about a static function
- not being called in the case that the application writer overrides this
- functionality by defining configTASK_RETURN_ADDRESS. */
- prvTaskExitError();
- /* Should not get here! */
- return;
- }
- /*-----------------------------------------------------------*/
- void vPortEndScheduler(void)
- {
- /* Not implemented in ports where there is nothing to return to.
- Artificially force an assert. */
- configASSERT(uxCriticalNesting == 1000UL);
- }
- /*-----------------------------------------------------------*/
- void vPortEnterCritical(void)
- {
- portDISABLE_INTERRUPTS();
- uxCriticalNesting++;
- }
- /*-----------------------------------------------------------*/
- void vPortExitCritical(void)
- {
- configASSERT(uxCriticalNesting);
- uxCriticalNesting--;
- if (uxCriticalNesting == 0) {
- portENABLE_INTERRUPTS();
- }
- }
- /*-----------------------------------------------------------*/
- void vPortAssert(int32_t x)
- {
- if ((x) == 0) {
- portDISABLE_INTERRUPTS();
- while (1) {
- /* Sleep and wait for interrupt */
- __WFI();
- };
- }
- }
- /*-----------------------------------------------------------*/
- void xPortTaskSwitch(void)
- {
- portDISABLE_INTERRUPTS();
- /* Clear Software IRQ, A MUST */
- SysTimer_ClearSWIRQ();
- #if (OS_CPU_HOOKS_EN > 0) && (OS_TASK_SW_HOOK_EN > 0)
- /* Call OSTaskSwHook */
- OSTaskSwHook();
- #endif
- OSPrioCur = OSPrioHighRdy;
- OSTCBCur = OSTCBHighRdy;
- portENABLE_INTERRUPTS();
- }
- /*-----------------------------------------------------------*/
- /*
- *********************************************************************************************************
- * SYS TICK HANDLER
- *
- * Description: Handle the system tick (SysTick) interrupt, which is used to generate the uC/OS-II tick
- * interrupt.
- *
- * Arguments : None.
- *
- * Note(s) : This function is defined with weak linking in 'riscv_hal_stubs.c' so that it can be
- * overridden by the kernel port with same prototype
- *********************************************************************************************************
- */
- __INTERRUPT void xPortSysTickHandler(void)
- {
- #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr;
- #endif
- /* The SysTick runs at the lowest interrupt priority, so when this interrupt
- executes all interrupts must be unmasked. There is therefore no need to
- save and then restore the interrupt mask value as its value is already
- known. */
- OS_ENTER_CRITICAL();
- SysTick_Reload(SYSTICK_TICK_CONST);
- OSIntEnter(); /* Tell uC/OS-II that we are starting an ISR */
- OS_EXIT_CRITICAL();
- OSTimeTick(); /* Call uC/OS-II's OSTimeTick() */
- OSIntExit(); /* Tell uC/OS-II that we are leaving the ISR */
- }
- /*-----------------------------------------------------------*/
- /*
- * Setup the systick timer to generate the tick interrupts at the required
- * frequency.
- */
- __attribute__((weak)) void vPortSetupTimerInterrupt(void)
- {
- TickType_t ticks = SYSTICK_TICK_CONST;
- /* Make SWI and SysTick the lowest priority interrupts. */
- /* Stop and clear the SysTimer. SysTimer as Vector Interrupt */
- SysTick_Config(ticks);
- IRQC_EnableIRQ(SysTimer_IRQn);
- IRQC_EnableIRQ(SysTimerSW_IRQn);
- }
- /*-----------------------------------------------------------*/
|