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
1.2.csr_msatus
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 i_status_ena; 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
1.3.csr_mtval
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