try ai
科普
编辑
分享
反馈
  • 纵向与横向微码

纵向与横向微码

SciencePedia玻尔百科
核心要点
  • 纵向微码通过对互斥信号进行编码来节省控制存储空间,但这会牺牲速度;而横向微码以庞大的内存占用为代价,提供最大的并行性。
  • 现代处理器的控制单元通常采用混合设计,以平衡纵向编码的紧凑性和横向控制位的并行性。
  • 微码格式的设计选择会产生深远的影响,不仅影响性能,还影响物理芯片面积、功耗和安全漏洞。

引言

在每个处理器内部,都有一个控制单元,它如同一支复杂硬件交响乐团的指挥,发出精确的时序信号,指导数据流和程序执行。这个控制单元的设计是计算机体系结构中的一个基础性挑战。其核心在于一个关键问题:现代CPU所需的大量控制信号如何能被高效地生成和管理?采用“一个信号对应一位”的直接方法虽然能提供最快速度,但会导致控制系统过于庞大,不切实际,从而在理论能力与实际实现之间造成了巨大的认知鸿沟。

本文深入探讨了为解决此问题而发展的精妙方案。在接下来的章节中,我们将剖析微程序控制的两种主要思想。在“原理与机制”中,我们将探索横向和纵向微码的基本概念,揭示在控制存储器大小、译码速度和操作并行性之间的核心权衡。随后,在“应用与跨学科联系”中,我们将追溯这一个设计选择对整个系统性能、芯片的面积和功耗等物理特性,乃至整机安全性和可信度的深远影响。

原理与机制

指挥家与交响乐团:信号的交响曲

想象一下,一个现代处理器的数据通路——即算术单元、寄存器和内存接口的集合——就是一个庞大而复杂的交响乐团。你有小提琴部(浮点运算单元)、打击乐部(整数算术逻辑单元,即ALU)、铜管乐部(内存总线)等等。为了让这支乐团演奏出一部连贯的乐曲——在我们的例子中是执行一个程序——它需要一位指挥家。这位指挥家就是​​控制单元​​。

控制单元的工作是在每个乐手需要指令的精确时刻,向他们发出指令。它不是大喊“演奏得快一点!”,而是传递一份精确的乐谱,指明“第3号小提琴手,演奏一个升C音,持续一拍,立即开始。”这些精确、即时的指令就是​​控制信号​​。它们是简单的二进制命令:使能某个寄存器、选择某个多路复用器的输入、告知ALU执行加法、指令存储器进行读取。计算机体系结构中的根本问题是:编写和分发这份极其复杂的“乐谱”的最佳方式是什么?

蛮力乐谱:纯横向控制

让我们从能想到的最直接的方法开始。我们创造一份宽度极大的乐谱。对于每个乐手可能采取的每一个动作,我们都在纸上为其留出单独的一行。如果ALU可以执行32种不同的操作,我们仅为它就准备了32行。如果有64个寄存器,每个都有一个“加载”信号,我们又多了64行。在节拍器(CPU时钟)的每一次滴答声中,指挥家只需在对应于该节拍内应发生动作的行上做个标记。

这就是​​横向微程序设计​​的本质。一条“微指令”是位于一个称为​​控制存储器​​的特殊存储器中的一个非常宽的字。这个字中的每一位都直接对应数据通路中的一条控制线。如果第17位是“1”,那么第17条控制信号就被断言(asserted)。这里没有歧义,无需解释,也不需要译码。

这种方法的内在美在于其原始的速度和并行性。因为每个控制信号都有自己的专属位,你可以在一个时钟周期内激活任意多个兼容的操作。你可以同时命令ALU执行加法、一个寄存器加载结果、以及程序计数器自增,只需在同一条微指令中将它们各自对应的位置为“1”。从控制存储器到硬件的路径是一根直接的导线,这使得它速度极快。

