欢迎光临散文网 会员登陆 & 注册

RISC-CPU五级流水线设计

2022-01-09 17:14 作者:ZTY巉岩之剑  | 我要投稿

一、概论

基于《verilog数字系统设计教程》及五级流水线CPU架构参考代码,设计出用于实现整数运算的五级流水CPU。通过前期研究、中期撰写及后期仿真测试,进行整体CPU架构设计和数的运算实现。

该设计主要有以下创新:首先,通过对教材《verilog数字系统设计教程》(第四版)中单周期CPU进行改进,自行设计出可以大幅度提高运算速度的五级流水线架构的高性能CPU。通过分析各模块的具体功能,探究出流水线中冲突的解决方案。其次,对于整数的运算,在加减法的基础上设计出乘法的指令编码,并进行仿真测试。最后,通过CPU与外设的组合连接,实现用七段数码管显示操作数及结果的相关功能,通过开发板上的开关控制操作数中的每一位数字,实现数据的顺序输入。

 

CPU外围架构

CPU内部架构

二、五级流水CPU架构设计

(1)整体架构设计

CPU的整体架构如图所示,按照五级流水线的标准结构,完成取址、译码、执行、访问和写回的五个步骤。通过每一模块的分工协作,以及冲突等待等关键步骤,完成流水线工作模式的整数加减乘法运算。值得注意的是,CPU整体架构采用的是“时序—组合—时序”的思想,在实现功能的组合电路两端加上用于寄存数据的时序电路完成数据的保存以及时钟信号控制下的输入输出同步。

取址

取址部分主要由ins_sel、ins_rn、rom核以及if_id_ir四个模块组成,通过接受外界加减乘及jump,skz等指令按需读取rom核中所在地址的指令编码,该指令编码可以完成加减乘的每一个步骤,并可以传递给后续的指令译码部分,完成后续的流水线工作。

Ø Ins_sel模块:

Ins_sel模块是时序电路,共有四个输入,其中opr_ini控制加减乘的运算信号,告诉CPU目前执行的是什么操作,并将该操作的起始地址通过输出端口data_ins_addr给到Ins_rn模块,为后续调用rom核做好准备。此外,当rom核读到jump指令时,会通过输入端口给到jump信号以及jump所要跳转的地址,通过输出进行后续跳转操作。

Ø Ins_rn模块:

Ins_rn模块是时序电路,通过接受Ins_sel模块的相关运算的起始地址以及跳转信号,传递到后续的rom核当中,与Ins_sel不同的是Ins_rn模块有wait信号,用于解决运算过程中步骤冲突的问题,当wait信号来临时,该模块不工作,等待一个周期。wait信号是一个全局控制信号,在之后的译码、操作、访问及写回步骤中也会涉及。

Ø Rom模块:

Rom模块是组合电路,主要实现的功能是在不同的地址中存放不同的指令编码,指令编码共十六位,由四位操作编码和十二位地址组成。其中操作编码表示该步骤执行什么功能,比如加载(LDA)、相加(ADD)、停机(HLT)等主要功能。十二位地址与操作编码一一对应,有时指代的是Ram核中存放数据的地址,有时则指代通用寄存器中寄存器的地址。所有操作编码构成指令集,指令集展示将在之后的内容提到。

Rom模块主要实现的是储存功能,在一开始撰写Rom模块的代码时,发现如何在Rom核中初始化数据是一个很棘手的问题,如果用Initial语句进行初始化赋值,则综合后无法实行正常功能。通过思考与创新,总结出了如下思路:可以通过case语句来实现上述功能,case语句后表示的是Rom核中的各个地址,当输入端输送进来地址后,直接通过case语句选择相应的赋值操作,赋给输出端口memory,实现选通相应地址下的数据输出。

Ø if_id_ir模块:

  If_id_ir模块的主要功能是作为时序电路保存组合电路Rom中给出的十六位指令编码,并在下一个时钟周期给到译码模块进行译码操作。同时,该模块也受wait信号控制,通过wait信号实现停止一个周期的操作,也就是空一格时钟周期后再把指令编码给到之后的译码模块。

