RISCV处理器核中关于存储访问部分的实现

这些代码可以借鉴在RISCV 里面实现,注意大小MIPS核是大字端,RISCV核实小字端。

 

由于是32位处理器,并且指令长度也是32位,所以为了性能要求我们要求存储器宽度要达到32位(如果达不到吗,那用32位处理器就有大材小用了,可以换成8位核或者16核)。而处理器要达到精确到字节的寻址,所以我们用四个8位的款的存储器拼接在一起,但是写信号可以分别控制。我们下面的代码就要实现这部分:

 


module mem_addr_ctl(
        input [3:0]ctl,
        input [31:0]addr_i,
        output reg[3:0]wr_en
    );
    always@(*)
    case (ctl)
        `DMEM_SB://store byte [8bits]
        begin
            case(addr_i[1:0])
                0:wr_en = 4'b0001;
                1:wr_en = 4'b0010;
                2:wr_en = 4'b0100;
                3:wr_en = 4'b1000;
                default :wr_en = 4'b000;
            endcase
        end
        `DMEM_SH  ://store half word [16bits]
        begin
            case(addr_i[1:0])
                'd2:wr_en=4'b1100;
                'd0:wr_en=4'b0011;
                default :wr_en = 4'b0000;
            endcase
        end
        `DMEM_SW ://store word [32bits]
        begin
            wr_en=4'b1111;
        end
        default wr_en=4'b0000;
    endcase

endmodule

 

module mem_din_ctl(
        input [3:0]ctl,
        input [31:0]din,
        output reg [31:0]dout
    );

    always @(*)

    case (ctl)
        `DMEM_SB   : // store byte[8bits]
            dout={din[7:0],din[7:0],din[7:0],din[7:0]};
        `DMEM_SH   : // store half word [16bits]
            dout = {din[15:0],din[15:0]};
        `DMEM_SW   :
            dout =din; // store word [32bits]
        default dout=32'bX;
    endcase

endmodule

mem_addr_ctl模块根据保存的要STORE的数据类型以及地址的低两位,确定那个需要写哪个存储器。这里的wr_en[3:0]信号可以对应axi 总线的strb[3:0]信号。

假设一种情况,我们将通用寄存器里的32'H0000_00AA这个数字保存到字节数字的某一位置,根据上面mem_addr_ctlr的处理,如果地址最后两位是2'B11,那么就是wr_en[3:0]=4'b1000.这时候要求寄存器内容的低8位出现在存储器的数据写入端。

        `DMEM_SB   : // store byte[8bits]
            dout={din[7:0],din[7:0],din[7:0],din[7:0]};

所以我们统一化处理,只要是store byte指令,就将低8位输出给每个字节存储器的数据写入端,具体写入到哪个存储器,由wr_en来确定。同样写入16位的half word我们将低16位呈现在总线的输入端。这里要写16位的halfword的地址必须是偶数的。而当写32位寄存器时可以直接对应这32位写入8个字节。

 

以上是我们看的是store指令,之后我们再看一下从存储器里面加载load 的处理。


module mem_dout_ctl(
        input [1:0]byte_addr,
        input [3:0]ctl,
        input [31:0] din,
        output reg [31:0] dout
    );

    always @(*)
    case (ctl)

        `DMEM_LBS : // load byte signed [8bits]
        case (byte_addr)

			'd3:dout={{24{din[31]}},din[31:24]};
            'd2:dout={{24{din[23]}},din[23:16]};
            'd1:dout={{24{din[15]}},din[15:8]};
            'd0:dout={{24{din[7]}},din[7:0] };
          //  default :   dout=32'bX;
        endcase 
        `DMEM_LBU : // load byte unsigned [8bits] 
        case (byte_addr)
            'd0:dout={24'b0,din[7:0]};
            'd1:dout={24'b0,din[15:8]};
            'd2:dout={24'b0,din[23:16]};
            'd3:dout={24'b0,din[31:24]};
          //  default :  dout=32'bX;
        endcase
        `DMEM_LHU : // load half word [16bits] unsigned 
        case (byte_addr)
            'd2:dout={16'b0,din[31:24],din[23:16]};
            'd0:dout={16'b0,din[15:8],din[7 :0]};
            default:dout=32'bX;
        endcase
        `DMEM_LHS :
        case (byte_addr) // load half_word[16its] signed 
   			'd2 :dout={{16{din[31]}},din[31:24],din[23:16]};
            'd0 :dout={{16{din[15]}},din[15:8],din[7 :0]};
            default:dout=32'bX;
        endcase
        `DMEM_LW  :   //load word [32bits] 
            dout=din;
        default :
            dout=0;
    endcase
endmodule

从存储器里load要解决两个问题:

1,输出的数据进行位处理。比如LOAD BYTE指令从某字节存储器里面读出数据对应放在32位输出总线的低8位。

2,进行符号的扩展。8位数据的BIT7就是符号位,16位数据的BIT15是符号位。32位数据的BIT31是符号位。

        `DMEM_LBS : // load byte signed [8bits]
        case (byte_addr)

			 'd0:dout={{24{din[7]}},din[7:0] };

以上一段典型的有符号扩展,将BIT7复制24次防止在32位数据总线的高24位。比如说以前din[7:0]=8'h80, 是8'B1000_0000,那么位扩展后就是32'hFFFF_FF80,如果din[7:0]=8'h7f,是8'B0111_1111,那么位扩展后就是32'h0000_007F。

无符号扩展就是将高24位全部填为0.

Half Word的符号扩展和无符号扩展也是类似这样。

当然从存储器读一个32位的字,直接将读出来的32位保存到寄存器就好,不牵扯是否扩展。

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值