【问题标题】:CISC machines - don't they just convert complex instructions to RISC?CISC 机器 - 他们不只是将复杂的指令转换为 RISC 吗?
【发布时间】:2012-06-25 15:47:54
【问题描述】:

也许我在架构上存在误解 - 但如果一台机器有一条乘法指令 - 该指令是否没有被转换为更小的指令或者太复杂以至于它最终与等效的 RISC 指令具有相同的速度?

乘法是一个不好的例子——它在两种架构中都是一条指令。将上面的“乘法”替换为 CISC 中更复杂的指令,RISC 没有等效的单指令。

【问题讨论】:

  • 乘法通常是 CISC 和 RISC 上的一条指令。你能澄清一下这个问题吗?
  • ^是的。我假设汇编代码中的乘法比实际复杂得多——所以这是一个不好的例子。我的理解是,CISC 的指令比 RISC 更复杂……但是,如果这些更复杂的指令确实需要与等量 RISC 指令一样多的周期,那么它们如何发挥优势?
  • 相关:RISC 与 CISC 仍然很重要(作者 Paul DeMone):realworldtech.com/risc-vs-cisc。相当不错的文章,并没有完全过时,写于 2000 年,当时解码到微指令还相对较新,奔腾 II / III 在工作站性能方面已经超过了 Alpha。但是“x86 税”仍然是真实的,尤其是对于具有遗留调用约定和只有 8 个架构寄存器的 32 位 x86。 (当您一次要在注册表中保留 8 件以上的东西时,重新命名将无济于事。)

标签: architecture assembly x86 system


【解决方案1】:

乘法既是好例子,也是坏例子。首先,乘法是一条昂贵的指令,一些处理器没有一个很好的理由。你可以和x86等有,拿多个时钟或者一个时钟。要获得一个时钟乘法需要(相对)大量的芯片空间(正如 Dani 提到的,可能需要一个专用的逻辑块,仅用于乘法)。绝对没有理由为什么一位设计师会做出与另一位设计师相同的选择,无论是在同一家公司(一个 x86 与另一个相比)还是不同的架构(x86 与 arm 与 mips 等)。每个设计师都知道乘法的结果是操作数的两倍,所以你选择给程序员所有操作数组合的完整答案(结果与操作数的大小不同)还是剪裁结果在操作数大小?如果你剪辑给他们一个溢出或异常,或者你让他们继续运行而不知道结果是错误的?您是否强制他们在所有 mul 和 div 指令周围添加包装器,以便可以检测到溢出成本性能?

x86 是一个非常糟糕的架构,首先学习或用作其他人的参考。它会导致很多错误的假设。并非所有处理器都是微编码的。并非所有 CISC 处理器都是微码。 RISC处理器没有理由不能进行微编码,您可以对CISC或RISC进行微编码,也可以不对CISC或RISC进行微编码,这是一种设计选择,而不是规则。

RISC 并不意味着最少的步数,即使是一个简单的寄存器到寄存器移动也是最少两个步骤(获取源,存储结果),这可能需要两个时钟来执行处理器有时实现的方式(使用 sram bank 进行寄存器不一定是双端口的文件)。 alu 指令是三个步骤,在 RISC 处理器上可以占用三个时钟,RISC 将平均每条指令一个时钟,但 CISC 也可以。您可以使用超标量并超过每条指令一个时钟,至少对于处理器受限时的突发。对于 CISC 和 RISC,超标量的复杂性是相同的。

我建议编写一个指令集模拟器,或者至少启动一个。如果没有别的,那就是反汇编程序。最好让 100 名程序员执行相同的编程任务,但彼此隔离。即使所有人都在同一所学校由同一位老师授课,您也会为该 iss 或反汇编程序获得 3 到 100 种不同的设计。让它成为一个文本编辑器作为一项编程任务,只是编程语言的选择首先会有所不同,然后程序的设计会有所不同。硬件设与 CISC 与 RISC 的关系较少,而与设计团队及其选择有关。英特尔有不同的设计目标,例如反向兼容,这是一个非常昂贵的选择。

BOTH CISC 和 RISC 将每条指令转换为基于处理器设计的更小的可消化/可分割的步骤。将乘法替换为加法,然后在 asm 级别比较 CISC 与 RISC,然后更深入。使用 x86,您可以将内存用作操作数,例如,您不能使用 arm。所以

register = memory + register

