计算机组成原理好难_计算机的流水线中每个阶段「建议收藏」

计算机组成原理好难_计算机的流水线中每个阶段「建议收藏」我们假设在执行操作进行浮点数的运算:我们假设有4条指令都需要进行浮点数的运算,所以我们就可以这样设计:在宏观上,对于流水线进行分段,分成5段,然后在运算执行阶段,如果需要使用到浮点运算器则再进行分段,这样A指令执行到浮


在这里插入图片描述

硬布线控制器对于不同周期触发器是如何写入的
水平型微指令的灵活性高于垂直型微指令?
混合编码
三种CPU的控制方式

指令流水线

一条指令的执行我们大致可以分为以下三个阶段。
在这里插入图片描述
在我们以往说的计算机中,指令的执行总是取完指令,分析指令,执行指令,然后再取下一条指令。
这种指令的执行方式通常叫做顺序执行方式或者是串行执行方式,冯诺依曼机采用的就是这种执行指令的方式。

我们假设取指,分析,执行三个阶段的耗时都是t,假设需要执行n条指令,我们可以看下执行完n条指令的总耗时是多少:
T= 3 × t × n = 3 n t \color{red}{3\times t \times n=3nt} 3×t×n=3nt
在这里插入图片描述
优点:因为每次只执行一条指令,所以内部电路设计比较简单。
缺点:执行指令的速度较慢(这里说的是平均执行一条指令的时间),在任意一个时刻,计算机中只能有一条指令在执行。但是我们知道,指令在不同阶段使用的部件是不同的,例如一般只有在取指周期才会用到pc,后面基本上用不到了。这就会导致很多部件在大部分时间都是空闲的,即利用率低。

而指令流水线就是抓住了指令在不同时刻使用的部件不同,所以在一个时间段内其实可以执行多条指令。指令流水线又分为了以下几种方式:

接下来无论我们将指令的执行分成几个阶段,我们都假设一个阶段耗时t,并且一个阶段只需要消耗一个节拍。

   ( 1 ) (1) (1)一次重叠方式

在一个时间内允许两条指令都在执行,一般处于不同的阶段。
耗时:3t+(n-1)2t=t+2nt
优点:可以看出,理想状态下,一次重叠可以使执行时间变成原来的 2 3 \color{red}{\frac{2}{3}} 32。部件的利用率得到了提高,指令的执行速度提高。
缺点:电路设计复杂了。
在这里插入图片描述
如何通过这种图快速看出执行n条指令需要的时间:
在这里插入图片描述
   ( 2 ) (2) (2)两次重叠方式
一个时刻最多执行三条指令执行。
优点:速度更快了,部件利用率再一次提高。
缺点:电路设计更复杂了。
在这里插入图片描述
除此之外,还有3次重叠方式等等,还可以将指令分成5个阶段,出现4次重叠方式这种等等,都是可以的,这里就不再赘述了。

空间并行和时间并行

空间并行:对于空间我们可以理解为资源,即有多组资源,例如多CPU,可以做到指令的并行,是一种空间(资源)换取时间的操作。多处理,超标量技术就是空间并行。

时间并行:时间并行是指,一般设备还是一套,不会增加很多,通过指令在不同的阶段使用的功能部件不同,从而达到。时间并行一般指流水线技术。
在这里插入图片描述

指令执行过程的两种分析图

在这里插入图片描述

流水线的性能指标

   ( 1 ) (1) (1)吞吐率(TP)
含义:单位时间内流水线完成指令(任务)的个数,但是实际计算的时候,一般是流水线执行n个任务,假设使用了 T k \color{red}{T_k} Tk的时间,那么平均执行一个任务需要的时间,就是吞吐率,这时候一般默认流水线就是n-1段重叠了。

