MPC860的中断处理技术研究
摘要:MPC860是网络通信设备中应用最广的一款RISC嵌入式处理器。本文介绍MPC860的中断体系结果及中断发生后服务程序的处理流程;以SMC1的接收中断为例,阐述在设计操作系统管理的条件下,中断初始化程序和中断服务程序的编写。
关键词:嵌入式处理器 MPC860 中断体系结构 中断处理技术
引言
Motorola公司推出的MPC860 PowerQUICC是目前在通信领域应用得非常广泛的一款嵌入式处理器,被誉为MC68360 PowerQUICC在网络和数据通信领域的新一代产品。与MC68360相比,MPC860 PowerQUICC在各方面的性能,包括器件的适应性、外部扩展能力和芯片集成度等都得到了提高。
MPC860PowerQUICC(简称MPC860)内部集成了两个处理单元。一个处理单元是嵌入的PowerPC核(PowerPCCore)。它是主处理单元(CPU),包括Cache和内存管理单元;是一个RISC芯片,通常编译后的程序指令都是由它执行。另一个是通信处理模块CPM(Communications Processor Module),内部也集成了一个RISC微处理器,对各种常用的通信模块进行管理。通信处理模块内部集成有4个串行通信控制器SCC(Serial Communication Controller)、2个串行管理控制器SMC(Serial Management Channels)、1个串行外围接口电路SPI(Serial Peripheral Interface)和1个I2C(Inter-Integrtaed Circuit)接口。两个处理单元之间的数据通常使用DMA方式传送。由于CPM分担了嵌入式PowerPC核的外围工作任务,这种双处理器体系结构极大减轻了CPU的工作负荷,而且功耗也要低于传统体系结构的处理器。另外,在MPC860中还有一个系统接口单元SIU(System Interface Unit),主要功能是提供内外总线的接口及一些其它功能(如SIU中断)的管理等。
由于MPC860的体系与通用的X86体系结构有很大的不同,其中断体系结构和处理机制也有自己的特点,使得它的中断管理及中断服务程序成为系统移植和应用中的难点。本文将对MPC860的中断体系结构和中断应用程序的编写进行介绍。
1 MPC860中断体系结构
与MPC860的两个处理单元相对应,对于CPM产生的中断,也有两级处理过程。整个MPC860的中断体系结构如图1所示。
从图1可以看出,MPC860的整个中断体系结构有3个模块:PowerPC核、SIU中断控制器SIU IC(SIU Interrupt Controller)和CPM中断控制器CPMIC(CPM Interrupt Controller)。
PowerPC Core是指令执行单元,使用异常(Exception)的目的就是要打断它的正常执行,使它转入处理紧急事件的异常处理程序中执行。对于每一类异常,异常发生后PowerPC跳转执行的位置是不同的。这些不同的位置组成了一个表――异常向量表。不同类型的异常在异常向量表中的偏移量不同。例如系统重启异常在异常向量表中的偏移量是0x100,机器自检异常的偏移量是0x200,而外部中断在异常向量表中的偏移量是0x500等等。
SIU中断控制器负责管理8个外部中断源(IRQ0~7)和8个内部中断源(Leve10~7),结构如图2的示。其中IRQ0一般用作不可屏蔽中断,通过NMI向PowerPC内核请求中断,其余15个通过IREQ请求中断。对于8个内部中断源,包括周期性的中断时钟(PIT)、实时时钟(RTC)、PCMCIA以及CPM等,用户可以通过对寄存器的操作,把它们设定为Leve10~7中的任何一级。这16个中断源之间的优先级SIU IC已经设定了。其中IRQ0的优先级最高,Leve10其次,依此类推,Leve17的优先级最低。
在SIU IC进行SIU中断处理时,有几个重要的寄存器与之相关的。它们是中断悬挂寄存器SIPEND、中断屏蔽寄存器SIMASK和中断向量寄存器SIVEC。
CPM中断控制器是对SIU中断控制器的下一级扩展。它管理通信处理模块的各个中断源,并向SIU IC申请中断处理,其结构如图3所示。CPIC接收12个外部中断源和17个内部中断源的中断请求,经过屏蔽和判优处理后,把中断请求送往SIU中断控制器。通过设置CPIC的配置寄存器,CPM在SIU IC中的优先级可以是Leve10~7中的任何一级,并且所有的CPM中断源都将以这个优先级向SIU申请中断。在CPM IC内部,它也为每个中断源分配了一个中断向量号,并且分配了不同的优先级,还可以编程设定哪个中断源为最高优先级。
在CPM的中断源中,如果一个中断源有多个子功能可以产生中断请求,并且每一项子功能的中断请求都可以屏蔽,那么这个中断源称为子块可屏蔽中断。例如,对串行管理通道SMI(Serial Management Channels),每一个SMC有一个事件寄存器SMCE和一个屏蔽寄存器SMCM,具体定义如图4所示。用户可以通过对SMCM进行编程,屏蔽掉某项子功能的中断请求功能。假如用户要使用中断接收功能,就应该置位SMCM的RX位以打开接收中断。在中断服务程序中还要读取SMCE,以判断是哪个子功能产生的中断。如果SMCE的RX位已被置位,就表明产生了接收中断,应进入接收中断处理函数。
CPM IC中提供了一些可编程寄存器。通过对这些寄存器进行设置,可以设定CPM IC的工作方式。这些寄存器分别是CPM中断配置寄存器CICR、CPM中断屏蔽寄存器CIMR、CPM中断向量寄存器CIVR、CPM中断是挂寄存器CIPR和CPM中断服务寄存器CISR。
2 编写MPC860中断应用程序
编写MPC860中断应用程序主要有两个方面的内容:一个是中断初始化程序,另一个是中断服务程序。
对于外部中断,PowerPC内核接收到中断请求信号后,会转入异常向量表中的外部中断偏移地址处(0x500)执行。这一段最大长度为256个字节的代码,也可以说是SIU中断的服务程序。在中断初始化程序中,还必须把SIU中断服务程序放到正确的位置。
中断服务程序是中断产生后自动跳转执行的程序,它对中断进行处理。对于其中比较复杂的CPM中断,它有两级处理程序,分别是SIU中断服务程序和CPM中断服务程序。中断服务程序的处理流程如图5所示。
在SIU中断服务程序中,要读取产生SIU中断有中断向量号,根据中断向量号判断中断源,然后跳转到对各个中断源处理的服务程序中执行。如果读到的中断向量号对应的是CPM,要转入CPM中断服务程序中执行。CPM又有29个中断源,每个中断源对应不同CPM中断向量号。在CPM中断服务程序中,也要读取CPM中断向量号,然后根据中断向量号调用对应的中断处理程序。这样,所有的CPM中断源,在进入中断处理程序之前,都经过了SIU IC和CPM IC两级处理。另外,由于MPC860是RISC处理器,它有许多通用寄存器,在中断服务程序中应该把影响到的寄存器压入到堆栈中,在退出中断服务程序之前再恢复。
3 实例应用
下面以CPM的SMC1用作串口,使用中断接收数据为例,说明MPC860的中断应用程序编写过程。
本程序的主函数是main()。它调用smc_init()进行smc初始化,然后循环等待接收数据。smc_init()是初始化函数。它设定smc1的工作方式,初始化接收描述字,然后初始化中断寄存器,并且把SIU中断服务程序拷贝到异常向量表的0x500处。Initbrn()是SIU中断服务程序,也就是外部中断产生后的入口程序。它读取SIU的中断向量号,如果是CPM中断,就调用CPM中断处理程序CPMHandler(),在这个程序中再读取CPM中断向量号,如果是CPM中断,就调用CPM中断处理程序CPMHandler(),在这个程序中再读取CPM中断向量号,处理SMC1发送过来的数据。
另外,函数getimmr()的作用是用汇编指令得到芯片双端口寄存器的基址,getmsr()的作用是读取机器状态字(MSR)的值,getevt()利用MSR的值得到的异常向量表的基址。整个程序代码如下:
#include "pc860.h" /*MPC860寄存器宏定义头文件*/
struct dprbase *pdpr; /*指向双端口内存基址的地址*/
void smc_init() /*初始化SMC函数*/
{ void intbrn(); /*定义SIU中断服务程序*/
int *ptrs,*ptrd; /*SIU中断服务程序搬移的源和目的地址*/
char intlv1=4;/*CPM中断级别*/
pdpr=(struct dprbase *)(getimmr() 0xFFFF0000); /*得到内部双端口寄存器的基址*/
…… /*初始化SMC的寄存器和工作参数,如工作模式,波特率等*/
…… /*初始化串口数据收发缓冲区的描述字,注意要把接收缓冲区描述字RxBD的中断位置为1*/
ptrs=(int *)intbrn; /*需要搬移的SIU中断服务程序源地址*/
ptrd=(int *)(getevt()+0x500);/*目标地址*/
do /*把SIU中断服务程序搬移到外部中断入口处*/
*ptrd++=*ptrs;
while(*ptrs++!=0x4c000064);/*0x4c000064是SIU中断服务程序返回指令RFI指令的二进制代码*/
pdpr->CICR.IRL2=(unsigned)(intlv1);/*设定CPM的中断级别为4*/
pdpr->CICR.HP0_HP4=0x1F; /*设定PC15为最高优先级中断*/
pdpr->CIMR.SMC1=1;/*打开CPM IC的SMC1中断屏蔽位*/
pdpr->SIMASK.ASTRUCT.LVM4=1;/*打开SIU IC的CPM中断屏蔽位*/
pdpr->CICR.IEN=1;/*使能CPM中断*/
pdpr->SMCE1=0xFF;/*清除SMC1的事件寄存器*/
pimm->SMCM1=1;/*打开子模块可屏蔽的接收中断*/
asm("mtspr 80,0");/*使能中断*/
…… /*使能SMC1的发送和接收功能*/
}
main() /*主函数*/
{ smc_init() /*初始化SMC1*/
while(1==1);/*等待接收*/
}
#pragma interrupt intbrn /*SIU中断服务程序
void intbrn()
{void CPMHandler();/*定义CPM中断服务程序*/
asm("stwu r9,-4(r1");/*把GRR9压入堆栈*/
switch(pdpr->SIVEC.IC)/*读取SIU的中断向量号,转入相应处理程序*/
{case 0x24;/*为CPM对应的中断向量号*/
asm("mfspr r9,8");/*把LR压入堆栈*/
asm("mfspr r9,8");/*把LR压入堆栈*/
asm("mfspr r9,8");/*把LR压入堆栈*/
asm("stwu r9,-4(r1)");
asm("bla CPMHandler")/*调用CPM中断处理函数*/
asm("lwz r9,0(r1)");/*把LR从堆栈中弹出*/
asm("addi r1,r1,4");/*恢复堆栈指针*/
asm("mtspr8,r9");
break;
default:;
}
asm("lwz r9,0(r1); /*把GPR9从堆栈中弹出/*
asm("addi r1,r1,4");/*恢复堆栈指针*/
}
void CPMHandler() /*CPM中断处理程序*/
{unsigned v1;
pdpr->CIVR.IACK=1;/*把CIVR的IACK位置为1,以读取CIVR中的中断向量号*/
v1=pdpr->CIVR.VN;/*读取中断向量号*/
switch(pimm->CIVR.VN)/*根据中断向量号进行处理*/
{case 4: /*SMC1的中断向量*/
…… /*SMC1中断处理程序,对接收到的数据进行处理*/
pimm->CISR=1(31-11);/*清除IN-SRVCE位*/
break;
default:;
}
}
getimmr() /*得到双端口寄存器的基址*/
{ asm("mfspr3,638");
}
getevt() /*得到中断入口的基址*/
{ if((getmsr() 0x40)==0)/*如果MSR.IP等于0*/
return(0); /*中断入口在低位*/
else
return(0xFFF00000);/*中断入口在高位*/
}
getmsr() /*得到机器状态寄存器MSR的值*/
{ asm(mfmsr 3; /*把MSR的值读到r3中*/
}
4 结论
以上讨论的中断应用程序的编写是在没有操作系统的情况下进行的;如果有操作系统,对中断管理的初始化会在操作系统初始化时完成,用户只需调用API函数安装中断服务程序即可。但即使这样,理解上述的中断处理过程,对编写MPC860中断服务程序也是有必要的。
从以上讨论可以看出,与MPC860带有两个处理器的体系结构相适应的,MPC860中断机制采用了两级中断处理,其优点是能最大限度地扩展外部中断源的数量,并可以加快对CPM中断的响应速度。编写MPC860中断处理程序的关键在两个方面:一个是在初始化时应该设置好各个中断寄存器,并且把SIU中断服务程序放到正确的位置;另一个是在中断服务程序的处理过程中,要根据读得的SIU和CPM中断向量号进行相应处理。
评论