CISC机器-它们不只是把复杂指令转换成RISC吗?

3
也许我的理解有误,但如果一台机器有一个乘法指令,那么这个指令不是被翻译成更小的指令,或者是非常复杂,最终与等效的RISC指令速度相同吗?
乘法是一个糟糕的例子 - 在两种体系结构中都是单个指令。在上面的"乘法"中用在CISC中更复杂且RISC没有等效的单个指令来替换它。

1
乘法通常在CISC和RISC上都是一条指令。您能澄清一下问题吗? - Mysticial
是的。我假设汇编代码中的乘法比实际情况更复杂,所以这是一个糟糕的例子。我的理解是CISC指令比RISC更复杂...但是如果这些更复杂的指令真的需要与等效数量的RISC指令一样多的周期,那么这些更复杂的指令如何带来优势呢? - PinkElephantsOnParade
http://en.wikipedia.org/wiki/Micro-operation - Hans Passant
相关文章:RISC vs. CISC仍然很重要(作者Paul DeMone):https://www.realworldtech.com/risc-vs-cisc/。这是一篇相当不错的文章,虽然写于2000年,当时decode-to-uops还比较新颖,Pentium II / III已经超过Alpha成为工作站性能的代表。但是,“x86税”仍然存在,特别是对于具有传统调用约定和仅有8个架构寄存器的32位x86。(当您需要在寄存器中保留超过8个内容时,寄存器重命名无法帮助您。) - Peter Cordes
5个回答

3
乘法指令是一个好的和坏的例子。首先,乘法指令很昂贵,一些处理器没有这个指令是有充分理由的。您可以使用x86和其他处理器,需要多个时钟或一个时钟。为了得到一个时钟的乘法,需要(相对较大的)大量芯片实际空间(正如Dani所提到的,可能是专门用于乘法的逻辑块)。绝对没有理由让一个设计师做出与另一个设计师相同的选择,无论是在同一家公司内(一个x86与另一个x86进行比较)还是不同的体系结构(x86 vs ARM vs MIPS等)。每个设计师都知道乘法的结果是操作数的两倍,因此您选择给程序员所有操作数组合的完整答案(结果与操作数大小不同),还是将结果剪切到操作数大小?如果您将其剪切到操作数大小,则会给他们溢出或异常,还是让他们继续运行而不知道结果是错误的?您是否强制要求他们在所有mul和div指令周围添加包装器,以便检测到溢出并导致性能下降?
x86架构是学习或参考其他架构的非常糟糕的架构。它会导致很多错误的假设。不是所有处理器都是微码的。不是所有CISC处理器都是微码的。RISC处理器为什么不能被微码化,您可以微码化CISC或RISC或不微码化CISC或RISC,这是一种设计选择,而不是规则。
RISC并不意味着步骤最少,即使是简单的寄存器到寄存器移动也至少需要两个步骤(获取源,存储结果),这可能需要两个时钟来执行处理器的方式有时实现(使用SRAM存储器库用于不一定是双端口的寄存器文件)。alu指令需要三个步骤,并且在RISC处理器上可能需要三个时钟,RISC将平均每个指令一个时钟,但CISC也可以。您可以超标量并超过每个指令的一个时钟,至少对于处理器绑定的爆发情况。 CISC与RISC转换的复杂性相同。
我建议编写指令集模拟器,或者至少开始编写一个反汇编程序。如果没有其他,则最好让100名程序员分别执行相同的编程任务。即使所有人都由同一所学校的同一位老师教授,您也会得到该iss或反汇编程序的3到100个不同的设计。将其作为编程任务的文本编辑器,只是编程语言的选择将与程序的设计略有不同。硬件设计非常类似于软件设计,您使用编程语言并具有编译器和类似链接器的东西。让一个充满硬件设计师的房间给他们相同的任务,您会得到不同的设计。这与CISC与RISC关系不大,而与设计团队及其选择有很大关系。英特尔有不同的设计目标,例如反向兼容性,这是一种非常昂贵的选择。

无论是 CISC 还是 RISC,都会根据处理器的设计将每个指令转换为更小、易于理解和分割的步骤。将乘法替换为加法,然后在汇编级别及更深层次上比较 CISC 和 RISC。例如,在 x86 中,您可以使用内存作为操作数,但在 ARM 中则不行。

register = memory + register

is

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为了正确执行指令,需要将从内存读取的值存储在额外的寄存器中(CISC从asm角度看有两个寄存器,而RISC则有三个或两个可重复使用的寄存器)。
如果从内存中读取的值未对齐,则在技术上CISC获胜(如果RISC通常不允许不对齐的传输)。在所有条件相等的情况下,CISC处理器获取未对齐数据所需的内存周期数与RISC相同(两个处理器都需要两个内存周期,CISC和RISC都会受到惩罚)。但是,如果将内存操作数设置为未对齐,则需要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)

