1.fii_irq_clint
Related reference articles:
RISC-V teaching plan
After writing into the timer interrupt related register, the module exu_lsu outputs it to the upper level, and finally passes it to the fii_irq_clint module in fii_riscv_cpu. irq stands for interrupt request, which means interrupt request. clint is core level interrupt, which means core level interrupt. Here, the module only generates two interrupt requests, software interrupt and timer interrupt. Because software interrupts are relatively simple, you only need to write software registers to send software interrupt requests, which will not be discussed here.
After fii_irq_clint receives the signal related to the timer interrupt, it directly passes it to the next-level module, fii_clint_top. The fii_irq_clint code is as follows:
module fii_irq_clint ( input sys_clk, //system clock input [ 31: 0 ] i_sft_int_v,//software interrupt register input [ 31: 0 ] i_timer_l, //Timer low 32-bit register input [ 31: 0 ] i_timer_h, //Timer high 32-bit register output [ 31: 0 ] o_timer_l, //output the current low 32-bit register of the timer output [ 31: 0 ] o_timer_h, //output the current timer high 32-bit register input [ 31: 0 ] i_tcmp_l, //Compare timer lower 32-bit register input [ 31: 0 ] i_tcmp_h, //Compare timer high 32-bit register input [ 1: 0 ] i_timer_valid,//The two bits control the low/high 32-bit register of the timer respectively input [ 31: 0 ] i_tm_ctrl, //timer control register output clint_tmr_irq, //output timer interrupt request output clint_sft_irq, //output software interrupt request input l_clk, //low frequency clock input rst_n //reset signal ); fii_clint_top u_fii_clint_top ( .sys_clk ( sys_clk ), .i_sft_int_v ( i_sft_int_v ), .i_timer_l ( i_timer_l ), .i_timer_h ( i_timer_h ), .o_timer_l ( o_timer_l ), .o_timer_h ( o_timer_h ), .i_tcmp_l ( i_tcmp_l ), .i_tcmp_h ( i_tcmp_h ), .i_timer_valid ( i_timer_valid ), .i_tm_ctrl ( i_tm_ctrl ), .l_clk ( l_clk ), .o_mtip ( clint_tmr_irq ), .o_msip ( clint_sft_irq ), .rst_n ( rst_n ) ); endmodule
2.fii_clint_top
In this module, in addition to continuing to pass the relevant timer interrupt signal to the next layer module fii_clint, a frequency division of l_clk is also done here. From the IP core of the clock, there are two main clock frequencies used, which are 50 MHz and 8.3888 MHz, as shown in Figure 1. Here, the 50MHz clock is mainly used as the system clock, which is the sys_clk that appears in many modules. The 8.3888 MHz clock is l_clk introduced by the upper module fii_irq_clint. The fii_clint_top code is as follows:
Figure 1 CPU clock IP core
module fii_clint_top ( input sys_clk,//system clock input l_clk,//low frequency clock input [31:0] i_sft_int_v, input [31:0] i_timer_l,//Timer low 32-bit register input [31:0] i_timer_h,//Timer high 32-bit register output [31:0] o_timer_l,//Output the current low 32-bit register of the timer output [31:0] o_timer_h,//output the current timer high 32-bit register input [31:0] i_tcmp_l,//Compare timer lower 32-bit register input [31:0] i_tcmp_h,//Compare timer high 32-bit register input [1:0] i_timer_valid,//The two bits control the low/high 32-bit register of the timer respectively input [31:0] i_tm_ctrl,//timer control register output o_mtip,//output timer interrupt request output o_msip,//output software interrupt request input rst_n//reset signal ); reg [7:0] rtc_r = 0; always @ (posedge l_clk)//Continue to divide frequency under low frequency clock rtc_r <= rtc_r + 1; reg rtc_sys = 0; always @ (posedge sys_clk )//get wide signal (128 times wide rtc_r signal) under high-speed system clock rtc_sys <= rtc_r[7]; reg [1:0] rtc_toggle = 0; always @ (posedge sys_clk or negedge rst_n)//under the system clock if(!rst_n) rtc_toggle <= 0; else if(i_tm_ctrl[31])//if the control register is valid begin rtc_toggle <= {rtc_toggle[0], rtc_sys};//get the shift signal of rtc_sys end wire rtcTick = (rtc_toggle == 2'b01) ? 1'b1 : 1'b0;//If rtc_sys has a rising edge, rtcTick will be pulled high (256 times of frequency division to 32.768 kHz) fii_clint u_fii_clint ( .sys_clk ( sys_clk ), .i_sft_int_v ( i_sft_int_v ), .i_timer_l ( i_timer_l ), .i_timer_h ( i_timer_h ), .o_timer_l ( o_timer_l ), .o_timer_h ( o_timer_h ), .i_tcmp_l ( i_tcmp_l ), .i_tcmp_h ( i_tcmp_h ), .i_timer_valid ( i_timer_valid ), .i_tm_ctrl ( i_tm_ctrl ), .o_mtip ( o_mtip ), .o_msip ( o_msip ), .i_rtcTick ( rtcTick ), .rst_n ( rst_n ) ); endmodule
3.fii_clint
The signal that actually generates the interrupt request occurs under the fii_clint module. The code is as follows:
module fii_clint ( input sys_clk,//system clock input [ 31: 0 ] i_sft_int_v, input [ 31: 0 ] i_timer_l,//Timer low 32-bit register input [ 31: 0 ] i_timer_h,//Timer high 32-bit register output [ 31: 0 ] o_timer_l,//output the current low 32-bit register of the timer output [ 31: 0 ] o_timer_h, //output the current timer high 32-bit register input [ 31: 0 ] i_tcmp_l,//Compare timer lower 32-bit register input [ 31: 0 ] i_tcmp_h,//Compare timer high 32-bit register input [ 1: 0 ] i_timer_valid,//The two bits control the low/high 32-bit register of the timer respectively input [ 31:0 ] i_tm_ctrl,//timer control register output o_mtip,//output timer interrupt request output o_msip,//output software interrupt request input i_rtcTick,//32.768 kHz clock input rst_n//reset signal ); reg [ 31: 0 ] time_l; reg [ 31: 0 ] time_h; wire [ 63: 0 ] timer; wire [ 31: 0 ] timecmp_l; wire [ 31: 0 ] timecmp_h; wire ipi_0; //soft interrupt //Condition for generating a timer interrupt request: whether the value of the timer register exceeds the value of the compare timer register assign o_mtip = ( { time_h, time_l } >= { timecmp_h, timecmp_l } ) ? 1'b1 : 1'b0; assign o_msip = ipi_0; assign timer = { time_h, time_l } + 64'h1;//timer register + 1 count always @( posedge sys_clk or negedge rst_n ) if ( !rst_n ) begin time_l <= 32'h0; end else begin if ( i_timer_valid[ 0 ] )//The low-order bit controls the low-order 32-bit register of the timer time_l <= i_timer_l; else if ( i_rtcTick & i_tm_ctrl[0]) //when 32.768 kHz clock and control register are active time_l <= timer[ 31: 0 ];//Latch to make the above timer count valid end always @( posedge sys_clk or negedge rst_n ) if ( !rst_n ) begin time_h <= 32'h0; end else begin if ( i_timer_valid[ 1 ] )//The high-order bit controls the high-order 32-bit register of the timer time_h <= i_timer_h; else if ( i_rtcTick & i_tm_ctrl[0])// when 32.768 kHz clock and control register are active time_h <= timer[ 63: 32 ];//Latch to make the above timer count valid end //The value written into the compare timer register assign timecmp_l = i_tcmp_l; assign timecmp_h = i_tcmp_h; assign ipi_0 = i_sft_int_v[ 0 ];//output assign o_timer_l = time_l;//output assign o_timer_h = time_h;//output endmodule