好了我们前面已经建立了移植ucos-II所需的目录,很整齐是吧,现在开始了移植中艰难的一段旅程,需要修改ucos-II的部分代码,主要是port目录下的,这个目录下的文件才是和移植有关的,要修改这么几个方面:
第三步:修改port/os_cpu_a.S,去掉如下代码:
.section .text,"ax",@progbits
.set noreorder
.set noat
在OSStartHighRdy()函数之前添加如下代码,小伙伴们很容易可以看出这是异常向量入口区域,0x0地址是复位异常处理地址,0x20是中断处理地址,0x40是其余异常处理地址:
/* 添加下面的stack section */
.section .stack, "aw", @nobits
.space 0x10000
/* 添加下面的异常向量处理区域 */
.section .vectors, "ax"
.org 0x0
_reset:
lui $28,0x0
la $29,_stack_addr
la $26,main /* 寄存器$26、$27留给中断、异常的处理程序使用 */
jr $26
nop
.org 0x20
/* 中断处理例程入口地址 */
la $26,InterruptHandler
jr $26
nop
.org 0x40
/* 异常处理例程入口地址 */
la $26,ExceptionHandler
jr $26
nop
/* 下面的是text段,可执行 */
.section .text,"ax",@progbits
.set noreorder
.set noat
第四步:修改port/os_cpu_a.S,去掉OSStartHighRdy函数的第2-6条指令,这几条指令是与新的MIPS ISA(MIPS M14K采用的就是新的MIPS ISA)有关的,OpenMIPS不需要这些代码,如下:
addu $9, $31, $0 /* Mask off the ISAMode bit */
srl $9, 16
andi $31, 0xFFFE
sll $9, 16
addu $31, $31, $9
去掉OSStartHighRdy函数的倒数第三条指令,即ei指令,该指令的作用是使能中断,OpenMIPS采取的策略是恢复下一个Task的中断状态,所以此处不用刻意使能中断,如下:
ei
第五步:修改port/os_cpu_a.S,去掉OSIntCtxSw函数的第2-6条指令,理由同第四步一样,如下:
addu $9, $31, $0 /* Mask off the ISAMode bit */
srl $9, 16
andi $31, 0xFFFE
sll $9, 16
addu $31, $31, $9
去掉OSIntCtxSw函数的倒数第二条指令,即ei指令,如下:
ei
这是和第四步一样的。
第六步:修改port/os_cpu_a.S,修改OS_CPU_SR_Save函数,原函数如下:
.ent OS_CPU_SR_Save
OS_CPU_SR_Save:
jr $31
di $2 /* Disable interrupts, and move the old value of the... */
/* ...Status register into v0 ($2) */
.end OS_CPU_SR_Save
修改为如下,主要还是替换掉di指令,这个中断禁止指令在MIPSr2指令集中才定义,OpenMISP不支持该指令:
.ent OS_CPU_SR_Save
OS_CPU_SR_Save:
/*将di指令使用下面5条MIPS32中定义的指令代替 */
ori $2,$2,0x0
mfc0 $2,$12,0
addi $3,$0,0xfffe
and $3,$2,$3
mtc0 $3,$12,0
jr $31
nop
.end OS_CPU_SR_Save
第七步:修改port/os_cpu_a.S,去掉对timer_handler这个section的定义,OpenMIPS采用的向量中断方式,所以不再单独定义timer_handler这个section,如下,去掉该代码:
.section .timer_handler,"ax",@progbits
第八步:修改port/os_cpu_a.S,修改其中InterruptHandler函数,去掉其第一条di指令,这条指令的作用是禁止中断,但是当OpenMIPS进入中断处理函数InterruptHandler时,已经由硬件禁止中断了,不需要多此一步,而且di指令也不是OpenMIPS支持的指令。
还要去掉InterruptHandler函数中的如下代码,共出现两次,都要去掉,这几条指令是与新的MIPS ISA(MIPS M14K采用的就是新的MIPS ISA)有关的,OpenMIPS不需要这些代码:
addu $9, $31, $0 /* Mask off the ISAMode bit */
srl $9, 16
andi $31, 0xFFFE
sll $9, 16
addu $31, $31, $9
去掉InterruptHandler函数倒数第二条指令,即去掉如下代码,理由同第四步一样:
ei /* Enable Interrupts */
第九步:修改port/os_cpu_a.S,去掉对gen_excpt这个section的定义,不需要该section,即去掉如下代码:
section .gen_excpt,"ax",@progbits
第十步:修改port/os_cpu_a.S,去掉ExceptionHandler函数的第一条指令,即di指令,这条指令的作用是禁止中断,但是当OpenMIPS进入异常处理函数ExceptionHandler时,已经由硬件禁止中断了,不需要多这一步,而且di指令也不是OpenMIPS支持的指令:
还要去掉ExceptionHandler函数中的如下代码,这几条指令是与新的MIPS ISA(MIPS M14K采用的就是新的MIPS ISA)有关的,OpenMIPS不需要这些代码:
addu $9, $31, $0 /* Mask off the ISAMode bit */
srl $9, 16
andi $31, 0xFFFE
sll $9, 16
addu $31, $31, $9
去掉ExceptionHandler函数倒数第二条指令,即去掉如下代码,理由同第四步一样::
ei /* Enable Interrupts */
第十一步:修改TickISR函数,增加对$8、$9寄存器压栈、出栈的过程,因为在TickISR中使用到了$8、$9寄存器的值,所以要将其先保存到堆栈中,然后再使用,TickISR结束之前,将其从堆栈恢复,如下:
.ent TickISR
TickISR:
addiu $29,$29,-24 /* $29中存放的是堆栈指针 */
sw $16, 0x4($29) /* 压栈 */
sw $8, 0x8($29) /* 压栈 */
……
lw $16, 0x4($29) /* 出栈 */
lw $8, 0x8($29) /* 出栈 */
addiu $29,$29,24
jr $31
nop
.end TickISR
去掉TickISR函数中的如下代码,这几条指令是与新的MIPS ISA(MIPS M14K采用的就是新的MIPS ISA)有关的,OpenMIPS不需要这些代码:
addu $9, $31, $0 /* Mask off the ISAMode bit */
srl $9, 16
andi $31, 0xFFFE
sll $9, 16
addu $31, $31, $9
第十二步:修改port/ os_cpu_c.c文件,去掉开始的如下代码,这两个宏定义没有作用:
extern char vec[], endvec[]; /* Create the hardware interrupt vector */
asm (".set push\n"
".set nomicromips\n"
".align 2\n"
"vec:\n"
"\tla $26,InterruptHandler\n"
"\tjr $26\n"
"endvec:\n"
".set pop\n");
extern char vec2[], endvec2[]; /* Create the exception vector */
asm (".set push\n"
".set nomicromips\n"
".align 2\n"
"vec2:\n"
"\tla $26,ExceptionHandler\n"
"\tjr $26\n"
"endvec2:\n"
".set pop\n");
第十二步:修改port/ os_cpu_c.c文件,将OSInitHookBegin函数的内容清空,如下:
void OSInitHookBegin (void)
{
}
第十三步:修改port/ os_cpu_c.c文件,修改OSTaskStkInit函数,将其中的如下代码:
sr_val |= 0x0000C001; /* Initialize stack to allow for tick interrupt */
改为:
sr_val |= 0x0000C401; /* Initialize stack to allow for tick interrupt */
因为在OpenMIPS中,时钟中断对应的是外部中断2。
第十四步:修改port/ os_cpu_c.c文件,添加中断处理函数,如下,首先得到CP0中Cause寄存器的值,然后判断是否是时钟中断引起的,也就是判断第10bit的值是否为1,如果是时钟中断,那么调用TickISR,该函数是时钟中断处理函数,最后清除Cause寄存器的时钟中断表示位,也就是第10bit为0。
void BSP_Interrupt_Handler (void)
{
INT32U cause_val;
INT32U cause_reg;
INT32U cause_ip;
asm ("mfc0 %0,$13" : "=r"(cause_val));
cause_reg = cause_val; /* 得到Exc Code */
cause_ip = cause_reg & 0x0000FF00;
if((cause_ip & 0x00000400) != 0 )
{
TickISR(0x0);
asm ("mfc0 %0,$13" : "=r"(cause_val));
cause_val = cause_val & 0xfffffbff;
asm volatile("mtc0 %0,$13" : : "r"(cause_val));
}
}
第十五步:修改port/ os_cpu_c.c文件,添加异常处理函数,如下,首先得到CP0中Cause寄存器的值,然后分别判断是否由syscall指令、自陷指令、无效指令引起的,此处不对这些异常进行处理,只是简单地调用OSIntCtxSw函数,进行Task切换。
void BSP_Exception_Handler (void)
{
INT32U cause_val;
INT32U cause_exccode;
INT32U EPC;
asm volatile("mfc0 %0,$13" : "=r"(cause_val));
cause_exccode = (cause_val & 0x0000007C); /* 得到Exc Code */
if(cause_exccode == 0x00000020 ) /* 判断是否是由于syscall指令引起 */
{
OSIntCtxSw();
}
else if(cause_exccode == 0x00000034) /* 判断是否是由于Txx指令引起 */
{
OSIntCtxSw();
}
else if(cause_exccode == 0x00000028)
/* 判断是否是由于invalid instruction引起 */
{
asm volatile("mfc0 %0,$14" : "=r"(EPC));
}
}