RISC-V单周期处理器设计(寄存器堆设计)(三)

一、寄存器堆介绍

对于RISC-V基础指令集中共包含32个通用寄存器(x0~x31)。寄存器堆可以说是整个cpu的核心,我们可以回想RISC-V指令集,几乎所有类型的指令都要与寄存器打交道的(个人理解)。

注意:x0默认为0x00000000,是一个只读寄存器。

二、寄存器堆功能

上图是一个寄存器module,我可以如果先不思考寄存器内部如何实现,只是把寄存器堆想成一个黑匣子,我们可以思考它到底要干什么那?

我个人理解,寄存器堆实际上就是在系统时钟的控制下,从寄存器堆中对于位置读取数据,或者向对应位置写入数据。如果这样理解的话我们就可以思考出一个寄存器堆都需要什么信号了。

1.系统时钟,复位信号(这个相信大家都理解)

2.读写地址信号。既然要向寄存器堆中读写数据,而一个寄存器堆共有32个寄存器,怎么确定要读写那个寄存器呀?事实上每个寄存器在寄存器堆中都有对应的地址,我们只需要给出地址,就可以找到对应地址。(为啥为5位地址:32个寄存器,如果要表示就要用5位二进制数来表示)

3.读写数据信号。如果上面这个地址信号理解了,那么寄存器堆已经知道了要读写的地址,那么这个地址到底要写入啥,或者读出了什么,则一定需要有信号表示读出的数据或者写入的数据。

4.是否写信号。如果对RISC-V指令系统了解的清楚的话,我们就知道有些类型数指令需要向寄存器堆中写入数据(如:I型 R型),而有些类型指令则不需要向寄存器堆中写入数据(如:S型)。因此一定需要一个信号来高速寄存器堆是否读写。

具体如下:

 可以看到输入信号有:时钟,复位,rs1,rs2,rd,wen,busw

而输出信号则是:从对应寄存器中读出的数据:BusA,BusB。

三、verilog代码实现