译码

Ø Ins_decode模块

ins_decode模块通过解析指令编码,产生对应的信号,控制后续模块完成相应的执行,访问和写回的操作。

Ø Id_ex_ir模块与ex_mem_ir模块

由于执行,访问和写回需要三个周期才能完成,因此id_ex_ir模块以及ex_mem_ir模块用于暂时保存Ins_decode中还没有用到的信号。

执行

Ø alu模块

alu模块用于实现各种运算,属于组合电路,部分运算只涉及一个操作数,由通用寄存器的regb给出,如果涉及到两个操作数,则是由通用寄存器的rega和regb共同给出。

Ø regwait模块

regwait模块是时序电路,用于保存alu模块的运算结果,在下一个时钟周期到来时写回到相应的通用寄存器中。

访存与写回

Ø 通用寄存器模块

通用寄存器模块分为四个部分rega、regb、regc和regd,属于时序电路。访问时在时钟上升沿读数据,写回时在时钟下降沿写入数据,受wait信号控制。其中加法、减法和乘法都用到rega和regb模块,分别加载两个操作数以及通过regb保存最后结果写回到ram核里。此外,乘法还用到了regc和regd分别存放部分积和移位之后的乘数,完成乘法运算。

Ø Memory_access模块

memory_access模块用于保存访存取出的数据,为写回操作做好准备。

Ø ram模块

ram模块用于输入要运算的操作数进行存储,并写回最终的运算结果,在七段数码管上输出,是连接CPU与外设的桥梁,属于时序电路。

冲突等待模块wait

冲突等待模块wait用于解决取址、译码、执行、访问和写回步骤中的冲突问题,与各个时序电路相连,起到控制作用。当wait信号来临时,所控制的时序电路暂停工作一个时钟周期,等到下一个时钟周期时将信号输出。通过控制取址部分的Ins_rn模块、if_id_ir指令编码寄存器模块、id_ex_ir和ex_mem_ir译码信号寄存器模块来解决冲突问题。同时在wait模块中还解决了skz判断指令的问题。wait模块与reg_wait模块相连,当skz信号输入时,通过判断reg_wait中的数据值来进行下一步操作,如果为0,则让if_id_ir暂停工作一个周期,由于rom核里的指令编码一直在读出,而在该周期if_id_ir暂停工作,无法接收rom核的指令编码,等到下一周期时,if_id_ir正常工作,接收rom核的下一条指令编码,完成跳过一条语句的步骤。

(2)扩展指令集概览

CPU扩展指令集概览

 指令集通过一定扩展,可由四位操作编码4b0000到4b1110组成,构成了整数加减乘运算的基本指令集。其中乘法运算比较复杂,需要用到skz,jump等高级指令,进行循环操作和条件判断。对于加法和减法来说,需要进行基本的操作,通过xorc与“1”异或来实现取反的操作,通过add来实现相加的操作。

(3)冲突解决方式

如图所示,如果不加wait,当上一个步骤的数据还没有写回时,下一步骤新的运算就开始执行,而下一步的运算要用到上次运算的结果,因此需要延迟一个时钟周期的时间,等数据写回完成后再执行下一步的操作。对于访存和写回则没有此问题,通过上升沿访问和下降沿写回可以有效避免冲突。

加法计算步骤
减法计算步骤

三、整数运算实现

    分析整数运算的实现,离不开对CPU外围结构的具体分析。总的来说,CPU的外围部分主要有以下几个。分别是输入模块Inp二进制转BCD模块七段数码管模块和分频电路模块。其中,输入模块Inp实现了数据的十进制输入,BCD转二进制的主要功能。

Inp模块

Inp模块主要实现以下功能:数据的十进制输入、BCD转二进制以及与CPU模块的连接。从输入输出端口模块可以看出,button,switch,num_sel,count,rst以及num端口都需要依靠开发板进行实现。输出的相关信号传递给CPU,完成相关的操作。理解Inp的主要功能首先要查看开发板的示意图。

