c - 抢占式调度算法
问题描述
尽管我知道内容切换的概念,但这个程序让我有点困惑。有人可以在下面的片段中具体解释他在做什么吗?
int* multistack = (int*) __get_SP_register();
int i=0; while(i<tasks-1){
int j = stacksize[i]; if (!j) j = 24;
multistack -= j;
*(multistack) = (int) taskpnt[++i]; // prefill in PC
*(multistack-1) = GIE; // prefill in SR
taskstackpnt[i] = (int) multistack-26; // needs 12 dummy push words
}
和
#pragma vector = WDT_VECTOR
__raw __interrupt void taskswitcher(void)
{
asm ("push R15\n push R14\n push R13\n push R12\n"
"push R11\n push R10\n push R9\n push R8\n"
"push R7\n push R6\n push R5\n push R4");
taskstackpnt[taskrun] = __get_SP_register();
if (++taskrun == tasks) taskrun = 0;
__set_SP_register(taskstackpnt[taskrun]);
asm ("pop R4\n pop R5\n pop R6\n pop R7\n"
"pop R8\n pop R9\n pop R10\n pop R11\n"
"pop R12\n pop R13\n pop R14\n pop R15");
}
谢谢。这是完整的代码:
#include "msp430.h"
#include "common.h"
//=========================(C) Tony Philipsson 2016 =======================
funcpnt const taskpnt[]={ task1, task2, task3, // <- PUT YOUR TASKS HERE
};
const int stacksize[tasks] = {28}; // a blank value defaults to 24 stack words
//=========================================================================
int taskstackpnt[tasks];
unsigned int taskdelay[tasks];
char taskrun;
int main( void )
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
if (CALBC1_8MHZ != 0xff){ // erased by mistake?
BCSCTL1 = CALBC1_8MHZ; // Set DCO to factory calibrate 1MHz
DCOCTL = CALDCO_8MHZ;
}
int* multistack = (int*) __get_SP_register();
int i=0; while(i<tasks-1){
int j = stacksize[i]; if (!j) j = 24;
multistack -= j;
*(multistack) = (int) taskpnt[++i]; // prefill in PC
*(multistack-1) = GIE; // prefill in SR
taskstackpnt[i] = (int) multistack-26; // needs 12 dummy push words
}
WDTCTL = WDTPW+WDTTMSEL+WDTCNTCL; // 4ms interval at 8MHz smclk
IE1 |= WDTIE;
__bis_SR_register(GIE);
asm ("br &taskpnt"); // indirect jmp to first task
}
//============= TASK SWITCHER ISR =============
#pragma vector = WDT_VECTOR
__raw __interrupt void taskswitcher(void)
{
asm ("push R15\n push R14\n push R13\n push R12\n"
"push R11\n push R10\n push R9\n push R8\n"
"push R7\n push R6\n push R5\n push R4");
taskstackpnt[taskrun] = __get_SP_register();
if (++taskrun == tasks) taskrun = 0;
__set_SP_register(taskstackpnt[taskrun]);
asm ("pop R4\n pop R5\n pop R6\n pop R7\n"
"pop R8\n pop R9\n pop R10\n pop R11\n"
"pop R12\n pop R13\n pop R14\n pop R15");
}
#include "msp430.h"
#include "common.h"
__task void task1(void){
P1DIR |= BIT0;
while(1){
__delay_cycles(800000);
P1OUT |= BIT0;
__delay_cycles(800000);
P1OUT &=~BIT0;
}
}
#include "msp430.h"
#include "common.h"
__task void task2(void){
P1DIR |= BIT6;
while(1){
__delay_cycles(1200000);
P1OUT |= BIT6;
__delay_cycles(1200000);
P1OUT &=~BIT6;
}
}
#include "msp430.h"
#include "common.h"
unsigned int fibo(int);
__task void task3(void){
int temp = 0;
while(1){
fibo(++temp);
}
}
unsigned int fibo(int n){
if (n < 2)
return n;
else
return (fibo(n-1) + fibo(n-2));
}
#ifndef COMMON_H_
#define COMMON_H_
#define tasks (sizeof(taskpnt)/2)
__task void task1(void);
__task void task2(void);
__task void task3(void);
typedef __task void (*funcpnt)(void);
#endif
解决方案
第一个代码片段为各种任务初始化所有堆栈。
首先将PC保存为任务函数的地址(第一条指令):
*(multistack) = (int) taskpnt[++i];
然后它保存启用 GIE 的状态寄存器(需要正确的任务切换功能):
*(multistack-1) = GIE;
这两个将在调度程序中断结束时由 reti 自动恢复。
还保存了任务的新堆栈指针(包括保存注册表的空间):
taskstackpnt[i] = (int) multistack-26;
第二个片段是调度程序中断本身。
PC和SR在中断调用时由硬件自动保存。在中断代码中,注册表被保存为当前任务:
asm ("push R15\n push R14\n push R13\n push R12\n"
"push R11\n push R10\n push R9\n push R8\n"
"push R7\n push R6\n push R5\n push R4");
然后软件保存当前任务的堆栈指针:
taskstackpnt[taskrun] = __get_SP_register();
并获取下一个任务堆栈指针索引:
if (++taskrun == tasks) taskrun = 0;
然后恢复新的任务堆栈指针:
__set_SP_register(taskstackpnt[taskrun]);
并弹出保存在堆栈中的注册表:
asm ("pop R4\n pop R5\n pop R6\n pop R7\n"
"pop R8\n pop R9\n pop R10\n pop R11\n"
"pop R12\n pop R13\n pop R14\n pop R15");
新任务的 PC 和 SR 由中断的 reti 恢复。
新任务已准备就绪!
推荐阅读
- c++ - 如何解释 GDB 中回溯的模板函数签名?
- kubernetes - 在 Kubernetes 的生产环境中部署 Schema Registry
- formatting - man 可以将选项传递给 roff 格式化程序吗?
- fiware - FIWARE 与 PAS182 有何不同?
- react-native - 执行 react-native run android 时出现问题
- r - R中的正则表达式:匹配节点词的搭配
- vue.js - 使用 VueJS 为用户显示图像 EXIF
- python - 在 Windows 10 中将 Sybase 与 Python 连接起来
- r - 使用条件操作矩阵并连接结果
- python - sql.Identifier 不带引号