Menu Close

RISC-V CSR读写控制(3)CSR寄存器实现上

1.寄存器模块

 

相关参考文章:

RISC-V教学教案

本文使用的代码是基于FII RISC-V V2.01(没有JTAG和总线)。上层模块csr_reg可参考前文RISC-V CSR读写控制(2)csr_reg模块,CSR寄存器的介绍可以参考RISC-V CSR寄存器(2)CSR寄存器。本文(碍于篇幅,分为上,中,下三篇文章,这里是CSR寄存器实现上)要介绍的寄存器模块主要包括以下(其中的有些CSR寄存器没有完全实现):

  • csr_mtvec
  • csr_mstatus
  • csr_mtval
  • csr_mepc
  • csr_mcause
  • csr_mie
  • csr_mip
  • csr_misa
  • csr_mcounteren
  • csr_mid:包括mvendorid,marchid,mimpid和mhartid
  • csr_scratch:mscratch寄存器
  • csr_mcycle:包括低位和高位的32位寄存器,共组成64位
  • csr_minstret:包括低位和高位的32位寄存器,共组成64位

 

1.1. csr_mtvec

mtvec是一个可读可写寄存器。虽然mtvec有两种模式,但这里只实现了MODE 0, 也就是说,所有的中断入口地址都是基地址。实现mtvec的寄存器的部分重要代码如下:

          
input [ 11: 0 ] i_csr_addr, //索引寄存器的地址
input [ 31: 0 ] i_csr_val,  //CSR指令写到寄存器上的值
input i_csr_wen,            //csr可写的属性

output [ 31: 0 ] o_mtvec,   //输出mtvec



wire wbck_csr_wen = i_csr_wen; //确定该寄存器可写
wire sel_mtvec = ( i_csr_addr == 12'h305 );     //通过地址索引确认寄存器

wire wr_mtvec = sel_mtvec & i_csr_wen;          //确认该寄存器既可写,又的确是mtvec
wire mtvec_ena = ( wr_mtvec & wbck_csr_wen );   //确认mtvec寄存器可写
wire [ 31: 0 ] mtvec_r;
wire [ 31: 0 ] mtvec_nxt = { i_csr_val[ 31: 2 ] , 2'b00 }; //中断入口地址都是基地址, MODE == 2'b00

fii_dfflr #( 32 ) mtvec_dfflr ( mtvec_ena, mtvec_nxt, mtvec_r, sys_clk, rst_n ); //锁存

assign o_mtvec = mtvec_r; //输出



1.2.csr_msatus

mstatus是一个可读可写寄存器。mstatus控制全局中断的使能。实现msatus的寄存器的部分重要代码如下(与上文重复的代码省略):

input i_mret_ena,        //中断返回
input i_status_ena,      //由全局中断&中断使能(包括计时器/外部/软件)&中断源组成

output [31:0] o_mstatus, //输出mstatus


wire sel_mstatus = (i_csr_addr == 12'h300);   //通过地址索引确认寄存器

wire wr_mstatus = sel_mstatus & wbck_csr_wen; //确认该寄存器既可写,又的确是mstatus
wire status_mpie_r;
wire status_mie_r;
// 在以下情况更新MPIE位
wire status_mpie_ena = 
                      // CSR指令写入
                      wr_mstatus |
                      // 中断返回
                      i_mret_ena |
                      // 中断到来
                      i_status_ena;

wire status_mpie_nxt = 
                      //中断来时,MPIE位更新为MIE位
                      i_status_ena ? status_mie_r :
                      // 中断返回时,MPIE设置成1
                      i_mret_ena ? 1'b1 :
                      // CSR指令写入
                      wr_mstatus ? i_csr_val[7] : // MPIE是mstatus寄存器的bit 7
                      status_mpie_r; // 如果以上条件都不满足,MPIE不变

fii_dfflr #(1) status_mpie_dfflr (status_mpie_ena, status_mpie_nxt, status_mpie_r, sys_clk, rst_n);//锁存

// MIE的实现与MPIE类似
wire status_mie_ena = status_mpie_ena; 
wire status_mie_nxt = 
                     // 中断来临时,MIE将值给MPIE,然后自己清零
                     i_status_ena ? 1'b0 :
                     // 中断返回时,MIE得到存储在MPIE中的值
                     i_mret_ena ? status_mpie_r :
                     // CSR指令写入
                     wr_mstatus ? i_csr_val[3] : // MIE是mstatus寄存器的bit 3
                     status_mie_r; // 如果以上条件都不满足,MIE不变

fii_dfflr #(1) status_mie_dfflr (status_mie_ena, status_mie_nxt, status_mie_r, sys_clk, rst_n);//锁存


//分别对mstatus的每一bit分开赋值
wire [31:0] status_tmp;
assign status_tmp[31]    = status_sd_r; // SD
assign status_tmp[30:23] = 8'b0; // 保留
assign status_tmp[22:17] = 6'b0; // TSR--MPRV
assign status_tmp[16:15] = status_xs_r; // XS
assign status_tmp[14:13] = status_fs_r; // FS
assign status_tmp[12:11] = 2'b11; // MPP 
assign status_tmp[10:9]  = 2'b0; // 保留
assign status_tmp[8]     = 1'b0; // SPP
assign status_tmp[7]     = status_mpie_r; // MPIE
assign status_tmp[6]     = 1'b0; // 保留
assign status_tmp[5]     = 1'b0; // SPIE 
assign status_tmp[4]     = 1'b0; // UPIE 
assign status_tmp[3]     = status_mie_r; // MIE
assign status_tmp[2]     = 1'b0; // 保留
assign status_tmp[1]     = 1'b0; // SIE 
assign status_tmp[0]     = 1'b0; // UIE


assign o_mstatus = status_tmp;//输出

 

1.3.csr_mtval

mtval也是可读可写的寄存器,用来存储引发异常的原因,比如非法指令,异常有关的信息等用来帮助软件处理,这里没有完全实现,只有基本的读写。在之前的定义中,是mbadaddr。相关的代码如下(与上文重复的代码省略):

input i_irq_src,          //中断源
input i_exp_src,          //异常源
input [ 31: 0 ] i_exe_pc, //当前的PC
input [ 31: 0 ] i_ir,     //当前的指令

output [ 31: 0 ] o_mtval, //输出mtval


wire sel_mtval = ( i_csr_addr == 12'h343 ); //通过地址索引确认寄存器
wire mtval_ena;
wire [ 31: 0 ] mtval_r;
wire [ 31: 0 ] mtval_nxt;
assign mtval_nxt = trap_mtval_ena ? i_trap_mtval_val : i_csr_val;//如果是中断/异常,存储相关的信息,不然由CSR指令写入
fii_dfflr #( 32 ) mtval_dfflr ( mtval_ena, mtval_nxt, mtval_r, sys_clk, rst_n );//锁存

assign o_mtval = mtval_r;//输出

endmodule

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

发表评论

相关链接