1. 初步 12条
1.1 分析
加载指令实现思路
加载指令在译码阶段进行译码,得到运算类型 alusel o、 aluop_o,以及要写的目的寄存器信息。这些信息传递到执行阶段,然后又传递到访存阶段,访存阶段依据这些信息,设置对数据存储器RAM的访问信号。从RAM读取回来的数据需要按照加载指令的类型、加载地址进行对齐调整,调整后的结果作为最终要写入目的寄存器的数据。
存储指令实现思路
访存阶段,设置对数据存储器RAM的访问信号,将数据写入RAM。
数据通路的改变👇
主要是在访存阶段增加了对数据存储器RAM的访问,同时,由于要写入目的寄存器的数据可能是执行阶段的结果,也可能是在访存阶段从数据存储器RAM加载得到的数据,所以在访存阶段增加了一个多路选择器,进行选择。
系统结构图的改变👇
主要是对于MEM模块的调整。MEM模块依据加载、存储指令的类型,确定对数据存储器RAM的访问信息,通过 mem_ce_o接口送出数据存储器使能信号, mem_addr_ o接口送出访问地址,mem_ we_o接口指出是加载还是存储操作、 mem_sel_o接口送出字节选择信号,如果是存储指令,那么还通过 mem_data_o接口输出要存储的数据,如果是加载指令,那么会从 mem_data_i接口获得读取到的数据,然后MEM模块依据具体的加载指令类型、加载地址,对获取的数据进行对齐调整,最终得到要写入目的寄存器的数据。

1.2 添加数据存储器RAM

其中,sel代表字选择信号
为了方便实现对数据存储器按字节寻址,在设计的时候使用4个8位存储器代替一个32位存储器,如图9-25所示,读操作时,从4个8位存储器中各读出一个字节,组合为一个32位的数据输出,写操作时,依据sel的值,修改其中特定存储器对应的字节即可。注意:地址addr的最低两位不需要使用,比如:读取地址n处的字,实际就是从4个8位存储器的地址n/4处各读取一个字节,组合起来就来地址n处的字。

1.3 修改最小SOPC
将数据存储器RAM连接进来
2.3 测试9 加载存储指令

✔看寄存器$3

✔看寄存器$1

✔看寄存器$1
2. load-use数据冒险

因为数据加载时,beq指令已经处于执行阶段,所以采用转发也不能消除
解决方法是:在译码阶段检査当前指令与上一条指令是否存在load相关,如果存在1oad相关,那么就让流水线的译码、取指阶段暂停,而执行、访存、回写阶段继续,相当于插入一个空指令,这样处于执行阶段的加载指令会继续运行,不受影响,当其运行到访存阶段时,将加载得到的数据转发到译码阶段,然后,流水线可以继续运行。

对于系统结构的修改👇

将一系列信息传递到译码阶段的ID模块,后者据此判断是否存在1oad相关,如果存在load相关,那么通过 stallereq接口通知CTRL模块请求流水线暂停。
主要修改ID模块的代码即可
测试10 load-use数据冒险的解决

如果load-use数据冒险得到正确解决,那么执行beq指令会使程序发生转移,转移到 Label处,从而不会执行ori $1, 0,0x4567这一指令,也就是通用寄存器S1的值不会为0x4567,而是直接为Ox89ab,,观察寄存器1的变化,可知正确解决了load相关问题✔