📄 kernel.c
字号:
{
//在中断通知处理中或者CPU锁定状态不允许禁止分发器//
if (INEST > 0 || SYSSTAT == TSS_LOC)
{
return E_CTX; //返回系统调用无效//
}
SYSSTAT = TSS_DDSP; //系统状态设定为禁止分发器状态//
return E_OK; //系统调用正常返回//
}
void _ena_dsp(void)
{
//在中断通知处理中或者CPU锁定状态不允许使能分发器//
if (INEST > 0 || SYSSTAT == TSS_LOC)
{
*USP = E_CTX; //返回系统调用无效//
return;
}
SYSSTAT = TSS_TSK; //系统状态设定为任务状态//
*USP = E_OK; //系统调用正常返回//
dispatch(); //激活分发器//
}
ER _loc_cpu(void)
{
//在中断通知处理中不允许锁定CPU//
if (INEST > 0)
{
return E_CTX; //返回系统调用无效//
}
SYSSTAT = TSS_LOC; //系统状态设定为CPU锁定状态//
return E_OK; //系统调用正常返回//
}
void _unl_cpu(void)
{
//在中断通知处理中不允许解锁CPU//
if (INEST > 0)
{
*USP = E_CTX; //返回系统调用无效//
return;
}
SYSSTAT = TSS_TSK; //系统状态设定为任务状态//
*USP = E_OK; //系统调用正常返回//
dispatch(); //激活分发器//
}
ER _iwup_tsk( ID tskid )
{
T_TCB *tcb; //指向任务TCB的临时指针//
//判断任务ID是否大于任务ID的最大值//
if (tskid > TSKID_MAX)
{
return E_NOEXS; //返回任务不存在//
}
//在中断通知处理中,TSK_SELF是无效的//
if (tskid == TSK_SELF)
{
//是TSK_SELF,返回//
return E_OBJ;
}
tcb = &TCB[tskid]; //通过任务ID得到任务的TCB//
//不能唤醒DORMANT状态的任务//
if (tcb->tskstat == TTS_DMT)
{
//要唤醒的任务是DORMANT状态,返回//
return E_OBJ;
}
//要唤醒的任务如果处在等待状态,并且是由于调用了tsk_slp(itsk_slp)//
//怎唤醒该任务,否则//
if (tcb->tskstat == TTS_WAI && tcb->tskwait == TTW_SLP)
{
//将要唤醒的任务状态改为Ready状态//
tcb->tskstat = TTS_RDY;
//将任务的TCB添加到Ready对列//
add_que( &RDQ[tcb->tskpri], tcb );
//调用slp_tsk时,将PC,FLG,FB,SB,A1,A0,R3,R2,R1,R0压入任务堆栈//
//tcb->sp为任务堆栈的栈顶指针//
//*(tcb->sp)为R0//
//任务唤醒后,R0中存放返回值//
*(tcb->sp) = E_OK; //等待唤醒的任务继续运行时的返回值为正常返回//
DELAY = SET; //设置调度器延时状态//
//iwup_tsk正常结束返回//
return E_OK;
}
else
{
//唤醒请求计数器是一个16位有符号值,最大值为32767//
//判断唤醒请求计数器是否溢出//
if (tcb->wupcnt < INT_MAX)
{
tcb->wupcnt ++; //唤醒请求计数器递增//
/*iwup_tsk正常结束返回*/
return E_OK;
}
else
{
/*唤醒请求计数器发生溢出错误,返回溢出错误状态*/
return E_QOVR;
}
}
}
void _slp_tsk(void)
{
//在中断通知处理或者分发器禁止状态不允许调用此系统调用//
if (INEST > 0 || SYSSTAT >= TSS_DDSP)
{
//返回错误状态//
//Context error (issued from task-independent portions or a task in dispatch disabled state)
*USP = E_CTX; //USP为中断時SP値,*USP为R0的值//
return;
}
//如果当前任务的唤醒请求计数器>0,则任务不进入等待状态//
if (RUNTCB->wupcnt > 0)
{
RUNTCB->wupcnt --; //唤醒请求计数器递减//
*USP = E_OK; //系统调用正常结束//
return;
}
//当前任务的唤醒请求计数器为0,任务进入等待状态//
else
{
RUNTCB->tskstat = TTS_WAI; //任务状态设为等待状态//
RUNTCB->tskwait = TTW_SLP; //等待模式为SLP//
//将当前任务的TCB从Ready对列中删除//
del_que( &RDQ[RUNTCB->tskpri], RUNTCB );
//调用分发器,运行其它任务//
dispatch();
return;
}
}
void _wup_tsk( ID tskid )
{
T_TCB *tcb; //指向任务TCB的临时指针//
//判断任务ID是否大于任务ID的最大值//
if (tskid > TSKID_MAX)
{
*USP = E_NOEXS; //返回任务ID不存在//
return;
}
//当前任务不能唤醒自身,只能唤醒其他任务//
//判断是否为任务自身//
if (tskid == TSK_SELF || tskid == RUNTCB->tskid)
{
//是当前任务,返回//
*USP = E_OBJ; //无效对象//
return;
}
tcb = &TCB[tskid]; //通过任务ID得到任务的TCB//
//不能唤醒DORMANT状态的任务//
if (tcb->tskstat == TTS_DMT)
{
//要唤醒的任务是DORMANT状态,返回//
*USP = E_OBJ; //无效对象//
return;
}
//要唤醒的任务如果处在等待状态,并且是由于调用了tsk_slp(itsk_slp)//
//怎唤醒该任务,否则//
if (tcb->tskstat == TTS_WAI && tcb->tskwait == TTW_SLP)
{
//将要唤醒的任务状态改为Ready状态//
tcb->tskstat = TTS_RDY;
//将任务的TCB添加到Ready对列//
add_que( &RDQ[tcb->tskpri], tcb );
//调用slp_tsk时,将PC,FLG,FB,SB,A1,A0,R3,R2,R1,R0压入任务堆栈//
//tcb->sp为任务堆栈的栈顶指针//
//*(tcb->sp)为R0//
//任务唤醒后,R0中存放返回值//
*(tcb->sp) = E_OK;
//wup_tsk的返回值用堆栈返回//
*USP = E_OK;
//调用分发器,调度任务//
dispatch();
return;
}
else
{
//唤醒请求计数器是一个16位有符号值,最大值为32767//
//判断唤醒请求计数器是否溢出//
if (tcb->wupcnt < INT_MAX)
{
tcb->wupcnt ++; //唤醒请求计数器递增//
//wup_tsk正常结束返回//
*USP = E_OK;
return;
}
else
{
//唤醒请求计数器发生溢出错误,返回溢出错误状态//
*USP = E_QOVR;
return;
}
}
}
ER _ista_tsk(ID tskid, INT stacd)
{
T_TCB *tcb; //指向任务TCB的临时指针//
UINT data;
//判断任务ID是否大于任务ID的最大值//
if (tskid > TSKID_MAX)
{
return E_NOEXS; //返回任务不存在//
}
tcb = &TCB[tskid]; //通过任务ID得到任务的TCB//
//只能启动DORMANT状态的任务//
if (tcb->tskstat != TTS_DMT)
{
//要启动的任务不是DORMANT状态,返回//
return E_OBJ;
}
//将任务状态改为Ready状态//
tcb->tskstat = TTS_RDY;
//设置任务的优先级//
tcb->tskpri = pri_tbl[tskid];
//设置任务堆栈指针
//任务启动前堆栈内容为:FLG,PC,FB,SB,A1,A0,R3,R2,R1,R0//
//nc30的堆栈生长方向为递减//
tcb->sp = (INT*)sp_tbl[tskid] - CTXSIZ;
//任务的唤醒请求计数器清零//
tcb->wupcnt = 0;
//设置任务的起始地址//
data = (UINT)stad_tbl[tskid]; //起始地址的低0~15位放到sp_tbl[tskid]-2//
*(sp_tbl[tskid]-2) = data;
data = (UINT)(stad_tbl[tskid] >> 8) & 0x0f00; //起始地址的16~20低位放到sp_tbl[tskid]-1的8~11位//
data |= INIFLG; //标志寄存器的0~7低位放到sp_tbl[tskid]-1的0~7位//
*(sp_tbl[tskid] - 1) = data; //标志寄存器的12~15低位放到sp_tbl[tskid]-1的12~15位//
//标志寄存器的8~11不保存//
*((tcb->sp)+1) = stacd; //将任务的参数放到R1寄存器内//
add_que(&RDQ[tcb->tskpri], tcb); //将启动的任务加入Ready对列//
DELAY = SET; //设置调度器延时状态//
return E_OK; //正常返回//
}
void main(void)
{
ID id;
//RTOS初始化(TCB,SEM,MBX)//
sysini();
//启动任务//
for(id=1; id<TSKID_MAX+1; id++)
{
_ista_tsk(id, DUMMY); //通过带i的系统调用不激活分发器//
}
//系统定时器的初始化//
systimini();
//开始多任务系统//
syssta(); //此函数模拟一次中断,永远不会返回//
}
void sysini(void)
{
ID id;
//初始化任务的TCB//
for(id=1; id<TSKID_MAX+1; id++)
{
TCB[id].tskid = id;
TCB[id].tskstat = TTS_DMT; //初始任务为Dormant状态//
}
//初始化信号量//
for(id=1; id<SEMID_MAX+1; id++)
{
SEM[id].cnt = semcnt_tbl[id]; //设定信号量的初始值//
}
//初始化邮箱//
for(id=1; id<MBXID_MAX+1; id++)
{
//初始化邮箱消息指针//
MBX[id].msghead = msgq_tbl[id];
MBX[id].msgtail = msgq_tbl[id];
}
DELAY = CLR; //清除调度器延时状态//
INEST = 0; //中断嵌套清零//
SYSSTAT = TSS_LOC; //系统状态设为CPU加锁状态//
UIPL = 0; //中断允许级别设为零//
}
void _syssta(void)
{
RUNTCB = &TCB[1]; //将第一个任务设为当前运行的任务//
USP = TCB[1].sp; //设置当前的用户堆栈指针//
SYSSTAT = TSS_TSK; //设置当前CPU状态为:正常状态,任务状态//
dispatch(); //调用分发器//
}
void systimini(void)
{
ta0mr = 0x80;
ta0ic = (UB)(0x07 & SYSTIM_IPL); //设定定时器的中断优先级//
ta0 = (UINT)(SYSTIM_CNT - 1); //设定计时时间//
tabsr = 0x01; //开始计数//
}
void add_que(T_TCB **head, T_TCB *addtcb)
{
//判断链表是否为空//
if(*head == NULL)
{
addtcb->prev = addtcb; //前向指针指向自身//
addtcb->next = addtcb; //后向指针指向自身//
*head = addtcb; //头节点指向添加的节点//
}
else
{ //定义并取得T_TCB的头,尾节点指针//
T_TCB *toptcb = *head;
T_TCB *endtcb = toptcb->prev;
//建立next单链//
endtcb->next = addtcb;
addtcb->next = toptcb;
//建立prev单链//
addtcb->prev = endtcb;
toptcb->prev = addtcb;
}
}
void del_que(T_TCB **head, T_TCB *deltcb)
{
//定义并获取删除节点的前后T_TCB节点指针//
T_TCB *prevtcb = deltcb->prev;
T_TCB *nexttcb = deltcb->next;
//如果链表中只有一个节点则清空链表//
if(deltcb == nexttcb)
{
*head = NULL; //清空链表//
}
else
{
//从双向链表中摘除//
prevtcb->next = nexttcb;
nexttcb->prev = prevtcb;
//如果删除的是头节点则头节点依次向下指//
if(deltcb == *head)
{
*head = nexttcb; //头节点指向下一个节点//
}
}
}
void dispatch(void)
{
T_TCB **rdq = &RDQ[1]; //指向最高优先级的队列头,itron规范不使用RDQ[0]//
//在分发器禁止状态要将分发器调度延时//
if (SYSSTAT >= TSS_DDSP)
{
DELAY = SET; //设置调度器延时状态//
return;
}
DELAY = CLR; //清除调度器延时状态//
//在Ready队列中查找优先级最高的任务//
while (*rdq == NULL) //*rdq = NULL,说明当前的优先级没有就绪的任务//
{
rdq++; //指向下一个就绪任务的TCB
}
RUNTCB->sp = USP; //保存当前任务堆栈//
RUNTCB = *rdq; //更改当前运行任务的TCB//
USP = RUNTCB->sp; //恢复新任务的任务堆栈指针//
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -