Menu Close

RISC-V CSR读写控制(4)CSR寄存器实现中

相关参考文章:

RISC-V教学教案

 

本文接着RISC-V CSR读写控制(3)CSR寄存器实现上进行介绍寄存器的实现。

 

1.4. csr_mepc

mepc寄存器中存储在中断或异常发生时的准备执行指令的PC值,将在异常子程序中作为返回地址,是一个可读可写的寄存器。实现mepc寄存器的部分重要代码如下(与前面模块中重复的代码省略):

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

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


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


wire mepc_valid = (i_irq_src | i_exp_src) ? 1'b1 : 1'b0;//中断或者异常到来
assign i_mepc = mepc_valid ? i_exe_pc : mepc_r;//如果有中断/异常到来,把PC设置成当前PC,否则用之前存储的mepc


wire sel_mepc = ( i_csr_addr == 12'h341 );//通过地址索引确认寄存器
wire wr_mepc = sel_mepc & i_csr_wen;// mepc寄存器可写
wire mepc_ena = wr_mepc | mepc_valid;//使能由CSR指令写入或者中断/异常置起来

wire [ 31: 0 ] mepc_nxt;
assign mepc_nxt[ 31: 1 ] = mepc_valid ? i_mepc[ 31 : 1 ] : i_csr_val[ 31 : 1 ];//如果有中断,写入中断的返回地址,不然由CSR指令写入
assign mepc_nxt[ 0 ] = 1'b0; // mepc的地址至少要以2字节对齐,不然可能会生成地址错位异常

fii_dfflr #( 32 ) epc_dfflr ( mepc_ena, mepc_nxt, mepc_r, sys_clk, rst_n );//锁存
assign o_mepc = mepc_r;//输出


 

1.5. csr_mcause

mcause是一个可读可写的寄存器,记录最近一次进入异常或者中断时间的原因,以记录号(异常代码)的方式服务于中断或异常子程序。其具体值的定义可参见RISC-V CSR寄存器(2)CSR寄存器中的图8。

mcause也会与mtvec配合使用,如果mtvec的MODE为1, 那么中断的入口地址就会变成BASE + 4 X cause,这里的cause就是中断的异常代码(异常发生时,中断入口地址依然是基地址)。实现mcause寄存器的部分重要代码如下(与前面模块中重复的代码省略):

 

input i_irq_src,//中断源
input i_mie,//中断全局使能

input i_meie,//机器模式下外部中断使能
input i_mtie,//机器模式下计时器中断使能
input i_msie,//机器模式下软件中断使能

input i_sft_irq,//软件中断请求
input i_tmr_irq,//计时器中断请求
input i_ext_irq,//外部中断请求

input i_EXE_vld,//是否为执行阶段

input i_exp_src,//异常源
//下面是一些异常,目前没有实现,在外层csr_reg模块中硬连线到0。
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,//输出mcause



wire m_is = i_mie & i_msie & i_sft_irq;//软件中断
wire m_it = i_mie & i_mtie & i_tmr_irq;//计时器中断
wire m_ie = i_mie & i_meie & i_ext_irq;//外部中断

//=============================异常和中断==================================================
wire [31:0] exp_mcause;
//发生异常时,mcause最高位是0
assign exp_mcause[31:5] = 27'b0;
//根据异常的种类,置相应的位
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;
//发生中断时,mcause最高位是1
assign irq_mcause[31] = 1'b1;
assign irq_mcause[30:4] = 27'b0;
//根据中断的种类,置相应的位
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;//判断中断还是异常
//===============================================================================
wire mcause_valid = (i_irq_src | i_exp_src) ? 1'b1 : 1'b0;//中断/异常是否发生

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

wire [31:0] mcause_r;
wire [31:0] mcause_nxt = mcause_valid ? mcause_val : i_csr_val;//如果中断/异常发生, mcause被赋值成中断/异常的原因,否则被CSR指令写入

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

assign o_mcause = mcause_r;//输出


1.6. csr_mie

mie寄存器是可读可写的,用于进一步对不同中断的分别使能控制,注意将其与mstatus的位MIE分开。实现mie寄存器的部分重要代码如下(与前面模块中重复的代码省略):

output [ 31: 0 ] o_mie,//输出mie
output o_meie,//输出机器模式下外部中断使能
output o_msie,//输出机器模式下软件中断使能
output o_mtie,//输出机器模式下计时器中断使能


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

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

assign mie_nxt[ 31: 12 ] = 20'b0;//将其他的位硬连线到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 );//锁存


assign o_mie = mie_r;//输出

//单独将重要的中断使能位输出
assign o_meie = o_mie[ 11 ];
assign o_mtie = o_mie[ 7 ];
assign o_msie = o_mie[ 3 ];


1.7. csr_mip

mip是中断悬挂寄存器,当中断请求到来时,mip相应的位就会被置高。

mip寄存器虽然定义上是可读可写的,但在这里使用的MEIP,MSIP和MTIP都是只读的。实现mip寄存器的部分重要代码如下(与前面模块中重复的代码省略):

input i_sft_irq,//软件中断请求
input i_tmr_irq,//计时器中断请求
input i_ext_irq,//外部中断请求


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


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


wire meip_r;
wire msip_r;
wire mtip_r;

//只要有中断请求,相应的中断悬挂位就会置起来
assign meip_r = i_ext_irq;
assign msip_r = i_sft_irq;
assign mtip_r = i_tmr_irq;

//将mip中的位分别赋值。
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;//输出
Posted in RISC-V, RISC-V IPcore设计, RISC-V 教案, 应用开发, 教材与教案, 文章

发表评论

相关链接