"); //-->
摘 要: 详细论述了4位RISC MCU中断系统的Verilog设计实现过程。该MCU采用PIC两级流水线结构,含4个中断源,2级优先级。最后通过整体的RISC MCU IP核对其中断系统进行完整的程序测试,完成功能与时序的仿真与验证。
关键词: verilog;PIC;RISC MCU;仿真;中断
微控制器(MCU)包括核心指令译码电路、寄存器/存储器模块和一组输入/输出(I/O)模块。当I/O模块处于操作进行时,I/O模块中断机制使微处理器可以忙于执行其他指令,取消MCU对端口的不必要等待时间,从而大大提高了MCU的执行效率[1]。
在微控制器或微处理器的设计中,控制信号的设计是最复杂的,而在控制信号的设计中,中断系统的设计又是最困难的部分[1]。本文以自主所开发的4位RISC MCU IP核为载体,采用自上而下的设计方法,给出了其中断系统的Verilog硬件描述语言的具体实现过程。该系统可以作为一个功能部件, 直接在微控制器中加以运用, 对各种复杂中断系统的设计具有很好的借鉴意义。
1 中断系统总体设计
本系统所处的载体是由自身所研发的、采用数据总线和指令总线相互分离的哈佛双总线和Microchip技术公司的微控制器PIC的两级流水线机制[2]。中断系统的主要功能与MCS-51相同,有4个中断请求源,2个中断优先级,可实现2级中断服务程序嵌套。整个中断系统结构图如图1所示。具体的设计主要包含以下四个设计过程[3]:
(1)微控制器如何识别发生了哪个中断;
(2)出现多个中断时, 微处理器优先处理哪个中断;
(3)微控制器如何处理中断嵌套;
(4)微控制器如何处理中断执行周期。
其中,(1)是中断源的问题,(4)是中断响应时间的考虑,(2)和(3)归结起来就是中断优先级单元的设计。
1.1 中断源
系统的4个中断源分别是:外部中断SE(由I/O提供);片内的定时/计数器T0的溢出中断请求ST;片内基准定时器BT0的溢出中断请求SB;液晶驱动模块的中断请求SL和中断系统相关的特殊功能寄存器及有中断允许控制寄存器IE,中断优先级控制寄存器IP和中断请求标志寄存器IF。IF、IE、IP寄存器中的中断源排位顺序一致,它们都可通过字节的指令操作来进行读写,MCU复位时,全部为0。当MCU同时收到几个同一优先级的中断请求时,由同级内的优先查询顺序确定哪个中断请求得到响应。各中断源得相应中断入口地址、默认同级优先级及IF/IE/IP寄存器的各位名称如表1所示。
IE的相应位置1,表明相应的中断源为允许,为0时,则是屏蔽;IF的相应位置1,表明相应的中断源有请求,为0,则没有中断源请求;IP的相应位为1,表明相应的中断源为高优先级中断,为0,则为低优先级中断。该部分的相关Verilog代码如下(以基准定时中断为例):
//基准定时模块中断源信号(高电平脉冲)的系统时钟同步;
always@(sysclk) begin
int_base1<=int_base;
int_base2<=int_base1;end
assign SB=!int_base1&int_base2;
//中断请求标志位:可由中断源SB触发,也可通过对IF
//的字节操作对其置位或清零,其余情况下则保持原状态
//不变。
assign FB=(resetn==0)? 1′b0:
(SB==1)? 1′b1:
(IF_wr)? IF[2]:
LF;
//把中断请求标志位写回中断请求暂存寄存器IF_out,若有
//对IF进行写操作(IF_wr=1),则把IF_out写回。
assign IF_out={FB,FT,FE,FL};
//中断请求响应条件位
assign FB_f=FB&IE[2];
1.2 中断优先级设计
系统设置有2个中断优先级,对于每一个中断请求源可编程为高优先级中断或低优先级中断。中断系统中有2个不可寻址的优先级状态编码器,一个指出MCU是否有高优先级的中断信号,另一个指出MCU是否有低优先级的中断信号。可根据这两个编码器的值来判断系统所处的中断状态。此部分为设计的重点。
如图1所示,把高、低优先级的中断分别归类到高优先级编码器(encoder2)和低优先级编码器(encoder1),无中断时,两编码器值都为零。若有一个不为零或两个都不为零,则会产生一中断信号(int_out),且会根据两优先编码器的值来确定中断入口地址(int_pc)、中断嵌套(int_nesting)、中断嵌套返回(int_nest_back)等信号,并将它们送入PC与堆栈处理模块。当然PC与堆栈模块也会产生相应的反馈信号以处理多种中断情况。相关的重点实现代码如下:
//低优先级编码器的输入端选择
assign encoder1_in[0]=(int_pri[0]==0)?FL:1′b0;
assign encoder1_in[1]=(int_pri[1]==0)?FE:1′b0;
assign encoder1_in[2]=(int_pri[2]==0)?FT:1′b0;
assign encoder1_in[3]=(int_pri[3]==0)?FB:1′b0;
//高优先级编码器的输入端选择
assign encoder2_in[0]=(int_pri[0]==1)?FL:1′b0;
assign encoder2_in[1]=(int_pri[1]==1)?FE:1′b0;
assign encoder2_in[2]=(int_pri[2]==1)?FT:1′b0;
assign encoder2_in[3]=(int_pri[3]==1)?FB:1′b0;
//低优先级编码器的实现:无中断时,值为0,进中断时优先
//编码赋值。其中把值寄存一次,用以辨别中断源变化时的
//编码状态,做为中断嵌套等多种中断情况的信号辨别条
//件;高优先级编码器的实现与低优先级类同,结果为out2
//和out2_pre。
always@(encoder1_in or out1)
begin
out1_pre<=out1;
casex(encoder1_in)
4′b0000:out1=3′b000;
4′b0001:out1=3′b001;
4′b001x:out1=3′b010;
4′b01xx:out1=3′b011;
4′b1xxx:out1=3′b100;
default:out1=3′b000;
endcase
end
//根据高低编码器出来的结果辨别优先级,即该跳转的中断
//向量地址。先仅取用到的5位数,用时再与前面补零;其
//中也已包含了同级默认优先级的功能;
assign int_pc= (out2==3′b100) ? 4′b0011:
(out2==3′b011) ? 4′b0101:
(out2==3′b010) ? 4′b0111:
(out2==3′b001) ? 4′b1001:
(out1==3′b100) ? 4′b0011:
(out1==3′b011) ? 4′b0101:
(out1==3′b010) ? 4′b0111:
(out1==3′b001) ? 4′b1001:
4′b0000;
//中断信号的产生,int_out_clear为PC和堆栈模块的反馈信
//号;
assign int_out=(int_out_clear==1)? 1′b0:
((out2!=3′b000)||(out1!=3′b000))? 1′b1:1′b0;
//中断嵌套信号的条件是通过两编码器输出结果的变化推
//断出来的,且已通过验证证明是正确的。中断嵌套返回的
//方法与此同,不细述。
assign
int_nest=(((out1!=3′b000)&(out2_pre==3′b000)&(out2!=
3′b000))==1′b1)?1′b1:1′b0;
//int_nest为一辨别信号,将其转换为系统脉冲信号;
always@(posedge sysclk) begin
int_nest1<=int_nest;
int_nest2<=int_nest1;
if(!int_nest2&int_nest)
int_nesting<=1;
else int_nesting<=0;end
1.3 中断响应
中断延迟是MCU的一个重要参数, 通常是指在最坏情况下响应中断的最长时间。因系统属于RISC单周期指令,也就不存在CISC中存在的指令未执行完而被打断的情况。当然MCU也是在现行一条指令执行完毕即下一个指令周期的Q1才开始响应中断的,并不是在一条指令执行期间响应中断,这样MCU才能正确返回断点继续执行原来的程序。由此也可知道系统大部分时刻中断响应时间为1个指令周期;除非正在执行的指令是现场保护(入栈)、现场恢复(出栈),则需要等这些指令执行完之后,再去响应新的中断请求,这一点本系统是通过软件程序来实现。软件程序的具体编写步骤与MCS-51相似,见参考文献[4]。
1.4 PC与堆栈模块
PC与堆栈模块通过接收来自中断优先级模块的信号处理多种中断情况的发生,并产生相应的反馈信号,且完成了现场保护(入栈)、现场恢复(出栈)、PC预取值等重要操作。除了跳转地址须等指令周期的Q4外,其余的大部分操作皆于Q1时刻完成。
always@(posedge clk1 or posedge int_nesting or negedge resetn) begin
if(resetn==0)
……
//中断嵌套信号需把int_out_clear清零,以辨别新中断信号;
//当有中断信号后的下一个Q1,置int_out_clear为1;中断
//返回指令RTI时置其为0;其余时刻保持不变。
else if(int_nesting) int_out_clear<=0;
else begin
pc_plus1<=pc_fetch+1;
pc<=pc_fetch;
casex({int_out,inst[15:12]})
5′b1xxxx:begin
int_out_clear<=1
//pc_int:中断发生标志;pc_pop:中断返回标志
pc_int<=1;
pc_pop<=0;
//中断嵌套返回时刻并不执行压栈操作,而应返回原压栈值
if(int_nest_back==0)
……//压栈
5′b01111:begin
pc_pop<=1;
pc_int<=0;
int_out_clear<=0;
……//进栈
default:begin
pc_pop<=0;
pc_int<=0;end
//预取值地址的辨别
assign pc_fetch=(resetn==0) ? 12′b0000_0000_0000:
(pc_pop==1) ? pc_fetch_pop:
(int_nest_back&pc_int) ? pc_fetch_pop:
(pc_int==1) ? {8′b00000000,int_pc}:
(sys_jmp==1) ? pc_jmp:
pc_plus1;
2 系统的测试与验证
本中断系统属于自主设计的RISC MCU IP核的子模块,其功能与时序仿真也是在整个IP核上进行的。经过六个含中断程序的下载验证和不断完善,整个中断系统是完全正确且可行的。功能仿真时,采取了将测试向量(汇编代码)通过虚拟ROM进行验证的方式;时序仿真则是利用Altera公司的LPM ROM/RAM模块完成。前者的平台是modelsim 6.0se,后者是quartus6.0。现举例详细说明:设置IE为0111,IP为0110。步骤如下:
(1)运行主程序,等待中断信号;
(2)先获得液晶中断源SL并执行相应的中断源程序,但在其中断程序未执行完之前,又来外部中断源SE,此时因中断源有高低优先级之别,应有中断嵌套状况;
(3)系统转而执行外部中断程序,但又在外部中断程序未执行完之前,获得定时/计数器中断源ST,此时因中断源同是高优先级中断,故不予理睬,但定时/技术中断器请求信号却一直保持,直至外部中断程序完毕后,系统紧接着响应定时/技术器中断;
(4)定时/技术器中断程序执行完毕后,系统返回液晶中断程序继续执行;
(5)待液晶中断程序执行完后,系统跳回主程序。
具体的仿真结果完全符合功能要求,时序图如图2所示。
随着微电子技术的飞速发展,微控制器以其性能好、体积小、价格优、功能齐全等突出优点被广泛应用于家用电器、计算和外设、通讯、工业控制、自动化生产、智能化设备以及仪器仪表等领域,在国内具有良好的应用前景,其设计也日益受到人们的重视。中断系统是微控制器设计的难点,本文介绍的中断系统设计方法具有很好的借鉴意义。采用这种用Verilog实现的自顶向下的方法,使问题在RTL级就暴露出来,便于及时修改,大大减少了开发时间。包含上述中断系统的4位RISC MCU IP核也已测试及验证成功。
参考文献
[1] 胡永华,高明伦,王锐.微处理器中中断电路的高层设计[J].微电子学与计算机,2001,(4).
[2] 2004 Microchip Technology Inc.PICmicro中档单片机系列参考手册.http://www.microchip.com,2004,9.
[3] 朱良辰,胡越黎,冉峰.高速MCU核中并行优先级中断系统的设计与实现[J].微电子学,2004,34(4):482.
[4] 张毅刚.单片机原理与应用(第1版)[M].北京:高等教育出版社,2004,(1):112.
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。