总耗时 T k \color{red}{T_k} Tk,所以吞吐率 T P = n / T k \color{red}{TP=n/T_k} TP=n/Tk
我们假设下面都是理想状态:
对于 T k \color{red}{T_k} Tk我们是可以算出的,因为如果流水线想要达到极致,那么k段的流水线,就会有k-1个部分重叠。
所以假设分成k段,每段的时间是 Δ t \color{red}{Δt} Δt,然后有n个任务。
所以 T k = \color{red}{T_k}= Tk= k Δ t + ( n − 1 ) Δ t \color{red}{kΔt+(n-1)Δt} kΔt+(n1)Δt

流水线中,为什么第一个任务是 k Δ t \color{red}{kΔt} kΔt后面的任务是 Δ t \color{red}{Δt} Δt

对此,我们可以画个图,假设是三段流水线,执行三条指令,每段的时间是 Δ t \color{red}{Δt} Δt
因为第一条指令是不重叠的,所以第一条指令需要经历全部的时间,而后面的指令除了取指阶段和上一条指令都是重叠的。
在这里插入图片描述
如何深入理解流水线流动起来以后,平均多少秒执行一条指令?
我们假设是n-1段重叠,因为取指阶段不可能重叠,所以除了取指阶段以外其实都是重叠的,所以其实平均多少秒执行一条指令是由取指阶段决定的。例如下面这题:

可以看出,这里每段的时间不是完全相同的,但是因为指令流水线是根据取指对齐的,所以本质也是由取指决定的。

在这里插入图片描述

在这里插入图片描述

分析:不同的CPU,相同指令条数下,计算结果越大,说明当前CPU执行这些指令需要的时间越少,即吞吐率越大。当n变大时,根据表达式可以看出计算结果也是在变大的,所以当n趋于无穷时,得到的就是最大吞吐率。

装入时间:第一条指令执行完的时间
排空时间:最后一条指令执行完的时间
从部件利用率来看,装入时间就是部件全部共同运作需要的时间。排空时间就是部件从全部运作到全部停止需要的时间。
在这里插入图片描述

   ( 2 ) (2) (2) 加速比

含义:完成相同数量的任务,不使用流水线完成的时间使用流水线完成的时间
分析:最后得到的结果就是使用了流水线以后,完成同一批任务,不使用流水线花费时间是使用流水线花费时间的几倍。即使用流水线效率提升的倍数。
当任务数量,即指令的数量趋于无穷时,这时候分成k段,那么效率就是k倍。
在这里插入图片描述

   ( 3 ) (3) (3)效率
效率:流水线的效率其实是部件的使用率

五段式指令流水线

指令流水线一般用于RISC精简指令系统,所以接下来的学习我们围绕RISC精简指令系统。
MIPS公司研发的MIPS架构中,采用的指令集就是RISC精简指令集,其中最为经典的就是五段式指令流水线。
即我们将一条指令的执行分为五段:
1.取指
2.译码
3.执行
4.写回cache
5.写回寄存器
对于这个过程我们需要回答一个问题:
不是所有的指令都具有这5个阶段的?

如果没有这5个阶段的指令怎么办?

为了指令流水线设计简单,所以一般的五段指令流水线在设计的时候都要求指令的允许必须分为这五段。即使有些指令没有这些阶段,那其在这些阶段就什么也不做就好。

前面我们在讲指令流水线的时候,我们在分段的时候默认每段的时间都是相同的,但是实际上一条指令在不同的阶段的时间是不同的,这个怎么解决呢?

同样的,一般来说指令流水线在设计的时候一般要求使用定长机器周期,即每个机器周期的长度都是相同的。并且为了流水线设计起来比较容易,也默认每个流水段含有的机器周期个数相同,其中机器周期的长度一般以最每个流水段最长的时间为基准。一个机器周期一般包含若干个时钟周期,在理想状态下,一个机器周期包含一个时钟周期。

如果题目说了流水段的锁存器具有延迟时间的话,那么还需要加上延迟时间。
例如下面这题功能部件的时间中需要取最长的时间+流水段的延迟时间,所以CPU时钟周期为100ps。
在这里插入图片描述

每个阶段的时间被强行延长,又带来了一个新的问题:

