每个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即可继续执行下个任务。