Menu Close

RISC-V Timer Interrupt(2)Timer Interrupt Request

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

 

Posted in FPGA, RISC-V, RISC-V Textbook, Textbook and Training Project

Related Articles

Leave a Reply

Your email address will not be published.

Leave the field below empty!