如何延长每个阶段的时间呢?
这个问题其实本质就是延迟数据的流动。我们可以这样做,在每个阶段的某尾加上一个缓冲寄存器(锁存器)用于暂时保存本条流水段的结果,等时间达到基准时,再发送到下一段。下图中,蓝色部分的都是锁存器。
在这里插入图片描述
我们先介绍下每个段的组成:
在这里插入图片描述
注:这里的操作控制器可以看作是微信号发生器。

接下里我们开始介绍每个段的大致功能:

取指:这里的取指和我们说的取指周期不是一回事。在这个取指阶段会讲根据pc取出指令cache中的指令然后暂时放到取指阶段IIF的锁存器中。
从图中可以看出我们使用的是指令cache和数据cache,前面我们说过,现代计算机的cache一般都是分级的,并且根据程序的局部性原理,所以我们大概率是能够在cache内命中指令和数据的。如果不命中就会导致流水线的断流(这种情况比较复杂,我们一般不考虑)。

译码阶段 IF阶段锁存器的指令流入到ID译码器阶段,译码器会根据指令的操作码进行译码,并且会取出指令中的操作数。这里有个点,我们取操作数不是在主存里取,而是在寄存器里取。前面我们说过RISC指令系统中,访存指令只能由专门的指令完成,所以对于主存内的数据,其也需要先加载到寄存器中。所以在这个阶段我们统一讲取数看作是从寄存器中取。取出的操作数会被放在A和B两个寄存器中暂存。除此之外, 我们还可以看到,其中有一个寄存器叫做IMM,这个IMM寄存器是用来取立即数的,即指令的立即数被会保存在这个IMM寄存器中。

执行阶段:执行阶段就根据译码阶段的操作数,将操作数放到ALU内进行运算,运算以后也是将结果暂时写在一个寄存器中。

写入cache阶段:在这个阶段,我们可能会将上一个阶段得到的执行结果写入到data cache内部。如果数据不是写入cache的,那么数据就会暂时保存在这个阶段的寄存器中。

写回寄存器阶段:将上一个阶段的数据写回寄存器内。

l

注:如果只是运行一条指令,指令流水线无法提高运行一条指令需要的时间,例如如果使用上述的5段指令流水线执行一条指令需要500ns,但是如果不使用指令流水线只需要350ns。指令流水线的提高效率是体现在运行程序上的。

在指令流水线中,我们一定要注意一个点,只有真正进入下一个阶段,那么上一个阶段锁存器内的内容才会流入下一个阶段。这里是个大坑 ⭐⭐⭐⭐因为可能出现这种情况。如下图:
I3指令在取完IF指令以后,I4是不能进行取指令的,因为I3这时候还没有进行ID阶段,也就是说I3指令还存在取指阶段的锁存器中,如果I4接着就进行取指,那么就会将取指阶段中锁存器内I3指令覆盖。所以只有I3指令进入了ID阶段,这时候I4指令才能进入取指阶段。
在这里插入图片描述

三种冲突

指令流水线的影响因素可以分为以下几个
   ( 1 ) (1) (1)结构相关(资源冲突)
资源冲突:资源冲突类似操作系统中的互斥,在同一个时刻可能有多条指令在访问相同的资源,这时候就会造成冲突。
例如:
在指令流水线中有以下几条指令:这里的MEM应该是cache,王道的图实在是不统一,但是是mem也是可以的。这个不重要。
然后我们看下这个图,在这个图中,当load指令执行到访存阶段(写回cache或者写回主存时),这时候指令3刚好执行到了取指阶段。这时候就会发生冲突,两条指令都需要访问主存,但是主存在同一时刻只能被一条指令访问。
其中寄存器的访问也是同理。
在这里插入图片描述

这里的三个冲突和多线程的关系,互斥,同步,后面我需要再思考。

对此有两种解决方法:

