首页 > 代码库 > OR1200处理器的可编程中断控制器PIC分析

OR1200处理器的可编程中断控制器PIC分析

以下内容摘自《步步惊芯——软核处理器内部设计分析》一书

16.3 可编程中断控制器PIC分析

16.3.1 PIC介绍

      可编程中断控制器Programmable Interrupt ControllerPIC)用来响应各种中断事件,如:键盘事件、串口数据到达等,PIC收集所有的中断,并通知CPU中断到达,后者转入到中断处理例程进行处理。OR1200最多支持32个中断。其功能实现主要依靠两个特殊寄存器:中断屏蔽寄存器PICMR、中断状态寄存器PICSR。通过PICMR可以设置是否屏蔽某些中断,通过PICSR可以知道中断源的信息。PICMRPICSR是第9组特殊寄存器,如表16.7所示。

      中断屏蔽寄存器PICMR的格式如表16.8所示,该寄存器可读、可写。标志IUM中的值表示对应中断是否被屏蔽,IUM0x0,表示所有中断都被屏蔽,IMU0xFFFFFFFF,表示所有中断都没有被屏蔽。在OR1200中,IUM的位数可以配置,配置范围是2-31,这是因为IUM的最低两位始终保持为1,即中断源01设置为不可屏蔽,可以将这两个中断源对应为电源关闭、系统复位。

      中断状态寄存器PICSR的格式如表16.9所示,该寄存器可读、可写。标志IS中的值表示对应中断是否发生并等待处理,IS0x0表示没有中断发生,第i位为1表示第i个中断源发生了中断。判断中断是否发生的方法有电平触发、边沿触发,OR1200支持的是电平触发,此时,IS的第i位实际对应的就是第i个中断源的当前电平值。

      OR1200中断处理过程如下:

      (1)中断源声明中断发生,PICSR[i]1,如果PICMR[i]1,那么通知处理器中断到达

      (2)处理器转入中断处理例程进行中断处理

      (3)中断已处理,中断处理例程通知中断源

      (4)中断源取消中断声明

      (5)中断处理例程设置PICSR[i]0,退出中断处理例程

      注意一点,单独设置PICSR[i]并不会清除中断,必须通知中断源,由后者取消中断声明。

16.3.2 PIC的对外连接关系及相关宏定义

      OR1200处理器中可编程中断控制器PIC的对外连接关系如图16.3所示,通过箭头方向表示该信号是输入还是输出。以spr_xxx开始的接口都是与特殊寄存器读写有关的信号,含义也很明了,此外,pic_int是一个宽度可配置的接口,最大为32,对应32个外部中断源输入。当中断发生时通过intr接口通知CPU模块,其值为1表示中断发生,连接到CPU模块的接口sig_int,同时还要通过pic_wakeup接口通知电源管理模块PM,如果中断发生时,处理器处于SleepDoze模式,PM模块在接收到pic_wakeup1后,会恢复正常模式,参考16.1节中对PM模块的分析。

      OR1200中与可编程中断控制器PIC有关的宏定义如下:

or1200_defines.v`define OR1200_PIC_IMPLEMENTED             //是否实施PIC模块,PIC模块是可选模块`define OR1200_PIC_INTS 20                 //定义外部中断源的数目,最多是32个,默认是20个`define OR1200_PIC_OFS_PICMR 2'd0          //PICMR、PICSR寄存器在第9组特殊寄存器中的索引`define OR1200_PIC_OFS_PICSR 2'd2`define OR1200_PICOFS_BITS 1:0`define OR1200_PIC_PICMR                   //需要定义这个宏,才可以使用PICMR寄存器`define OR1200_PIC_PICSR                   //需要定义这个宏,才可以使用PICSR寄存器`define OR1200_PIC_READREGS                //有了这个宏定义,才可以读PIC中的特殊寄存器PICMR、PICSR`define OR1200_PIC_UNUSED_ZERO


 

16.3.3 PIC代码分析

      PIC的主要代码就是配置PICMRPICSR寄存器,以及依据PICMRPICSR的值判断中断是否发生,分析如下(为了方便理解,笔者改变了代码顺序):

