实验任务书
基础实验包: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