1.让后执行的指令先暂停一个周期。
让先执行的指令先访存,后面的指令先暂停一会。
对此我们可以类比,多线程中的互斥,多线程中互斥我们访问临界资源的时候进行加锁,本质也是让线程先等待一会,都是同理的。

2.资源重复配置
说白了就是让不同阶段使用不同的存储器,例如前面我们在取指阶段使用的指令cache,写回阶段使用的数据cache,这时候就可以解决这个冲突问题

3.加入空操作或者空指令

   ( 2 ) (2) (2)数据相关(数据冲突)
数据冲突类似消费者生产者模型中的同步,后面指令执行的数据需要依赖前面指令执行的结果。
例如下图中,add指令将r2和r3的结果运算后会写入r1,后面的sub,and,or,xor指令都需要用到这个计算结构,即这些指令都需要访问r1寄存器。
但是出现了一个问题:add指令在第五个阶段才将数据写回r1寄存器,但是sub,and,or指令在其写回之前就需要使用r1寄存器的数据,其中xor在其写回以后才使用,所以不会发生数据冲突。
这时候这三条指令的执行结果就是错误的,因为这时候add指令还没有将结果写回r1寄存器。

哪些可能会造成数据冲突,如何更深刻的理解数据冲突?

数据冲突是相邻的指令之间产生的冲突,例如以A指令和B指令举例子,假设A指令在B指令的前面。
我们以5段指令流水线为例子:
取指令 取操作数 执行 访存 写回

首先,我们需要铺垫一个知识:顺序流水线
顺序流水线:我们介绍的指令流水线就是一种顺序流水线。

前一条指令还没写,就已经读了

RAW:B依赖的指令A要写入的寄存器内的数据。例如A指令的结果需要写回R1,B指令需要取A指令写入R1内的结果。在顺序流水线中是可能出现这种冲突的,例如第一条指令在wb阶段才写回,但是第二条指令在ID阶段就需要读入寄存器内的数据了。

WAW:WAW本质是一个写入的顺序,即应该第一条指令先写,第二条指令再写。不然寄存器或者存储器内部的数据就会被第一条指令覆盖。这个在顺序流水线中不存在,因为一定是前面的指令先写。

一条指令一定是先读后写。

前一条指令还没读就已经写了

WAR:WAR也就是前面的指令读取寄存器或者存储器的数据的时候,但是这个数据已经被后面的指令修改了,这个也不可能,因为修改数据只有在MM和WB阶段,后面的指令在执行其中某个阶段的时候,前面的指令早就已经取完数据了,所以不会发生在顺序流水线中。

在这里插入图片描述

在这里插入图片描述
对此我们有如下几种解决方法:
1.把sub,add,or这些指令暂停几个时钟周期,直到add指令将数据写回r1寄存器,即不可能产生冲突以后再执行这些指令。
而这个操作可以分为在软件层面实施和硬件层面实施:
硬件层面上,使用硬件stall:当这条指令要产生数据冲突的时候,硬件系统会根据指令设置几个bubble气泡,我们简单理解为就是将后续的指令暂停。从图可以看出,在这三个节拍中,计算机是没有取后续的指令的,也可以看作就是插入空指令。
在这里插入图片描述
软件层面上,使用软件nop:可以由程序员或者编译器完成,如果是编译器完成的话可以看作是编译器的一种编译优化:
编译器在代码允许前,对代码进行进行检查,即在发生冲突的指令后面插入几条空指令,空指令也会完整的执行完5个阶段。只不过在5个阶段什么都不干,待空指令执行完毕,数据冲突也就消失了。

编译优化除了能够插入空操作以后,还具有一种优化的方式:
前面说的编译优化的方式是插入空指令,虽然说解决了问题,但是空指令的执行本没有什么意义,其实就是浪费时间。而第二种编译优化的方式就是将产生冲突的指令和后面不产生冲突的指令的位置调换,即先执行后面的指令。这样一来就不会浪费时间了。

