P3-单周期CPU(Logisim实现)

差点以为自己会鸽掉P3的博客,不过经过努力目前还是造出来了课下测试要求的CPU。作为一个刚接触培养工程能力课程的萌新,不能缺少重来一次的勇气(第一版十个小时造完了,一堆bug加没法很好地拓展),只有搭完了第一遍,才能真正体会到会遇到哪些问题,才会体会到高老板课件中的精髓,才能在第二版中更好地布线,命名以及合理使用tunnel。为了更好地写实验报告,先把博客补上,然后基于博客修改出实验报告。

下文内容:第一次搭建的过程,坑点易错点以及trick总结,

搭建过程:(本段类似叙事,相当于日记)

先看完那几页要求!

当时还没学懂理论,先搭建了一下各个部件。GRF不用说了,肯定是用P0搭好的,CPU可以重新来过,但是GRF必须复用。注意GRF要有Reset,总Reset按下的时候PC、DM、GRF都要回到原始状态(助教在讨论区说了)。IFU(取指令单元)我拆成了PC与IM两个子电路。注意PC有Reset,IM用的是ROM,这些只要仔细读过要求应该不会出问题。32bitALU也没什么特别的,只是考虑到为了方便以后扩展(比如加运算指令),我的ALUOp用了3位,也就是说ALU支持8种运算,目前只有无符号加减以及或运算。对于DM(我也不知道叫啥,反正是内存),注意其输入地址为5位(32bit*32要求),注意有reset,注意MemWrite的作用是为1的时候写入数据,是数据从外面进入内存,而不是从内存写出去!至此,我们上课讲的基础元件已经搭好了。但是我推荐大家搭建一个万能分线器,它的顶层长这样:

 功能大家可以望文生义一下,有了他之后的顶层布线大家亦可以想象,会十分简洁,需要的信号只需要一条线就能引出来。

下面从数据通路开始连接,这里强推高老板的工程化方法!只靠课本或者自己老师(我的理论课老师不是老板)的课件对于7条指令的CPU也不会麻烦,但指令多了之后工程化方法会很好地让我们加指令与加元件。我是先从addu开始连的通路,具体连法课本或课件已经讲得很清楚了,不再详述。然后连lw和sw,随后又补上lui指令。此处lui指令我没有放入ALU,而是单独在顶层里面加了一个16位逻辑左移移位器,然后把这个结果和ALU的结果做一个多路选择,选择信号叫做AorS_sel,当然,这个选择出来的结果最后还是免不了与从内存中读出来的数据做另一个多路选择,信号叫做MemtoReg.在加这些I型指令的时候,务必仔细阅读MIPS手册,看看到底是0扩展还是符号扩展,需不需要左移两位之类的。最后我加上了beq,为了使得线不乱,我在IFU那里的算PC+4+offset处用了tunnel进行简化布线。

数据通路不难画,控制器需要想想,并且好好查表,造表。我把控制器分成了两部分,一个只看OpCode的部分,另一个是需要综合第一部分给出的ALUOp信号以及Func信号去生成ALUcontrol信号(位数自己看着来)。两部分的结构都是与或门阵列,第一部分是OpCode六位以及其取反的战场,第二部分是ALUOp及其取反以及Func及其取反的战场。为了连线,我们需要先查mips手册,连接与门阵列,然后再造表连接或门阵列。关于造表的顺序,下面简单说一下。先搬过来教程中的

我开始是个铁憨憨,横着填的表,这是一种麻烦的填表顺序,因为每填一行,需要把所有指令的数据通路都想一遍,想得脑壳疼。第二次搭建的时候我考虑竖着填表,每填一列只需要把该指令的通路走一遍,思考量从O(n^2)降低到O(n),还不容易错。表中数据的确定是由自己的设计决定的,不能与教程中给出的数据苟同。另外,对于R型指令,所有的R型指令在与门阵列中合成一个与门就行,叫if R,因为R型指令最终干什么,还是取决于Func,所以在第一部分控制器中所有R型指令统统归为一类即可。对于if R的结果,考虑到R型指令必然写入Regfile,所以是要和RegWrite连接的。至于第一部分中的ALUOp,值的情况取决于ALU的设计以及自己的规定,一种规则是000为加法,001为减法,010为或,011为比较,100为取决于Func字段。第一部分控制器的大体思路已经讲完了,下面考虑第二部分控制器的搭建思路。我第一次搭建第二部分的时候,由于考虑不周+没看高老板课件,出了严重的漏洞,至于哪里错了待会儿再讨论。一种正确(应该正确吧,等课上就知道了)的方案是仍然用与或门阵列。与或门阵列没看懂?对于R型指令,考虑一个例子:比如addu,它的Func是100001,需要在ALUOp为100时才会生效,所以,我们要把这对应的9条线(1取原信号,0取取反之后的信号)都连到addu的与门上才行。如图:

这样的话,如果ALUOp信号不是100的话,就说明不是R型指令,addu自然不能生效。相信有了这个例子,能更好地理解与或门中的与部分。由于学艺不精,我最开始不会搭这里,在室友提醒下才发现和第一部分控制器如出一辙(脑子笨不会融会贯通啊)有了这个例子,相信其他情况也容易类比实现。但是讲真的,第二部分控制器我设计的不好,用到一个常量0来辅助,要是加指令的话,我需要去掉0,并且思考如何扩展使得信号不会乱。这里是个雷,不知道周四能不能炸死自己。两部分都结束之后,控制器也就搭完了。控制信号我统统用tunnel连到各处的,这样感觉更加可读。

就这样,CPU就搭完了,它出生时是长这样的:

 太难看,但是如果按照我写的思路搭的话,第二遍就是这样:

 增加了信号的名字,并刻意加大骨干元件大小之后,看起来终于像一个CPU了(没强测过,不知道有没有问题)

现在是2:47,刚刚发现弱测结果终于出来了,WA了第三个点。看了讨论区,发现自己的MemAddr取错了(图中32 to 5封装起来的内部错了)。为了保证4的倍数,类似于PC部分的取址,应该取2-6位而不是0-4位!!!讨论区万能!!!这其实也是我的一个知识盲点:现代计算机按字节编址,如果写sw $s1,20($s2)的话,是存在第五个字里(32位机器)。而DM中一个地址是一个字,所以要除以4,即取2-6位!!

关于测试:http://shell-storm.org/online/Online-Assembler-and-Disassembler/     反汇编转化网站,选择mips,bigendian,然后disassemble就行了。

过了弱测的话,目测还需要重点检查一下分支跳转指令和与负数有关的指令,目前没想起来其他的(是太困了),想到再补吧!

猜你喜欢

转载自www.cnblogs.com/BUAA-Wander/p/11790154.html
今日推荐