MIPS寄存器堆
阅读原文时间:2023年09月03日阅读:1

实验目的

  • 熟悉并掌握 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。

设计代码

`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

测试

测试代码

`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,其余寄存器的值符合预期。当同时写和读,即写地址和读地址相同,且写使能时,发现读到的数据为旧数据,而写入的数据不会冲突。