【仿真波形图】
- 波形图一共执行了14条指令,具体的测试指令详细见文档
test.txt
- 第一条指令是
addi
指令,仿真的时候是选择了rs=2,rt=3的寄存器地址,立即数为5,所以得到的结果是将计算结果5写入rt=3对应的寄存器地址,与仿真结果相符,而且从下一个周期的Q2的输出可以看出写入操作成功进行 - 第二条指令是
andi
指令,将rs,rt对应地址的寄存器进行了交换,立即数设置为1,5&1=1,将结果1写入rt=2对应的寄存器地址,依然与仿真波形结果相符,从下一个周期的Q2的输出也可以看出写入操作成功进行 - 第三条指令是
ori
指令,保持上述寄存器地址不变,立即数变成2 ,5|2=7,将结果2写入rt=2对应的寄存器地址,从下一个周期的Q2的输出可以看出写入7操作成功进行 - 第四条指令是
slti
指令,立即数设置为7,因为5<7,所以按照slt运算的规定,计算结果是1,与result的值相符,从下一个周期的Q2的输出可以看出写入1操作成功进行 - 第五条指令是
add
指令,将rs和rt对应地址的寄存器内部的数值5,1取出,进行加法操作,得到结果6,写入rd=1位置的寄存器。 - 第六条指令是
sub
指令,将rs和rt对应地址的寄存器内部的数值5,1取出,进行减法操作,得到结果4,写入rd=1位置的寄存器。 - 第七条指令是
slt
指令,将rs和rt对应地址的寄存器内部的数值5,1取出,进行slt操作,得到结果0,写入rd=1位置的寄存器。 - 第八条指令是
and
指令,将rs和rt对应地址的寄存器内部的数值5,1取出,进行与操作,得到结果1,写入rd=1位置的寄存器。 - 第九条指令是
or
指令,将rs和rt对应地址的寄存器内部的数值5,1取出,进行加法操作,得到结果5,写入rd=1位置的寄存器。 - 第十条指令是
sw
指令,立即数设置为1,将rs对应的寄存器的数值5取出,加上立即数1,得到result=6,则将rt对应地址的寄存器里面的数据5写入data_memory
中6对应位置的存储。 - 第十一条是
lw
指令,和sw
指令几乎相反,将rs
对应的寄存器的数值5取出,加上立即数1,得到result=6,将data_memory
中6对应位置的存储,也就是上一条指令已经存储的数据5,重新写入到rt对应地址的寄存器中,从Dataout
可以看到结果是正确的。 - 第十二条指令是
nop
指令,即不进行任何的操作,所有的数据全部输出0 - 第十二条指令是j指令,跳转到label对应的指令进行执行,在我的测试指令中设置的是跳转到第一条,也就是
currentAddress
=0时候对应的指令进行执行。从下一个周期进行执行的操作我们可以看出,确实是执行了第一条指令。
以下的13条指令中,前9条主要是进行数据的取出计算和重新写入
add
指令:取出rs,rt对应地址的寄存器中的数据,输入到ALU运算模块进行加法操作,随后把计算所得到的结果写入rd对应寄存器中sub
指令:取出rs,rt对应地址的寄存器中的数据,输入到ALU运算模块进行减法操作,随后把计算所得到的结果写入rd对应寄存器中and
指令:取出rs,rt对应地址的寄存器中的数据,输入到ALU运算模块进行与操作,随后把计算所得到的结果写入rd对应寄存器中or
指令:取出rs,rt对应地址的寄存器中的数据,输入到ALU运算模块进行或操作,随后把计算所得到的结果写入rd对应寄存器中slt
指令:取出rs,rt对应地址的寄存器中的数据,输入到ALU运算模块进行比较两者的大小,若前者小于后者,则将1写入rd对应地址的寄存器;反之,则将0写入rd对应的寄存器addi
指令:取出rs对应地址的寄存器中的数据,和立即数部分在ALU运算模块进行加法操作,随后将计算结果写入rt对应地址的寄存器中andi
指令:取出rs对应地址的寄存器中的数据,和立即数部分在ALU运算模块进行与操作,随后将计算结果写入rt对应地址的寄存器中ori
指令:取出rs对应地址的寄存器中的数据,和立即数部分在ALU运算模块进行或操作,随后将计算结果写入rt对应地址的寄存器中slti
指令:取出rs对应地址的寄存器中的数据,和立即数部分在ALU运算模块进行比较,若前者大于后者将计算结果0,否则将运算结果1写入rt对应地址的寄存器中sw
指令:主要是在CPU需要将当前的数据进行长期存储时调用,具体操作是将dmem的使能信号设置为写,将rd对应地址的寄存器的数据写入到Data_memory中rs对应寄存器中的数值加上立即数所对应的存储器中,Regfile的使能信号关闭,以防止断电后有用的数据全部丢失的情况的发生lw
指令:主要是CPU需要将dmem的使能信号设置为读,将先前存储在Data_memory中的数据重新调用,进行数值运算的时候调用。具体的操作是先将rs对应地址的寄存器和立即数相加,得到Data_memory中要调用数据的地址,进行取出操作之后,把Regfile的使能信号开启,写入Regfile中rd对应地址的寄存器nop
指令:不进行任何的操作j
指令:跳转指令,即该指令的26位左移两位后所对应instruction_memory中地址的指令在下一个时钟周期进行执行
主要是有一个核心控制单元Control Unit
负责选择调用所有的模块,它的真值表已经在第一部分的说明文档中提供。它有输入:运算符号func
,操作符号op
;输出Jump
,M2reg
,Wmem
,ALUop
,ALUimm
,Wreg
,REgrt
,sext
。Jump
表示下一个时钟周期运行的指令地址是下一条指令还是指定跳转的指令;M2Reg
表示选择Data_memory
的模式是写入还是读出;ALUop
表示R类型的指令的运算操作符;ALUimm
表示进行计算操作的时候第二个操作数是rt对应的数据还是立即数;Wreg
表示寄存器的写入操作是否允许;REgrt
表示写入寄存器的地址是R类型指令的rd寄存器,还是I类型指令的rt寄存器;sext
主要是负责表示I类型指令是否需要进行符号位的扩展。
在一个时钟周期内,进行一条指令的读取和执行操作。首先PC
模块会将当前要执行指令在imem
中的地址输出到imem
中,同时将当前指令地址+4获得下一条指令的地址,imem
将对应位置的指令取出并将其分隔为操作符op,函数运算符func
,立即数immediate
,目标跳转地址label
,寄存器地址rs,rt,rd。根据op和func的参数,控制模块Control Unit
得到指令的具体类型和接下来应该进行什么具体的操作。接着,在Regfile
模块中取出rs和rt对应地址的寄存器中的数值,又使用了一个数据选择器对于写入寄存器的地址关于R类型和I指令进行了区分;然后将数据输入到ALU运算模块,其中的第二操作数对于R类型指令的rd地址寄存器的数值和I类型指令的立即数也进行了数据选择。得到了计算结果result之后,如果是计算类型的指令,则选择直接将result重新读回到Regfile
中;如果是lw
指令,则选择将dmem
中result
地址的数据都会到Regfile
中去;如果是sw
指令,则将result
读入要求的dmem
中的位置,同时关闭Regfile
的寄存器数据写入信号。最后,再使用一个数据选择器,选择下一条即将进行执行的指令的地址是imem
中的下一条还是j指令指定跳转的指令地址,并将其输入回PC
模块,从而顺利地实现了一个单周期CPU的自动更新运行。
个人认为这样的单周期CPU已经是比较完善的了,如果说设计还有改进和提高性能的空间的话,受到先前所自愿完成的Lab4 流水线加法器设计的启发,我觉得可以将流水线的思想应用到这个单周期CPU设计中的ALU运算单元中。具体的设计操作我觉得,可以给ALU运算单元添加一个内部时钟。在这个过程中,第一个周期将70位的数据进行计算并寄存起来,第二个周期将158位的数据进行计算并寄存起来,第三个周期将2316位的数据进行计算并寄存起来,第四个周期将3124位的数据进行计算并连同前面寄存的数据一同输出。这样一来,在一个时钟周期内,不会出现两个数据进行运算操作的时候,只有当前时刻进行运算的位正在执行,而剩余的位都在“休息“;现在的情况是:在一个时钟周期内,在这两个数在进行高位计算的同时,CPU也在进行下一个组数据的低位运算,这样一来,大大提高了计算运行的效率。
在这个单周期CPU设计project完成的过程中,还是遇到了一些困难的。首先就是各个模块的敏感信号的选择,不知道是选择是上升沿触发,还是下降沿触发还是电平信号触发。一开始并没有特别考虑到这一点,后来手动实现了一遍,对于这方面触发器的触发信号的 选择有了全新的认识。还有就是imem模块中每一条32位的指令没有用一个32位的寄存器存储,而是使用4个8位寄存器来存储。这样的一种和以往思维大不相同的存储思路也是给我带来了很大的困惑。后来经过和同学们与老师的一番讨论之后,体会到了这样的指令存储方式才是更加符合计算机客观的处理方式。一般在真实的CPU中,指令和数据都是存在同一个memory里的。memory中数据是以字节为最小单位存储的,所以内存地址也都是以字节为单位,这样方便了指令和数据的统一处理。本次单周期CPU设计实验,将理论课上所讲的指令处理过程自己重复并实现了单周期CPU的设计,加深了CPU处理指令过程理解,之前由于没有系统地学习过计算机体系结构,通过自己自主学习线上的视频,也更加了解每条指令的处理过程以及单周期CPU是如何工作的。同时本次pj也更加了解verilog语言。之前的lab都在完成的过程中遇到了非常多的困难,现在学会了如何更加高效的完成。最重要的是学会模块化,将一项工作分成多个模块进行完成,先简化成小部分,然后再将其组合起来。