但这种美伴随着一个巨大的代价:体积。一个复杂的处理器可能需要成百上千个控制信号。这意味着每条微指令字的宽度将达到成百上千位。而必须存储CPU能执行的每条指令的全部“乐谱”的控制存储器,将变得异常庞大、昂贵且耗电。这就像把一部交响乐印在一张一英里宽的纸上。

神来之笔:为乐谱编码

一位聪明的指挥家很快会注意到一种模式。ALU可以被告知执行加法(ADD),或者被告知执行减法(SUBTRACT),但绝不能在同一时刻被告知同时执行两者。它的操作是​​互斥的​​。对于一个多路复用器的输入也是如此;你可以选择输入A或输入B,但不能同时选择两者。

既然如此,我们为什么要用单独、专用的谱线来表示那些永远不会同时发生的动作,从而浪费宝贵的乐谱空间呢?这一个洞见催生了​​纵向微程序设计​​。

我们可以不为16种可能的ALU操作各自分配一位(需要16位),而是为每种操作分配一个唯一的二进制码。要表示16种不同的选择,我们只需要⌈log⁡2(16)⌉=4\lceil \log_2(16) \rceil = 4⌈log2​(16)⌉=4位。我们微指令中的ALU部分从16位缩减到了仅4位。为了实现这一点,ALU这位“乐手”现在需要一个小型“译码器”电路,它接收这个4位代码,并激活对应的一条控制线。

这种分组和编码的原则可以应用于整个数据通路。我们识别出所有互斥的控制信号集,并将每个集合替换为一个紧凑的编码字段。例如,一组8个总线驱动器可以被一个3位字段取代,而一组12个寄存器可以被编码成一个4位字段。我们那曾经一英里宽的乐谱被显著地压缩成了一本易于管理的小册子。

普适的交易:以空间换取时间和并行性

然而,这个优雅的解决方案并非没有代价。它引入了所有工程领域中最基本的权衡之一:空间与时间之间的交易。

​​收获:空间的巨大缩减​​

纵向编码的主要好处是控制存储器大小的急剧减小。我们可以用惊人优雅的方式量化这种节省。如果我们从总共SSS个控制信号开始,并将它们划分为ggg个大小为sis_isi​的互斥组(因此s1+s2+⋯+sg=Ss_1 + s_2 + \dots + s_g = Ss1​+s2​+⋯+sg​=S),那么横向微指令的宽度就是SSS。而纵向微指令的宽度大约是∑i=1glog⁡2(si+1)\sum_{i=1}^{g} \log_2(s_i+1)∑i=1g​log2​(si​+1)。在对称情况下,尺寸之比,即压缩因子,可以简化为R=Sglog⁡2(Sg+1)R = \frac{S}{g \log_{2}\left(\frac{S}{g} + 1\right)}R=glog2​(gS​+1)S​。这个优美的公式揭示了只要我们将信号分组(g<Sg \lt Sg<S),这个比率就大于1,从而保证了控制存储器会更小。

​​代价:不可避免的译码延迟​​

我们为这种紧凑性付出的代价是时间。将编码字段翻译回直接控制信号的译码器电路并非瞬时完成。一个沿“纵向”路径传播的信号必须首先通过译码器逻辑,然后才能控制数据通路。这给处理器的关键路径增加了传播延迟。现在,一个控制信号准备就绪的总时间是译码器延迟和任何后续逻辑延迟的总和,tv=td+tlogict_v = t_d + t_{logic}tv​=td​+tlogic​。在横向方案中,这仅仅是导线延迟,tht_hth​。这额外的译码时间会侵占宝贵的时钟周期预算;如果译码时间过长,整个处理器就必须以较慢的时钟速度运行来适应它。

​​隐藏成本:并行性丧失的危险​​

还有一个更微妙的危险。如果我们对编码过于热心会怎样?假设我们将两个可能同时发生的动作——比如一次ALU操作和一次内存访问——错误地分组成一个单一的编码字段。我们现在创造了一台在给定周期内只能做其中一件事,而绝不能两者都做的机器。我们已经将我们的交响乐团串行化了,迫使小提琴手等待打击乐手演奏完毕。