2.数据盘路技术
这个技术简单来说就是更改数据的获取路径。例如
add指令的执行的结果是在ALU内完成的,所以sub指令可以不需要去r1寄存器内获取执行结果。我们直接让add指令的输出端和输入端连一根线,这时候执行结果就会自动流到ALU的输入端,sub指令甚至不用访问任何存储器就能直接获取到结果,而且还不会产生数据冲突。这种思想是相通的,例如add指令要使用执行结果时,其也可以让ALU的输入端直接连接到写回主存/cache段后面的寄存器也是可以的。
在这里插入图片描述

   ( 3 ) (3) (3)控制相关(控制冲突)
控制冲突:控制冲突本质是pc修改引起的流水线的断流。
存在这样一种场景:函数调用,转移指令,中断等等都会改变pc的值,我们以jmp无条件转移指令为例,在jmp指令的写回阶段将结果写入pc。但是指令流水线中,我们在写入pc时,可能已经根据原有的pc值读入了好几条指令了,这时候就出现问题了,后面的指令我们本来是不应该执行的。
在这里插入图片描述
解决办法:

方法一:转移指令预测
1.简单预测:判断指令永远会跳转或者永远不会跳转,然后流水线的取指根据预测结果进行修改,例如判断永远都会跳转,那么一旦遇到跳转指令,就直接取跳转地址后的指令。
2.动态预测,保存之前的跳转结果,根据历史结果动态预测是否需要跳转

2.取跳转成功后的指令和不成功的指令。
例如if else 语句,这种做法就是分别取if和else语句中部分的指令。

3.加快判断的速度
即类似并行进位加法器提前算出进位信息,这个的做法就是提前算出是否需要跳转的条件,让判断跳转的时间提前。

4.提高预测的可能性
这个就是对预测的一个优化,即通过某些措施使得对是否跳转的预测更加准确。

5.加入空操作或者空指令。
即可以在可能改变pc指的操作后面加入若干的空指令或者空操作。

6.编译器调整指令的执行顺序(即编译优化)也可以解决部分的控制相关,例如加入几个空操作或者空指令,或者调整下指令的执行顺序。

流水线的断流

以下的操作都可能会造成流水线的断流:
1.三种冲突,其中控制相关不好理解,可以理解为计算机本来可能不应该执行的指令,因为控制相关而执行了这些指令。
2.cache不命中

流水线的分类

如何理解指令流水线?

对于指令流水线我们可以这样理解:
一个指令流水线一般是用于一个CPU的,即一个核或者一个处理器使用一段指令流水线,在计算机中,指令的不同阶段使用到功能部件一般是不同的,所以指令流水线就是抓住了这一点,其将指令分成不同的段,从而让计算机能够在宏观上达到并行执行指令,但是并不是真的并行,因为指令之间还是需要分段的。
并且多线程场景下,多线程场景下线程的切换需要保存现场和恢复现场,这一工作都是操作系统完成的,所以保存和恢复现场的本质就是执行操作系统的代码,所以指令流水线的存在可以很好的做到这点,即在运行当前线程的同时,当时间片快要到时,即开始取操作系统的指令,为操作系统指令的执行准备好运行环境,并且保存当前线程的运行环境。

处理机级流水线:处理机级流水线就是一个核配一个流水线或者一个处理器是一个流水线,也就是前面我们说的。处理机级流水线其实就是指令流水线。指令流水线可以看作是时间并行技术。

部件功能级流水线:部件功能级流水线我们可以简单看作对部件的进行流水段的划分,例如浮点运算器可以划分为:求阶差,对阶,尾数相加,结果规格化。我们假设在执行操作进行浮点数的运算:我们假设有4条指令都需要进行浮点数的运算,所以我们就可以这样设计:在宏观上,对于流水线进行分段,分成5段,然后在运算执行阶段,如果需要使用到浮点运算器则再进行分段,这样A指令执行到浮点运算的对阶的时候,B指令开始执行求阶差,以此类推,可以达到功能部件级别的流水线,可以更大化的提高部件的利用率,但是也会使电路的部件设计变得复杂。

