Menu Close

RISC-V CSR Read and Write Control Module(4)CSR Register Implementation 2

Related reference articles:

RISC-V teaching plan

 

This article then introduces the implementation of the register on the RISC-V CSR read and write control (3) CSR register implementation.

 

1.4. csr_mepc

The mepc register stores the PC value when an interrupt or exception occurs, which will be used as the return address in the exception subroutine and is a readable and writable register. Part of the important code to implement the mepc register is as follows (the code repeated in the previous module is omitted):

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

output [ 31: 0 ] o_mepc,//output mepc


wire [ 31: 0 ] i_mepc;
wire [ 31: 0 ] mepc_r;


wire mepc_valid = (i_irq_src | i_exp_src) ? 1'b1 : 1'b0;//Interrupt or exception arrives
assign i_mepc = mepc_valid ? i_exe_pc : mepc_r;//If there is an interrupt/abnormal arrival, set the PC as the current PC, otherwise use the previously stored mepc


wire sel_mepc = ( i_csr_addr == 12'h341 );//Confirm register by address index
wire mepc_ena = wr_mepc | mepc_valid;//Enable written by CSR instruction or set by interrupt/abnormal

wire [ 31: 0 ] mepc_nxt;
assign mepc_nxt[ 31: 1 ] = mepc_valid ? i_mepc[ 31 : 1 ] : i_csr_val[ 31 : 1 ];//If there is an interrupt, write the return address of the interrupt, otherwise it will be written by the CSR instruction
assign mepc_nxt[ 0 ] = 1'b0; // The address of mepc must be aligned with at least 2 bytes, otherwise an address misalignment exception may be generated

fii_dfflr #( 32 ) epc_dfflr ( mepc_ena, mepc_nxt, mepc_r, sys_clk, rst_n );//Latch
assign o_mepc = mepc_r;//output

 

1.5 csr_mcause

mcause is a readable and writable register that records the reason for the last entry exception or interrupt time and serves the interrupt or exception subroutine in the form of a record number (exception code). The definition of its specific value can be found in Figure 8 in the RISC-V CSR register (2) CSR register. mcause will also be used in conjunction with mtvec. If the MODE of mtvec is 1, the entry address of the interrupt will become BASE + 4 X cause, where the cause is the exception code of the interrupt ( when an exception occurs, the interrupt entry address is still the base address. ). Part of the important code to implement the mcause register is as follows (the code repeated in the previous module is omitted):

input i_irq_src,//Interrupt source
input i_mie,//interrupt global enable

input i_meie, // external interrupt enable in machine mode
input i_mtie, // timer interrupt enable in machine mode
input i_msie,//Software interrupt enable in machine mode

input i_sft_irq,//software interrupt request
input i_tmr_irq,//Timer interrupt request
input i_ext_irq,//External interrupt request

input i_EXE_vld,//Whether it is the execution stage

input i_exp_src,//Exception source
//The following are some exceptions, currently not implemented, hardwired to 0 in the outer csr_reg module.
input i_iam_exp,
input i_iaf_exp,
input i_illi_exp,
input i_bp_exp,
input i_mti_exp,
input i_lam_exp,
input i_laf_exp,
input i_saam_exp,
input i_saaf_exp,

output [ 31: 0 ] o_mcause,//output mcause



wire m_is = i_mie & i_msie & i_sft_irq;//software interrupt
wire m_it = i_mie & i_mtie & i_tmr_irq;//Timer interrupt
wire m_ie = i_mie & i_meie & i_ext_irq;//External interrupt

//==============================Exceptions and Interrupts================ =====================================
wire[31:0] exp_mcause;
//When an exception occurs, the highest bit of mcause is 0
assign exp_mcause[31:5] = 27'b0;
//According to the type of exception, set the corresponding bit
assign exp_mcause[4:0] =
                         i_iam_exp ? 5'd0 //Instruction address misaligned
                       : i_iaf_exp ? 5'd1 //Instruction access fault
                       : i_illi_exp ? 5'd2 //Illegal instruction
                       : i_bp_exp ? 5'd3 //Breakpoint
                       : i_lam_exp ? 5'd4 //load address misalign
                       : i_laf_exp ? 5'd5 //load access fault
                       : i_saam_exp ? 5'd6 //Store/AMO address misalign
                       : i_saaf_exp ? 5'd7 //Store/AMO access fault
                       : 5'h1F; //Otherwise a reserved value


wire[31:0] irq_mcause;
//When an interrupt occurs, the highest bit of mcause is 1
assign irq_mcause[31] = 1'b1;
assign irq_mcause[30:4] = 27'b0;
//According to the type of interrupt, set the corresponding bit
assign irq_mcause[3:0] = m_is ? 4'd3 : // 3 Machine software interrupt
                         m_it ? 4'd7 : // 7 Machine timer interrupt
                         m_ie ? 4'd11 : // 11 Machine external interrupt
                         4'b0;

wire [31:0] mcause_val = i_irq_src ? irq_mcause : exp_mcause;//Determine interrupt or exception
//==================================================== =================================
wire mcause_valid = (i_irq_src | i_exp_src) ? 1'b1 : 1'b0;//Whether interrupt/exception occurs

wire sel_mcause = (i_csr_addr == 12'h342);//Confirm register by address index

wire[31:0] mcause_r;
wire [31:0] mcause_nxt = mcause_valid ? mcause_val : i_csr_val;//If an interrupt/exception occurs, mcause is assigned as the cause of the interrupt/abnormal, otherwise it is written by the CSR instruction

fii_dfflr #(32) mcause_dfflr (mcause_ena, mcause_nxt, mcause_r, sys_clk, rst_n);//Latch

assign o_mcause = mcause_r;//output

 

1.6. csr_mie

The mie register is readable and writable and is used for further separate enable control of different interrupts. Note that it is separated from the bit MIE of mstatus. Part of the important code to implement the mie register is as follows (the code repeated in the previous module is omitted):

output [ 31: 0 ] o_mie,//output mie
output o_meie,// external interrupt enable in output machine mode
output o_msie,//Software interrupt enable in output machine mode
output o_mtie, // timer interrupt enable in output machine mode


wire sel_mie = ( i_csr_addr == 12'h304 );//Confirm the register by the address index

wire [ 31: 0 ] mie_r;
wire [ 31: 0 ] mie_nxt;

assign mie_nxt[ 31: 12 ] = 20'b0;//hardwire other bits to 0
assign mie_nxt[ 11 ]     = i_csr_val[ 11 ]; //o_meie
assign mie_nxt[ 10: 8 ]  = 3'b0;
assign mie_nxt[ 7 ]      = i_csr_val[ 7 ]; //o_mtie
assign mie_nxt[ 6: 4 ]   = 3'b0;
assign mie_nxt[ 3 ]      = i_csr_val[ 3 ]; //o_msie
assign mie_nxt[ 2: 0 ]   = 3'b0;

fii_dfflr #( 32 ) mie_dfflr ( mie_ena, mie_nxt, mie_r, sys_clk, rst_n );//Latch


assign o_mie = mie_r;//output

// Output the important interrupt enable bit separately
assign o_meie = o_mie[ 11 ];
assign o_mtie = o_mie[7];
assign o_msie = o_mie[3];

 

1.7. csr_mip

Although the mip registers are by definition readable and writable, the MEIP, MSIP and MTIP used here are read-only. Part of the important code to implement the mip register is as follows (the code repeated in the previous module is omitted):

input i_sft_irq,//software interrupt request
input i_tmr_irq,//Timer interrupt request
input i_ext_irq,//External interrupt request


output [ 31: 0 ] o_mip,//output mip


wire sel_mip = ( i_csr_addr == 12'h344 );//Confirm the register by the address index


wire meip_r;
wire msip_r;
wire mtip_r;

//As long as there is an interrupt request, the corresponding interrupt hanging bit will be set
assign meip_r = i_ext_irq;
assign msip_r = i_sft_irq;
assign mtip_r = i_tmr_irq;

//Assign the bits in the mip respectively.
wire [ 31: 0 ] ip_r;
assign ip_r[ 31: 12 ] = 20'b0;
assign ip_r[ 11 ]     = meip_r;
assign ip_r[ 10: 8 ]  = 3'b0;
assign ip_r[ 7 ]      = mtip_r;
assign ip_r[ 6: 4 ]   = 3'b0;
assign ip_r[ 3 ]      = msip_r;
assign ip_r[ 2: 0 ]   = 3'b0;

assign o_mip = ip_r;//output

 

Posted in 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!