流水线 cpu 的简易实现
一、整体思路
1. 流水线 cpu
流水线 cpu 中一个指令执行的五个周期如上图所示。
为了解决流水线同步问题,设计 cpu 中级间寄存器由上升沿触发,周期内器件由下降沿触发。
上图为书上的流水线 cpu 基本数据通路,本次实验主要在此基础上进行改进,且添加冲突处理模块,在实验过程中,我也发现了该图中很多不足的地方。
2.mips 指令集
mips 指令分为 R 型,I 型和 J 型,其中 R 型有三个操作数,I 型携带立即数,J 型为跳转指令。
MIPS 指令
3. 冲突管理
冲突管理是流水线 cpu 不得不面对的一个问题,解决方法主要为插入气泡来阻塞指令运行,已经增加新的数据回路使前指令的结果尽快回送到寄存器中。本次实验主要采取的是气泡插入法,结构较为简单但是降低了效率。
cpu 的冲突主要分为三种,结构冲突,数据冲突和控制冲突。结构冲突通过流水线 cpu 的结构设计可以避免,数据冲突主要是相距较近的指令所需数据地址相同产生的时间冲突,控制冲突主要针对跳转指令,本次实验中的冲突检测模块维护了一个队列用来检测冲突,从而解决数据冲突,对于控制冲突,由于数据通路问题无法较早回送,只能插入气泡。
二、组成模块
1. 存储器
存储器分为指令存储器(IM)和数据存储器(DM)两部分。
指令存储器通过 PC 的输出
verilog 代码实现
1 |
|
2. 级间寄存器
级间寄存器是流水线 cpu 最为关键的部分,承担着在各不同周期之间传递指令和标志位的作用。
级间寄存器由同步信号驱动,控制各自周期内部计算的开始并分割指令的各周期。
在冲突发生时,FI/ID 级间寄存器阻塞并将所有标志位置零,防止指令向下运行。
verilog 代码实现
1 |
|
3. 控制模块
控制模块通过识别指令输出对应的个标志位的值给级间寄存器。
由于流水线 cpu 的标志位较少,且可以借助级间寄存器传递相应指令的标志位,
可以直接使用组合逻辑电路实现。
verilog 代码实现
1 |
|
4. 运算器及运算控制器
运算器(ALU)即指令执行的主要模块,工作在 EX 周期。
在流水线 cpu 中,通过添加加法器,分离部分运算器功能的方法可以解决部分冲突问题
verilog 代码实现
1 |
|
5. 程序计数器
程序计数器(PC)记录下一步指令的地址,主要在 FI 周期工作。
PC 通过加法器实现自增功能,但在冲突发生时,关闭自增。
verilog 代码实现
1 |
|
6. 冲突检测模块
流水线 cpu 主要需要解决数据冒险和控制冒险的问题,主要工作于 FI 周期。
本次实验采用后推产生气泡的方法解决冒险,在冲突检测模块中建立队列存储已经执行指令影响的寄存器;
取出新指令时,在队列中对比,如发现冲突,则产生气泡,后退冲突影响指令。
产生气泡时阻塞 PC 自增并使 FI/ID 级间寄存器中各数据位归零,使得指令无法运行。
由于级间寄存器上升沿触发,冲突检测模块应由下降沿触发。
verilog 代码实现
1 |
|
7. 寄存器组模块
寄存器组(RF)是 cpu 中的主要存储模块,工作在 ID 和 WB 周期。
在 ID 周期中,寄存器组取出以指令中操作数为地址的值,并输入下一层。
在 WB 周期中,RF 接受回送地址和回送数据,实现将结果存入目标地址。
verilog 代码实现
1 |
|
8. 其他逻辑模块
其他逻辑模块主要包含加法器,16/32 位扩展模块,移位模块,多路选择模块。
加法器主要用于 PC 自增和分担运算器功能;
16/32 扩展模块用于处理指令中的立即数;
移位模块用于处理 beq 跳转指令,工作在 EX 周期;
多路选择器是标志位的主要作用对象,工作于 FI, MA, WB 模块。
verilog 代码实现
1 |
|
9.cpu 顶层模块
顶层模块中实例化各模块,计算 PC_src, 产生时钟信号,并初始化 PC,使得 cpu 从第一条指令开始运行。
verilog 代码实现
1 |
|
三、测试方法和工具
1. 汇编器
汇编器是将汇编语言转换成机器语言指令的工具,通过 python 中 ply 模块的 lex 模块和 yacc 模块可以较为轻松的编写汇编器。
需要 python3,pip 环境
安装依赖
1 |
|
代码
1 |
|
2. 存储器初始化
指令存储器和寄存器组可以通过 verilog 自带函数读取.txt 文件初始化。
数据存储器在代码中自行初始化。
PC 初始化为 0.
RF 初始化如下:
11111111
22222222
33333333
44444444
55555555
66666666
77777777
88888888
99999999
aaaaaaaa
bbbbbbbb
cccccccc
dddddddd
eeeeeeee
ffffffff
12345678
87654321
01234567
76543210
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
00000000
四、测试结果
1. 测试指令
1 |
|
转换为十六进制机器指令
1 |
|
2.vivado 模拟
3. 测试模块
1 |
|
4. 波形效果
五、改进方案
本次实验中为了解决数据冲突和控制冲突,主要采用了插入气泡的后退法,但是尽管后退法的结构简单,不会引入较为复杂的连线和结构,但浪费了较多的 cpu 周期,削弱了
流水线 cpu 相较于其他 cpu 效率更高的优点。为了保证指令执行的效率,可以使用专用的数据通路提前回送数据从而取代气泡的插入。同时,对于控制冒险,可以将 J 指令在 FI
周期内完成,BEQ 指令在 FI 和 ID 周期内完成,可以实现 J 指令不插入气泡,BEQ 指令只插入一个气泡,但要实现这一结构,本次实验会对级间寄存器结构有较大的改动,因此没有实现。