实验任务书
基础实验包:reg_file
龙芯杯比赛所设计的CPU是基于MIPS指令集的,所以我们应该先熟悉MIPS指令集CPU的设计规范。
关于寄存器这块,我找到了下列资料。
MIPS通用寄存器
MIPS指令集简明手册:MIPS汇编语言学习笔记03:print HelloWorld,强烈推荐!!文章内有一个pdf手册,即MIPS简明手册。
建议先学MIPS汇编,这样会对MIPS体系有着较为深刻的理解。MIPS学习笔记
MIPS寄存器模块特点
寄存器堆的功能:提供32个32位寄存器,并提供“一写两读”功能。

写寄存器
如果我们想把一个内容写入寄存器,那么至少先需要复位失效(rst == Disable)并且需要时钟信号来临(posedge clk)。
将指定内容写入到寄存器,需要:
- 写入的数据本身(写数据)
- 写入编号为几的寄存器(写地址)
因为对于写寄存器来说,我们至少需要两个input端口完成。
为了方便对写寄存器的控制,我们引入了控制信号wen(写使能)。
PS:
- MIPS规定0号寄存器不能被写入,所以我们还需要添加判断
- 第0号寄存器如果没有被写入任何值,那么它是一个非稳态数值(即 32’hx)。需要在rst信号有效的时候将其先行赋值0
读寄存器
目标:实现两读功能。
为方便译码阶段立即取得寄存器的数据,不同于写数据阶段使用时序逻辑,在读阶段使用的是组合电路,也就是说读阶段不受始终约束。
读取的话就比较简单,只需要:
- 读1的数据
- 读1的地址
- 读2的数据
- 读2的地址
注意:无论是写寄存器还是读寄存器,testbench给的测试代码是非常无语的,甚至有给-8寄存器赋值的代码验证。所以我们无论是读还是写寄存器都需要对寄存器编号进行判断!
更正:这里好像不是testbench问题,我把Wave显示格式调成二进制后发现正常的。

调成十进制就会是负数,我不知道为什么?

寄存器堆verilog实现代码
`timescale 10 ns / 1 ns
`define DATA_WIDTH 32
`define ADDR_WIDTH 5
module reg_file(
input clk,
input rst,
input wire [`ADDR_WIDTH - 1:0] waddr, // 写地址
input wire [`ADDR_WIDTH - 1:0] raddr1,
input wire [`ADDR_WIDTH - 1:0] raddr2,
input wire wen, // 写使能
input wire [`DATA_WIDTH - 1:0] wdata, // 写数据
output reg [`DATA_WIDTH - 1:0] rdata1,
output reg [`DATA_WIDTH - 1:0] rdata2
);
reg [31:0] r [31:0];
always @ (posedge clk) // 时钟上升沿来临
begin
if(rst==1)
begin // when rst is high, reset everthing to 0
r[0] <= 0;
end
if(wen==1)
begin //when wen is high, write register
if (waddr >= 1 && waddr <= 31) begin
r[waddr] <= wdata;
end
// TODO: Please add your logic code here
end
end
always @(*) begin
begin // code for output rdata1 and rdata2
if (raddr1 >= 0 && raddr1 <= 31) begin
rdata1 <= r[raddr1];
end
if (raddr2 >= 0 && raddr2 <= 31) begin
rdata2 <= r[raddr2];
end
end
end
endmodule
参考文献:
https://github.com/gzhy5111/cpu/blob/master/codes/Chapter7/regfile.v