指令流水线和每条指令的周期之间的链接

人气:792 发布:2022-10-16 标签: executable cpu assembly cpu-architecture

问题描述

我了解instruction pipelining的基本原理。

我还了解到某些指令可能需要更长时间才能执行(cycles per instruction)。

但我不明白两者之间的联系。

我看到的所有流水线图似乎都有"完美"的指令,它们都有相同的长度(周期数)。

但是,如果第一条指令需要5个周期,而第二条指令需要3个周期,该怎么办?CPU是否停顿了2个周期?

这个摊位叫bubble吗?或者这与hazards和数据依赖项不同?

还有,指令的长度(以字节为单位)有什么关系吗?

推荐答案

您在问题中涉及了相当多的事情,所以我会提出我的2点意见,试图让这一切更清楚一些。让我们以有序的MIPS体系结构为例--除了可变长度的指令之外,它具有您提到的所有功能。

许多MIPS CPU都有5级流水线:IF -> ID -> EX -> MEM -> WB。(https://en.wikipedia.org/wiki/Classic_RISC_pipeline)。让我们首先来看看这些指令,其中每个阶段通常会占用一个时钟周期(例如,高速缓存未命中的情况可能不是这样)。例如,Sw(将字存储到内存)、BNEZ(分支为非零)和ADD(添加两个寄存器并存储到寄存器)。并非所有这些说明在所有管道阶段都有有用的工作。例如,软件在WB阶段没有工作,BNEZ最早可以在ID阶段完成(这是最早可以计算出目标地址),而ADD在MEM阶段没有工作。

尽管如此,这些指令中的每一条都将通过流水线的每个阶段,即使它们在其中的一些阶段中没有工作。指令将占用给定级,但不会执行实际工作(即,不会将结果写入WB级中的寄存器以用于SW指令)。换句话说,在这种情况下不会有任何停顿。

转到更复杂的指令,其EX阶段可能需要多达数十个周期,如MUL或DIV。这里的情况变得棘手得多。现在,指令可以无序完成,即使它们始终是按顺序获取的(这意味着WAW hazards现在是可能的)。举个例子:

MUL R1, R10, R11
ADD R2, R5, R6
首先获取MUL,并且它在ADD之前到达EX级,但是,由于MUL的EX级运行超过10个时钟周期,所以ADD将在ADD之前完成。然而,管道在任何时候都不会停滞,因为在这个序列中没有危险的可能性--无论是原始危险还是WAW危险都是不可能的。再举一个例子:

MUL R1, R10, R11
ADD R1, R5, R6
现在,MUL和ADD都写入相同的寄存器。由于ADD将比MUL早完成,因此它将完成WB并写入其结果。稍后,MUL将执行相同的操作,而R1最终将具有错误的(旧)值。这是需要管道停顿的地方。解决这一问题的一种方法是在MUL进入MEM阶段之前阻止ADD发布(从ID阶段转移到EX阶段)。这是通过冻结或拖延管道来实现的。引入浮点运算会导致管道中出现类似的问题。

我将通过触及固定长度指令格式与可变长度指令格式的主题来结束我的回答(即使您没有明确要求它)。MIPS(和大多数RISC)CPU采用固定长度编码。这极大地简化了CPU流水线的实现,因为可以在单个周期内解码指令和读取输入寄存器(假设寄存器位置以给定的指令格式固定,这对于MIPS是正确的)。此外,由于指令的长度始终相同,因此无需开始解码指令即可找到其长度,从而简化了获取操作。

当然也有缺点:生成紧凑二进制文件的可能性降低,这会导致更大的程序,而这又会导致较差的缓存性能。此外,内存流量会增加,从内存读取/向内存写入的数据字节也会增加,这对高能效平台可能很重要。

这一优势导致一些RISC体系结构定义了16位指令长度模式(或ARM Thumb),甚至定义了可变长度指令集(ARM Thumb2具有16位和32位指令)。与x86不同的是,Thumb2的设计使得快速确定指令长度变得容易,因此它仍然很容易被CPU解码。

这些紧凑的ISA通常需要更多的指令来实现相同的程序,但如果代码获取比流水线中的指令吞吐量更成瓶颈,则占用的总空间更少,运行速度更快。(小/不存在指令高速缓存,和/或从嵌入式CPU中的只读存储器读取)。

866