将陆续上传本人写的新书《自己动手写CPU》(尚未出版)。今天是第16篇。我尽量每周四篇

5.2 OpenMIPS对数据相关问题的解决措施

OpenMIPS处理器採用数据前推的方法来解决流水线数据相关问题。

通过补充完好图4-4原始的数据流图,加入部分信号使得能够完毕数据前推的工作,如图5-7所看到的。主要是将运行阶段的结果、訪存阶段的结果前推到译码阶段。參与译码阶段选择运算源操作数的过程。

图5-8给出了为实现数据前推而对OpenMIPS系统结构所做的改动。有两个方面。

(1)将处于流水线运行阶段的指令的运算结果,包含:是否要写目的寄存器wreg_o、要写的目的寄存器地址wd_o、要写入目的寄存器的数据wdata_o等信息送到译码阶段,如图5-8中虚线所看到的。

(2)将处于流水线訪存阶段的指令的运算结果。包含:是否要写目的寄存器wreg_o、要写的目的寄存器地址wd_o、要写入目的寄存器的数据wdata_o等信息送到译码阶段。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGVpc2hhbmd3ZW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

为此。译码阶段的ID模块要添加如表5-1所看到的的接口。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGVpc2hhbmd3ZW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

译码阶段的ID模块会根据送入的信息。进行综合推断。解决数据相关,给出最后要參与运算的操作数。

ID模块的代码要做例如以下改动,当中主要改动部分使用加粗、斜体表示。改动后的代码位于本书光盘的Code\Chapter5_1文件夹下的id.v文件。

