看着各位学长的代码,觉得他们,,都好牛逼。。
沿着他们的足迹,我也搭了一个自己的单周期CPU。
并且重新设计了main.circ,方便对比。
再者就是多看、多分析学长的代码、博客,里面提到了很多坑。
-
全大写。如:
IFU、CTL -
(大)驼峰。如:
AluOp、MemAddr
当然也可以选择ALUOp,我个人在P4中选择了AluOp(保佑我能过P4呜呜呜)
不过我在P5中选择了ALUOp的命名方式(当事人非常后悔)。 -
全小写。如:
instr、addr
我的想法是:
模块定义都是大写,
单个单词尽量缩写,
多个单词(词组)的拼接,用大驼峰。
驼峰命名有一个不好,也可能是我菜,不知道怎么处理,
就是有缩写时,会难受。比如“ALUOp”还是“AluOp”
想要设计Multiplexer,有三种解决方法:
-
if-else,需要设计寄存器,然后always@(*)
-
case-endcase,同1
-
assign语句。
设定某些常数时,可以考虑使用宏,放置在多路选择中,
如各种ALU的Op等,这样代码的可读性也更高。
有至少两种方法建模多路选择:
-
建模Multiplexer
-
assign直接多路选择
我个人现在比较倾向后面一种。因为到了P5,多路选择很烦,
ALU可以看作一个很大的MUX,而小型的MUX用2~4行代码就可完成建模。
又考虑到P4MUX不多,挺纠结的。
这一部分建议阅读学长代码。
个人比较纠结的是lui,参考了YushengZhao学长的结构,把它放到了ALU里。
我一开始根本就不知道怎样用ISE设计一个有结构的project,
因为平常都是写个状态机再写个testbench就过去了。
其实只要写好一个Verilog Module后,
View选择implementation,
Processes内找到View HDL Instantiation Template,双击,
拷贝实例化的文件内容,放到另一个module里,连好线就可以了。
ISE会自动帮我们以一个“层次”的视角看到我们的架构。
以下是我的架构:
mips----|-Controller
|-Datapath--|--NPC
|--PC
|--IM
|--GRF
|--ALU
|--DM
|--GRF
|--EXT
|--MUX
有的人设计了IFU,把NPC、PC还有IM放一块,
还有人直接不要Datapath了,,
各种各样,什么都有,我还是跟着教程走了。
具体的模块如何设计?我用Logisim重新搭了一遍,对着翻译就好了。
-
多定义了线
这个就是有的线(wire),已经作为端口了,但是在后面又重复定义了。 -
Mux错了
当初定义的不纯粹,把控制ALU的操作数的输出端口命名成AluSrc了,在实例化又叫做out,导致仿真的时候,一堆z -
多次CTRL+V,导致AluOp[0]出现3次
这个也会导致一堆z或x
这个地方,虽然Logisim中对ALU的op每一位都生成了表达式,
但是我建议不要按照Logisim的思路,
在Verilog中,直接assign+三元表达式才快速、可读性高 -
Mux端口位宽
这个一不小心就错了 -
输出格式
要注意空格啥的,否则会“fewer outputs”,
测评机会对输出进行匹配,匹配不上,就miss了。
至于更多要注意的地方,可以参考这位学长的博客:
BUAA-Wander的P4解析
一般都是xxx和zzz
这个没有办法,得老老实实跟着数据通路走一遍。
先看模块定义,再看实例化。
ALU的operandB要有一个sel
x = (x >> 32-k) | (x << k);
生成中间变量,然后做或运算