基于RISC-V架构的三级流水线处理器内核设计。最后搭建仿真测试平台,对设计的处理器内核以及外设模块进行仿真测试。并将SOC用FPGA进行了原型验证。
完成的工作:
设计了三级流水线取值、译码、执行和访存写回的 处理器内核,完成处理器内核与外设资源的交互,ROM的取指,RAM的访存。
使用32位riscv处理器格式,完成了R型指令,I型指令,J型指令,B型指令,以及访存指令等。对于流水线中的冒险处理,对于访存和取指令带来的结构冒险,将内存分为存放指令的程序内存和存放数据的数据内存。对于R型指令ADD指令可能存在的RAW,先写后读相关性数据冲突,数据冒险采用前递的方式,将数据通过数据旁路传递给下一条指令。
对于load指令的写回与下一条指令译码阶段的数据冲突,采用流水线阻塞,听对于IF阶段和ID阶段的指令停顿,禁止PC和IF/ID阶段寄存器的改变即可,就可以阻止这两条指令的执行。
对于分支指令,beq条件判断。采用静态预测,假设分支不发生并顺序执行指令流。一旦分支发生,已经被读取和译码的指令被丢弃。流水线冲刷,通过控制模块,设置信号,发送NOP空指令,然后PC寄存器下一条指令为条件分支的跳转地址。
对于冒险处理的流程是这样的。
验证: RTL验证。windows系统 中通过iverilog和gtkwave。iverilog编译仿真程序,vvp工具仿真生成vcd文件,gtkwave查看vcd文件。
时钟频率: 100MHZ
解决的问题:
数据冒险的处理:比如load加载指令在执行阶段,写回的寄存器。 和下一条命令译码阶段存在数据冲突。需要等待load加载完数据后,再进行译码。所以在执行load指令执行阶段,需要对后续两条指令进行流水线停顿。停顿一个时钟周期后再进行流水线操作。 具体需要ID 和IF阶段发送空指令,且不进行取新的指令,和新的寄存器数据。
对于分支预测模块,使用静态预测,没有采用动态调度流水线的方式,动态调度流水线由硬件选择后续执行的指令,并对指令进行重排来避免流水线停顿。
raw加法运算时候先读后写,没有意识到,通过看时序才反应过来,没处理这种数据冲突。
1 对于流水线时间,取决于一级流水线所需的时间,一些长指令需要的时间长一点,如乘除法指令,访存指令等。
2 结构冒险:在流水线数据通路设计中的每一个逻辑部件,如指令存储器,数据存储器等只能在单个流水线阶段中被使用。否则会发生结构冒险。
CPU在同一个时钟周期,同时运行两条计算机指令的不同阶段。这两个不同阶段用到同样的硬件电路。
3 分支指令根据ALU输出来确定下一条指令的地址,地址为PC和分支偏移量相加的加法器,或者PC+4的加法器。
4 使用32位riscv处理器格式
对于R型指令。 0-6位共7位为操作码,7-11位5位位rd目的寄存器。 12-14 3位位funct3和25-31位7位funct7 判断指令。 15-19 5位。20-24位r1源寄存器1和r2源寄存器2.
5 CPU执行程序过程
程序经编译生成二进制指令码,烧写程序到硬件系统。将指令码存放在系统硬盘。 当打开程序,将指令码和数据保存到了内存中。指令加载到了CPU缓存,CPU根据程序计数器取指令地址。 完成取指。
取指完成开始译码。 数据寄存器把数据从内存中加载到算术逻辑单元,进行执行。
三级流水线执行过程。
ADD的三级流水线过程为,从ROM进行取值,ROM按字节进行存储指令,所以一条指令占用四个地址空间,if模块根据pc_reg寄存器地址进行取值,取出指令后通过if_id进行打一拍。后进入译码电路,id译码模块通过寄存器组,rs1和rs2得到数据1和数据2。打一拍id_ex模块。 将输入传入执行模块。在第三个时钟周期到来时,进行ex执行。执行结束将回写,把结果写回到寄存器组中的目的寄存器中rd。
行测试是通过txt文件进行testbench验证。通过readmemb,将文本中数据赋值到存储器中。通过display打印输出信息。 第一个时钟上升沿开始,第一个周期为不定态,未复位。第二个周期开始复位。第三个周期为cpu第一个周期取指。以此译码执行。 则第五个周期到来时,完成第一条指令,第一条指令耗时三个周期,第6个周期完成第二条指令。。。
完成了ADD指令的设计以及验证。
ADDI x27,x0,imm
000000100110_00000_000_11011_0010011
ADDI x28,x0,immm
000000110110_00000_000_11011_0010011
ADD X29,X28,x27
0000000_11100_11011_000_rd_0110011
流水线的理解:
流水线的深度越深,寄存器使用的数量增加,从而加大处理器设计的面积,消耗更多的资源。
处理器流水线之间的每一级信号传递都会进行握手,握手就会导致流水线最后一级产生反压信号,反压信号可能会干扰流水线第一级,从而带来时序上的问题。
对于分支指令,越深的流水线预测失败,代价会更高。
正面: 流水线深度越深,带来吞吐率的增大,主频升高。
负面: 随之带来反压问题,功耗和面积增大
jal: 20位有符号数立即数作为偏移量,偏移量乘以2,然后与当前指令所在的地址相加,生成得到最终的跳转目标地址。同时将下一条指令的PC值写入结果寄存器。