module id(

	......

	//处于运行阶段的指令的运算结果
input wire ex_wreg_i,
input wire[`RegBus] ex_wdata_i,
input wire[`RegAddrBus] ex_wd_i, //处于訪存阶段的指令的运算结果
input wire mem_wreg_i,
input wire[`RegBus] mem_wdata_i,
input wire[`RegAddrBus] mem_wd_i, ...... //送到运行阶段的源操作数1、源操作数2
output reg[`RegBus] reg1_o,
output reg[`RegBus] reg2_o,
......
); ...... //给reg1_o赋值的过程添加了两种情况:
//1、假设Regfile模块读port1要读取的寄存器就是运行阶段要写的目的寄存器。
// 那么直接把运行阶段的结果ex_wdata_i作为reg1_o的值;
//2、假设Regfile模块读port1要读取的寄存器就是訪存阶段要写的目的寄存器,
// 那么直接把訪存阶段的结果mem_wdata_i作为reg1_o的值;
always @ (*) begin
if(rst == `RstEnable) begin
reg1_o <= `ZeroWord;
end else if((reg1_read_o == 1'b1) && (ex_wreg_i == 1'b1)
&& (ex_wd_i == reg1_addr_o)) begin
reg1_o <= ex_wdata_i;
end else if((reg1_read_o == 1'b1) && (mem_wreg_i == 1'b1)
&& (mem_wd_i == reg1_addr_o)) begin
reg1_o <= mem_wdata_i;
end else if(reg1_read_o == 1'b1) begin
reg1_o <= reg1_data_i;
end else if(reg1_read_o == 1'b0) begin
reg1_o <= imm;
end else begin
reg1_o <= `ZeroWord;
end
end //给reg2_o赋值的过程添加了两种情况:
//1、假设Regfile模块读port2要读取的寄存器就是运行阶段要写的目的寄存器,
// 那么直接把运行阶段的结果ex_wdata_i作为reg2_o的值;
//2、假设Regfile模块读port2要读取的寄存器就是訪存阶段要写的目的寄存器,
// 那么直接把訪存阶段的结果mem_wdata_i作为reg2_o的值;
always @ (*) begin
if(rst == `RstEnable) begin
reg2_o <= `ZeroWord;
end else if((reg2_read_o == 1'b1) && (ex_wreg_i == 1'b1)
&& (ex_wd_i == reg2_addr_o)) begin
reg2_o <= ex_wdata_i;
end else if((reg2_read_o == 1'b1) && (mem_wreg_i == 1'b1)
&& (mem_wd_i == reg2_addr_o)) begin
reg2_o <= mem_wdata_i;
end else if(reg2_read_o == 1'b1) begin
reg2_o <= reg2_data_i;
end else if(reg2_read_o == 1'b0) begin
reg2_o <= imm;
end else begin
reg2_o <= `ZeroWord;
end
end endmodule

除了改动译码阶段ID模块的代码,还要改动顶层模块OpenMIPS相应的代码,在当中添加图5-8所看到的的连接关系。详细改动过程不在书中列出,读者能够參考本书附带光盘的Code\Chapter5_1文件夹下的openmips.v文件。

(代码会在稍后上传)

5.3 測试数据相关问题解决效果

測试程序例如以下,当中存在5.1节讨论的RAW相关的三种情况,源文件是本书附带光盘Code\Chapter5_1\AsmTest文件夹下的inst_rom.S文件。

.org 0x0
.global _start
.set noat
_start:
ori $1,$0,0x1100 # $1 = $0 | 0x1100 = 0x1100
ori $1,$1,0x0020 # $1 = $1 | 0x0020 = 0x1120
ori $1,$1,0x4400 # $1 = $1 | 0x4400 = 0x5520
ori $1,$1,0x0044 # $1 = $1 | 0x0044 = 0x5564

指令的凝视给出了预期运行效果。

将上述inst_rom.S文件,与第4章实现的Bin2Mem.exe、Makefile、ram.ld这三个文件复制到Ubuntu虚拟机中的同一个文件夹下,打开终端,使用cd命令进入该文件夹,然后输入make  all,就可以得到可以用于ModelSim仿真的inst_rom.data文件。

在ModelSim中新建一个project。加入本书附带光盘Code\Chapter5_1文件夹下的全部.v文件。然后能够编译。再复制上面得到的inst_rom.data文件到ModelSimproject的文件夹下,就能够进行仿真了。ModelSim中新建project、仿真的具体步骤能够參考第2章。

执行仿真,观察寄存器$1值的变化,如图5-9所看到的。$1的变化符合预期,所以改动后的OpenMIPS正确攻克了数据相关问题。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGVpc2hhbmd3ZW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">



下一步将实现逻辑、移位、空指令,敬请关注!

自己动手写CPU之第五阶段(2)——OpenMIPS对数据相关问题的解决措施的更多相关文章

  1. 自己动手写CPU之第五阶段(1)——流水线数据相关问题

    将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第15篇,我尽量每周四篇 上一章建立了原始的OpenMIPS五级流水线结构,可是仅仅实现了一条ori指令,从本章開始,将逐步完 ...

  2. 自己动手写CPU之第五阶段(3)——MIPS指令集中的逻辑、移位与空指令

    将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第17篇.我尽量每周四篇 5.4 逻辑.移位操作与空指令说明 MIPS32指令集架构中定义的逻辑操作指令有8条:and.and ...

  3. 自己动手写CPU之第六阶段(2)——移动操作指令实现思路

    将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第21篇,我尽量每周四篇 6.2 移动操作指令实现思路 6.2.1 实现思路 这6条移动操作指令能够分为两类:一类是不涉及特殊 ...

  4. 自己动手写CPU之第七阶段(7)——乘累加指令的实现

    将陆续上传本人写的新书<自己动手写CPU>.今天是第30篇.我尽量每周四篇 亚马逊的销售地址例如以下.欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8 ...

  5. 自己动手写CPU之第四阶段(3)——MIPS编译环境的建立

    将陆续上传本人写的新书<自己动手写CPU>(尚未出版).今天是第13篇.我尽量每周四篇 4.4 MIPS编译环境的建立 OpenMIPS处理器在设计的时候就计划与MIPS32指令集架构兼容 ...

  6. 自己动手写CPU之第七阶段(2)——简单算术操作指令实现过程

    将陆续上传本人写的新书<自己动手写CPU>.今天是第25篇.我尽量每周四篇 亚马逊的预售地址例如以下,欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8 ...

  7. 自己动手写CPU之第七阶段(5)——流水线暂停机制的设计与实现

    将陆续上传本人写的新书<自己动手写CPU>,今天是第28篇.我尽量每周四篇 China-pub的预售地址例如以下(有文件夹.内容简单介绍.前言): http://product.china ...

  8. 自己动手写CPU之第八阶段(4)——转移指令实现过程2

    将陆续上传本人写的新书<自己动手写CPU>,今天是第36篇,我尽量每周四篇 开展晒书评送书活动,在亚马逊.京东.当当三大图书站点上,发表<自己动手写CPU>书评的前十名读者,均 ...

  9. 自己动手写CPU之第七阶段(6)——乘累加指令实现思路

    将陆续上传本人写的新书<自己动手写CPU>.今天是第29篇.我尽量每周四篇 亚马逊的销售地址例如以下,欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8 ...

随机推荐

  1. LeetCode 771. 宝石与石头(java)

    给定字符串J 代表石头中宝石的类型,和字符串 S代表你拥有的石头. S 中每个字符代表了一种你拥有的石头的类型,你想知道你拥有的石头中有多少是宝石. J 中的字母不重复,J 和 S中的所有字符都是字母 ...

  2. Activity(活动)生命周期(3)--活动的生存期

    Activity类中定义了7中回调方法,覆盖了活动生命周期的每一个环节. 回调方法: 1.onCreate() 这个方法会在活动第一次被创建的时候调用.我们应该在这个方法中完成活动的初始化操作,比如: ...

  3. Educational Codeforces Round 9 D. Longest Subsequence dp

    D. Longest Subsequence 题目连接: http://www.codeforces.com/contest/632/problem/D Description You are giv ...

  4. PHP“Cannot use object of type stdClass as array”

    php再调用json_decode从字符串对象生成json对象时,如果使用[]操作符取数据,会得到下面的错误 错误:Cannot use object of type stdClass as arra ...

  5. GDB的一些技巧

    查看栈信息 bt info stack 查看源程序 list ctrl + x + a 分屏调试,上半部分显示代码,下半部分显示调试信息. 查看内存 p  xxxptr@n  查看xxxptr 指针内 ...

  6. E-R图样例

    基本知识 基本的ER模型包含三类元素:实体.关系.属性. 实体(Entities):实体是首要的数据对象,常用于表示一个人.地方.某样事物或某个事件.一个特定的实体被称为实体实例(entity ins ...

  7. OpenShift应用镜像构建(4) - fabric8-maven-plugin

    适合开发的构建fabric8-maven-plugin 在项目过程中越来越多的出现在开发阶段就需要把部分微服务直接做容器化发布,然后自己的代码还需要和这些发布后的微服务进行调用的开发过程,这个阶段基本 ...

  8. 基于Python的交互式访问

    应用迁移中遇到一些有特殊要求的应用,比如需要通过交互生成一些新的config文件,然后启动应用需要依赖于这些文件,这样在构建镜像的时候基本上是没有办法把这些文件固定的,因为他需要根据运行环境去进行动态 ...

  9. 784 - Maze Exploration

    #include <stdio.h> #include <string.h> char maze[50][100]; void search(int i,int j) { if ...

  10. Java笔记19:Java匿名内部类

    匿名内部类也就是没有名字的内部类.正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写.但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口 例1:不使用匿名内部类来实现抽象方 ...