Menu Close

RISC-V CSR Read and Write Control Module(1)exu_csr Module

1. Input/Output


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). For a review of the six CSR instructions, see the article RISC-V CSR register (1) CSR introduction and CSR instructions . This article will start with the exu_csr module to introduce how to control the reading and writing of CSR in the RISC-V CPU.



The following are the more important input and output signals, and the corresponding explanations are marked in the code segment.

input sys_clk,              //system clock 
input i_SYSTEM,             //opcode of CSR instruction 
input [ 31: 0 ] i_rs1_val,  // the value of rs1 
input [ 4: 0 ] i_rd_idx,    //index of rd 
input [ 5: 0 ] i_csr_instr, // csr instruction (one of 6) 
input [ 11: 0 ] i_csr_addr, // 12-bit address of index CSR register 
input [ 31: 0 ] i_csr_imm,  //immediate number after zero extension 
input i_ext_irq,            //External interrupt request 
input i_sft_irq,            //software interrupt request 
input i_tmr_irq,            //Timer interrupt request 
input i_irq_src,            //interrupt source 
input i_exp_src,            // exception source 
input [ 31: 0 ] i_exe_pc,   //executed program counter 
input [ 31: 0 ] i_ir,       //instruction register 
output [ 31: 0 ] o_irq_pc,  //Interrupt entry address 
output [ 31: 0 ] o_mepc,    //PC that needs to be executed after the interrupt returns 
input i_mret_ena,           //Interrupt return enable 
//-----------------------------Omit debug-related signals------------ ----------------------- 
input i_EXE_vld,            //execute valid 
output [ 31: 0 ] o_wr_csr_nxt,  //The value written to the CSR register 
output o_rd_wen,            //CSR register read enable for write back 
output [ 4: 0 ] o_wb_rd_idx,    // write back index 
output [ 31: 0 ] o_wb_data,     //write back data 
output o_meie,              // external interrupt enable 
output o_msie,              //software interrupt enable 
output o_mtie,              // timer interrupt enable 
output o_glb_irq,           //Global interrupt enable 
input rst_n                 //reset


It can be seen that the above can be mainly divided into interrupt-related signals and CSR instruction execution-related signals. Similar to the exu_alu module, the execution of the CSR instruction also requires register-related indices and values. Interrupt-related signals mainly include the interrupt/abnormal request signal input by the high-level module, and the interrupt enable and PC signal output by the bottom module.


2. Execute

The main part of the code is the 6 instructions of CSR. The explanation of the code is as follows:

// CSR instructions are arranged as follows
// i_csr_instr = {rv32i_csrrci, rv32i_csrrsi, rv32i_csrrwi,
//                rv32i_csrrc,  rv32i_csrrs,  rv32i_csrrw};

// write the value to the register
always @ ( * )
    reg_csr_val <= 32'b0;//initialization
    if ( i_SYSTEM & csr_wen )
        case ( i_csr_instr )
            6'h01:            //rv32i_csrrw
                reg_csr_val <= i_rs1_val;              
            6'h02:            //rv32i_csrrs
                reg_csr_val <= i_rs1_val | w_csr_val;  
            6'h04:            //rv32i_csrrc
                reg_csr_val <= ( ~i_rs1_val ) & w_csr_val; 
            6'h08:            //rv32i_csrrwi
                reg_csr_val <= i_csr_imm; 
            6'h10:            //rv32i_csrrsi
                reg_csr_val <= i_csr_imm | w_csr_val;  
            6'h20:            //rv32i_csrrci
                reg_csr_val <= ( ~i_csr_imm ) & w_csr_val; 
            default: ;