关键在于只对那些因硬件特性而真正互斥的信号进行分组。独立的,或称​​正交的​​信号组必须在微指令中拥有各自独立的字段。如果我们做不到这一点,就会削弱机器的并行性,增加执行一条指令所需的周期数(CPI),从而损害整体性能。这门艺术在于辨别真正的互斥界线与潜在的并发界线。

驯服指数级恶龙:译码器设计艺术

所以,我们决定使用纵向编码,并且小心翼翼地保留了并行性。但一个新问题出现了:译码器本身。对于一个nnn位的编码字段,一个全功能译码器必须能够识别2n2^n2n个不同的输入代码。在最坏的情况下,所需逻辑电路(如可编程逻辑阵列,即PLA)的规模和复杂性呈指数级增长,其量级为O(n⋅2n)O(n \cdot 2^n)O(n⋅2n)。

这个“数字的暴政”是一个强大的敌人。一个4位字段的译码器是可管理的。而一个8位字段(n=8n=8n=8)的译码器将大约大28−4=162^{8-4} = 1628−4=16倍,并且速度显著减慢,很可能成为性能和面积的瓶颈。那么架构师们如何驯服这只指数级增长的恶龙呢?

他们运用智慧和经验。

  • ​​保持字段短小:​​ 首先,他们遵循一个简单的经验法则:不使用大的编码字段。在实践中,字段宽度通常被限制在3到5位的范围内,从而将译码器的复杂性保持在可控区域。

  • ​​分而治之:​​ 如果必须对一个更大的操作集进行编码,架构师可以分解问题。想象一下需要编码256个操作,这将需要一个8位字段。他们可能不会构建一个巨大的8-256译码器,而是设法将问题构建为两个独立的4位字段。这样,总复杂度就与两个4-16译码器的复杂度成正比。逻辑项的数量从28=2562^8 = 25628=256急剧下降到24+24=322^4 + 2^4 = 3224+24=32。这是通过在问题中发现结构而取得的巨大胜利。

  • ​​两级控制:​​ 对于非常复杂的指令集,架构师可能会使用一种称为​​纳程序设计​​的绝妙技术。我们一直在讨论的主控制存储器存放着非常窄的微指令。但这些并非最终的控制字。相反,它们是指向第二个、更小更快的控制存储器——称为​​纳存储器​​——的指针或地址。这个纳存储器包含最终的、宽的、横向风格的控制字。这就像主乐谱上只有一个音符写着“演奏华彩乐段#7”,而每个乐手都有一个本地的、硬连线的“短语手册”(纳存储器),他们可以立即从中查到“华彩乐段#7”的含义。这用一点间接寻址换取了主可编程控制存储器体积的大幅节省。

控制的谱系

我们从对比两个极端开始:纯横向和纯纵向微码。但现实是,这不是一个二元选择。它是一个丰富而连续的​​控制谱系​​。

一个现实世界中的微指令几乎总是混合体。它会包含几个紧凑的、用于互斥操作组(如ALU功能)的纵向编码字段。同时,它也会有一组单独的、横向风格的位,用于需要并行控制的关键、独立信号。

计算机架构师的工作不是在横向和纵向之间做出选择。而是在这个谱系中航行,在成本、速度和并行性之间处处做出明智的权衡。通过对互斥的部分进行编码,对并发的部分保持分离,并用纳程序设计等技术来驾驭复杂性,他们精心打造出一种既强大又高效的控制机制——为他们的硅基交响乐团谱写出一份完美的乐章。

应用与跨学科联系

在我们上次的讨论中,我们揭示了微程序控制的两种基本思想:横向格式的直接、显式的“开关板”,以及纵向格式的紧凑、编码的“字典”。乍一看,这似乎只是一个实现细节,一个处理器设计内部密室中的枯燥选择。但正如科学和工程中常有的情况一样,在核心处做出的一个简单选择,可能会产生深远而有趣的连锁反应,其影响波及从原始性能到物理现实,乃至计算机安全堡垒的方方面面。

