• MIPS寄存器堆


    实验目的

    • 熟悉并掌握 MIPS 计算机中寄存器堆的原理和设计方法
    • 理解源操作数/目的操作数的概念

    实验环境

    • Vivado 集成开发环境

    MIPS寄存器

    • 寄存器R0的值恒为0

    模块接口设计

    1个写端口和2个读端口

    名称 宽度 方向 描述
    clk 1 IN 时钟信号
    raddr1 5 IN 寄存器堆读地址1
    rdata1 32 OUT 寄存器堆返回数据1
    raddr2 5 IN 寄存器堆读地址2
    rdata2 32 OUT 寄存器堆返回数据2
    we 1 IN 寄存器堆写使能
    waddr 5 IN 寄存器堆写地址
    wdata 32 IN 寄存器堆写数据

    寄存器堆(regfile)实现了32个32位通用寄存器。

    • 可以同时进行两个寄存器的读操作和一个寄存器的写操作。
    • 写:写使能信号(we)为1时写有效,为0时无效。(write enable
    • 读:读操作可以同时读两个寄存器。
    • 同时对同一个寄存器进行读写时,读的数据为旧的数据。
    • 读写均为同步。
    • 0号寄存器恒为0。

    设计代码

    verilog
    `define REG_DATA_WIDTH 31:0
    `define REG_NUM 31:0
    `define REG_ADDR_WIDTH 4:0
    `define REG_ADDR_BIT 5 // 地址线宽
    `define REG_DATA_BIT 32 // 数据线宽
    module regfile(
        input clk,
        input [`REG_ADDR_WIDTH] raddr1,
        input [`REG_ADDR_WIDTH] raddr2,
        input we, // 写使能
        input [`REG_ADDR_WIDTH] waddr, // 写地址
        input [`REG_DATA_WIDTH] wdata, // 写数据
        output reg [`REG_DATA_WIDTH] rdata1,
        output reg [`REG_DATA_WIDTH] rdata2
        );
        
        // 数组表示寄存器堆
        reg [`REG_DATA_WIDTH] mips_regfile [`REG_NUM];
        
        // 读1
        always @(posedge clk) begin
            if (raddr1 == {`REG_ADDR_BIT{1'b0}}) begin
                rdata1 <= {`REG_DATA_BIT{1'b0}};
            end
            else begin
                rdata1 <= mips_regfile[raddr1];
            end
        end
        // 读2
        always @(posedge clk) begin
            if (raddr2 == {`REG_ADDR_BIT{1'b0}}) begin
                rdata2 <= {`REG_DATA_BIT{1'b0}};
            end
            else begin
                rdata2 <= mips_regfile[raddr2];
            end
        end
        // 写
        always @(posedge clk) begin
            if (we == 1'b1 ) begin
                if (waddr == {`REG_ADDR_BIT{1'b0}}) begin
                    mips_regfile[0] <= {`REG_DATA_BIT{1'b0}};
                end
                else begin
                    mips_regfile[waddr] <= wdata;       
                end
            end
            else begin
                mips_regfile[0] <= {`REG_DATA_BIT{1'b0}};
            end
        end
        
    endmodule
    

    测试

    测试代码

    verilog
    `timescale 1ns / 1ps
    
    `define REG_DATA_WIDTH 31:0
    `define REG_NUM 31:0
    `define REG_ADDR_WIDTH 4:0
    `define REG_ADDR_BIT 5
    `define REG_DATA_BIT 32
    module sim();
        reg clk;
        reg [`REG_ADDR_WIDTH] raddr1;
        reg [`REG_ADDR_WIDTH] raddr2;
        reg we; // 写使能
        reg [`REG_ADDR_WIDTH] waddr; // 写地址
        reg [`REG_DATA_WIDTH] wdata; // 写数据
        wire [`REG_DATA_WIDTH] rdata1;
        wire [`REG_DATA_WIDTH] rdata2;
        
        integer i;
        regfile u0 (
            .clk(clk),
            .raddr1(raddr1),
            .raddr2(raddr2),
            .we(we),
            .waddr(waddr),
            .wdata(wdata),
            .rdata1(rdata1),
            .rdata2(rdata2)
        );
        initial begin
            clk = 1;
            forever begin
                #10 clk = ~clk;
            end
        end
        
        initial begin
            raddr1 = `REG_ADDR_BIT'd0;
            raddr2 = `REG_ADDR_BIT'd0;
            we = 1'b0;
            waddr = `REG_ADDR_BIT'd0;
            wdata = `REG_DATA_BIT'd0;
            
            // 写数据
            #100 
            we = 1'b1;
            wdata = `REG_DATA_BIT'hFF;
            for (i = 0; i < `REG_DATA_BIT; i = i + 1) begin
                waddr = i;
                wdata = wdata + `REG_DATA_BIT'h100;
                #20;
            end
            // 读数据
            we = 1'b0;
            
            for (i = 0; i < `REG_DATA_BIT; i = i + 1) begin
                raddr1 = i;
                raddr2 = `REG_DATA_BIT - raddr1 - 1;
                #20;
            end
            
            // 读写相同
            // 读到的数据是旧数据
            we = 1'b1;
            wdata = `REG_DATA_BIT'h100;
            for (i = 0; i < `REG_DATA_BIT; i = i + 1) begin
                raddr1 = i;
                raddr2 = i;
                waddr = i;
                wdata = wdata - `REG_DATA_BIT'h1;
                #20;
            end
            
            we = 1'b0;
            #100 $finish;
            
        end
    endmodule
    

    测试波形

    写数据:

    从 0号寄存器开始到 31号寄存器,分别写入 01ff到 20ff。

    读数据:

    读地址 1和读地址 2分别读寄存器值,0号寄存器读得值为 0。其余寄存器读值正确。

    结果分析

    先进行写数据测试,从 0号寄存器开始到 31号寄存器,分别写入 01ff20ff。然后进行读数据测试,发现 0号寄存器值为 0,其余寄存器的值符合预期。当同时写和读,即写地址和读地址相同,且写使能时,发现读到的数据为旧数据,而写入的数据不会冲突。


    __EOF__

  • 本文作者: 江水为竭
  • 本文链接: https://www.cnblogs.com/Az1r/p/17674985.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    vue中组件模板为什么只有一个根元素?
    XtraBackup 搭建从库的一般步骤及 XtraBackup 8.0 的注意事项
    [Android]从app的trace打桩原理回顾zygote的fork
    Nacos有几种负载均衡策略?
    操作系统——死锁及其解决方案(p38-p41王道视频、课本ch6)
    C++ 学习系列 -- std::stack 与 std::queue
    C++类对象反制机制实现_精简修改版
    【计组】I/O系统
    LeetCode 78 子集
    Linux入门学习20
  • 原文地址:https://www.cnblogs.com/Az1r/p/17674985.html