实验目的
现代 CPU 普遍采用流水线技术,只需要增加很少寄存器和一些逻辑线路,就能使 CPU 的速度提高很多倍。
1.在掌握多周期 CPU 的设计下,深入理解 CPU 流水线的概念。利用已有的计算机组成原理知识和对计算机系统结构的初步学习,设计一个包括指令系统、寻址方式、数据表示、寄存器组、存储系统、流水线结构的 CPU。该 CPU 必须具有复位功能,复位脉冲按负脉冲设计;
2.熟练掌握硬件描述语言 Verilog HDL,编写 CPU 的各功能模块的代码,并将上述各功能模块组成一个比较完整的 CPU 体系结构。
3.熟悉并掌握流水线 CPU 的原理和设计;
4.通过亲自设计和实现静态 5 级流水线 CPU,加深对计算机组成原理和体系结构理论知识的理解;
5.学会硬件设计工具软件 Vivado 对程序进行仿真和调试的方法,并掌握 FPGA 的 CPU 调试方法。
实验原理
多周期 CPU 在单周期基础上提高了时钟频率,但并没有降低执行一条指令的时间,且存在资源闲置的问题。例如,当指令在执行级有效时,译码级实际上在空转。若每一级都在执行有效的指令,将解决资源闲置的问题。最理想的情况是,当第一条指令从取指级转换到下一级译码时,第二条指令进入取指级,当第一条指令完成译码进入执行级时,第二条指令进入译码级,第三条指令进入取指级……静态 5 级流水 CPU 就是基于这样的设计思路。
流水线技术是时间并行,在流水 CPU 中,当在一个时钟周期内完成了某条指令的全部执行时(写回级完成),则有望在下一时钟周期内完成下条指令的执行,因此依然相当于是一个周期完成一条指令,而时钟频率更高,因此 CPU 可以运行得更快。它是通过分时使用同一个功能部件的不同部分来提高指令的执行速度,即在流水线的每个阶段的末尾都要设置一个流水线寄存器,这样每段做完后,都把结果送入寄存器,然后同步往下走。流水线技术是一种非常经济,对提高处理机的运算速度非常有效,是多数处理机中普遍采用的一种并行处理技术。流水线理想 CPU 时空图如图 1 所示。

流水线的 CPU 结构
指令的执行过程可以分为多个阶段,具体分法要根据各种处理机的情况而确定。图 2 为流水线CPU结构,分为 5 个阶段,各段的功能对应英文指令的名称来命名。流水线段与段之间被流水线寄存器分开,这些流水线寄存器就可以用被分开段来命名。
取指模块给出内存地址 (IF),读取指令并送入指令寄存器,为下一段准备数据。由于 PC 控制部分处于取指部分中,因此控制相关的检测也置于取指阶段。

读取寄存器值和指令译码 (ID) 采取一次译码、逐级传递方式,译出后面流水线段所需的控制信号和数据,在每次时钟上升沿到来时送入下一段。结构相关、控制相关、数据相关检测可以置于寄存器堆内的相应寄存器。
执行模块 (EXE) 完成算术逻辑运算,计算有效地址和提供数据通道。
访存模块 (MEM) 选择地址线的数据来源和数据流向。访存模块与取指模块在功能上是独立的,但 CPU 对外只有一条地址线数据线,决定了访存和取指令是相互联系的。如果在执行 LOAD/STORE 指令,那么地址线由 ALU 送入“访存模块”的值提供;如果在执行取指令,那么由程序计算器 PC 提供。当写内存时,CPU 内部数据送数据线;当需要读内存时,CPU 往数据线送高阻。
写回模块 (WB) 选择回写数据源和根据写使能信号,将数据回写到通用寄存器。
流水线各段功能描述
**1.**取指令模块的结构: 取指令模块的结构如图 3 所示。IF 段执行从存储器 ROM 中取指令操作,并将已取出的指令机器码与程序计数器的输出值存储在 IF/ID 寄存器中,作为临时保存,以便在下一个时钟周期开始时为下一步所用。

对 IF 段的主要功能描述如下:
1)取指令及锁存。根据程序计数器 PC 的值,从指令存储器中取出指令,并将取出的指令送往本段的锁存单元,即 IF/ID 寄存器锁存。
2)地址计算。根据选择信号值,从 4 个地址转移源中选择程序计数器 PC 的下一个值。若流水线中 WB 段的指令是跳转指令或分支成功指令,则选择 BranchPC 的值,以程序跳转的目标地址作为地址计算结果;若是非跳转指令或分支失败指令,则 PC 取 PC+1 的值,指向指令存储器中的下一条指令;若是中断返回指令,则取 retiPC 的值;若是子程序返回指令,则取 retPC 的值。
3)检验指令的合法性。检验指令的操作码和功能码是否符合指令集设计中的定义,如果指令不正确,那么返回一个异常。
4)同步控制。用时钟 CLK 对外部信号进行同步。
**2.**指令译码模块 ID 段的结构: 指令译码模块 ID 段的结构如图 4 所示。ID 段从程序存储器取出的指令被送到控制单元,再由控制单元对指令译码,将译码后产生的各种控制命令送入处理器的各部件;读寄存器命令从寄存器文件 RegFile 中取出数据;分支控制模块 Branch Unit 进行分支转移判断。