module RegFile(
    input clk,
    input rstn,
    input [4:0]Rs1,     //第一个寄存器地址
    input [4:0]Rs2,     //第二个寄存器地址
    input [4:0]Rd,      //写入的寄存器地址
    
    input Wen,          //控制信号
    output [31:0]BusA,      //输出第一个寄存器中的值
    output [31:0]BusB,      //输出第二个寄存器中的值
    input [31:0]BusW       //写个的寄存器的值
);

    reg [31:0]DataReg[31:0];        //定义出来这个寄存器
    reg [31:0]BusA1,BusB1;          //输出的中间变量
    
    
    reg [31:0]Waddr;
    always@(Rd)begin
        case(Rd)
            5'b00000 : Waddr=32'h0000_0001;
            5'b00001 : Waddr=32'h0000_0002;
            5'b00010 : Waddr=32'h0000_0004;
            5'b00011 : Waddr=32'h0000_0008;
            5'b00100 : Waddr=32'h0000_0010;
            5'b00101 : Waddr=32'h0000_0020;
            5'b00110 : Waddr=32'h0000_0040;
            5'b00111 : Waddr=32'h0000_0080;
            5'b01000 : Waddr=32'h0000_0100;
            5'b01001 : Waddr=32'h0000_0200;
            5'b01010 : Waddr=32'h0000_0400;
            5'b01011 : Waddr=32'h0000_0800;
            5'b01100 : Waddr=32'h0000_1000;
            5'b01101 : Waddr=32'h0000_2000;
            5'b01110 : Waddr=32'h0000_4000;
            5'b01111 : Waddr=32'h0000_8000;
            5'b10000 : Waddr=32'h0001_0000;
            5'b10001  :Waddr=32'h0002_0000;
            5'b10010 : Waddr=32'h0004_0000;
            5'b10011 : Waddr=32'h0008_0000;
            5'b10100 : Waddr=32'h0010_0000;
            5'b10101 : Waddr=32'h0020_0000;
            5'b10110 : Waddr=32'h0040_0000;
            5'b10111 : Waddr=32'h0080_0000;		
            5'b11000 : Waddr=32'h0100_0000;
            5'b11001 : Waddr=32'h0200_0000;
            5'b11010 : Waddr=32'h0400_0000;
            5'b11011 : Waddr=32'h0800_0000;	
            5'b11100 : Waddr=32'h1000_0000;
            5'b11101 : Waddr=32'h2000_0000;
            5'b11110 : Waddr=32'h4000_0000;
            5'b11111 : Waddr=32'h8000_0000;
        endcase
    end

    
    wire [31:0] W_en;
    assign W_en=Waddr&{32{Wen}};

    //向第1个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[0]<=32'd0;
        else if(W_en[0]==1'b1) DataReg[0]<=32'd0;
        else DataReg[0]<=32'd0;
    //向第2个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[1]<=32'd0;
        else if(W_en[1]==1'b1) DataReg[1]<=BusW;
        else DataReg[1]<=DataReg[1];
    //向第3个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[2]<=32'h7fff_fff0;
        else if(W_en[2]==1'b1) DataReg[2]<=BusW;
        else DataReg[2]<=DataReg[2];
    //向第4个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[3]<=32'h1000_0000;
        else if(W_en[3]==1'b1) DataReg[3]<=BusW;
        else DataReg[3]<=DataReg[3];  
    //向第5个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[4]<=32'd0;
        else if(W_en[4]==1'b1) DataReg[4]<=BusW;
        else DataReg[4]<=DataReg[4];
    //向第6个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[5]<=32'd0;
        else if(W_en[5]==1'b1) DataReg[5]<=BusW;
        else DataReg[5]<=DataReg[5];
    //向第7个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[6]<=32'd0;
        else if(W_en[6]==1'b1) DataReg[6]<=BusW;
        else DataReg[6]<=DataReg[6];
    //向第8个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[7]<=32'd0;
        else if(W_en[7]==1'b1) DataReg[7]<=BusW;
        else DataReg[7]<=DataReg[7];  
    //向第9个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[8]<=32'd0;
        else if(W_en[8]==1'b1) DataReg[8]<=BusW;
        else DataReg[8]<=DataReg[8];
    //向第10个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[9]<=32'd0;
        else if(W_en[9]==1'b1) DataReg[9]<=BusW;
        else DataReg[9]<=DataReg[9]; 
    //向第11个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[10]<=32'd0;
        else if(W_en[10]==1'b1) DataReg[10]<=BusW;
        else DataReg[10]<=DataReg[10];
    //向第12个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[11]<=32'd0;
        else if(W_en[11]==1'b1) DataReg[11]<=BusW;
        else DataReg[11]<=DataReg[11];
    //向第13个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[12]<=32'd0;
        else if(W_en[12]==1'b1) DataReg[12]<=BusW;
        else DataReg[12]<=DataReg[12];
    //向第14个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[13]<=32'd0;
        else if(W_en[13]==1'b1) DataReg[13]<=BusW;
        else DataReg[13]<=DataReg[13];  
    //向第15个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[14]<=32'd0;
        else if(W_en[14]==1'b1) DataReg[14]<=BusW;
        else DataReg[14]<=DataReg[14];
    //向第16个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[15]<=32'd0;
        else if(W_en[15]==1'b1) DataReg[15]<=BusW;
        else DataReg[15]<=DataReg[15];
    //向第17个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[16]<=32'd0;
        else if(W_en[16]==1'b1) DataReg[16]<=BusW;
        else DataReg[16]<=DataReg[16];
    //向第18个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[17]<=32'd0;
        else if(W_en[17]==1'b1) DataReg[17]<=BusW;
        else DataReg[17]<=DataReg[17];  
    //向第19个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[18]<=32'd0;
        else if(W_en[18]==1'b1) DataReg[18]<=BusW;
        else DataReg[18]<=DataReg[18];
    //向第20个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[19]<=32'd0;
        else if(W_en[19]==1'b1) DataReg[19]<=BusW;
        else DataReg[19]<=DataReg[19];  
    //向第21个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[20]<=32'd0;
        else if(W_en[20]==1'b1) DataReg[20]<=BusW;
        else DataReg[20]<=DataReg[20];
    //向第22个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[21]<=32'd0;
        else if(W_en[21]==1'b1) DataReg[21]<=BusW;
        else DataReg[21]<=DataReg[21];
    //向第23个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[22]<=32'd0;
        else if(W_en[22]==1'b1) DataReg[22]<=BusW;
        else DataReg[22]<=DataReg[22];
    //向第24个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[23]<=32'd0;
        else if(W_en[23]==1'b1) DataReg[23]<=BusW;
        else DataReg[23]<=DataReg[23];  
    //向第25个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[24]<=32'd0;
        else if(W_en[24]==1'b1) DataReg[24]<=BusW;
        else DataReg[24]<=DataReg[24];
    //向第26个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[25]<=32'd0;
        else if(W_en[25]==1'b1) DataReg[25]<=BusW;
        else DataReg[25]<=DataReg[25];
    //向第27个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[26]<=32'd0;
        else if(W_en[26]==1'b1) DataReg[26]<=BusW;
        else DataReg[26]<=DataReg[26];
    //向第28个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[27]<=32'd0;
        else if(W_en[27]==1'b1) DataReg[27]<=BusW;
        else DataReg[27]<=DataReg[27];  
    //向第29个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[28]<=32'd0;
        else if(W_en[28]==1'b1) DataReg[28]<=BusW;
        else DataReg[28]<=DataReg[28];
    //向第30个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[29]<=32'd0;
        else if(W_en[29]==1'b1) DataReg[29]<=BusW;
        else DataReg[29]<=DataReg[29]; 
    //向第31个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[30]<=32'd0;
        else if(W_en[30]==1'b1) DataReg[30]<=BusW;
        else DataReg[30]<=DataReg[30];
    //向第32个寄存器写入
    always@(posedge clk or negedge rstn)
        if(!rstn) DataReg[31]<=32'd0;
        else if(W_en[31]==1'b1) DataReg[31]<=BusW;
        else DataReg[31]<=DataReg[31];   
        
   
    //读取寄存器a的值
    always@(Rs1 or BusW or Rd)begin
        case(Rs1)
            5'b00000 : BusA1=DataReg[0];
            5'b00001 : BusA1=DataReg[1];
            5'b00010 : BusA1=DataReg[2];
            5'b00011 : BusA1=DataReg[3];
            5'b00100 : BusA1=DataReg[4];
            5'b00101 : BusA1=DataReg[5];
            5'b00110 : BusA1=DataReg[6];
            5'b00111 : BusA1=DataReg[7];
            5'b01000 : BusA1=DataReg[8];
            5'b01001 : BusA1=DataReg[9];
            5'b01010 : BusA1=DataReg[10];
            5'b01011 : BusA1=DataReg[11];
            5'b01100 : BusA1=DataReg[12];
            5'b01101 : BusA1=DataReg[13];
            5'b01110 : BusA1=DataReg[14];
            5'b01111 : BusA1=DataReg[15];
            5'b10000 : BusA1=DataReg[16];
            5'b10001  :BusA1=DataReg[17];
            5'b10010 : BusA1=DataReg[18];
            5'b10011 : BusA1=DataReg[19];
            5'b10100 : BusA1=DataReg[20];
            5'b10101 : BusA1=DataReg[21];
            5'b10110 : BusA1=DataReg[22];
            5'b10111 : BusA1=DataReg[23];		
            5'b11000 : BusA1=DataReg[24];
            5'b11001 : BusA1=DataReg[25];
            5'b11010 : BusA1=DataReg[26];
            5'b11011 : BusA1=DataReg[27];	
            5'b11100 : BusA1=DataReg[28];
            5'b11101 : BusA1=DataReg[29];
            5'b11110 : BusA1=DataReg[30];
            5'b11111 : BusA1=DataReg[31];  
        endcase
    end
    
    always@(Rs2 or BusW or Rd)begin
        case(Rs2)
            5'b00000 : BusB1=DataReg[0];
            5'b00001 : BusB1=DataReg[1];
            5'b00010 : BusB1=DataReg[2];
            5'b00011 : BusB1=DataReg[3];
            5'b00100 : BusB1=DataReg[4];
            5'b00101 : BusB1=DataReg[5];
            5'b00110 : BusB1=DataReg[6];
            5'b00111 : BusB1=DataReg[7];
            5'b01000 : BusB1=DataReg[8];
            5'b01001 : BusB1=DataReg[9];
            5'b01010 : BusB1=DataReg[10];
            5'b01011 : BusB1=DataReg[11];
            5'b01100 : BusB1=DataReg[12];
            5'b01101 : BusB1=DataReg[13];
            5'b01110 : BusB1=DataReg[14];
            5'b01111 : BusB1=DataReg[15];
            5'b10000 : BusB1=DataReg[16];
            5'b10001  :BusB1=DataReg[17];
            5'b10010 : BusB1=DataReg[18];
            5'b10011 : BusB1=DataReg[19];
            5'b10100 : BusB1=DataReg[20];
            5'b10101 : BusB1=DataReg[21];
            5'b10110 : BusB1=DataReg[22];
            5'b10111 : BusB1=DataReg[23];		
            5'b11000 : BusB1=DataReg[24];
            5'b11001 : BusB1=DataReg[25];
            5'b11010 : BusB1=DataReg[26];
            5'b11011 : BusB1=DataReg[27];	
            5'b11100 : BusB1=DataReg[28];
            5'b11101 : BusB1=DataReg[29];
            5'b11110 : BusB1=DataReg[30];
            5'b11111 : BusB1=DataReg[31];  
        endcase
    end

    assign BusA=BusA1;
    assign BusB=BusB1;
        
endmodule

另一种方法

在后面的学习以及和同学交流中我发现其实实现这个寄存器可以不需要这样麻烦代码如下

module Regfile(
    input clk_n,
    input rst_n,
    input [4:0]Rs1,     //第一个寄存器地址
    input [4:0]Rs2,     //第二个寄存器地址
    input [4:0]Rd,      //写入的寄存器地址
    
    input Wen,          //控制信号
    output [31:0]BusA,      //输出第一个寄存器中的值
    output [31:0]BusB,      //输出第二个寄存器中的值
    input [31:0]BusW       //写个的寄存器的值


);
    reg [31:0]DataReg[31:0];
    
    //写
    always@(negedge clk_n or negedge rst_n)begin
        if(!rst_n)begin
            DataReg[0]<=32'd0;
            DataReg[1]<=32'd0;
            DataReg[2]<=32'd0;
            DataReg[3]<=32'd0;
            DataReg[4]<=32'd0;
            DataReg[5]<=32'd0;
            DataReg[6]<=32'd0;
            DataReg[7]<=32'd0;
            DataReg[8]<=32'd0;
            DataReg[9]<=32'd0;
            DataReg[10]<=32'd0;
            DataReg[11]<=32'd0;
            DataReg[12]<=32'd0;
            DataReg[13]<=32'd0;
            DataReg[14]<=32'd0;
            DataReg[15]<=32'd0;
            DataReg[16]<=32'd0;
            DataReg[17]<=32'd0;
            DataReg[18]<=32'd0;
            DataReg[19]<=32'd0;
            DataReg[20]<=32'd0;
            DataReg[21]<=32'd0;
            DataReg[22]<=32'd0;
            DataReg[23]<=32'd0;
            DataReg[24]<=32'd0;
            DataReg[25]<=32'd0;
            DataReg[26]<=32'd0;
            DataReg[27]<=32'd0;
            DataReg[28]<=32'd0;
            DataReg[29]<=32'd0;
            DataReg[30]<=32'd0;
            DataReg[31]<=32'd0;
        end
        else if(Wen&Rd!=5'd0) DataReg[Rd]<=BusW;
    end
    
    //读
    assign BusA=DataReg[Rs1];
    assign BusB=DataReg[Rs2];



endmodule

四、总结

代码我是把每一种情况罗列出来的,当然了其实也是可以使用循环的。代码一定要注意x0这个寄存器是只读寄存器,且内部一直时0x00000000(我自己在这里快把自己坑死了)。

代码有什么疑问欢迎私信讨论,一起进步。

内容中存在什么错误也欢迎大家指出。

  • 6
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值