自己动手写CPU(8)转移指令+延迟槽解决流水线控制相关
延迟槽
流水线中存在的三种相关:数据相关、结构相关、控制相关。其中控制相关是指流水线中的转移指令或者其他需要改写PC的指令造成的相关。这些指令改写了PC的值,所以导致后面已经进入流水线的几条指令无效。
比如当第一条指令为分支跳转指令,那么在执行阶段才会知道要不要跳转;但当时第二条指令已经进入译码;第三条指令已经进入取指阶段。在流水线执行阶段进行转移判断,并且转移发生,那么会有两条无效指令,导致浪费两个时钟周期,为减少损失发明了“延迟槽”
我们规定转移指令后面的指令位置为延迟槽
但是,即使加入延迟槽,在转移发生时仍然会导致已经进去取指阶段的指令无效,仍浪费一个时钟周期。所以我们可以在译码阶段进行转移判断,并且让延迟槽后一指令继续执行。
此时需要注意的是:
延迟槽里的指令,在目标跳转指令前面执行,所以延迟槽里的指令不能修改目标跳转指令会用到的寄存器或者变量的内容,否则会出错。
下面我们来介绍转移指令
其中跳转指令是绝对转移,分支指令是相对转移
跳转指令
指令格式
jr指令
用法:jr rs
作用:pc <- rs
将地址为rs的通用寄存器的值赋给寄存器PC,作为新的指令地址
jalr指令
用法:jalr rs 或者 jalr rd,rs
作用:rd <- return_address,pc <- rs
将地址为rs的通用寄存器的值赋给寄存器PC,作为新的指令地址,同时将跳转指令后面第2条指令的地址作为返回地址保存到地址为rd的通用寄存器,如果没有在指令中指明rd,那么默认将返回地址保存到寄存器$31
j指令
用法:j target
作用:pc <- (pc+4)[31,28]||target||‘00’
转移到新的指令地址,其中新地址的低28位是target左移两位后的值,新指令地址高4位是后一指令的高四位
因为处理器按照字节寻址,二指令存储器每个地址是一个32bit字,所以要给指令中的立即数乘4,即左移两位
jal指令
用法:jal target
作用:pc <- (pc+4)[31,28]||target||‘00’
转移到新的指令地址,其中新地址的低28位是target左移两位后的值,新指令地址高4位是后一指令的高四位,jal指令要将跳转指令后面的一条指令地址(pc+4)写入$31寄存器
分支指令
指令格式
指令说明
beq、b、bgtz、blez、bne这5条指令可以直接依据指令中的指令码进行判断是哪一条指令,bltz、bltzal、bgez、bgezal、bal这5条指令指令码相同,依据指令中16~20bit的值进一步判断是哪一条指令
所有分支指令的第0~15bit存储的都是offset,如果发生转移,那么将offset左移2位,并符号扩展至32位
转移目标地址 = (signed_extend)(offset||‘00’)+(pc+4)
beq指令
用法:beq rs,rt,offset
作用:if rs = rt then branch
将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值进行比较,如果相等,则发生转移
b指令
用法:b offset
作用:无条件转移
beq指令的rs,rt都为0时的情况,实现时不需要特意实现b指令,只需要实现beq即可
bgtz指令
用法:bgtz rs,offset
作用:if rs > 0 then branch
如果地址为rs的通用寄存器的值大于0,则发生转移
blez指令
用法:blez rs,offset
作用:if rs <= 0 then branch
如果地址为rs的通用寄存器的值小于等于0,则发生转移
bne指令
用法:bne rs,rt,offset
作用:if rs != rt then branch
将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值进行比较,如果不相等,则发生转移
bltz指令
用法:bltz rs,offset
作用:if rs < 0 then branch
如果地址为rs的通用寄存器的值小于0,则发生转移
bltzal指令
用法:bltzal rs,offset
作用:if rs < 0 then branch
如果地址为rs的通用寄存器的值小于0,则发生转移,并且将指令后面的指令地址作为返回地址,保存到通用寄存器$31
bgez指令
用法:bgez rs,offset
作用:if rs >= 0 then branch
如果地址为rs的通用寄存器的值大于等于0,则发生转移
bgezal指令
用法:bgezal rs,offset
作用:if rs >= 0 then branch
如果地址为rs的通用寄存器的值大于等于0,则发生转移,并且将指令后面的指令地址作为返回地址,保存到通用寄存器$31
bal指令
用法:bal offset
作用:无条件转移
如果地址为rs的通用寄存器的值大于等于0,则发生转移,并且将指令后面的指令地址作为返回地址,保存到通用寄存器$31
bal是bgezal指令的特殊情况,即bgezal指令的rs为0,不用特意实现这个指令
代码的修改
- 在译码阶段增加转移判断步骤,PC分成三种取值
- 译码阶段增加延迟槽处理信号
PC的三种取值:
1.PC = PC + 4(下一条指令)
2.PC不变(流水线暂停)
3.PC等于转移判断的结果(如果是转移指令且满足转移条件,将转移目标给PC)
译码阶段:
如果处于译码阶段的指令是转移指令,并且满足转移条件,那么ID模块设置转移发生标志 branch_flag_o为 Branch,同时通过branch_target_address_o接口给出转移目的地址,送到PC模块,后者据此修改取指地址。
如果处于译码阶段的指令是转移指令,并且满足转移条件,那么ID模块还会设置next_inst_in_delayslot_o为 InDelaySlot,表示下一条指令是延迟槽指令,其中 InDelaySlot是一个宏定义。next_inst _in_delayslot_o信号会送入ID/EX模块,并在下一个时钟周期通过ID/EX模块的is_in_delayslot_o接口送回到ID模块,ID模块可以据此判断当前处于译码阶段的指令是否是延迟槽指令。
如果转移指令需要保存返回地址,那么译码模块还要计算返回地址,并通过link_addr_o接口输出,该值最终会传递到EX模块,作为要写入目的寄存器的值。
修改PC代码:
always @ (posedge clk) beginif (ce == `ChipDisable) beginpc <= 32'h00000000;end else if(stall[0] == `NoStop) beginif(branch_flag_i == `Branch) beginpc <= branch_target_address_i;end else beginpc <= pc + 4'h4;endend
end
总结
要注意延迟槽里的指令,在目标跳转指令前面执行,所以延迟槽里的指令不能修改目标跳转指令会用到的寄存器或者变量的内容,否则会出错。
还要在本次添加宏定义
`define Branch 1'b1 //发生转移
`define NotBranch 1'b0 //不发生转移
`define InDelaySlot 1'b1 //是延迟槽指令
`define NotInDelaySlot 1'b0 //不是延迟槽指令
自己动手写CPU(8)转移指令+延迟槽解决流水线控制相关相关推荐
- 自己动手写CPU(7)转移指令的实现
自己动手写CPU(7)转移指令的实现 分支延迟槽 在MIPS五级流水线中,一条指令被分成了五个阶段:取指.译指.执行.仿存.回写.当第一条指令的执行阶段结束时,第二条指令的译指阶段也已经结束了. 那么 ...
- 【自己动手写CPU】转移指令的实现
概述 转移指令包括跳转.分支两种.跳转指令是绝对转移,分支指令是相对转移,两者实现方法相似.转移指令涉及延迟槽,所以首先介绍延迟槽的概念. #延迟槽 控制相关指流水线中的转移指令或者其他需要改写PC的 ...
- 【自己动手写CPU】异常相关指令的实现
MIPS架构中定义的异常类型 MIPS32架构中,有些事情打断程序的正常的执行流程,这些事情称为中断.陷阱.系统调用以及其他打断程序执行流程的情况,统称为异常. 此处的OpenMIPS处理器只实现了其 ...
- 自己动手写CPU之第七阶段(5)——流水线暂停机制的设计与实现
将陆续上传本人写的新书<自己动手写CPU>,今天是第28篇.我尽量每周四篇 China-pub的预售地址例如以下(有文件夹.内容简单介绍.前言): http://product.china ...
- 自己动手写CPU(8)加载存储指令的实现
自己动手写CPU(8)加载存储指令的实现 好久没更新blog了,暑假提前放了.现在收假也该收收心了,继续捡起之前的CPU,自己开的坑不管咋样把它填完吧. 指令介绍 1.加载指令 2.存储指令 修改系统 ...
- 自己动手写CPU(6)流水线暂停、乘累加减与除法器的实现
自己动手写CPU(6)流水线暂停.乘累加减与除法器的实现 流水线暂停 因为OpenMIPS设计乘累加.乘累减.除法指令在流水线执行阶段占用多个时钟周期,因此需要暂停流水线,以等待这些多周期指令执行完毕 ...
- 自己动手写CPU(5)简单算术操作指令实现_1
自己动手写CPU(5)简单算数操作指令实现_1 指令介绍 MIPS32指令集架构定义的所有算术操作指令,共有21条 共有三类,分别是: 简单算术指令 乘累加.乘累减指令 除法指令 算术指令操作介绍 一 ...
- 自己动手写CPU(4)移动操作指令的实现
自己动手写CPU(4)移动操作指令的实现 指令说明 MIPS32指令集架构中定义的移动操作指令共有6条: movn.movz.mfhi.mthi.mflo.mtlo,后4条指令涉及对特殊寄存器HI.L ...
- 自己动手写CPU(3)逻辑、移位操作与空指令
自己动手写CPU(3)逻辑.移位操作与空指令 指令说明 MIPS32指令集架构中定义的逻辑操作指令有8条: and.andi.or.ori.xor.xori.nor.lui,其中 ori指令已经实现. ...
最新文章
- 链表中倒数第k个节点
- 64位php oracle,64位系统无法加载PHP的oracle扩展问题
- python处理流程-Python文件处理流程
- selenium2与python自动化5-iframe和163邮箱登录
- python 常见内置函数setattr、getattr、delattr、setitem、getitem、delitem
- 从尾到头打印链表---剑指Offer
- 心路历程(五)-find work and find house
- linux ntp 'ntp_request.c'远程拒绝服务漏洞,NTP 'ntp_request.c'远程拒绝服务漏洞
- springCloud - 第5篇 - 断路器 Hystrix ( Feign 、Ribbon )
- shell 进入hadoop_shell启动hadoop集群
- 比较器与滞回比较器的原理及应用
- 阿里巴巴交易平台技术揭秘
- qq浏览器android flash,支持flash游戏 安卓QQ浏览器2.0预览版体验
- 用手机打开word图表位置很乱_干货 | 论文格式调半天?Word攻略帮你统统都搞定...
- Required request body is missing 错误解决,400状态码
- 大学计算机云计算与虚拟服务实验,虚拟化与云计算实验报告.doc.pdf
- 数据库基本原理==嵌套查询
- sdkman的介绍、安装及使用
- Linux关闭防火墙命令总结
- CSDN、博客园、简书、oschina、Iteye各大社区现状