ID 段的主要功能描述如下:
1)访问寄存器文件。从寄存器文件读取寄存器操作数并送入 ID/EX 寄存器。
2)向寄存器文件回写数据。把流水线中已经执行完毕的指令所需回写寄存器文件的执行结果送入寄存器文件。
3)符号位扩展。对指令中 8 位或 6 位立即数进行零扩展或者符号位扩展,把扩展后得到的 16 位操作数送入 ID/EX 寄存器。
4)相关性检测。对正在 ID 段进行处理的指令和流水线中 EX、MA、WB 段中的指令进行数据相关检测和控制相关检测。如果检测到数据相关,就对流水线各段发出 pipeline flush 信号;如果检测到分支指令,就对流水线各段发出 control flush 信号。
**3.**指令译码的模块 EX 段的结构: 指令译码的模块EX段的结构如图 5 所示。EX 段的主要部件是 ALU,由算术逻辑单元、移位寄存器、寄存器数据输入模块组成。ALU 还包括 EX/MEM 寄存器和总线多路选择器。

对 EX 段主要功能的描述如下:
在前一个周期 ID 已准备好指令要处理的操作数后,就开始执行有效地址计算,那么本段 EX 的主要功能是根据对指令操作码部分的译码结果,ALU 对两个 16 位操作数完成算术、逻辑、移位或置位的运算,然后输出结果。根据不同指令类型,该周期的操作分为如下几种。
1)存储器访问指令 LOAD/STORE,即 R1 ← (R2+imm)。当指令为存储器访问指令时,该周期的操作是 ALU 将操作数相加形成有效地址,并将结果送入寄存器 R1。
2)R 型 ALU 操作,即 R1 ← R2 op R3。当指令为 R 型 ALU 操作时,该周期的操作是 ALU 根据操作码指出的功能对寄存器 R2 和 R3 的值进行处理,并将结果送入寄存器 R1。
3)R-I 型 ALU 操作,即 R1 ← R2 op imm。当指令为 R-I 型 ALU 操作时,该周期的操作是 ALU 根据操作码指出的功能对寄存器 R2 和 imm 的值进行处理,并将结果送入寄存器 R1。
4)分支操作,即 Branch Condition ← R1 op 0。当指令为分支操作时,即 BZ 或 BNZ,该周期的操作是对 R1 的值进行检测。若 R1=0 或 R1<>0,则转移到 R2 所指向的目标地址;若不满足条件,则执行后续指令。
5)跳转操作,即 Branch Condition ← 0。当指令为 JAL 指令时,是无条件转移。该周期的操作是直接将分支成功标志 Branch Condition 置位。由于该指令给出的是绝对偏移量,故在上一周期准备的立即操作数就是跳转的目标地址。
注意:执行 EX 段进行分支转移成功与否的判断,得到分支转移成功标志 Branch Condition,并送到 IF 段,用作程序计数器 PC 选择多路的输入 npc_sel;同时本段提供定向路径到 IF 段,把 ALU_resultde 的值直接回送到多路选择器 NPC 的输入端,这条定向路径可以使分支指令的执行节拍数从 4 拍减少到 3 拍,达到消除部分控制的目的。若遇到 pipeline_stall 信号被置位,则 IF 段停顿,ID 段输出空指令,EX 段、MA 段、WB 段正常执行。
**4.**访存储器 MA 段的结构: 访存储器 MA 段的结构如图 6 所示。MA 段主要负责从存储器或 IO 端口存取数据,同时向处理器输入数据以及将处理器的数据向外输出。如果当前指令不是存储器或 IO 指令,那么 ALU 得到结果将送入写回段 WB。

对 MA 段主要功能的描述如下:
1)在时钟上升沿,将 MA 段的值写入存储器/写回寄存器 MA/WB。
2)输出端口寄存器要向 CPU 外部输出数据,若使能信号 enable 置为 1,则在时钟信号 CLK 的上升沿将来自寄存器的 16 位数据锁存后输出。
3)多路数据选择器要根据选择信号 SEL 的状态,从三组输入数据中选择一组输出。
**5.**写回段 WB 的结构: 写回段 WB 的结构如图 7 所示。写回段 WB 主要负责将计算结果和存储器或输入数据写入寄存器文件。经过流水段 MA/WB 寄存器后,数据达到写回段 WB。本段要对需要写回寄存器文件的数据进行处理。根据指令操作码,从三个数据源中选择写回数据,并给出写回目的地址。由于在指令编码当中进行优化,要写回寄存器文件的寄存器目的操作数由内存选择信号决定,因此只需对指令操作码部分进行判断,即可确定是否有结果需要写回,并执行写回操作。数据存储器用 FPGA 中的 EAB 设计而成。

