每个task都要用到栈,下面将task栈独立开来。
注意:
在调度函数中,即这里的TickISR函数不能操作栈,否则就将任务栈弄乱了。 TickISR()函数反汇编发现函数头部有 "push si; push di;",这明显改变了栈,所以要手动加上asm {pop di; pop si;}
代码下载:funnyos_twotask_twostack.zip
调度代码如下:
void TickISR(void) {
static int i = 0; //用到的变量都用static定义,放在堆中,不能使用栈
static int j = 0;
static int mip_task1 = 0;
static int mcs_task1 = 0;
static int meflag_task1 = 0;
static int mip_task2 = 0;
static int mcs_task2 = 0;
static int meflag_task2 = 0;
static int taskid = 0;
static int cnt = 0;
static int tmp;
static int task1_ss;
static int task1_sp;
static int task2_ss;
static int task2_sp;
asm {pop di; pop si;}
asm cli;
//outp(0x20, 0x20);
asm {
push ax;
push dx;
mov dx,0x20;
mov al,0x20;
out dx,al;
mov al,0x0;
pop dx;
pop ax;
}
asm sti;
if(isTask1Start == 0) {
isTask1Start = 1;
asm { //设置任务1的栈底为0x90100
mov tmp, ax;
mov ax, 0x9000;
mov ss, ax;
mov ax, 0x100;
mov sp, ax;
mov ax, tmp;
}
testTask1();
}
else if(isTask2Start == 0) {
taskid = 1;
asm {
push ax; push bx; push cx; push dx; push si; push di; push bp; push ds; push es;
push ss;
push sp;
pop task1_sp;
pop task1_ss;
};
task1_sp += 2;
asm {
mov tmp, ax;//push ax; //设置任务1的栈底为0x80100
mov ax, 0x8000;
mov ss, ax;
mov ax, 0x100;
mov sp, ax;
mov ax, tmp;//pop ax;
}
isTask2Start = 1;
testTask2();
} else if(isTaskAllStart == 0) {
isTaskAllStart = 1;
taskid = 2;
}
if(taskid==1) {
taskid = 2;
//save task1 stack
asm {
push ax; push bx; push cx; push dx; push si; push di; push bp; push ds; push es;
mov task1_sp, sp;
mov task1_ss, ss;
};
//restore task2 stack
asm {
mov tmp, ax;//push ax;
mov ss, task2_ss;
mov sp, task2_sp;
mov ax, tmp;//push ax;
pop es; pop ds; pop bp; pop di; pop si; pop dx; pop cx; pop bx; pop ax;
iret;
}
} else {
taskid = 1;
//save task2 stack
asm {
push ax; push bx; push cx; push dx; push si; push di; push bp; push ds; push es;
mov task2_sp, sp;
mov task2_ss, ss;
};
//restore task1 stack
asm {
mov tmp, ax;//push ax;
mov ss, task1_ss;
mov sp, task1_sp;
mov ax, tmp;//push ax;
pop es; pop ds; pop bp; pop di; pop si; pop dx; pop cx; pop bx; pop ax;
iret;
}
}
//asm iret;
}
每次调度,都先将之前的任务寄存器保存在任务自己的栈中,再将下个任务栈中的寄存器放置CPU中,然后iret即可继续执行下个任务。