首先,将数据选择端置0,通过位选模块和数据输入模块进行第一个整数的输入。当输完第一个数时,按下对应的按钮告知CPU目前执行什么运算。其次,将数据选择端置1,再次通过位选模块和数据输入模块完成第二个整数的输入。最后,通过数据CPU控制模块完成CPU数据输入以及运算,最终结果将在七段数码管上显示。值得注意的是,在减法操作中,数据选择端为0时输入的是减数,数据选择端为1时输入的是被减数。

开发板交互示意图
开发板使用说明



Bin2bcd模块

Bin2bcd模块是较为关键的模块,由于CPU的数据是二进制的,而七段数码管上需要用BCD码来进行显示,因此需要进行转换,转换的思路如图十九所示:实现通过表格划分数据的个位、十位和百位。逐步右移二进制数据,每当一个单元的数据大于等于5时,给此数加3,继续右移,直至右移结束,完成二进制向BCD码的转换。

七段数码管及分频电路模块

    七段数码管通过动态扫描的方法进行四位不同数字的显示,在显示过程中需要考虑数据冲突的问题,比如什么时候显示输入的两个操作数,什么时候显示最后的运算结果,这些问题可以通过Inp模块的CPU控制模块进行解决,当开始CPU运算时,数码管显示的是最后的运算结果,当CPU未进行运算时,数码管显示的是输入的两个操作数。

分频电路主要有两个部分,第一个分频电路决定CPU的运算速度,大约在3kHz左右。第二个分频电路决定七段数码管的动态扫描,进行位选的功能。

四、实验心得

(1) 在写五级流水线CPU内部代码时,对于端口名的命名是极为重要的,端口名的模糊定义将给顶层模块的连接带来很大的困扰。采用的命名方式如下,以参数寄存器的端口命名方式为例。主要分为以下三个部分:<执行的步骤><作用的对象><当前的模块>。以ctl_mem_rega_ex_ir_in为例,首先从ctl_mem可以看出,这个信号控制的是访问的步骤,作用对象是rega,当前是id_ex_ir模块的输入端口。通过此命名方式,可以明确每个端口的具体含义,在后续模块连接时不会混淆。

(2) 在编写rom核的过程中,可以适当地在加减乘运算步骤所指的地址中间间隔几条地址。如果不在每个运算步骤之间间隔几条地址,当添加或删去一个操作步骤时,后续的地址编码都要重新排序,耗时耗力。通过此方法,可以节约编写代码的时间成本。

(3) 一定要明确数据是以什么进制进行显示。比如在一开始验证加法步骤时,输入的两个数是0008和0009,输出的结果是0011,一开始认为是CPU内部的代码问题导致,最后发现,vivado自带的默认仿真界面所有的数据是以十六进制进行显示。0011是十六进制的表示方式,其十进制表示数据为0017,符合加法运算原理:8+9=17.因此,明确数据的显示形式可以有效避免一些不必要的麻烦。

(4) 在开始写代码之前,画好五级流水CPU的架构图是有必要的。CPU架构图可以直观清晰地表明每一个模块的连接方式和实现功能。不会出现漏写模块的情况。同时,CPU架构图有利于在debug过程中寻找问题,通过CPU架构图可以进行大致的运算模拟,逐步缩小问题出现的范围,最终找到出现bug的模块。

五、总结

 通过对教材《verilog数字系统设计教程》(第四版)中单周期CPU进行改进,自行设计出可以大幅度提高运算速度的五级流水线架构的高性能CPU。通过分析各模块的具体功能,探究出流水线中冲突的解决方案。对于整数的运算,在加减法的基础上设计出乘法的指令编码,并进行仿真测试。通过CPU与外设的组合连接,实现用七段数码管显示操作数及结果的相关功能,通过开发板上的开关控制操作数中的每一位数字,实现数据的顺序输入。在CPU的设计过程中,不仅丰富了自我的专业知识,更学会了“工程化”的思考模式,掌握了解决冲突的能力,为后续更加专业化的设计奠定基础。



RISC-CPU五级流水线设计的评论 (共 条)

分享到微博请遵守国家法律