一条 RISC/CISC 指令执行需要多少个时钟周期?

电器工程 计算机架构 mips
2022-01-20 19:54:10

根据Harris 和 Harris 的Digital Design and Computer Architecture,有几种方法可以实现 MIPS 处理器,包括:

周期微架构在一个周期内执行整条指令。(...)

多周期微架构以一系列较短的周期执行指令。(...)

流水线微架构流水线应用于单周期微架构。

架构通常分为 RISC 或 CISC。RISC 与 CISC

RISC 处理器只使用可以在一个时钟周期内执行的简单指令。

由于 MIPS 是 RISC 架构,我对上述定义有点困惑,想知道它们之间是否存在某种矛盾。进一步来说:

  1. 如果一条 RISC 指令可以分成更短的周期(取指、解码、...),我们怎么能说只需要一个时钟周期来执行整条指令呢?执行每个步骤不需要一个时钟周期吗?
  2. 执行一条RISC指令真的需要一个时钟周期吗例如,如果发生高速缓存未命中并且处理器必须等待慢速 DRAM,会发生什么情况?这不应该将指令的执行时间延长很多吗?
  3. 一个指令周期到底是什么?是完成一条指令所需的时间(即一个/多个时钟周期)吗?
  4. 一条 CISC 指令在时钟/指令周期中需要多长时间?
4个回答

RISC 和 CISC 的实际定义现在如此混乱和模糊,几乎毫无意义。现在最好将它们更多地视为“哲学”,因为 CISC 体系结构具有更丰富的指令集和更强大的单个指令(例如 DIV 等),而 RISC 指令集是简单且快速的,并将其留给编译器来实现复杂的操作。甚至据称,CISC 指令集(如 x86)在 Intel 和 AMD 芯片中都被转换为内部指令,并更像 RISC 处理器那样实现。要回答您的问题:

  1. 最初的学术 RISC 处理器(我认为可能是第一个商业版本)确实每个周期执行一条指令,包括获取和解码。这是可能的,因为数据路径非常干净,因为每个阶段的操作都简单且定义明确。(这里的权衡是只有非常简单的指令可以这样实现)。一旦它触及现实世界,事情就会变得模糊。流水线和超标量架构之类的东西使简单的 RISC/CISC 二分法变得不可能。

  2. 最初的 RISC 芯片试图每个周期执行一条指令,如果数据在寄存器文件中可用,它们可以。当然,如果处理器必须使用 DRAM,则需要(很多)更长的时间。RISC 是关于“尝试”每个周期执行一条指令。

  3. 一个指令周期是两次取指之间的时间。

  4. 很大程度上取决于指令和指令集架构。即使在 CISC 架构中,一些指令也可以非常快速地执行(例如左移或右移)。有些执行非常缓慢(10 秒或更多周期)。VAX 架构(可能是 CISC 哲学的巅峰之作)具有非常复杂的指令。顺便说一句,CISC 架构通常比 RISC 架构更容易用汇编编程,因为它几乎就像一种高级语言!

简短的回答

  1. 解码和执行指令的步骤与前一条指令的下一步并行执行。这种技术被称为流水线。请参阅下面的关于 RISC 处理器

  2. 由于等待状态和加载/存储操作所花费的时间会影响内存,而不仅仅是寄存器到寄存器,因此单个问题的 RISC 架构通常平均每个周期略少于一条指令。延迟槽为您提供了一个架构挂钩,可以让您获得一些时间。请参阅下面的关于 RISC 处理器

  3. 指令周期是执行一条指令所需的时间长度。这会因架构和(在某些情况下)指令而异。例如,MIPS R2000/3000 之类的大多数指令需要一个周期。涉及内存访问(加载/存储、分支)的指令需要多个周期,尽管延迟槽意味着您可以在延迟槽中执行其他操作(可能只是一个 NOP)。非流水线架构可以有几个时钟周期的指令周期,通常随寻址模式而变化。请参阅下面的关于 RISC 处理器、传统 CISC 架构硬连线架构

    多问题设计可以通过并行执行多条指令来稍微模糊这个概念。

  4. CISC 处理器的指令可能需要不同的时间长度。确切的时钟周期数取决于架构和指令。CISC ISA 所采用的不同数量的时钟周期是它们难以构建到大量流水线架构中的原因之一。请参阅下面的传统 CISC 架构