现在,让我们踏上追溯这些涟漪的旅程。我们将看到,这一个单一的决定——编码还是不编码——如何将计算的抽象逻辑与硅、能量和信任的实体世界联系起来。我们的探索始于任何机器最直接的问题:它的思考速度能有多快?

控制的通货:性能与并行性

假设你希望一台机器执行一次乘法,比如使用经典的移位加算法。这涉及一个循环:检查乘数的一位,有条件地加上被乘数,移动几个寄存器,并递减一个计数器。使用宽的横向微指令,设计者可以将所有这些独立的操作打包成一个单一的“想法”。一条微指令可以并行地命令:“如果此位为1,则相加;将此寄存器左移;将彼寄存器右移;顺便准备循环。”整个迭代在时钟的一个滴答内完成。对于一个nnn位的乘法,这精确地需要nnn个滴答,即nnn条微指令。

现在,考虑纵向方法。它的词汇量更有限。一条微指令可能表示“加法”,另一条表示“左移”,还有一条表示“如果计数器不为零则分支”。横向机器那种复杂的、并行的“想法”必须被分解成一系列更简单的步骤。仅条件加法本身就可能需要一个“测试并分支”的微操作,然后才是“加法”操作。因此,乘法循环的一次迭代可能需要五六条纵向微指令,这使得整个过程明显变慢。横向并行性的速度优势似乎清晰而具有决定性。

在作为现代计算基石的、复杂的流水线处理器中,这种张力变得更加突出。流水线就像一条指令的装配线,要保持其顺畅运行,需要在瞬间发现并解决交通堵塞,即“冒险”。如果这种冒险检测是用微码完成的,横向格式可能能够在单个时钟周期内检查冲突并发出停顿信号。而纵向格式需要多条顺序的微指令来执行相同的检查,可能需要几个周期才能意识到问题的存在,从而引入额外的停顿周期并损害性能。当流水线在分支预测错误后必须被冲刷时,也会出现类似的性能损失;横向格式的精细、位级的控制可以精确地作废正确的指令,而纵向格式必须通过其译码器发出更宽泛的“清除”命令。

但情况总是这么简单吗?是不是越宽、越并行就一定越好?不尽然。微指令本身必须从一个存储器——控制存储器——中取出。而在这里,纵向格式的主要优点——其紧凑性——发挥了作用。因为纵向微指令更小,更多的指令可以被装入一个快速的、片上的微指令缓存中。一个每周期能提供512位的缓存或许能取回两条宽的横向指令,但在同样的时间内,它可能取回八条窄的纵向指令。如果程序大量时间花费在紧凑的循环中,纵向微码的较小体积可以带来更高的缓存命中率和更大的有效取指带宽(以每周期指令数衡量)。突然之间,执行较慢的格式可能在取指上更快,从而在控制并行性与存储层次结构性能之间形成了一个优美而复杂的系统级权衡。

物理代价:从抽象位到硅、焦耳和信任

微码格式的选择不仅在短暂的时间维度上留下印记,也在芯片本身的物理实体上刻下痕迹。让我们深入到硅的层面,看看其后果。

最明显的物理成本是空间。由微码生成的控制信号并非魔术般地出现在需要它们的地方;它们必须通过金属导线在芯片上进行物理布线。一条144位的横向微指令需要一条144车道的“超级高速公路”般的导线,而一条36位的纵向指令只需要一条36车道的道路。这种互连总线消耗了大量宝贵的芯片面积。切换到纵向格式可以显著减小这部分面积,为其他功能(如更多的缓存或功能单元)释放出硅片资源。

