6.5 分支指令的控制信号

Posted doctorx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了6.5 分支指令的控制信号相关的知识,希望对你有一定的参考价值。

计算机组成

6 单周期处理器

6.5 分支指令的控制信号

技术分享图片

分支指令,是一类特殊的指令,它能够改变程序的流向。因此,想要执行分支指令,我们还需要对现有的结构进行进一步的改造。

技术分享图片

在我们现在这个示例的指令系统当中,分支指令只有一条,它的格式是I型的,那我们首先来看一看分支指令是如何工作的。

技术分享图片

左边是一段C语言的代码,是一段典型的 if else 语句,那我们看对应如何产生 MIPS 的汇编语言代码会是怎么样的。 首先就是一条beq的分支指令,看来编译器已经把 i 和 j 这两个局部变量分别放到了s3和s4这两个寄存器当中,那么这条指令就是比较s3和s4的值。如果它们相等,则会跳转到 True 这个标号所标明的地址,是一条加法指令,这条指令就是执行了 f=g+h 这条语句。也就是C语言代码当中,if 条件为真时,所要执行的语句。执行完这条语句之后,程序将顺序地执行后面的内容。

而如果 if 语句的判断条件不成立,那对应的这条beq 指令在执行时,也会发现 s3 和 s4 寄存器的内容不相等,从而不发生分支转移,而是执行顺序的后一条指令。后一条指令是一条减法指令,那与刚才我们看到的那条加法指令相对应,实际上,它执行的就是 f=g-h 这条语句。也就是C语言当中,else 的这条语句。那么执行完这条指令之后,下一条指令是一条无条件的转移指令,直接跳到 Next,那这就是应用条件分支指令的实例。那我们就来看一看 beq 这条指令的控制信号是如何生成的。

技术分享图片

beq指令的操作,同样也可以分为三步。第一是取指令;第二条,是判断 rs 和 rt 两个寄存器的内容是否相等,那我们可以用一个减法来进行判断;第三步,是更新PC寄存器。

那么对于beq指令来说,所谓的分支,就是如何去改写PC寄存器。所以它的重点在于第三步。

我们先来看条件不成立的情况,也就是else对应的PC=PC+4,那在转移条件不成立的时候,我们是顺序执行后一条指令(也就是上一张ppt中的sub指令),
这就和其他的运算指令、访存指令是一样的。

那如果条件成立的时候,PC的更新条件则相对复杂一些。其中也有PC+4,然后需要加上这个16位的立即数的符号扩展,并乘以4。也就是说,在beq指令当中,所带的这个立即数,也就是刚才在示例中出现的那个目标地址的标号True,它实际的数值,是转移目标地址和下一条指令地址之间的差值(True处的地址减sub指令处的地址),而且这个差值是以4个字节,也就是32位为一个单位的。那么这个规则,是在制定MIPS指令系统的时候约定的。 我们现在重点是看如何去实现相应的控制信号。

技术分享图片

同样,我们直接来看第二步。那么对于这一步,要做的操作包括,从寄存器堆当中取出两个寄存器的内容,而且进行减法运算,这个操作和我们之前学习的减法指令需求是一样的。因此,现有的结构不需要修改,就可以完成这个功能。我们注意,当取回一条指令之后,rs的位域被连接到寄存器堆,它所指定的寄存器的内容会放到busA上,然后连接到ALU的一个输入端;rt位域的信号会被连接到寄存器堆的Rb的输入端,它所指定的寄存器的内容,会通过busB信号,再经过这个(ALUSrc)多选器传递到ALU的另一个输入端,然后这个ALU就可以执行这个减法。不过问题在于,之前的减法运算指令会将这个ALU运算的结果,通过这个多(MemtoReg)选器之后,写回到寄存器堆(RegFile)当中去。而beq指令是不需要写回寄存器堆的,而且也不应该写回。 我们希望通过这个ALU,得出一个判断,就是这个减法操作的结果是不是0。因此,我们还需要增加一个新的功能,来完成这样的一个判断:判断一个数是否等于0。这是非常简单的,所以我们可以很轻松地在ALU当中增加这个功能,并让ALU提供一个信号的输出,标明当前的运算结果是否为0,我们把这个信号命名为zero。如果运算结果为0,ALU会把zero信号置为1;否则,置为0。那因为运算结果是否为0,将会影响到IFU如何去更新PC寄存器,所以我们需要把zero信号连接到IFU。这样,我们就可以把第二步操作的描述补充完整。

那么在这一步操作中,红色这些控制信号又是如何设置的呢?

技术分享图片

首先,下一个PC的选择方式,我们就不能再设置为加4了。但是究竟如何更新,IFU还需要做一些工作,这个我们一会儿再说。所以我们先把这个选择信号标记为branch,然后我们再来看其他的控制信号。

