P4课下
写在开始前
万里长征已过一半,同志们继续努力!
关于比较具体的理论分析,请看我的另一篇博客P3课下。本博客只讲解从P3升级到P4过程中需要注意的内容。
P4要求用verilog实现P3中搭建的单周期cpu。整体上来说就是一个翻译的过程,但是因为毕竟用的载体不一样,还是存在一些需要修改的地方。
在开始编写代码前,千万要确定好自己的代码风格和编写规范,这很重要,能避免很多问题。
P4课上已更新,见我另一篇博客。
开发流程
建议先写好模块,在写顶层电路,将模块按照logisim或课本上的电路图进行连接,这样可以避免很多错误。
设计规范举例
模块
我的做法是给每个实例化的模块都定义好针对该模块的接线,然后再慢慢连接。如下所示:
wire rst_DM;
wire clk_DM;
wire WE_DM;
wire[31:0] A_DM;
wire[31:0] WD_DM;
wire[31:0] RD_DM;
DM _DM(reset,clk,WE_DM,PC_IFU,A_DM,WD_DM,RD_DM);//DM
//需要注意的是,这里无论output的规格是reg还是wire,外部的接线都得定义为wire
//*********************************************
//DM init
assign A_DM=ALUResult_ALU;
assign WD_DM=AD2_GRF;
assign WE_DM=MemWrite_Controller;
这么做的好处很明显,就是规范和工整,方便纠错。但坏处也很明显,就是代码量会很容易膨胀的特别大。
而所有在顶层电路中出现的多路选择器,我在给每个模块的输入连线的时候实现它们的功能。
需要注意的是,P4可能会增添一些P3没有的指令,这时候要想好新增逻辑是否会造成什么别的影响。
控制信号
我的做法是针对每个func和op,直接给出对应的控制信号,如下:
if(Func==6'b100000)//add
begin
nop=1'b0;
RegWrite=1'b1;
RegDst=1'b1;
ALUSrc=1'b0;
Branch=1'b0;
MemWrite=1'b0;
MemtoReg=1'b0;
ALUControl=3'b000;
ExtControl=1'b1;
LinkLable=1'b0;
JrLable=1'b0;
end
好处是简单而且直白,不会给以后的开发增添思维负担。坏处是代码很容易过长。不过controller是封装好的模块,只要能在课下保证controller是正确的那代码过长的问题也影响不大。
控制信号约定
参数 | 含义 |
---|---|
RegWrite | 是否要写入寄存器文件 |
RegDst | 决定存放被写入寄存器的地址为哪几位,0为I型指令,1为R型 |
ALUSrc | 决定ALU的第二个数据是立即数还是寄存器的值。0为寄存器 |
Branch | 决定当前是否为分支指令,1为是 |
MemWrite | 决定是否要写入数据存储器,1为是 |
MemtoReg | 所需结果是ALU计算结果还是读取结果,0为计算 |
ALUOp | ALU的操作指令 |
ExtControl | 决定扩展是符号扩展还是0扩展,1为符号,0为0 |
LinkLable | 是否要将PC+4写入31号寄存器,1是 是 |
JrLable | 是否从寄存器跳转,1是 |
linklable>RegDst
————————————
Branch>JrLable>LinkLable//这部分是在判断输入时信号的先后顺序
指令 | RegWrite | RegDst | ALUSrc | Branch | MemWrite | MemtoReg | ALUOp | ExtControl | LinkLable | JrLable |
---|---|---|---|---|---|---|---|---|---|---|
add | 1 | 1 | 0 | 0 | 0 | 0 | 000 | 1 | 0 | 0 |
sub | 1 | 1 | 0 | 0 | 0 | 0 | 001 | 1 | 0 | 0 |
ori | 1 | 0 | 1 | 0 | 0 | 0 | 010 | 0 | 0 | 0 |
lw | 1 | 0 | 1 | 0 | 0 | 1 | 000 | 1 | 0 | 0 |
sw | 0 | x | 1 | 0 | 1 | x | 000 | 1 | 0 | 0 |
beq | 0 | x | 0 | 1 | 0 | x | 001 | 1 | 0 | 0 |
lui | 1 | 0 | 1 | 0 | 0 | 0 | 100 | 1 | 0 | 0 |
jal | 1 | x | x | 0 | 0 | x | 000 | 0 | 1 | 0 |
jr | 0 | x | x | 0 | 0 | x | 000 | 0 | 0 | 1 |
jal和jr
可以看出来,这个控制信号和P3的控制信号对比增添了两个信号。我采用比较笨的方式,对于jr和jal都直接用一个新的控制信号控制。
对于jal,LinkLable控制是否链接。当LinkLable为1时,会强制改变寄存器文件的输入地址和输入数据。同时,也会强制改变PC的值,表现在电路中等于是多加了一些多路开关,表现在代码中相当于多加了几个if。
对于jr,同理,JrLable会控制是否跳转。若JrLable为1,会强制修改PC的值。
需要注意的是,修改PC时一定要理清不同的特判间的关系,千万不能出现逻辑漏洞,比如没有给Branch=1,Zero=0这种情况赋值
结语
到这里,P3和P4间的差别基本讲完了,剩下的就看你对P3和P4的理解了。加油,过了P4就是P5,那才是重头戏。