Bil*_*low 8 cpu assembly executable cpu-architecture
我理解指令流水线的基本原理.
我还得到一些指令可能需要更长的时间来执行(每条指令的周期).
但我没有得到两者之间的联系.
我看到的所有管道图似乎都有"完美"指令,它们都具有相同的长度(周期数).
但是,如果第一条指令需要5个周期,第二条指令需要3个周期呢?cpu是否会停顿2个周期?
此外,指令的长度(以字节为单位)是否以任何方式重要?
你在你的问题中提到了很多东西,所以我会投入我的 2 美分,试着让它更清楚一点。让我们以有序 MIPS 架构为例——它具有您提到的所有内容,但可变长度指令除外。
许多 MIPS CPU 具有 5 级流水线,其中包含以下阶段:IF -> ID -> EX -> MEM -> WB. (https://en.wikipedia.org/wiki/Classic_RISC_pipeline)。让我们首先看看这些指令,其中每个阶段通常都需要一个时钟周期(例如,高速缓存未命中可能不是这种情况)。例如,SW(将字存储到内存)、BNEZ(非零分支)和 ADD(添加两个寄存器并存储到寄存器)。并非所有这些指令都适用于所有管道阶段。例如,SW 在 WB 阶段没有工作,BNEZ 可以在 ID 阶段(即最早可以计算目标地址)完成,而 ADD 在 MEM 阶段没有工作。
无论如何,这些指令中的每一条都会经历管道的每一个阶段,即使它们在其中的某些阶段没有工作。该指令将占用给定的阶段,但不会完成实际工作(即,没有结果写入 WB 阶段中 SW 指令的寄存器)。换句话说,在这种情况下不会有摊位。
转向更复杂的指令,其 EX 阶段可能需要多达数十个周期,例如 MUL 或 DIV。事情在这里变得更加棘手。现在指令可以乱序完成,即使它们总是按顺序获取(这意味着WAW 危险现在是可能的)。以下面的例子为例:
MUL R1, R10, R11
ADD R2, R5, R6
Run Code Online (Sandbox Code Playgroud)
MUL 首先被获取,它在 ADD 之前到达 EX 阶段,但是 ADD 将在之前完成,因为 MUL 的 EX 阶段运行超过 10 个时钟周期。然而,管道不会在任何时候停止,因为在这个序列中不可能出现危险——RAW 和 WAW 危险都不可能发生。再举一个例子:
MUL R1, R10, R11
ADD R1, R5, R6
Run Code Online (Sandbox Code Playgroud)
现在 MUL 和 ADD 写入相同的寄存器。由于 ADD 将比 MUL 更早完成,因此它将完成 WB 并写入其结果。稍后,MUL 会做同样的事情,而 R1 最终会得到错误的(旧的)值。这是需要流水线停顿的地方。解决这个问题的一种方法是防止 ADD 发出(从 ID 到 EX 阶段),直到 MUL 进入 MEM 阶段。这是通过冻结或停止管道来完成的。引入浮点运算会导致流水线中出现类似的问题。
我会通过触及固定长度与可变长度指令格式的主题来完成我的回答(即使您没有明确要求它)。MIPS(和大多数 RISC)CPU 具有固定长度编码。这极大地简化了 CPU 流水线的实现,因为可以在单个周期内解码指令并读取输入寄存器(假设寄存器位置在给定的指令格式中是固定的,这对于 MIPS 是正确的)。此外,由于指令始终具有相同的长度,因此提取得到简化,因此无需开始解码指令以找到其长度。
当然也有缺点:减少了生成紧凑二进制文件的可能性,这会导致程序变大,进而导致缓存性能变差。此外,内存流量增加以及从/向内存读取/写入更多字节的数据,这对于节能平台可能很重要。
这种优势导致一些 RISC 架构定义了 16 位指令长度模式(MIPS16或 ARM Thumb),甚至是可变长度指令集(ARM Thumb2有 16 位和 32 位指令)。与 x86 不同,Thumb2 旨在使快速确定指令长度变得容易,因此 CPU 解码仍然很容易。
这些压缩的 ISA 通常需要更多的指令来实现相同的程序,但如果代码提取比管道中的指令吞吐量更成为瓶颈,则占用的总空间更少并且运行速度更快。(小的/不存在的指令缓存,和/或从嵌入式 CPU 中的 ROM 读取)。