更长的答案

对于单个问题 MIPS、SPARC 或其他 CPU,所有(对于第一个近似值)指令在一个周期内发出,尽管它们可能具有称为“延迟槽”的东西。

在 RISC 处理器上

在这种情况下,单问题 CPU 是指 CPU 不像现代 CPU 那样执行任何即时依赖性分析和并行发布指令,即它们只有一个执行单元来执行指令从记忆中读取它们的顺序。稍后再谈。

大多数较旧的 RISC 处理器都是单问题设计,这些类型仍然广泛用于嵌入式系统。一个 32 位单期整数 RISC 内核可以在大约 25,000-30,000 个门中实现,因此这种类型的 CPU 内核具有非常低的功耗和非常小的占用空间。这使得它们可以轻松且便宜地集成到 SOC(片上系统)产品中。

RISC CPU 设计是流水线的——处理指令分几个阶段完成,每条指令在每个时钟周期通过流水线传递到下一个阶段。在大多数情况下,单发流水线 CPU 将在每个时钟周期执行接近一条指令的内容。

某些体系结构具有诸如从内存中分支或加载/存储之类的指令,其中内存访问所花费的额外周期对代码是可见的。

例如,在SPARC V7/V8设计中,分支之后的下一条指令实际上是在分支本身发生之前执行的。通常,您会在分支之后将 NOP 放入槽中,但如果您能找到有用的操作,您可以将另一条指令放入其中。

MIPS R2000/R3000架构在加载/存储指令中有类似的延迟槽。如果您从内存中加载一个值,它实际上不会出现在另一个周期的寄存器中。如果你能找到一些有用的东西,而不依赖于你刚刚发出的加载操作,你可以在槽中放置一个 NOP 或做其他事情。

如果内存比 CPU 慢(通常是这种情况),您可能会在内存访问时获得额外的等待状态。等待状态将 CPU 冻结一个或多个时钟周期,直到内存访问完成。实际上,这些等待状态和内存访问的额外时间意味着单次 CPU 设计平均每个时钟周期略少于一条指令。延迟槽为您提供了一些可能的机会,通过在内存操作发生时执行一些其他指令来优化代码。

传统 CISC 处理器

CISC 处理器的设计可能具有不同时间长度的指令。通常他们有更复杂的指令直接在硬件中实现,而这些指令必须在 RISC CPU 上的软件中完成。

大多数大型机架构和几乎所有直到 M68K 和英特尔 386 的 PC 设计都是传统的微编码 CISC CPU。事实证明,这些设计比 RISC CPU 更慢,并且使用了更多的门。

微码

可以在此处的仿真中看到微编码架构 (MOS 6502)的示例微码可以在图像的顶部看到。

微码控制 CPU 内激活的数据流和动作,以执行指令。通过循环执行微代码中的步骤,您可以激活 CPU 的各个部分,通过 ALU 移动数据或执行其他步骤。CPU 中的可重用组件可以在多个时钟周期内进行协调以执行一条指令。在 6502 的情况下,一些流水线操作也可以由微码执行。

与硬连线芯片相比,微编码设计使用的硅更少,但代价是可能需要几个时钟周期才能完成一条指令。根据设计,这些 CPU 每条指令需要不同的时间长度。

硬连线架构

硬连线设计(不一定与微代码互斥)同步执行指令,或者可能有自己的协调器跨多个时钟周期执行某些操作。它们通常以更多专用硬件为代价更快,因此实施起来比等效功能的微编码设计更昂贵。

一个著名的例子是原始的Amdahl 470/6 CPU,它是某些 IBM System/370 型号上 CPU 的直接替代品。在 IBM 的 370 CPU 主要基于微码的时候,Amdahl CPU 是一种硬连线设计。Amdahl CPU 比他们替换的 IBM CPU 快大约 3 倍。

不用说,IBM 并不好笑,这导致了一场法庭斗争,最终迫使 IBM 开放他们的大型机架构,直到几年前的同意法令到期。

通常,这种类型的硬连线设计仍然不如 RISC CPU 的时钟对时钟快,因为不同的指令时序和格式不允许像 RISC 设计那样大的流水线空间。

多问题设计