你还有指令大小,像ARM和MIPS这样的流行RISC处理器倾向于固定指令长度,而x86则是可变的。x86可以用一个字节完成另一个需要四个字节才能完成的操作。是的,你的提取和解码更复杂(更多逻辑,更多功率等),但你可以在相同大小的高速缓存中放置更多的指令。
微编码不仅仅是将一个指令集分解为另一个指令集(另一个可能非常痛苦,您永远不想本地编程)。微编码可以帮助您更快地进入市场,假设较低级别的系统更快地实现并且有较少的错误。假设您可以更快地增加生产量,因为您可以在事后修复一些错误,并且可以在以后在现场打补丁。并不总是完美的,也不总是成功的,但与不使用微编码的处理器相比,您必须让编译器人员修复错误或召回处理器或作为公司蒙受损失并希望赢回一些客户等等,这是一个好的选择。
所以答案是否定的。RISC和CISC都将单个指令转换为可以微编码或不可以微编码的步骤序列。简单地认为它们是状态机中的状态,无论你喜欢如何实现。CISC可能会将更多的步骤打包到一个指令中,但这意味着较少的指令提取。并且如果了解整个CISC指令,则可以在芯片上自然地实现这些步骤,而RISC处理器可能必须检查一系列指令并即时优化以获得相同数量的步骤(ldr r0,[r1];add r0,r0,r2)。如果CISC检查一组指令而不是专注于单个指令,则也可以寻找相同类型的优化。两者都使用管道和并行执行。CISC通常暗示x86,而RISC则暗示具有更现代和更清洁架构的东西。从人类编程和实现的角度来看更加简洁,不一定意味着更快。执行相同工作的步骤更多。与固定指令长度的RISC相比,x86具有可变字长的历史可以追溯到单字节指令,因此x86可以在高速缓存中打包更多指令,从而可能提高性能。为什么RISC不只是将许多指令转换为一个更小的指令,以更快地移动通过高速缓存和流水线?

2

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


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

那么你为什么要支付解码阶段的代价...有什么好处吗?为什么不直接从一开始就使用RISC指令,而要包含它呢? - PinkElephantsOnParade
@PinkElephantsOnParade "有什么好处呢?"。我们只能说x86已经显现出它的老态了。大多数新的扩展(如SSE)非常类似于RISC。 - Mysticial
正如 @Mystical 所解释的那样,CISCS机器无法更改其指令集以向后兼容现有应用程序。 - Deniz
3
如果每个CISC指令都能完成更多的工作,那么程序会更小。一个更小的程序可能会更快地运行,比如当它适合缓存时。 - Bo Persson

1

@Pink 把它想象成一个工人使用手推车搬运砖块,一次装载10个, 相比于10个工人排队互相递送砖块,优势在于用更低的价格购买手推车, 除非那10个是太阳能机器 ;)


0

我对老一辈的回答感到惊讶。虽然RISC指令也可以分解成小步骤,并且它们通常被流水线化,每个周期产生一个指令(不是平均值)。用于寄存器文件的SRAM几乎总是双端口的(具有同时读写),因为这几乎可以没有成本地完成,因为它们是SRAM(只需参加数字系统课程即可)。因此,RISC处理器的实现方式是设计选择,它们可以使用微码实现,但RISC指令集被选择使得它们不需要,而实际上非微编码的CISC接近不可能。 CISC指令在实践中从未直接进行流水线处理,而仅进行CISC微码处理(实现RISC指令)。

RISC指令集不容易由人类编程。 它们更难以由人类编程,但编译器更容易优化它们。

如果指令的微码很复杂,仅通过更正微码来更正指令中的错误似乎是合理的。你不能通过微码来更正加法中的错误。因此,你可以通过更改微码来更正的错误是在RISC处理器中没有的,因为这些复杂的指令通常是由软件实现的。然而,在某些情况下,可能会将简单的RISC指令替换为微编码指令以修复错误(例如在除法中),但代价是性能大幅下降。

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

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

最终,如今高性能的CISC架构的芯片(例如x86)也将它们的指令分解成类似于RISC的微代码指令。

1
ARM是一种加载/存储机器,但它并不是非常RISCy。他们的push/pop(存储多个/加载多个)指令基本上必须进行微代码化。这对于需要小代码大小的应用程序(如嵌入式系统,特别是在ARM最初设计时)是一个很好的设计决策,但绝对不是RISC。谓词也可以说不是非常RISCy。毫不奇怪,这两者都被放弃了AArch64,使ISA更像其他RISCs。 - Peter Cordes
1
你说CISC指令在实践中从不会被直接地流水线化。这就是现代x86所做的,但是Pentium P5微架构系列并没有将其解码为多个uop。为了调整到P5,编译器必须选择类似于RISC的x86子集,例如避免像push / pop或内存目的地add这样的指令,因为它们无法有效地流水线化。P5是双发射超标量的按顺序uarch,具有有关哪些指令可以一起运行的配对规则。请参阅Agner Fog微体系结构指南中的P5章节以获取详细信息。 - Peter Cordes
我不知道,也许你的意思是早期的MIPS可以使用指令字本身的位作为管道阶段内部控制信号。同意没有任何CISC能够做到这一点。但是流水线获取/解码/执行不需要在内部解码为类似于RISC的uops。 - Peter Cordes
你说得没错,将memcpy作为单个指令可以在内部实现优化处理。x86的rep movsb / rep movsd正是如此,而P6(PPro / Pentium II)引入了“快速字符串”优化微码实现以及memsetREP设置是什么?)。但是,在具有SIMD向量的CPU上,使用SSE或AVX向量进行调整的memcpy通常可以击败微码。rep movs非常适合只能触摸整数寄存器的内核代码。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接