处理机间流水线:处理机间流水线我们可以认为是粗或者细粒度多线程。即所有的处理器或者核在某个时间段运行的是同一个线程中不同的指令序列。
然后因为处理器之间可以共享主存或者cache,所以处理器之间的处理结果可以主存或者cache进行传输,即A处理完的结果通过主存或者cache转发给B,这样就可以实现处理器级别的流水线的协同工作。
在这里插入图片描述

如何理解CPU调度一个线程,和CPU执行指令之间的关系?

CPU调度一个线程,本质是跑一个线程的指令,即不断的取指令,分析指令,执行指令。而单CPU下只能支持并发,即线程之间只能有”顺序”的被CPU调度。但是在调度期间,CPU是可以通过流水线宏观上并行的执行线程的指令的。

单功能流水线:单功能流水线我们可以简单理解为是部件功能级流水线,即流水线每个段要做的工作基本都是固定的。例如在第一个阶段进行求阶差,第二个阶段进行对阶等等。

多功能流水线:多功能流水线我们可以理解为是一个比较大的流水线,例如指令流水线或者是处理器级间流水线,即流水线在每个段的工作可以变化的。

静态流水线:静态流水线我们可以这样理解,假设一条指令要执行浮点加法和定点乘法,都是在执行阶段进行,而静态流水线中,当执行浮点加法的时候,那么执行段就只能进行浮点加法,不能进行定点乘法,只有当浮点加法全部完成后,才能进行定点的乘法。

动态流水线:动态流水线就是,同样在执行段进行浮点加法和定点乘法,其在执行段是允许一段时间进行浮点加法和定点乘法的。
在这里插入图片描述

线性流水线:线性流水线我们可以理解为从输入到输出,信息不存在回路,即信息从输入端流入,然后最终从输出端流出。

非线性流水线:非线性流水线存在反馈回路,例如我们在解决数据冲突的时候,我们让ALU的输出端直接接入到输入端,这时候数据就产生了反馈回路,因为反馈回路的存在,所以非线性流水线适合进行递归的运算。

在这里插入图片描述

顺序发射技术)和乱序发射技术

顺序发射技术和乱序发射技术一般都是相对一个线程/进程而言,对于这种技术我们可以推广到多CPU。

顺序发射技术:顺序发射技术一般是指CPU在调度某个线程,在执行该线程的指令的时候,会根据指令在主存内的顺序顺序的取指令,然后顺序执行。

乱序发射技术:乱序发射技术一般是指CPU在调度某个线程,在执行该线程的指令的时候,不会完全根据指令在主存中的存放顺序来执行,CPU内部会根据一些算法机制选择当前应该执行的指令。

乱序发射和顺序发射技术哪个好?

一般来说乱序发射是优于顺序发射的,因为在顺序发射中,在指令流水线下,两条指令发生结构冲突,数据冲突,控制冲突的可能性更大。而乱序发射可以更好的优化这一环节,CPU在调度下一条指令的时候,可以根据内部算法调度下一条指令,从而尽可能的避免冲突。

两者的区别是什么?

顺序发射技术就是完全依靠程序员或者编译器来对指令的顺序进行优化,以减少冲突,其只能在程序未运行前进行优化。乱序发射技术在静态调度技术上的提升,其在程序未运行前,同样使用顺苏发射技术,然后程序运行以后,CPU可以根据当前指令的运行状态,配合算法选择当前要执行的指令。
在这里插入图片描述
在这里插入图片描述

单发射技术和多发射技术

单发射技术:单发射技术可以理解为内部就一个CPU,即无法同时并行的执行两条指令,在微观上。

多发射技术:多发射技术可以理解为多CPU,即可以做到并行。

流水线的多发技术

超标量技术:超标量技术可以理解为内部具有多个CPU,从而可能达到并行的执行指令。是一种空间并行技术。

发射技术:顺序发射技术,即不能调整指令的执行顺序。

如何提高超标量技术