大多数现代 CPU 是多问题架构,可以在单个线程中一次处理多个指令。该芯片可以对传入指令流进行动态依赖性分析,并在不依赖先前计算结果的情况下并行发出指令。

这些芯片的吞吐量取决于代码中可以实现多少并行性,但大多数现代 CPU 在大多数代码上平均每个周期会执行几条指令。

现代英特尔和其他 x86/X64 ISA CPU 有一个层,可以将老式的 CISC 指令集解释为微指令,这些微指令可以通过流水线 RISC 风格的多问题内核提供。这增加了一些开销,这些开销在具有专为流水线设计的 ISA(即 RISC 架构,如 ARM 或 PowerPC)的 CPU 上不存在。

VLIW 设计

VLIW 设计(其中Intel Itanium可能是最知名的)从未成为主流架构,但 IIRC 有许多 DSP 架构使用这种类型的设计。VLIW 设计通过包含多个并行发出的指令的指令字来明确多次发出。

这些依赖于良好的优化编译器,这些编译器确定了并行性的依赖关系和机会,将指令放入每个指令字上可用的多个插槽中。

VLIW 架构非常适合数值应用程序,因为矩阵/数组操作往往为广泛的并行性提供机会。Itanium 在超级计算应用程序中有一段时间的利基市场,并且至少有一种超级计算机架构 - Multiflow TRACE - 是使用这种类型的 ISA 生产的。

内存和缓存

现代 CPU 比内存快得多,因此直接从内存读取会产生数百个等待状态,这些等待状态会阻塞 CPU,直到内存访问完成。缓存,现在在多个层中完成,在缓存中保存最近使用的内存位置。由于 CPU 通常将绝大多数时间花在循环中执行代码,这意味着您在重用最近使用的内存位置方面获得了良好的命中率。此属性称为“参考位置”。

在您获得参考位置的地方,CPU 可以以接近最佳速度运行。缓存未命中到下一个级别会导致许多等待状态;缓存未命中到主内存可能会导致数百次。

因此,CPU 芯片的实际吞吐量在很大程度上取决于内存访问模式的效率。已经写了整本书来为此优化代码,这本身就是一个复杂的话题。

这对学生来说是一种简化。

每个重要的处理器都是流水线的。一端有一个预取单元铲除指令,中间有多个执行单元做实际工作,还有一个发布单元负责在写入寄存器或内存完成后声明指令完成。如果有多个执行单元(例如,整数 ALU、浮点 ALU 和向量单元),则每个时钟周期可能会发出(有时称为“退出”)多条指令。CPU如何在每个周期提供多条指令?对此进行了更详细的介绍。

如您所说,如果存在缓存未命中延迟怎么办?英特尔超线程是一个新颖的解决方案:两批 CPU 状态寄存器、一批控制逻辑和发布单元。一旦一个虚拟 CPU 停止,就切换到另一个虚拟 CPU 的状态。(这本身就是一个严重的过度简化)

这样做的结果是,现代 CPU 手册给出了更模糊的指令时序,并且编写周期精确的时序代码要困难得多,例如,如果您试图从不具备此功能的硬件实时输出视频

(对“一条 CISC 指令在时钟/指令周期中需要多长时间?”的具体答案是“查看制造商的参考手册,每条指令都会有计时”)

其他人写了很多好材料,所以我会简短地回答:在过去(1980 年代),当时的 8 位处理器(6800、6502、Z80、6809 等)被认为是思科。有些指令可以在 2 个时钟周期内执行,但这些都是简单的指令,例如设置/清除处理器状态寄存器中的标志位。其他指令可能需要 2-6 甚至最多 9 个时钟周期来执行。这些处理器有一些相当强大的指令,Z80 有一些内存块清除指令,它们会将相同的值写入内存中的一系列字节,有效地在一条指令中清除一个大块,只需设置几个寄存器并执行LDIR 指令(加载、递增和重复)。

6502 处理器(来自内存)有 56 条指令,但有 13 种寻址模式,创建了一个强大的指令集。

RISC 出现了很长时间并采用了不同的方法,有少量指令,它们都在一个时钟周期内执行。程序往往更长,占用更多内存,因为指令在它们执行的操作中很简单,所以你需要更多的指令。

如果我没记错的话,RISC 架构的第一次尝试是晶片机还是 Acorn Risc 处理器?