是

load register from memory
regster = register + register

你有额外的步骤。

但它们都分解成相同的步骤顺序

resolve memory address
start memory cycle,
wait for memory cycle to end,
fetch register from register memory
send operands to alu
take alu output and store in register memory

现在 cisc 实际上稍微快了一点,因为要正确执行指令,risc 需要将从内存读取的值存储在额外的寄存器中(从 asm 的角度来看,cisc 有两个寄存器,risc,三个或两个 on 重用)。

如果从内存中读取的值未对齐,则 cisc 在技术上胜出(如果 risc 通常不允许未对齐传输)。 cisc 处理器需要相同数量的内存周期来获取所有保持相等的未对齐数据(两个处理器都需要两个内存周期,cisc 和 risc 都会受到惩罚)。但是要专注于 asm 指令与 asm 指令,如果内存操作数未对齐,则 risc 必须这样做

read memory to register a
read memory to register b
shift a, 
shift b,
or/add

cisc 的作用:

read memory to register (takes two memory cycles)

您还具有指令大小,流行的 risc 处理器(如 arm 和 mips)倾向于固定指令长度,而 x86 是可变的。 x86 可以在一个字节内完成另一个需要四个字节才能完成的工作。是的,您的获取和解码更复杂(更多逻辑,更多功能等),但您可以在相同大小的缓存中容纳更多指令。

微编码不仅仅是将一个指令集分解成另一个指令集(另一个指令集可能非常痛苦,您永远不想在本机编程)。假设较低级别的系统可以更快地实现且错误更少,微编码可以帮助您更快地进入市场。假设您可以更快地提高产量,因为您可以在事后修复一些错误,并且可以在现场进行修补。并不总是完美,也不总是成功,但将其与非微码处理器相比,您必须让编译器人员修复错误或召回处理器或将公司视为黑眼圈并希望赢得一些客户等等……

所以答案是否定的。 RISC 和 CISC 都将单个指令转换为可以微编码或不编码的一系列步骤。简单地认为它们是您喜欢的状态机中的状态。 CISC 可能有一些将更多步骤打包到一条指令中,但这意味着更少的指令获取。并且知道整个 CISC 指令,这些步骤自然可以在芯片中更有效地实现,其中 RISC 处理器可能必须检查一系列指令并动态优化以获得相同数量的步骤。 (ldr r0,[r1]; 添加 r0,r0,r2)。如果 CISC 要检查指令组而不是专注于一个指令组,它也可以寻找相同类型的优化。两者都使用管道和并行执行。 CISC 通常意味着 x86,而 RISC 则意味着具有更现代和更简洁的架构。更清洁是指人类更容易编程和实施,但这并不意味着更快。完成相同工作的更多步骤。 x86 是可变字长,历史可以追溯到单字节指令,与 4 字节固定指令长度相比,x86 有可能将比固定指令长度 risc 更多的指令打包到缓存中,从而使 x86 成为可能性能提升。为什么 risc 不直接将许多指令转换成一条更小的指令,从而更快地通过缓存和流水线?