超标量技术由于不支持乱序发射技术,程序运行过程发生冲突的
可能性大,所以可以对这一环节进行优化,即在程序还未变成指令之前,即在编译优化阶段,编译器对指令的顺序进行优化,让尽可能并行的指令排在一起,并且减少指令之间的联系,较少冲突。

在这里插入图片描述

超流水技术:超流水技术就是划分更多的流水段,让每个流水段持续的时间更短,从而在流水线内可以运行更多的指令。但是流水段的划分是有限的,因为流水段多了,锁存器这类存储介质的数量也会增多,所以流水段的数据需要根据计算机当前的配置来选择最合适的分段数量。是一种时间并行的是技术。

发射技术:顺序发射。

如何提高超流水技术?

由于不支持顺序发射,所以同样可以在编译阶段对程序的指令排列顺序进行优化。
在这里插入图片描述
超长指令字:超长指令字可以理解为在编译阶段,编译器对指令进行分析,如果发现一些指令可以并行,那么就将这些指令合成一条指令,这条指令可以非常长,可以达到几百个bit。
由于多条指令合成一条指令,所以内部可能也需要类似多个CPU的处理方式。通过这种超长指令字减少了访存次数。
在这里插入图片描述

三种多发技术一般内部都会使用指令流水线技术。

指令流水线的指令实操

我们这里说的是RISC精简指令集下的部分指令,按照运算指令,访存指令,跳转指令分别进行举例,需要注意,RISC下只有LOAD和STORE才能进行访存,其他指令的操作数一定是来自寄存器的。即可以这样理解:即使当前指令的计算需要使用到主存内数据,但是在这条指令的前面一定会被插入STORE或者LOAD这类指令。

在这里插入图片描述
一般来说,运算类的指令如果要写回寄存器,那么都是在WB阶段进行写回,并且运算类的指令一般不需要对地址进行计算了,因为访问寄存器只有寄存器间接寻址和寄存器寻址,但是寄存器间接寻址需要访存,所以是不可能出现在运算类指令的。

1.根据PC从指令cache内取出指令,然后将指令放在取指阶段的锁存器
2.取指阶段锁存器内的指令流到ID阶段,ID阶段完成译码以后发现是一条add指令,其根据add指令内的两个寄存器的编号到对应的寄存器取出操作数,然后将操作数存入到ID译码阶段的锁存器A和B中。
3.译码器阶段锁存器的数据流到EX执行阶段,EX执行阶段中,ALU根据两个操作数算出结果,然后将结果放入EX阶段得锁存器中。
4.访存阶段,这个阶段基本不用干什么。EX段的锁存器内的结果流入到访存阶段的锁存器
5.访存阶段的锁存器内的数据流入到WB写回阶段,然后WB写回到Rd寄存器。

这里有一个非常重要的细节。我们写回是一定需要地址的,写入寄存器那么是需要寄存器的编号的,但是在我们整个过程中,寄存器的编号似乎没有从ID阶段一直流入到WB阶段,简单来说就是要写回的地址是没有流入到ID阶段的锁存器的。
对此我们可以这样理解,在ID阶段外面我们可以看到有好几条线,要写回的寄存器的地址直接通过导线送到WB写回阶段。

在这里插入图片描述
LOAD指令是将主存某个地址的数据写入寄存器。

在LOAD指令中,可能会用到基址寻址,图中假设的指令就是使用的基址寻址。而在基址寻址中,需要让基址寄存器和形式地址进行相加,而相加就需要ALU。
所以在这条load指令中,需要将基址寄存器的值放入A锁存器,形式地址偏移量放入IMM锁存器中。

1.通过PC到指令cache内取出对应的指令,将指令放在取指阶段的锁存器中。
2.取指阶段的锁存器的指令流入到ID阶段,ID进行译码以后发现是LOAD指令,并且知道是基址寻址,将指令内的形式地址放入IMM锁存器,将基址寄存器内的地址放入A锁存器。
3.取指阶段内的IMM锁存器和A锁存器内的偏移量和基地址流入ALU内,ALU进行运算以后得到有效地址,将有效地址存入EX阶段的锁存器
4.EX阶段锁存器内的有效地址流入到访存阶段,根据有效地址取出数据cache内的数据,然后将数据放到访存阶段的锁存器内
5.访存阶段锁存器内的数据流入到WB阶段,WB根据ID阶段导线流入过来的要写入的Rd寄存器的地址,然后将数据写回对应的寄存器。