or1200_pic.vmodule or1200_pic(	clk, rst, spr_cs, spr_write, spr_addr, spr_dat_i, spr_dat_o, pic_wakeup, intr, pic_int);……output		pic_wakeup;	                    //输出到PM模块output		intr;		                        //输出到CPU模块input	[`OR1200_PIC_INTS-1:0]	pic_int;    //输入的中断信号,其宽度可通过OR1200_PIC_INTS配置`ifdef OR1200_PIC_IMPLEMENTED                    `ifdef OR1200_PIC_PICMR      reg	[`OR1200_PIC_INTS-1:2]	picmr; //PICMR寄存器的宽度也和OR1200_PIC_INTS相匹配,但少了两位,                                         //这是由于中断源0、1不可屏蔽,所以PICMR的宽度比中断输入                                         //pic_int的宽度少了两位`elsewire	[`OR1200_PIC_INTS-1:2]	picmr;	`endif`ifdef OR1200_PIC_PICSRreg	[`OR1200_PIC_INTS-1:0]	picsr;	     //PICSR寄存器的宽度也和OR1200_PIC_INTS相匹配`elsewire	[`OR1200_PIC_INTS-1:0]	picsr;	`endif……//如果spr_cs为1,那么依据spr_addr的最低两位判断指令l.mfspr/l.mtspr的访问目标是PICMR还是PICSR//picmr_sel为1,表示访问目标是PICMR,picsr_sel为1,表示访问目标是PICSRassign picmr_sel = (spr_cs && (spr_addr[`OR1200_PICOFS_BITS] == `OR1200_PIC_OFS_PICMR))                    ? 1'b1 : 1'b0;                   assign picsr_sel = (spr_cs && (spr_addr[`OR1200_PICOFS_BITS] == `OR1200_PIC_OFS_PICSR))                    ? 1'b1 : 1'b0;//将pic_int与{picmr,2’b11}相与,得出未屏蔽的中断信息保存在um_ints,注意中断源0、1不可屏蔽,//与PICMR的值无关,此处直接就是2’b11assign um_ints = pic_int & {picmr, 2'b11};  //um_ints不为0,表示有中断发生,设置intr为1,intr输出到CPU模块的sig_int接口assign intr = |um_ints;//中断发生后还要通过pic_wakeup接口通知PM模块assign pic_wakeup = intr;`ifdef OR1200_PIC_PICMRalways @(posedge clk or `OR1200_RST_EVENT rst)	   if (rst == `OR1200_RST_VALUE)		  picmr <= {1'b1, {`OR1200_PIC_INTS-3{1'b0}}};	   else if (picmr_sel && spr_write) begin		  picmr <=  spr_dat_i[`OR1200_PIC_INTS-1:2];    //写PICMR,注意最低两位不受影响	   end`elseassign picmr = (`OR1200_PIC_INTS)'b1;`endif//给PICSR寄存器赋值,PICSR的值取决于指令l.mtspr写入的数据,以及当前发生的外部中断情况,//从这里也可以发现:当中断发生时,单独使用l.mtspr清除PICSR寄存器并不会使得PICSR的值改//变,因为外部设备没有取消中断声明,um_ints的值没变,所以必须要外部设备取消中断声明`ifdef OR1200_PIC_PICSRalways @(posedge clk or `OR1200_RST_EVENT rst)	    if (rst == `OR1200_RST_VALUE)		   picsr <= {`OR1200_PIC_INTS{1'b0}};	    else if (picsr_sel && spr_write) begin 		   picsr <=  spr_dat_i[`OR1200_PIC_INTS-1:0] | um_ints; 	    end else		   picsr <=  picsr | um_ints;`elseassign picsr = pic_int;`endifalways @(spr_addr or picmr or picsr)	  case (spr_addr[`OR1200_PICOFS_BITS])	// synopsys parallel_case		`OR1200_PIC_OFS_PICMR: begin		   spr_dat_o[`OR1200_PIC_INTS-1:0] = {picmr, 2'b11};            //读PICMR,最低两位始终为1		   spr_dat_o[31:`OR1200_PIC_INTS] = {32-`OR1200_PIC_INTS{1'b0}};		end	  default: begin	     spr_dat_o[`OR1200_PIC_INTS-1:0] = picsr;                     //读PICSR	     spr_dat_o[31:`OR1200_PIC_INTS] = {32-`OR1200_PIC_INTS{1'b0}};	  end	endcase   `else                                                 //没有配置PIC模块的情况如下assign intr = pic_int[1] | pic_int[0];                //没有配置PIC模块时,中断0、1还可以使用assign pic_wakeup= intr;assign spr_dat_o[`OR1200_PIC_INTS-1:0] = `OR1200_PIC_INTS'b0;assign spr_dat_o[31:`OR1200_PIC_INTS] = 32-`OR1200_PIC_INTS'b0;`endifendmodule


      当中断发生后,PIC模块置高intr,参考图16.3可知,intr连接到CPU模块的sig_int接口,CPU内部的EXCEPTION模块接收该信号,并进行处理,与计时器中断相似,并不会立即响应该中断,而是需要满足一定条件才会响应,如下:

or1200_exception.vassign int_pending = sig_int & (sr[`OR1200_SR_IEE] | (sr_we & to_sr[`OR1200_SR_IEE]))                     & id_pc_val & delayed_iee[2] & ~ex_freeze & ~ex_branch_taken                       & ~ex_dslot & ~(sr_we & ~to_sr[`OR1200_SR_IEE]);

      各个条件的说明参考计时器中断,当条件满足后,int_pending为1,处理器进入外部中断异常的处理,具体过程与计时器中断一样,此处不再赘述。