【讨论】:

    【解决方案2】:

    CISC 机器的解码电路很复杂,它们将复杂的 CISC 指令解码为更简单的指令。例如,理论上可以有一条 CISC 指令来获取两个内存地址的值并将乘法结果设置到另一个内存地址。 CISC机器的解码器将这条指令解码为多个类似RISC的操作,例如从内存位置获取一个值到寄存器,向该寄存器添加另一个寄存器等。解码后应该没有区别。这就是当前的 CISC 机器(如 x86)与 RISC 机器竞争的方式。但是您必须为复杂的解码阶段付出代价。

    【讨论】:

    • 所以你为解码阶段付出了这个代价……为了什么优势?当您可以从一开始就使用 RISC 指令直接切入正题时,为什么还要包含它?
    • @PinkElephantsOnParade "for what advantage?"。我们只是说 x86 显示了它的年龄。大多数较新的扩展(例如 SSE)都非常类似于 RISC。
    • 正如@Mystical CISCS 所解释的,机器无法更改其指令集以向后兼容现有应用程序。
    • @Pink - 如果每条 CISC 指令完成更多工作,则意味着程序会更小。一个较小的程序可能会运行得更快,就像它适合缓存时一样。
    【解决方案3】:

    它可能会转化为更小的指令,但是像乘法这样经常使用的指令通常会有一个指定的电路。

    【讨论】:

      【解决方案4】:

      @粉红 把它想象成一个工人用推车搬砖,一次装载 10 个 vs 10 名工人排着队互相递砖,所以优势较低 支付购物车的价格,除非这 10 个是太阳能机器;)

      【讨论】:

        【解决方案5】:

        我只是对老前辈的回答感到惊讶。尽管 RISC 指令也可以分成小步骤,而且它们确实如此,但这些步骤通常是流水线的,每个周期执行一条指令(不是平均数)。用于寄存器文件的 SRAM 几乎总是双端口的(同时读取和写入),因为这几乎可以免费完成,因为它们是 SRAM(只需学习数字系统课程)。因此,如何实现 RISC 处理器确实是一种设计选择,它们可以 7 使用微码实现,选择 RISC 指令集以便它们不需要,而实用的非微码 CISC 几乎是不可能的。 CISC 指令在实践中从不直接流水线化,而只有 CISC 微码(实现类似 RISC 的指令)。

        RISC 指令集并不容易由人类编程。它们更难由人类编程,但编译器更容易对其进行优化。

        只有在指令有复杂的微码时,通过更正微码来纠正指令中的错误似乎是合理的。您无法更正添加微码中的错误。因此,您可以通过更改微码来纠正的错误是您在 RISC 处理器中没有的错误,因为这种复杂的指令通常由软件实现。然而,在某些情况下,可以用微码指令替换简单的 RISC 类指令来修复错误(如 div 中的错误),但代价是性能损失很大。

        CISC 指令可能比 RISC 指令更有效,因为它们可以有专用的硬件。例如,向量移动需要 RISC 中的加载、存储、递增、比较和跳转指令,而它可以是单个 CISC 指令。 CISC 处理器可以有一个额外的增量单元,它将与加载和比较并行地增加地址寄存器。但是,这实际上在 RISC 机器(如 ARM)中得到了支持。事实上,RISC 背后的基本思想是拥有代码而不是微码。这导致直接在硬件中实现的指令较少,有点像程序员或编译器直接编写微代码。缺点是代码更大,

        最后,RISC 指令不会分解成更小的指令,因为它们已经在单个时钟周期中运行,并且在硬件中以非常快的时钟运行。

        最后,今天像 x86 这样的高性能 CISC maxinex 也将它们的指令分解为 RISC,就像微码指令一样。

        【讨论】:

        • ARM 是一个加载/存储机器,但它不是很 RISCy。他们的 push/pop (store-multiple / load-multiple) 指令基本上必须是微编码的。对于小代码量很重要的应用程序(例如嵌入式,尤其是在最初设计 ARM 时),这是一个很好的设计决策,但绝对不是 RISC。可以说,预测也不是很 RISCy。毫不奇怪,AArch64 放弃了这两者,这使得 ISA 更像其他 RISC。
        • 你说 CISC 指令在实践中永远不会直接流水线化。现代 x86 就是这样做的,但 Pentium P5 微架构系列并没有解码为多个微指令。为了调整 P5,编译器 必须选择 x86 的 RISCy 子集,例如避免像 push / pop 或 memory-destination add 这样的指令,因为它们没有有效地流水线。 P5 是双问题超标量有序 uarch,具有关于哪些指令可以一起运行的配对规则。详情请参阅 P5 章节in Agner Fog's microarch guide。
        • IDK,也许你的意思是直接,因为早期的 MIPS 可以使用指令字本身的位作为流水线阶段的内部控制信号。同意没有 CISC 可以做到这一点。但是流水线获取/解码/执行不需要在内部解码为类似 RISC 的微指令。
        • 您说得对,将memcpy 作为单个指令启用内部优化处理是正确的。 x86 的rep movsb / rep movsd 就是这样,P6(PPro / Pentium II)引入了“快速字符串”优化的微码实现和memset(What setup does REP do?)。但是在具有 SIMD 向量的 CPU 上,经过良好调整的具有 SSE 或 AVX 向量的memcpy 通常可以击败微码。 rep movs 非常适合只能接触整数寄存器的内核代码。
        猜你喜欢
        • 2017-04-23
        • 1970-01-01
        • 1970-01-01
        • 2012-10-15
        • 2016-01-21
        • 2021-01-28
        • 1970-01-01
        • 1970-01-01
        • 2013-06-21
        相关资源
        最近更新 更多