手里有一块ADSP21469的开发板,于是想把μc/os移植上去
SHARC系列处理器是32/40位浮点处理器,每一个通用寄存器可以配置为32位或者40位,在硬件上,这些通用(计算用)寄存器是40位的,而与寻址相关的M0-M15 I0-I15 B0-B15和L0-L15都是32位的
同时,SHARC还是单指令集多数据架构的处理器,所以对于第一个处理单元EPx来说,有通用计算寄存器(这些寄存器不能用于寻址,赋值给Mx或者Ix才能寻址)R0-R15,对于第二个处理单元来说有S0-S15,也就是用同样的并行取地址或者计算指令,可以同时处理两组32位数据,通用寄存器在进行浮点运算时,只要改变指令中的寄存器对应名称R4-F4 S8-SF8就可以进行硬件浮点运算,具体的运算指令这里不做详细说明。
通常I6 I7指令用来保存堆栈的栈底和栈入口指针,M5=0 M6=1 M7=-1 用来做入栈出栈时的地址偏移量,这些寄存器在进行复杂多数据运算如FFT FIR滤波器时可以加快运算速度和减少寻址开销。
我们来计算一下我们需要保存的上下文数量,以32位单指令多数据结构来说有Rx(16)+Sx(16)+Ix(16)+Mx(16)+Bx(16)+Lx(16)+MODE1(全局控制寄存器)+ASTAT(计算状态寄存器)
这仅仅是没有中断的情况下,已经有98个寄存器了,如果进入中断(μc/os的切换是在TICK中断服务中进行的,所以中断中的状况也要保存)
SHARC的中断会自动设置MODE1中的备用寄存器位,这两个位设置后经过两个时钟周期,会切换上述所有通用寄存器和寻址寄存器,共有96个,同时将PC压栈如硬件PC栈,将重要的寄存器ATSTX和ASTATY和MODE1压入硬件状态栈,这样我们就需要压栈96*2个寄存器,再加上从PC栈中弹栈压栈,从状态寄存器中弹栈压栈(虽然这些都可以做到,可是地址寄存器不能直接被保存到内存中,必须经由通用寄存器,这样就消耗了两个时钟周期)
这相对于ARM只保存R0-R15再加上计算状态寄存器的上下文切换开销来说,确实有点大。并且占用过多的RAM资源。
400M的时钟周期,一次的切换可能会消耗几百个周期。对于DSP来说,进行多任务运算的应用场合较少,对于雷达接收机之类的运算量奇大的设备,通常是多片DSP联合使用完成同一项运算任务,很少需要用到操作系统和任务切换。
在任务切换的中断服务中,保存上下文环境的步骤是:
1.保存R0'-R15',I1'-I15',M0'-M15' B0'-B15' L0'-L15'我将任务环境堆栈指针放在I0寄存器中,并保证以后的操作不会用到I0寄存器,只有在任务切换,恢复上下文环境时才从当前TCB中的指针读取I0的值
2.保存pcstk中的PC值,这个是程序从当前tick中断退出时跳转到的PC
3.保存status stk中的MODE1和ASTAT寄存器值,保存I0'到TCB栈
4.修改MODE1中的寄存器选择标志位SRRFH和SRRFL将Rx'和Rx交换
5.弹出I0'到I0,重复第一步,保存程序在非中断状态下的上下文环境(Rx Ix Mx Bx Lx)
6.保存I0到TCB中
切换操作系统中的两个参数 OSTCBCur = OSTCBHighRdy;OSPrioCur = OSPrioHighRdy;
1.从TCB栈中获取I0值
2.恢复上下文环境
3.入TCB栈I0,修改MODE1标志位切换寄存器
4.弹出硬件堆栈中的值并将值赋给硬件Pcstk和status stk
5.从TCB栈恢复I0值,恢复中断中的上下文
注1:系统程序初始化时,有一个用来存局部变量的任务栈,放在I6和I7处,I6是栈底I7是入栈指针,在进入子程序时使用,使用指令为
R2=i6;i6=i7;jump(pc,x);DM(i7,m7)=r2;DM(i7,m7)=PC;
保存子程序在返回时主程序的堆栈栈底和返回的PC值,并将栈顶变栈底,用来做子程序的堆栈
子函数使用rts返回主程序
而中断使用rti返回,并且返回pcstk硬件堆栈中的pc值,中断子程序也会将堆栈底下移至入栈口,并保存重要的上下文到堆栈的头几个地址内
注2:TCB中OSTCBStkPtr指向的上下文栈,操作系统使用,初始化这个栈的时候要给其中的I6 I7和I6'
I7’赋值注1中的栈,这个栈的大小在初始化时就已经确定了
注3:硬件栈pcstk和statu不需要分配内存,是硬件栈,只在中断服务中才会使用到
sharc的片上ram是很小的只有5M所以想要分配大一点的内存是不妥当的,当我想要多建立几个task时编译器就会报错,所以我实验时只创建了3个task,每个task的堆栈为2048。
阅读(2011) | 评论(0) | 转发(0) |