当然,天下没有免费的午餐。纵向格式节省了“道路”上的空间,但在目的地需要“工厂”——即译码器。用于纵向微码的控制存储器内存更小,但你现在必须将面积用于逻辑门,以将编码字段翻译成最终的控制信号。当我们同时考虑存储器和译码器逻辑时,哪种格式胜出?答案取决于设计的具体情况和底层技术。在一个可能的场景中,即在现场可编程门阵列(FPGA)上实现控制系统,由更小的纵向控制存储器带来的面积节省,可以完全补偿译码器的面积成本,从而导致所用逻辑资源总数的净减少。这种权衡是真实存在的,必须经过仔细计算。

除了静态面积,还有可靠性问题。存储在控制存储器中的位并非对宇宙的“恶作剧”免疫;宇宙射线或电噪声可能会将一个0翻转为1,可能导致机器执行错误的命令。为了防范这种情况,我们使用纠错码(ECC)添加额外的“校验位”。对于一个单比特纠错、双比特检错(SECDED)码,对于kkk个数据位所需的校验位数rrr大致与log⁡(k)\log(k)log(k)成正比。这种非线性关系意味着两种格式的开销是不同的。一个128位的横向字可能需要8个ECC位,而一个32位的纵向字可能需要6个。这为物理成本计算增加了另一个维度:为了我们控制信号的给定可信度级别,我们必须支付多少额外空间?。

最后,我们考虑最微妙的物理成本:能量。在驱动几乎所有数字设备的CMOS技术中,每当一根导线的电压从低切换到高时,就会消耗能量。这就是动态功耗。微码格式的选择直接影响这些开关模式。横向格式有一个宽的微指令寄存器,其中许多位可能在相邻周期之间翻转。纵向格式的寄存器则窄得多,因此在那里翻转的位也较少。然而,活动并未消失;它只是被转移了。译码器输入端变化的编码字段会在译码器逻辑内部引起一连串的开关活动。分析总动态功耗需要我们统计整个控制系统——寄存器中、互连总线上以及译码器内部——的预期位翻转总数。令人惊讶的结果是,没有哪种格式在功耗效率上普遍更优;这完全取决于所运行程序的统计特性以及逻辑门的物理特性。这生动地提醒我们,在处理器设计中,每一个逻辑抽象都有其能量成本。

王国的钥匙:机器中的安全与信任

我们以一个在现代至关重要的话题来结束我们的旅程:安全。如果我们设计一个带有*可写控制存储器*的处理器,允许软件在芯片制造后修改微码,会发生什么?这曾是修复错误或添加新功能的常用技术。然而,从安全角度看,这就像把王国的钥匙放在门垫下。

微码在体系结构状态的“地板”之下运行,可以直接接触到机器最敏感的杠杆。一个获得了可写控制存储器访问权限的恶意程序,可以编写一个微例程,简单地绕过所有安全检查。它可以禁用内存保护,更改处理器的特权级,或直接控制硬件,从而变得实际上无所不能。

我们如何降低这种巨大的风险?答案是将体系结构的安全概念下推到微体系结构层面。我们可以在每一条微指令中增加一个“访问控制字段”。该字段可以包含一个特权级别,要求主处理器处于足够高的特权状态(例如,内核模式)才能执行该微操作。它还可以包含一个“能力掩码”,即一组针对特定敏感操作的权限位。要执行更新内存保护寄存器的微指令,运行上下文就需要拥有“可更新保护”的能力。

这就使我们的故事回到了起点。这个至关重要的安全机制为每条微指令增加了额外的位。对于宽的横向格式,增加(比如说)8位的安全信息可能只代表很小的比例开销。但对于已经很紧凑的纵向格式,同样的8位代表了更大比例的尺寸增加,可能会削弱其在存储密度和缓存性能方面的一些优势。事实证明,编码格式这个简单的选择,甚至对实现机器可信度的成本也有影响。

从编码方案的信息论等价性出发,我们看到了一连串的后果。微码格式的选择塑造了处理器的性能轮廓、其物理尺寸和功耗,甚至其受攻击的脆弱性。这是一个完美的设计统一性范例,其中一个单一的原则,当其逻辑结论被追寻到底时,揭示了将逻辑、物理和安全世界联系在一起的美丽而错综复杂的网络。