目录
4. 部分加载和存储(partial_load 和 partial_store)
(1)RgeWen、ImmSel、BrUn、ASel、BSel、MemWe、WBSel的设计
一、实验内容
设计一个相对完整的RISC-V或MIPS处理器,它能够支持更多的指令,并且运行一个具有应用价值的测试代码。
二、实验步骤
1. ALU与寄存器文件
直接使用实验为你准备的一个框架(完整的寄存器文件和包含复杂功能的ALU)。
2. 分支比较器(branch-comp)
在此模块中,需要比较两个输入BrData1和BrData2的值是否相等,相等则BrEq=1,小于则BrLt=1。
所以,在这里需要用到一个比较器。
具体设计如下图所示:
3. 立即数生成器(imm-gen)
在此模块中,我们的目的是将正在执行的指令中的立即数提取出来。根据指令的类型(I型、B型、S型、U型、J型)不同,立即数的生成方式也不一样。我们根据实验指导书中的RISC-V手册中提供的下图
设计出了如下电路:
4. 部分加载和存储(partial_load 和 partial_store)
(1)加载(partial_load)
在此模块中,我们需要判断当前指令是否为lw指令(从指令类型、opcode的值、funct3的值、MemAddress的最低两位来判断)。当这些条件都满足时,我们将DataFromMem的值赋给DataToReg。
根据上面思路,我们设计了以下电路:
(2)存储(partial_store)
在这个模块,我们需要根据sw指令的特性(MemAddress的最低两位和fun3的值),如果这两个都满足,就将DataFromReg的值赋给DataToMem,并且将0xf的值赋给MemWriteMask。
根据上面思路,设计出以下电路:
5.控制逻辑(control-logic)模块
(1)RgeWen、ImmSel、BrUn、ASel、BSel、MemWe、WBSel的设计
在这里,通过填写表格,将蕴含的信息编写为机器码,加载到ROM中。再通过识别当前指令为什么指令(opcode、fun3、fun7来识别),对应取出ROM中的机器码,再进行译码后,就可以将当前指令的RgeWen、ImmSel、BrUn、ASel、BSel、MemWe、WBSel算出来。
根据实验指导书的表12,通过opcode、fun3、fun7来识别当前指令是8条指令的哪一条。由于ROM的输入地址的位宽为6,所以需要通过两个复用器(选择位为4,数据位为6)来进行选择,两个复用器分别处理4条指令,所以选择位的数值为0bxxxx(0b0000、0b0010、0b0100、0b1000)分别对应复用器的1、2、4、8位,所以在这几个位上分别设置常量0、1、2、3,表示是ROM中的第几条指令。另一个复用器的常量设为4、5、6、7,将两个复用器用或门连接后送个ROM的输入地址。
根据以上思路,设计如下电路:
表格填写如下:
(2)PCSel的设计
PCSel信号根据指令的类型来决定下一个程序计数器(PC)的值应该来自哪里。
如果为J型或者B型且满足BrEq==1,则PCSel的值置为1(表示PCPC=PC+4+跳转值),否则为0(表示PC=PC+4)
根据以上思路,设计如下电路:
6.Cpu设计模块
(1)程序计数器PC的值(取指令模块):
PC的值有两种可能:a.PC=PC+4。(正常情况下)b.PC=PC+4+跳转值(遇到跳转指令时)。
选取PC的值来自哪里,需要用到控制逻辑(control-logic)模块设计的PCSel值来选择(PCSel==0时,PC为a情况。PCSel==1时,PC为b情况)
跳转指令有可能是B型,也可能是J型。无论是哪一种,我们只需将指令中的地址加载出来,加上PC+4就可以了。而指令中的地址,我们已经通过立即数生成器(imm-gen)模块完成好了,所以此时只需将立即数生成器(imm-gen)模块中的输出Immediate加上PC+4即可。
此部分的电路如下图所示:
(2)寄存器文件模块(译码模块)
将当前指令解码后,rs1传给ReadIndex1(读索引信号,即寄存器文件中需要读取的第一个寄存器的地址),rs2传给ReadIndex2,rd传给WriteIndex(写索引信号),写回寄存器文件的数据有3种,从RAM中读取的值、ALU运算的结果、PC的值,通过WBSel来选择。寄存器文件的输出(rs1、rs2寄存器中的数据)传给R1、R2,并将它连给分支比较器的输入,用于判断两个值是否相等。
此部分的电路如下图所示:
(3)ALU模块
ALU的输入A有两个选择,R1和PC的值,通过ASel来选择。ALU的输入B也有两个选择,R2和立即数的值,通过BSel来选择。ALU需要进行哪种运算,有ALUSel来控制。ALU的输出结果有两种可能,一种是进行普通的加、乘等操作,可以得到数值结果,写会给寄存器文件。一种是lw和sw等需要求出地址的结果,所以需要连到RAM和load、store的地址输入端。
此部分的电路如下图所示:
(4)访问数据存储器和写回寄存器文件模块
根据上面设计的加载和存储模块,将对应的引脚连接起来即可。
此部分的电路如下图所示:
(5)暂停程序
当指令进行到最后一条ecall时,需要暂停程序。此时,我们只需要将当前指令的值与0x73对比即可。如果相等,则点亮LED灯,并且将时钟设为0,暂停程序。
此部分的电路如下图所示:
(6)CPU的总体设计
三、运行结果演示
如图可以看到,程序结束后,LED灯点亮,结果存储在t0寄存器中。而Venus仿真器的结果也是存到t0寄存器中。
四、实验环境
使用Logisim完成RISC-V处理器的设计和调试。
使用Venus仿真器完成测试程序的运行和调试、内存转储(memory dump)。
五、实验小结与思考
1.体会
在这个实验中,了解到了CPU的设计,巩固了课堂学习的知识。
2.收获
(1)了解了PCSel是什么,以及作用。
PCSel信号根据指令的类型来决定下一个程序计数器(PC)的值应该来自哪里。
A. 为所有B型指令选择ALU输入:
在RISC-V指令集中,B型指令通常指的是有条件跳转指令,这些指令的执行结果取决于分支比较器的输出。
当执行B型指令时,PCSel信号会选择ALU的某个输入,该输入包含了根据分支比较器输出确定的下一条指令的地址。如果分支条件满足,则跳转到指定的地址;如果不满足,则继续执行下一条顺序指令。
B. 为所有跳转指令选择ALU输入:
除了B型指令外,RISC-V系统中还有其他类型的跳转指令,如无条件跳转指令j等。这些指令用于实现程序中的跳转操作。
当执行跳转指令时,PCSel信号同样会选择ALU的某个输入,该输入包含了跳转目标地址。然后,处理器会根据该地址跳转到相应的指令处继续执行。
C. 为所有其他指令选择PC+4输入:
在RISC-V系统中,除了跳转指令和B型指令外,还有其他类型的指令,如算术运算指令、逻辑运算指令等。这些指令通常按照顺序执行。
当执行这些指令时,PCSel信号会选择ALU的“PC+4”输入。这意味着下一条指令的地址是当前指令地址加上4。这样,处理器就可以顺序地执行下一条指令。
(2)了解了一些指令的具体操作
Eg.lw rd, offset(rs1)的第一个输入为rs1、第二个输入为offest。