Menu Close

RISC-V CSR Read and Write Control Module(3)CSR Register Implementation 1

1. Register module


Related reference articles:

RISC-V teaching plan

The code used in this article is based on FII RISC-V V2.01 (without JTAG and bus). The upper module csr_reg can refer to the previous RISC-V CSR read and write control (2) csr_reg module, and the introduction of the CSR register can refer to the RISC-V CSR register (2) CSR register. The register modules to be introduced in this article (due to the space, are divided into three articles: upper, middle, and lower, here is the implementation of CSR registers ) mainly include the following (some of the CSR registers are not fully realized):

  • csr_mtvec
  • csr_mstatus
  • csr_mtval
  • csr_mepc
  • csr_mcause
  • csr_mie
  • csr_mip
  • csr_misa
  • csr_mcounteren
  • csr_mid: includes mvendorid, marchid, mimpid and mhartid
  • csr_scratch: mscratch register
  • csr_mcycle: 32-bit registers including low-order and high-order bits, forming a total of 64 bits
  • csr_minstret: 32-bit registers including low-order and high-order bits, forming a total of 64 bits


1.1. csr_mtvec

mtvec is a readable and writable register. Although mtvec has two modes, only MODE 0 is implemented here, that is, all interrupt entry addresses are base addresses. Part of the important code to implement the register of mtvec is as follows:

input i_acc_dis,//access disable, hard-wired to 0, to determine whether the register can be accessed/writable
input [ 11: 0 ] i_csr_addr,//The address of the index register
input [ 31: 0 ] i_csr_val,//The value written to the register by the CSR instruction
input i_csr_wen,//csr writable attributes

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

wire wbck_csr_wen = i_csr_wen & ( ~i_acc_dis );//Make sure the register can be written
wire sel_mtvec = ( i_csr_addr == 12'h305 );//Confirm register by address index

wire wr_mtvec = sel_mtvec & i_csr_wen;//Confirm that the register is writable and indeed mtvec
wire mtvec_ena = ( wr_mtvec & wbck_csr_wen );//Confirm that the mtvec register can be written
wire [ 31: 0 ] mtvec_r;
wire [ 31: 0 ] mtvec_nxt = { i_csr_val[ 31: 2 ] , 2'b00 }; //Interrupt entry addresses are all base addresses, MODE == 2'b00

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

assign o_mtvec = mtvec_r;//output



mstatus is a readable and writable register. mstatus controls the enablement of global interrupts. Part of the important code that implements the register of msatus is as follows (the code that is repeated above is omitted):

input i_mret_ena,//interrupt return
input i_status_ena,//Consists of global interrupt & interrupt enable (including timer/external/software) & interrupt source

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

wire sel_mstatus = (i_csr_addr == 12'h300);//Confirm register by address index

wire wr_mstatus = sel_mstatus & wbck_csr_wen;//Confirm that the register is writable and indeed mstatus
wire status_mpie_r;
wire status_mie_r;
// Update the MPIE bit in the following cases
wire status_mpie_ena =
                       // CSR instruction write
                       wr_mstatus |
                       // interrupt return
                       i_mret_ena |
                       // interrupt arrives

wire status_mpie_nxt =
                       //When the interrupt comes, the MPIE bit is updated to the MIE bit
                       i_status_ena ? status_mie_r :
                       // When the interrupt returns, MPIE is set to 1
                       i_mret_ena ? 1'b1 :
                       // CSR instruction write
                       wr_mstatus ? i_csr_val[7] : // MPIE is bit 7 of mstatus register
                       status_mpie_r; // If none of the above conditions are met, MPIE remains unchanged

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

// The implementation of MIE is similar to MPIE
wire status_mie_ena = status_mpie_ena;
wire status_mie_nxt =
                      // When the interrupt comes, MIE will give the value to MPIE, and then clear it by itself
                      i_status_ena ? 1'b0 :
                      // When the interrupt returns, MIE gets the value stored in MPIE
                      i_mret_ena ? status_mpie_r :
                      // CSR instruction write
                      wr_mstatus ? i_csr_val[3] : // MIE is bit 3 of mstatus register
                      status_mie_r; // If none of the above conditions are met, MIE remains unchanged

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

//Assign each bit of mstatus separately
wire [31:0] status_tmp;
assign status_tmp[31] = status_sd_r;    // SD
assign status_tmp[30:23] = 8'b0;        // reserved
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;         // reserved
assign status_tmp[8] = 1'b0;            // SPP
assign status_tmp[7] = status_mpie_r;   // MPIE
assign status_tmp[6] = 1'b0;            // reserved
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;            // reserved
assign status_tmp[1] = 1'b0;            // SIE
assign status_tmp[0] = 1'b0;            // UIE

assign o_mstatus = status_tmp;//output



mtval is also a readable and writable register, which is used to store the cause of an interrupt or exception, such as illegal instructions, exception-related information, etc. to help software processing. It is not fully implemented here, only basic reading and writing. In the previous definition, it was mbadaddr. The relevant code is as follows (the duplicated code above is omitted):

input i_irq_src,          //Interrupt source
input i_exp_src,          //Exception source
input [ 31: 0 ] i_exe_pc, //current PC
input [ 31: 0 ] i_ir,     //The current command

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

wire sel_mtval = ( i_csr_addr == 12'h343 );  //Confirm the register by the address index
wire mtval_ena;
wire [ 31: 0 ] mtval_r;
wire [ 31: 0 ] mtval_nxt;
//If it is an interrupt/abnormal, store the relevant information, otherwise it will be written by the CSR instruction
assign mtval_nxt = trap_mtval_ena ? i_trap_mtval_val : i_csr_val;
fii_dfflr #( 32 ) mtval_dfflr ( mtval_ena, mtval_nxt, mtval_r, sys_clk, rst_n );  //latch

assign o_mtval = mtval_r;  //output


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!