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