Menu Close

RISC-V 定时器及中断(1)读写定时器中断寄存器

1.读定时器中断寄存器

 

相关参考文章:

RISC-V教学教案

 

之前在RISC-V LSU,SRAM,GPIO模块(1)exu_lsu模块中介绍过exu_lsu模块可以让RISC-V CPU访问外设模块,本文将介绍之前没有提到的exu_lsu模块下的子模块fii_timer_lsu。

%title插图%num

首先,参考FII RISC-V Address Map上对定时器中断(timer interrupt)有关的寄存器定义,如图1所示。可以看到有定时器控制寄存器,定时器值的低32位和高32位寄存器,及定时器比较值的低32位和高32位寄存器。其相关读(load)的代码在exu_lsu模块中,见下面代码:

timer interrupt register

图1 定时器中断寄存器

 

parameter [ 31: 0 ] TMR_BASEADDR = 32'h0200_0000//计时器中断寄存器基地址参数
wire t_sft_cs   = ( i_D_PC[ 31: 16 ] == TMR_BASEADDR[ 31: 16 ] ) ? 1'b1 : 1'b0;//定时器有关的寄存器片选
wire sft_cs     = t_sft_cs & ( ( ~i_D_PC[ 12 ] ) & ( i_D_PC[ 5: 2 ] == 0 ) );
wire tm_ctrl_cs = t_sft_cs & ( ( ~i_D_PC[ 12 ] ) & ( i_D_PC[ 5: 2 ] == 1 ) );//定时器控制寄存器片选
wire t_cs0 = t_sft_cs & ( ( ~i_D_PC[ 12 ] ) & ( i_D_PC[ 5: 2 ] == 2 ) );//定时器值的低32位寄存器片选
wire t_cs1 = t_sft_cs & ( ( ~i_D_PC[ 12 ] ) & ( i_D_PC[ 5: 2 ] == 3 ) );//定时器值的高32位寄存器片选
wire tcmp_cs0 = t_sft_cs & ( ( ~i_D_PC[ 12 ] ) & ( i_D_PC[ 5: 2 ] == 4 ) );//定时器比较值的低32位寄存器片选
wire tcmp_cs1 = t_sft_cs & ( ( ~i_D_PC[ 12 ] ) & ( i_D_PC[ 5: 2 ] == 5 ) );//定时器比较值的高32位寄存器片选

wire [ 31: 0 ] ls_rb_d_t_sft = sft_cs     ? o_sft_int_v ://根据片选信号,确定要读的寄存器
                             ( tm_ctrl_cs ? o_tm_ctrl :
                                  ( t_cs0 ? i_timer_l :
                                  ( t_cs1 ? i_timer_h :
                               ( tcmp_cs0 ? o_tcmp_l :
                               ( tcmp_cs1 ? o_tcmp_h : o_CPU_dout ) ) ) ) );


wire [ 31: 0 ] ls_rb_d = mem_cs ? mem_dout : ( GPIO_cs ? rb_GPIO_d : ( UART_cs ? o_UART_dout : ls_rb_d_t_sft ) );//根据片选信号,确定要读的寄存器



always@( * )//省略了该代码块的部分代码
begin
if ( i_LOAD )
begin //&mem_init_rdy
    case ( i_load_instr ) // i_load_instr ={rv32i_lbu, rv32i_lb, rv32i_lhu, rv32i_lh, rv32i_lw};
    5'b00001:
    begin //rv32i_lw
        o_wb_data <= ls_rb_d;
    end
    5'b00010:
    begin //rv32i_lh
        o_wb_data <= { { 16{ ls_rb_d[ 15 ] } }, ls_rb_d[ 15: 0 ] };
    end
    5'b00100:
    begin //rv32i_lhu
        o_wb_data <= { { 16{ 1'b0 } }, ls_rb_d[ 15: 0 ] };
    end
    5'b01000:
    begin //rv32i_lb
        o_wb_data <= { { 24{ ls_rb_d[ 7 ] } }, ls_rb_d[ 7: 0 ] };
    end
    5'b10000:
    begin //rv32i_lbu
        o_wb_data <= { { 24{ 1'b0 } }, ls_rb_d[ 7: 0 ] };
    end
default: ;

endcase
end

 

2.写定时器中断寄存器

定时器中断寄存器的写(store)是在fii_timer_lsu模块中完成的。通过从外层模块exu_lsu中引进的写使能信号,以及各个片选信号等,选择相应要写的寄存器。代码如下:

 

wire [31: 0] cpu_data_in = i_rs2_val << {i_D_PC[1:0],3'b000};//exu_lsu模块中的cpu_data_in最后传递给了i_sft_timer_din

always@( posedge clk or negedge rst_n )
if ( !rst_n )//复位
begin
    o_tm_ctrl <= 0;//初始值
    o_sft_int_v <= 0;
    o_timer_l <= 0;
    o_timer_h <= 0;
    o_tcmp_l <= 0;
    o_tcmp_h <= 16'h8000;
    o_timer_valid <= 0;
end
else
begin
    o_timer_valid <= 0;

    if ( i_tmr_sft_we )//写使能信号
    begin
        if ( i_tcs0 )//定时器值的低32位寄存器片选
        begin
            o_timer_l <= i_sft_timer_din;//写进定时器值的低32位寄存器
            o_timer_valid[ 0 ] <= 1'b1;
        end

        if ( i_tcs1 )//定时器值的高32位寄存器片选
        begin
            o_timer_h <= i_sft_timer_din;//写进定时器值的高32位寄存器
            o_timer_valid[ 1 ] <= 1'b1;
        end

        if ( i_tcmp_cs0 )//定时器比较值的低32位寄存器片选
            o_tcmp_l <= i_sft_timer_din;//写进定时器比较值的低32位寄存器

        if ( i_tcmp_cs1 )//定时器比较值的高32位寄存器片选
            o_tcmp_h <= i_sft_timer_din;//写进定时器比较值的高32位寄存器

        if ( i_tm_ctrl_cs )//定时器控制寄存器片选
            o_tm_ctrl <= i_sft_timer_din;//写进定时器控制寄存器
    end
end

 

Posted in FPGA, RISC-V, RISC-V, RISC-V IPcore设计, RISC-V 教案, 应用开发, 开发板, 教材与教案, 文章

发表评论

相关链接