在这里插入图片描述
store指令:将寄存器内的数据放入主存。

在这里插入图片描述
1.根据pc取出指令cache内的指令然后存入取指阶段的锁存器中(这时候一般PC自动进行加”1″)。
2.取指阶段锁存器内的指令流入到ID阶段,ID译码以后发现是条件转移指令,取出Rs和Rt两个寄存器内的数据到A锁存器和B锁存器,并且偏移量放入到IMM锁存器中。
3.ID译码阶段三个锁存器内的数据流入到执行阶段,ALU内部根据两个操作数进行运算得到结果
4.在经过执行阶段以后,内部就知道是否要进行跳转了,跳转可以称做wrpc,即写回pc,需要注意的是写回pc这个操作不是在WB写回阶段,WB写回阶段一般是写回通用寄存器。而写回pc准确来说不属于某个阶段,并且这个操作耗时较短,所以我们可以将其安排在访存阶段完成,即在访存阶段根据偏移量修改pc的值。

在这里插入图片描述
1.根据pc取出指令cache内的指令然后存入取指阶段的锁存器中(这时候一般PC自动进行加”1″)。
2.取指阶段的锁存器内的指令流入到ID阶段,ID译码以后发现是无条件转移指令,由于是无条件转移指令,所以不需要操作数,所以只需要将偏移量放入IMM。
3.IMM的偏移量流入到EX阶段,无条件转移指令在EX阶段实际上是一个空段,因为不需要进行计算,所以可以将wrpc安排在EX阶段。
最后的访存阶段和写回阶段都是空段。
wrpc的具体写回时间得看题目,一般是越早写回越好,因为pc写回晚了,就可能导致控制冲突。

⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐
总结:一般来说写入主存,这时候一般就需要在ID阶段给出主存的形式地址和偏移量,需要保存到锁存器中。如果是写回寄存器这种操作,一般就不会将要写回的寄存器的地址保存到锁存器中。而是通过导线直接流入到WB写回阶段。

指令周期的四大周期 vs 五段指令流水线

注意:因为指令流水线技术是用于RISC,RISC非访存指令无法访存,所以其寻址方式只有:寄存器寻址,立即数。在寻址的时候是不需要进行ALU的运算的,事实上ID段也不能使用ALU,如果取出来的操作数需要运算,那就是在EX阶段完成,并且非访存指令写回操作也是写回寄存器。而对于访存指令来说,其可以寄存器写入主存,也可以主存写入寄存器,其支持所有的寻址方式,那就意味着支持偏移寻址,所有寻址方式中,只有偏移寻址需要使用到ALU,也就是LOAD和STORE。将主存写入寄存器或者寄存器写入主存。所以LOAD中对应主存要写入寄存器的操作数是无法在ID阶段完成的,因为ID阶段也不进行访存,并且不提供ALU,所以需要在EX阶段通过ALU计算有效地址,然后在访存阶段读取出,然在WB阶段写回。
STORE也是如此,STORE在ID阶段可以取出寄存器的数据,但是如果是偏移寻址,那么主存的地址也需要在EX阶段通过ALU计算,最后访存阶段写回主存。

指令的四个周期:
取指周期:取出指令,Pc+1
间址周期:取到有效地址
执行周期:根据有效地址,取出操作数并且进行计算
中断周期…

在指令周期中,取操作数的任务是在执行周期,而指令流水线中,取操作数的任务基本上是在ID阶段完成。这块还需要思考。

今天的文章计算机组成原理好难_计算机的流水线中每个阶段「建议收藏」分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/89009.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注