//CSR[11:10]/ If bit 30-31 of machine code is not 2'b11, it is a readable and writable attribute
wire csr_wen  = i_EXE_vld & i_SYSTEM & (i_csr_addr[11:10] != 2'b11);
wire csr_rden = i_EXE_vld & i_SYSTEM;


The above code uses case selection to distinguish the CSR instructions and the realization of the write register. Example with the following code



reg_csr_val <= i_rs1_val | w_csr_val; //rv32i_csrrs


The CSR instruction corresponding to bit 2 of i_csr_instr is CSRRS rd, csr, rs1. t = CSRs[csr]; CSRs[csr] = t | x[rs1]; x[rd] = t

This instruction reads and assigns the value in the CSR register to the rd register, and writes the result of bitwise OR (bitwise OR) between the value in the CSR register and the value in the register rs1 into the CSR register.


The machine code of its instructions is shown in Figure 1. The function to implement CSR setting here is reg_csr_val <= i_rs1_val | w_csr_val; 

Another part of the CSR read register function will be implemented in the csr_reg module, which will be explained later when this module is mentioned.


Figure 1 CSRRS machine code format [1]

In the RISC-V CSR register (1) CSR introduction and CSR instructions mentioned,

All CSR instructions can only operate on one CSR register at a time, and its machine code is shown in Figure 1. It can be seen that the CSR instruction is similar to the I-type instruction. Although there is also a 12-bit immediate field, bits 20-31 of the machine code are actually used to index the address of the corresponding CSR register. So in theory, a total of 2^12 = 4096-bit CSR registers can be implemented.

By convention, the upper bits of the CSR address (CSR[11:8]/bits 28-31 of machine code) are used to encode the read and write accessibility of the CSR according to the privilege level.

//CSR register bit 10-11 is readable and writable if it is not 2’b11
wire csr_wen = i_EXE_vld & i_SYSTEM & (i_csr_addr[11:10] != 2’b11);
wire csr_rden = i_EXE_vld & i_SYSTEM;

  • The first two bits (CSR[11:10]/bits 30-31 of machine code) indicate whether this CSR register is readable and writable (00, 01 or 10) or read-only (11).
  • The next two bits (CSR[9:8]/bits 28-29 of machine code) are encoded to indicate the lowest privilege level [2] that can access this CSR register.

Here, through the realization of the wire csr_wen and wire csr_rden signals, the readable and writable attributes of the corresponding CSR registers are distinguished.


3. csr_reg instance

The exu_csr module is instantiated by the csr_reg module. Many output signals of exu_csr are passed up by the csr_reg module. Similarly, some input signals of exu_csr are also passed down to the csr_reg module. The detailed code is shown in the following figure:

csr_reg csr_reg_U
    .sys_clk        ( sys_clk ), //system clock
    .i_mret_ena     ( i_mret_ena ),//interrupt return enable
    .i_EXE_vld      ( i_EXE_vld ),//The execution is valid
//Interrupt request and interrupt source
    .i_ext_irq      ( i_ext_irq ),
    .i_sft_irq      ( i_sft_irq ),
    .i_tmr_irq      ( i_tmr_irq ),
    .i_irq_src      ( i_irq_src & o_glb_irq),
//Exception source, exception PC and exception instruction 
    .i_exp_src      ( i_exp_src ),
    .i_exe_pc       ( i_exe_pc ),
    .i_ir           ( i_ir ),
//Interrupt PC and interrupt entry address
    .o_irq_pc       ( o_irq_pc ),
    .o_mepc         ( o_mepc ),
//CSR instruction related signals  
    .i_csr_rden     ( csr_rden ),
    .i_csr_addr     ( i_csr_addr ),
    .i_csr_val      ( reg_csr_val ),
    .i_csr_wen      ( csr_wen ),
    .o_csr_val      ( w_csr_val ),
//Interrupt enable signal output by mie, mstatus registers
    .o_meie         ( o_meie ),
    .o_msie         ( o_msie ),
    .o_mtie         ( o_mtie ),
    .o_glb_irq      ( o_glb_irq ),
    .rst_n          ( rst_n )//reset


4. Article references

[1] D. Patterson and A. Waterman, The RISC-V reader. Berkeley: Strawberry Canyon LLC, 2018.

[2] , 2021. [Online]. Available: [Accessed: 22- Feb- 2021] .

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!