流水线功能段问题处理建议
如果使流水线 CPU 能够顺利地执行程序,就需要解决在各功能段出现数据相关、结构相关和功能相关问题。也就是说,CPU 要有相应的自动检测单元来检测数据相关、结构相关的发生,并且用相应的控制单元根据一定控制策略来处理这些相关性问题。这两个相关检测单元均设计在 ID 段。
数据相关的检测与处理建议: 数据相关性检测方式是直接从各段的锁存器中将相关的信号反馈回译码段,然后将正在 ID 段进行的指令源操作数,与 ID 段以后各段的锁存段中的目的操作数进行比较,从而发现数据相关。 如果发现数据相关,就采用阻塞和前推两种途径。阻塞是暂停指令流的进行,直至所需的结果可用为止,这是解决数据相关的最简单方法。前推是将某段产生的中间结果提前送入需要段寄存器。
控制相关的检测与处理建议: 任何正常执行程序流出现变化时就会发生控制相关,如分支转移、中断和中断返回等,因为分支、中断等发生相关要等到指令被译码的 ID 段才知道转移成功。此时指令被译码,但后续指令已经进入流水线,流水线中就会停留一条未被阻止的不需要的指令。 解决这种控制相关方法只有一种方案,就是采用硬件阻塞。硬件阻塞是从流水线中去掉不需要执行的指令。
结构相关的检测与处理建议: 结构相关就是资源相关。结构相关检测是在流水线上执行分支指令时,PC 值有两种情况:一种是 PC 值发生变化,即分支转移的目标地址,另一种是 PC 值保持正常值。
如果检测是发生结构相关,就可以采取阻塞、预取和资源重复方法。阻塞方法与数据相关处理方法一样。预取就是 IF 段取出两条指令,将它们存储在一个小的缓冲器中。这个小缓冲器不能大,建议该缓冲器的大小为 4 条指令;而且,只有所用存储器速度足够快,可以在一个时钟周期内进行两次访问时,预取方法才会比阻塞方法好。资源重复方法就是为了消除在解决结构相关问题而引入停顿方法对流水线的影响。
实验内容和要求
根据总体逻辑结构设计实现静态 5 级流水线 CPU。
完成一个 8位×8位 乘法程序,即初始值 R0=15,R1=8,其运算结果 120 存放在 R2 寄存器中。并在 Vivado 工具中检查 R2 结果。如果不符合请进行调试,直至结果为 120。
完成一个内存读写测试。即将 32~1 写入内存 0x11F~0x110,将 16~1 取出,存入 0x020F~0x0200,并在 Vivado 工具中检查上述内存单元结果。
完成一个求质数的程序,即完成一个求 64 以内的质数,分别存入内存 0x300~0x0311,并在 Vivado 工具中检查上述内存单元结果。
module pipeline_cpu (clock, memclock,resetn, pc,inst,ealu, malu, walu);
input clock , memclock , resetn;
output [31:0] pc,inst,ealu, malu, walu;
wire [31:0] bpc,jpc, npc, pc4,ins, dpc4,inst, da, db, dimm, ea,eb,eimm;
wire [31:0] epc4, mb , mmo , wmo , wdi;
wire [4:0] drn,ern0,ern, mrn, wrn;
wire [3:0] daluc,ealuc; //daluc = aluc
wire [1:0] pcsource;
wire wpcir;
wire dwreg , dm2reg , dwmem, daluimm, dshift,djal;
wire ewreg, em2reg , ewmem, ealuimm, eshift,ejal;
wire mwreg , mm2reg , mwmem;
wire wwreg, wm2reg;
pipepc prog_cnt (npc, wpcir,clock , resetn, pc);
pipeif if_stage (pcsource, pc, bpc,da,jpc, npc,pc4,ins) ;
pipeir inst_reg (pc4,ins, wpcir,clock , resetn, dpc4,inst);
pipeid id_stage (mwreg,mrn,ern,ewreg, em2reg,mm2reg, dpc4,inst,
wrn, wdi,ealu, malu , mmo , wwreg, clock , resetn,
bpc,jpc,pcsource, wpcir , dwreg, dm2reg , dwmem,
daluc,daluimm, da , db , dimm, drn, dshift,djal);
pipedereg de_reg (dwreg, dm2reg, dwmem, daluc, daluimm, da, db, dimm,
drn, dshift,djal, dpc4,clock , resetn,
ewreg,em2reg , ewmem,ealuc,ealuimm, ea,eb,eimm,
ern0 ,eshift,ejal,epc4);
pipeexe exe_stage (ealuc,ealuimm, ea,eb,eimm, eshift,ern0,epc4,
ejal,ern,ealu) ;
pipeemreg em_reg (ewreg, em2reg, ewmem,ealu, eb,ern,clock, resetn,
mwreg , mm2reg , mwmem, malu , mb , mrn);
pipemem mem_stage (mwmem, malu, mb,clock , memclock , memclock, mmo);
pipemwreg mw_reg (mwreg, mm2reg , mmo , malu, mrn,clock , resetn,
wwreg , wm2reg, wmo , walu , wrn) ;
mux2x32 wb_stage (walu, wmo , wm2reg, wdi ) ;
endmodule