现在我们已经知道,ALU要执行一个减法运算,而且它的两个操作数都应该来自寄存器堆,所以这一个多选器就应该选择通道0(ALUSrc=0)。 由此,扩展部件功能选择信号可以任意设置(ExtOp=x)。而ALU的功能选择信号,则需要设置为减法(ALUCtr=“SUB”),那现在虽然我们新增了这个zero信号,但是ALU原本的功能还是必须保持的。所以,当我们设置ALU执行减法运算时,它的输出 依然会是减法运算的结果,并送到数据存储器的地址端(Adr)和下一个多选器的0号通道。那为了保证数据存储器不被改写,那我们还要设置数据存储器的写使能信号为0(MemWr=0)。 那对于条件分支指令来说,它是不要回写寄存器堆的,所以这个多选器无论选择哪一条通道,都是没有意义的,那我们可以把它的选择信号任意设置为0或者1(MemtoReg=x)。

最后我们来看寄存器堆这一边(RegFile),因为不需要回写寄存器堆,所以我们必须要设置寄存器堆的写使能信号为0(RegWr=0),以免错误地更改其中的内容,那因为写使能信号已经设为0,那寄存器堆的写入寄存器的编号,则可以任意的设置(RegDst=x)。

技术分享图片

这样,我们就可以看出,beq指令执行时真正有效的信号了。不过我们要注意,这一步仅仅是完成了判断,那我们还要根据判断的结果,对PC寄存器进行更新。因此,这条指令的第三步和其他指令是不一样的。

技术分享图片

那好,现在对于IFU来说,它有了两个输入的信号,一个是之前就有的nPC_ select,还有一个是我们后来增加的zero。

而我们知道,对于IFU如何更新PC寄存器,其关键就是这个多选器如何选择的问题。 它的0号通道连接的是PC+4,1号通道连接的是分支指令的目标地址。那现在我们这个选择信号应该如何生成呢?我们不妨把输入列一个表来进行观察。

当nPC_select的信号为0的时候,就代表当前在执行的指令是运算指令,或者是访存指令,而不是分支指令。那在这个时候,无论zero信号是0还是1,这个多选器都应该选择0号通道,从而顺序地执行下一条指令。

而当nPC_select的信号等于1时,说明当前正在执行一条分支指令。但如果此时zero信号为0,表示分支的判断条件不成立,那这个多选器仍然应该选择0号通道,从而顺序地执行下一条指令。

只有当nPC_select的信号为1,说明当前是一条分支指令,而且zero信号也为1,说明当前的判断条件成立。这时,这个多选器才可以选择1号通道,从而将分支的目标地址更新到PC寄存器当中去,这样在下一个时钟周期,指令存储器就会将分支目标地址所指向的那条指令的编码送出来,从而实现指令执行流向的改变。

那通过这张表,我们是否能够得出这个多选器的控制信号的生成方法呢?请你想一想。 给一点提示,实际上只需要一个逻辑门就可以了。如果还没有想出来,那我们不妨回来再观察一下,对于这个多选器的选择信号,只有在nPC_select和zero信号都为1时,它才会为1;在其他时候,这个选择信号均为0。 那这个描述大家是不是很熟悉呢?这是哪个逻辑门的功能描述?我们还是来看最右边吧,其实,只需要一个与门就可以了。

技术分享图片

那基于这样的分析,我们就可以对IFU进行进一步的改造, 从而支持beq指令的需求。 不过这里还有一个问题,那就是分支目标地址究竟是如何生成的?那现在我们就来完成最后这一项工作,这个分支目标地址有两个部分,一部分是PC+4,一部分是对立即数进行符号扩展,然后乘以4,而这个立即数就是指令编码当中的低16位,因此,我们先把这一部分信号连出来。

技术分享图片

现在,我们把这个立即数取出来,连接到一个符号扩展的部件上。对于这个符号扩展的部件,我们再增加一个很简单的小功能,就是向左再移动两位,左移两位就相当于乘以4。因此,经过这个部件,我们将这16位的立即数扩展成了32位,并且完成了乘以4的操作。那现在我们有了这个算式的后半部分,而前半部分是PC+4。幸运的是,我们现在已经有了PC+4,就是这个加法器的输出,那我们只需要直接把它连出来,然后再增加一个加法器,这样就可以得到了分支指令的目标地址(Target Address)。

现在这个IFU,我们也已经补充完整了。

技术分享图片

现在,我们已经分析完了这个指令系统当中的最后一条指令了。 那我们已经知道,对于每一条指令,每一个控制信号,我们应该赋予什么样的值。但是还有一个问题,我们依然不是很清楚,就是这些信号的值是如何自动地产生的呢?我们在下一节就来一起探讨这个问题。

以上是关于6.5 分支指令的控制信号的主要内容,如果未能解决你的问题,请参考以下文章

汇编语言程序设计

Python开发—流程控制

git 删除本地分支/远程分支

10shell编程+流程控制+分支嵌套

php流程控制

awk学习笔记