📄 ucos.c
字号:
/* * u C / O S . c * * Modified * by Geary Chopoff * for VLSI * * Version October 18, 1994 * Added IRQMboxPost() to post a message from an IRQ * * Version July 27, 1994 * Changed CreateTask so that pdata is passed in a1 (as ARM intended) * * Version July 18, 1994 * Changed ENTER_CRITICAL to OS_ENTER_CRITICAL * Changed EXIT_CRITICAL to OS_EXIT_CRITICAL * * Version July 15, 1994 * Changing OSInit(), removed OSEnter * Added call to InitTask in OSTaskCreate * * Version July 14, 1994 * need to fix IRQ vector (look for ***) * * Version July 13, 1994 * Placed prototypes here * * Version July 12, 1994 * Continuing with effort to bring uC/OS code inline with manual * Removed PIDLED code from OSTimeTick(). * * Version July 11, 1994 * Noted changes between current code and one from manual. * OSIntExit() may have a major flaw as implemented, remember to investigate. * * Version May 9, 1994 * Bringing code closer to manual... * Added comments. * Verified code * * File: os.c * * uC/OS Real-time multitasking kernel for the ARM processor. * * Copyright (C) 1992 Jean J. Labrosse. All rights reserved. * Copyright (C) 1993 VLSI Technology Inc. All rights reserved. * * VLSI Technology Inc. does not assume any liability arising out of * this program or use thereof. * */#define uC_OS#include "ucos.h" /* uC/OS interface */#include "osdefs.h" /* VLSI "OS_STAT_*" values are in here *//* VLSI let's stay on the safe side */#pragma no_check_stack#pragma no_optimise_crossjump#pragma no_optimise_multiple_loads#pragma no_optimise_cse/* * E x t e r n a l F u n c t i o n s */extern void OSStartHighRdy(void); /* kern600 */extern void OSCtxSw(void); /* kern600 */extern void *InitTask(void *pstk, void *pdata, PTV task); /* kern600 *//* * P r o t o t y p e s */void OSInit(void); /* initialize uC/OS */void OSTaskIdle(void *data); /* idle task */void OSStart(void); /* start multitasking */void OSSched(void); /* scheduler */void OSSchedLock(void); /* prevent rescheduling */void OSSchedUnlock(void); /* allow rescheduling */int OSTCBInit(uint prio, void *pstk); /* initialize Task Control Block */void OSIntEnter(void); /* interrupt entered */int OSIntExit(void); /* interrupt exited */int OSTaskChangePrio(uint oldp, uint newp); /* change priority of task */int OSTaskDel(uint p); /* delete a task */void OSTimeDly(uint ticks); /* delay a task */void OSTimeTick(void); /* process a system tick */void OSTimeSet(uint ticks); /* set system time */uint OSTimeGet(void); /* get system time */OS_EVENT *OSSemCreate(int cnt); /* create a semaphore */void OSSemPend(OS_EVENT *pevent, uint timeout, uint *err); /* wait semaphore */uint OSSemPost(OS_EVENT *pevent); /* signal semaphore */OS_EVENT *OSMboxCreate(void *msg); /* create mailbox */void *OSMboxPend(OS_EVENT *pevent, uint timeout, uint *err); /* pend for message */uint OSMboxPost(OS_EVENT *pevent, void *msg); /* post message */OS_EVENT *OSQCreate(void **start, uint size); /* create a queue */void *OSQPend(OS_EVENT *pevent, uint timeout, uint *err); /* pend for message */uint OSQPost(OS_EVENT *pevent, void *msg); /* post a message */void OSEventTaskResume(OS_EVENT *pevent);int OSTaskCreate(PTV task, void *pdata, void *ptsk, uint prio);uint IRQMboxPost(OS_EVENT *pevent, void *msg); /* post message *//* mapping table to map bit position to bit mask */uint const OSMapTbl[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };/* priority resolution table */uint const OSUnMapTbl[] = { 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,};/* * G L O B A L V a r i a b l e s */uint OSCtxSwCtr; /* context switches counter */uint OSIdleCtr; /* Counter used in OSTaskIdle() (idle counter) */uint OSRunning = FALSE; /* kernel running flag */uint OSIntNesting; /* VLSI interrupt nesting level */OS_TCB *OSTCBCur; /* current running TCB pointer */OS_TCB *OSTCBHighRdy; /* highest priority TCB ready to run */OS_TCB *OSTCBPrioTbl[OS_LO_PRIO + 1]; /* GIC 94Jul11 (chg'ed 64 to OS_LO_PRIO+1) table of pointers to created TCBs *//* local variables */static OS_TCB *OSTCBList; /* TCBs are doubled linked list */static uint OSRdyGrp; /* ready list group */static uint OSRdyTbl[MAXbits]; /* GIC 94Jul11 (chg'ed 8 to MAXbits) table of ready to run tasks */static uint OSLockNesting; /* multitasking lock nesting level *//* static UBYTE OSIntNesting *** missing GIC 94Jul11 Interrupt nesting level */static OS_TCB *OSTCBFreeList; /* free TCBs list */static OS_EVENT *OSEventFreeList; /* free EVENT CB list */static OS_Q *OSQFreeList; /* free QUEUE CB list */static uint OSTime; /* system time in ticks *//* static UBYTE OSIntExitY *** missing GIC 94Jul11 Variable used by 'OSIntExit' to prevent using locals */static uint OSIdleStk[OS_IDLE_STK_SIZE]; /* idle task stack */static OS_TCB OSTCBTbl[OS_MAX_TASKS + 1]; /* TCBs table */static OS_EVENT OSEventTbl[OS_MAX_EVENTS]; /* EVENT CBs table */static OS_Q OSQTbl[OS_MAX_QS]; /* QUEUE CBs table */IRQHandlerFn IRQvectors[NUMIRQS]; /* VLSI: IRQ source bit handlers */FIQHandlerFn FIQvectors[NUMFIQS]; /* VLSI: FIQ source bit handlers *//* * O S I n i t * * initialize uC/OS * * NOTE: this function must be called before OSStart() */void OSInit(void){ const void *pZERO = 0; /* need a pointer to value of 0 */ int i; /* initialize variables */ OSTime = 0; /* VLSI, org = 0L */ OSTCBHighRdy = (OS_TCB *)0; OSTCBCur = (OS_TCB *)0; OSTCBList = (OS_TCB *)0; OSIntNesting = 0; OSLockNesting = 0; OSRunning = FALSE; /* VLSI, org = 0 */ OSRdyGrp = 0; OSIdleCtr = 0; /* VLSI, org = 0L */ OSCtxSwCtr = 0; for (i = 0; i < NUMIRQS; i++) /* VLSI - initialise IRQvectors */ IRQvectors[i] = DummyIRQ; for (i = 0; i < NUMFIQS; i++) /* VLSI - initialise FIQvectors */ FIQvectors[i] = DummyFIQ; /* At the moment we do not check that the uC/OS IRQ handler is * attached properly. There is no error return information from * the OSInit function, and all that will happen is that no * interrupts are processed. */ (void)SWI_InstallHandler(0x46,0,IRQHandler) ; /* TODO: uC/OS system FIQ handler to be coded */ for (i = 0; i < MAXbits; i++) /* GIC 94Jul11 chg'ed 8 to MAXbits */ { OSRdyTbl[i] = 0; } for (i = 0; i <= OS_LO_PRIO; i++) /* GIC 94Jul11 chg'ed 64 to OS_LO_PRIO and < to <= */ { OSTCBPrioTbl[i] = (OS_TCB *)0; } for (i = 0; i < OS_MAX_TASKS; i++) /* init list of free TCBs */ { OSTCBTbl[i].OSTCBNext = &OSTCBTbl[i + 1]; } OSTCBTbl[OS_MAX_TASKS].OSTCBNext = (OS_TCB *)0; /* last OS_TCB is for OSTaskIdle() */ OSTCBFreeList = &OSTCBTbl[0]; for (i = 0; i < OS_MAX_EVENTS - 1; i++) /* init list of free EVENT control blocks */ { OSEventTbl[i].OSEventPtr = &OSEventTbl[i + 1]; } OSEventTbl[OS_MAX_EVENTS - 1].OSEventPtr = (OS_EVENT *)0; OSEventFreeList = &OSEventTbl[0]; for (i = 0; i < OS_MAX_QS - 1; i++) /* init list of free QUEUE control blocks */ { OSQTbl[i].OSQPtr = &OSQTbl[i + 1]; } OSQTbl[OS_MAX_QS - 1].OSQPtr = (OS_Q *)0; OSQFreeList = &OSQTbl[0]; /* create the idle task */ OSTaskCreate(OSTaskIdle,(void *)&pZERO, (void *)&OSIdleStk[OS_IDLE_STK_SIZE], OS_LO_PRIO);}/* * O S T a s k I d l e * * idle task */void OSTaskIdle(void *data){ while(FOREVER) { OS_ENTER_CRITICAL(); OSIdleCtr++; OS_EXIT_CRITICAL(); }} /* OSTaskIdle *//* * O S S t a r t * * start multitasking */void OSStart(void){ uint y; uint x; uint p; y = OSUnMapTbl[OSRdyGrp]; /* find the highest priority task */ x = OSUnMapTbl[OSRdyTbl[y]]; p = (y << 3) + x; OSTCBHighRdy = OSTCBPrioTbl[p]; /* point to highest priority task ready to run */ OSRunning = TRUE; /* VLSI org = 1 */ OSStartHighRdy(); /* enable interrupts and run the highest priority task */}/* * O S S c h e d * * uC/OS scheduler */void OSSched(void){ uint y; /* VLSI org is 'register UBYTE y' */ OS_ENTER_CRITICAL(); /* * NOTE: following is a deviation from uC/OS manual. In the manual it * is: * if((OSLockNesting | OSIntNesting) == 0) * GIC 94Jul11 */ if (OSLockNesting == 0 && OSIntNesting == 0) /* VLSI task scheduling enabled and not interrupt level */ { y = OSUnMapTbl[OSRdyGrp]; /* get pointer to highest task ready to run */ OSTCBHighRdy = OSTCBPrioTbl[(y << 3) + OSUnMapTbl[OSRdyTbl[y]]]; if (OSTCBHighRdy != OSTCBCur) /* make sure this is not the current running task */ { OSCtxSwCtr++; /* increment context switch counter */ OSCtxSw(); /* VLSI perform context switch */ /* OS_TASK_SW(); is used in place of previous line *** missing GIC 94Jul11 */ } } OS_EXIT_CRITICAL(); }/* * O S S c h e d L o c k * * prevent scheduling */void OSSchedLock(void){ OS_ENTER_CRITICAL(); OSLockNesting++; /* increment lock nesting level */ OS_EXIT_CRITICAL();}/* * O S S c h e d U n l o c k * * allow scheduling */void OSSchedUnlock(void){/* * NOTE: the following is equivalent to the code in the manual, but different */ OS_ENTER_CRITICAL(); if (OSLockNesting == 0) { OS_EXIT_CRITICAL(); return; } /* ELSE */ OSLockNesting--; if ((OSLockNesting == 0)&&(OSIntNesting == 0)) { OS_EXIT_CRITICAL(); /* scheduling re-enabled and not an ISR */ OSSched(); /* check if a higher priority task became ready */ } else { OS_EXIT_CRITICAL(); }}/* * O S T C B I n i t * * find and initialize a TCB */int OSTCBInit(uint prio, void *pstk){ OS_TCB *ptcb; OS_ENTER_CRITICAL(); ptcb = OSTCBFreeList; /* get a free TCB from TCB free list */ if (ptcb == (OS_TCB *)0) { OS_EXIT_CRITICAL(); /* no TCB available */ return(OS_NO_MORE_TCB); } /* ELSE */ OSTCBFreeList = ptcb->OSTCBNext; /* link to the next free */ OSTCBPrioTbl[prio] = ptcb; ptcb->OSTCBStkPtr = pstk; /* top of private stack */ ptcb->OSTCBPrio = prio; /* task priority */ ptcb->OSTCBStat = OS_STAT_RDY; /* task is ready to run */ ptcb->OSTCBDly = 0; ptcb->OSTCBX = prio & 0x07; ptcb->OSTCBBitX = OSMapTbl[prio & 0x07]; ptcb->OSTCBY = prio >> 3; ptcb->OSTCBBitY = OSMapTbl[prio >> 3]; ptcb->OSTCBEventPtr = (OS_EVENT *)0; ptcb->OSTCBNext = OSTCBList; if (OSTCBList == (OS_TCB *)0) /* GIC chg'ed for clarification */ { ptcb->OSTCBPrev = (OS_TCB *)0; } else { ptcb->OSTCBPrev = ptcb; } OSTCBList = ptcb;/* * NOTE: following needs to be changed if MAXbits is changed from 8 to something else */ OSRdyGrp |= OSMapTbl[prio >> 3]; OSRdyTbl[prio >> 3] |= OSMapTbl[prio & 0x07]; OS_EXIT_CRITICAL(); return(OS_NO_ERR);}/* * O S I n t E n t e r */void OSIntEnter( void ){#if 0 /* the current ARM implementation executes this with interrupts disabled */ OS_ENTER_CRITICAL();#endif OSIntNesting++; /* increment ISR nesting level */#if 0 /* see comment above */ OS_EXIT_CRITICAL();#endif}/* * O S I n t E x i t * * exit from interrupt * */int OSIntExit(void){ uint y;#if 0 /* see comment in OSIntEnter above */ OS_ENTER_CRITICAL();#endif if (--OSIntNesting == 0 && OSLockNesting == 0) /* reschedule if all ISR completed and not locked */ { y = OSUnMapTbl[OSRdyGrp]; OSTCBHighRdy = OSTCBPrioTbl[(y << 3) + OSUnMapTbl[OSRdyTbl[y]]]; if (OSTCBHighRdy == OSTCBCur) /* VLSI */ return(FALSE); /* the highest priority task is the current task */ else return(TRUE); /* signal preemption to IRQTrap */ }#if 0 /* see comment in OSIntEnter above */ OS_EXIT_CRITICAL();#endif return(FALSE);}/* * O S T a s k C h a n g e P r i o * * change task priority * * NOTE: VLSI rearrange the logic so that the ELSE is implied */int OSTaskChangePrio(uint oldp, uint newp){ OS_EVENT *pevent; /* VLSI org prefixed with 'register' */ OS_TCB *ptcb; /* VLSI org prefixed with 'register' */ int rdy; /* VLSI org was type BOOLEAN */ OS_ENTER_CRITICAL(); /* first check that new priority not in use */ if (OSTCBPrioTbl[newp] != (OS_TCB *)0) /* New priority must not already exist */ { OS_EXIT_CRITICAL();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -