news 2026/9/15 20:21:06

超标量处理器全面解析:从IPC到乱序执行与寄存器重命名

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
超标量处理器全面解析:从IPC到乱序执行与寄存器重命名

这篇是体系结构学习笔记系列的第六篇,聊超标量处理器(Superscalar Processor)。学到这里先要有心理准备:它和前面几篇的流水线、冒险这些基础章节不一样,超标量把流水线“时间重叠”的思路升级成了“空间并行”的思路,CPU里几乎所有关键部件——取指、译码、发射、执行、访存、提交——都得为了“每个周期多发几条指令”这个目标重新设计一遍。虽然有点烧脑子,但搞明白它之后,再看任何现代CPU的微架构资料,你会觉得世界一下子清晰了很多。

这篇文章不会堆一堆论文式的术语,我会从“它到底解决了什么问题”开始,把超标量为什么会出现、流水线各阶段怎么改造、乱序执行背后的寄存器重命名和Tomasulo算法、分支预测为什么变成老大难,以及它跟VLIW、多核这些技术路线的关系都过一遍,最后聊聊我自己学习时踩过的坑和排查思路。适合刚啃完流水线、准备进入指令级并行(ILP)这部分的朋友。

1. 为什么说IPC能超过1,才是超标量

1.1 IPC等于1已经是天花板?这句话到底什么意思

先回顾一个基础概念。单周期处理器一个时钟周期执行一条指令,CPI(Cycles Per Instruction)等于1。流水线处理器把指令执行拆成取指、译码、执行、访存、写回等多个阶段,让不同指令的不同阶段重叠起来,理想状态下CPI可以逼近1,也就是一个周期完成一条指令。

但请注意,流水线只是把一个车道优化到了极致,它始终只有一条车道。每个周期最多只能取一条指令、只能发射一条指令、只能写回一条指令。就算后面的站台空着,前面来的车也只有一辆。所以标量流水线再怎么优化,CPI的下限就是1,IPC(Instructions Per Cycle)的上限就是1。

超标量做的事情,就是把这个“一条车道”拓宽成“多条车道”。每个周期可以同时取多条指令、同时发射多条指令、同时执行多条指令,让IPC真正超过1。Intel Pentium是双发射,IBM POWER、MIPS R10000、Alpha 21264、ARM Cortex-A系列、AMD Zen系列,这些都是超标量。可以说,从20世纪90年代开始,高性能处理器的地基就是超标量。

这里可以用厨房来类比。单周期CPU就像一个厨师独自做一整桌菜,流水线是后厨分工——一个切菜、一个炒菜、一个摆盘,出菜速度从“做完一道再下一道”变成“连续出菜”,但同一时刻灶台上只能有一道菜在炒。超标量就是加了两个灶台,同一时间能开好几口锅,出菜吞吐量自然上去了。

1.2 并行从哪来:指令级并行(ILP)的本质

问题接着来了:CPU凭什么能每个周期同时发射多条指令?因为程序里相邻的指令很多时候互相不依赖,天然就可以并行执行。比如这段伪代码:

LD x1, 0(x2) # 第1条:加载 ADD x3, x1, x4 # 第2条:依赖x1,必须等第1条完成 MUL x5, x6, x7 # 第3条:完全独立 SUB x8, x9, x10 # 第4条:完全独立

第3条和第4条既不需要等第1条,也不影响第2条,它们完全可以和第1条同一周期发射。如果一个2-发射(2-wide)的超标量处理器能在一个周期内同时发射第1条和第3条,下一个周期再发射第2条和第4条,那同样4条指令,标量流水线至少要4个周期,超标量可能2个周期就够了。

这种隐藏在指令流里的并行性,就叫指令级并行(Instruction-Level Parallelism,ILP)。ILP的发现方式主要有两种:一种靠编译器静态分析,在软件层面重排指令顺序;另一种靠硬件动态调度,在运行时乱序执行、乱序发射。超标量主要走的是后一条路,也就是硬件在运行过程中动态寻找并行性。

这里有一个很重要的认知:程序的ILP是有限度的。不是说发射宽度越大,能挖掘的并行就越多。指令之间有真实的数据依赖、分支造成的控制依赖、访存指令之间的地址依赖,这些都会限制ILP。现实里一个4发射的乱序处理器,跑普通程序能把IPC跑到2到3就已经相当不错了,很难达到理论上的4。

1.3 从CPI到IPC:超标量的关键指标

性能公式是CPU时间 = 指令数 × CPI × 时钟周期。超标量的目标就是降低CPI,也就是提高IPC。但要注意,这里存在一个彻底的思维转变。

在流水线阶段,我们关心的核心问题是冒险怎么处理、怎么让流水线尽量不stall,目标是CPI尽量接近1。到了超标量阶段,目标变成了每个周期平均发射多少条、完成多少条指令,也就是IPC比1高多少。这个指标直接决定了处理器的单核性能上限。

实际运行中IPC会被四类因素吃掉不少:数据冒险、控制冒险、结构冒险(比如寄存器堆端口不够、发射槽不够)、以及缓存缺失(Cache Miss)带来的访存停顿。所以看一颗处理器的微架构,不要光看发布会PPT上写的“4-wide”“6-wide”发射宽度,那个数字是理论最大值。衡量超标量做得好不好,最终要看它在真实负载下能把IPC推到多高,这个数字才是产品力。

2. 超标量流水线的骨架:从取指到提交的每一站

2.1 取指和译码:为什么RISC天生适合超标量,x86则要翻译

超标量的第一站是取指,这里的要求就和标量不一样:每个周期必须取回多条指令。假设处理器是4发射,取指级每周期至少要拿到4条指令,这意味着指令缓存(I-Cache)的带宽必须足够大,不能再像标量那样每次只读一个地址对应的32位或64位数据。通常I-Cache会设计成每周期能读出足够宽的指令块,再配合指令缓冲队列,把指令连续喂给译码器。

译码环节更有意思。RISC指令集天生适合超标量:指令定长、格式规整、编码简单,译码器可以把指令直接拆成操作数、操作类型、目的寄存器,逻辑简单,延迟也低。而x86是变长指令,一条指令从1字节到15字节都有可能,译码极难,早期的x86超标量处理器在译码上吃亏不少。

x86后来是怎么解决的?从Pentium Pro开始,x86处理器在译码阶段前面加了一层“预译码/翻译”逻辑,把复杂的变长x86指令拆成内部统一的微操作(uop,micro-operation)。后面整条超标量流水线处理的都是这种定长的uop,相当于在头上先做了一层翻译。所以所谓“x86也是RISC核心”这种说法不准确,更准确的说法是“x86的取指和译码是一个复杂翻译器,翻译完之后的乱序超标量部分,本质上是RISC式的”。

2.2 译码之后的大排队:发射队列、保留站与调度

指令经过译码、重命名之后,会进入一个非常重要的结构——发射队列,也叫保留站(Reservation Station)。可以把发射队列理解成一个“等待室”:每条指令在这里等待它需要的操作数。操作数没准备好就继续等;操作数一旦就绪,这条指令就变成“可发射”状态,等待被调度器选中,进入执行单元去执行。

调度器每个周期要做几件事:扫描发射队列里所有“操作数就绪”的指令,按照某种策略选出最多w条(w就是发射宽度),然后把它们送到对应的执行单元。这个过程叫指令发射调度。

这里有个常见的理解误区:超标量并不等于乱序执行。很多经典超标量处理器是顺序发射的,比如早期的Pentium就是双发射但基本按程序顺序发射。真正让超标量性能大幅提升的,是加上乱序执行能力。而现代的高性能处理器几乎都是乱序超标量结合体:顺序取指、顺序译码、顺序重命名,但发射和执行是乱序的,提交则又是顺序的。

这也带出一个核心思想:乱序执行不是随便乱来,而是为了让“已经就绪的指令”不要傻等“还没就绪的指令”,先把能干的活干了,但最终对外界观察到的结果必须严格按照程序顺序。这个“结果按序”的任务,就交给下面要说的提交级和重排序缓冲(Reorder Buffer,ROB)。

2.3 执行和提交:乱序执行不能乱序下结论

乱序执行带来的最大麻烦是:指令执行完成的顺序和程序顺序不一致了。假设程序顺序是A、B、C,结果B先算完了,A还没算完。如果这时候来个中断,CPU怎么知道程序执行到哪一步了?如果直接把B的结果写进架构寄存器,状态就乱了,因为程序是按照A、B、C的顺序期望状态的。

为了解决这个问题,超标量处理器引入了ROB。它的原理像一个环形缓冲队列,译码重命名阶段的每条指令按程序顺序在ROB里占据一个槽位。指令执行完之后,把结果标记为“已完成”,但先不提交;只有当ROB队头的指令变成“已完成”,才允许把它真正写到架构状态中,也就是提交(Commit)阶段。

这样设计的好处是:异常和中断发生时,CPU只要把ROB里没有提交(in-flight)的指令全部作废,把状态回滚到最近一条已提交指令那个点,就恢复了精确中断状态,程序可以从这个点重新开始,外部观察不到任何乱序痕迹。

ROB的容量很关键,它决定了可以同时有多少条指令在流水线里“在途”。现代乱序超标量处理器的ROB通常有128到512项左右。ROB越大,能容忍的乱序范围越大,越有机会填满发射槽,但硬件成本和实现复杂度和做时序收敛的难度都会上升。

3. 乱序执行的核心:寄存器重命名与三个依赖问题

3.1 三条经典冒险,只有RAW是“真冲突”

流水线那章我们讲过数据冒险,这里要再深挖一层。数据冒险其实有三种:RAW(Read After Write,写后读)、WAR(Write After Read,读后写)、WAW(Write After Write,写后写)。

RAW是真正的数据依赖:后一条指令要读前一条指令写的结果,比如前一条算完x1,后一条要用x1,顺序必须保持,这叫真依赖(true dependency),无法消除,只能“等”。

WAR和WAW属于名字相关(Name Dependency),本质上是两个指令用了同一个寄存器名,但实际数据流并不需要这个顺序。比如:

I1: R1 = R2 + R3 I2: R4 = R1 + 1 # 对I1的R1有RAW,必须等 I3: R1 = R5 + R6 # 和I1写同一个R1,WAW I4: R7 = R1 + R2 # 想读I3要写的R1

I1和I3都要写R1,如果I3先执行完,I1再写R1,最终R1的值就是I1的旧值,错了——这是WAW;I4要读R1,但如果I4先执行、I3后执行,I4读到的就是旧R1而不是I3的结果,这是WAR。如果硬件老实按顺序执行这些指令,就白白浪费了很多等待时间,ILP就被这些名字冲突吃掉了。

3.2 寄存器重命名怎么解决问题

寄存器重命名的思路非常直接:既然问题是多个指令共用同一个逻辑寄存器名,那就多准备一些物理寄存器,把逻辑寄存器名动态映射到不同物理寄存器上,让“重名”的指令实际上操作的是不同的物理寄存器。

比如上面那四行指令,如果CPU有16个逻辑寄存器、64个物理寄存器,重命名过程大概是这样的:架构里有一张寄存器别名表RAT(Register Alias Table),记录每个逻辑寄存器当前映射到哪个物理寄存器。指令I1要写R1,就分配一个空闲的物理寄存器P10,更新RAT使R1→P10;指令I3也要写R1,就再分配一个P20,更新RAT使R1→P20。这样一来,I1和I3写的是完全不同的物理寄存器,WAW冲突消失了。I4读R1时,RAT已经指向P20,所以I4会等I3的结果,和I1没关系,WAR冲突也消失了。

这就彻底消掉了WAR和WAW,剩下的只有RAW真依赖。物理寄存器文件的数量一般比逻辑寄存器多不少,常见的设计里物理寄存器数量是逻辑寄存器数量的2到4倍。为什么需要这么多?因为重命名不能随便覆盖旧映射,旧物理寄存器可能还有没读它的指令,必须等所有读它的指令都读完之后才能释放。如果物理寄存器不够用了,重命名阶段就必须停顿,前面的取指译码也会被堵住,这就是一种结构冒险。

学习到这里,强烈建议自己拿纸笔把上面这个小例子完整推一遍:每来一条指令,RAT变成什么,分配了哪个物理寄存器,原来映射的物理寄存器何时释放。推完三条指令,寄存器重命名的机制就通了。只读不画,很容易觉得懂了,实际做题就懵。

3.3 Tomasulo算法在超标量里的角色

说到乱序执行,绕不开Tomasulo算法。它最早用在IBM 360/91的浮点部件上,后来成了几乎所有乱序超标量处理器的调度理论基础。

Tomasulo的核心是保留站 + 公共数据总线(Common Data Bus,CDB)。保留站里保存指令和它需要的操作数状态。操作数没到,就监听CDB;CDB上广播的某个结果一旦匹配上自己需要的那个寄存器,就把数据捕获到保留站里。所有操作数都到齐了,指令就进入“就绪”状态,可以被发射到执行单元。

现代处理器里,CDB这种全局广播的方式已经很少直接使用,更多是分布式调度器,但“数据流驱动执行”这个思想没变:指令能不能执行,不取决于前面指令执行到第几步,而取决于自己需要的操作数是否已经产生。这个操作数可以来自寄存器堆,可以来自执行单元的直接转发(旁路网络),也可以来自CDB广播或专用的结果总线。

我在学习过程中踩过一个坑:把Tomasulo和Rename的功能搞混。重命名解决的是寄存器别名和WAR/WAW问题,让你摆脱名字冲突;Tomasulo解决的是“数据就绪后怎么尽快执行”的调度问题,让你摆脱顺序等待。两者是合作搭配的关系:重命名保证了后续指令不会因为名字冲突而被迫等待,Tomasulo保证了数据一就绪就能发射执行。

4. 分支预测和访存系统:两个最容易拖后腿的瓶颈

4.1 为什么分支预测在超标量里变得生死攸关

分支指令会带来控制流的不确定性。标量流水线里,每次分支预测错误可能只损失几拍;到了4发射、16级流水线的超标量处理器里,一次预测错误意味着:取指、译码、重命名、发射、执行中所有“在途”指令全部作废,可能一次就冲掉几十条指令的执行进度。预测错误率哪怕只差1%,在频繁分支的程序里累计下来的性能损失都相当可观。

所以现代超标量处理器在分支预测上投入巨大。预测器的构成通常包括:分支历史表(BHT)记录分支跳转的历史,常采用两位饱和计数器;分支目标缓冲器(BTB)记录分支跳转的目标地址;返回地址栈(RAS)专门用于call/return指令,因为函数返回的地址通常是压栈动态决定的,用历史栈可以预测得特别准;更高级的两级自适应预测器(比如gshare、锦标赛结构)则会结合全局分支历史和每一条分支的历史来动态选择预测策略。

分支预测准确率在现代高性能处理器里一般能到95%以上,甚至接近99%,但那一小撮预测错误依然会卡住性能,因为它们的惩罚太大了。还有一点容易被忽略:乱序执行里,预测错误之后不仅要冲刷在途指令,还要恢复RAT和ROB状态,这个恢复逻辑的快慢也直接影响分支惩罚周期数。

4.2 Load/Store队列与访存消歧

访存指令的乱序比普通ALU指令更麻烦。Load指令想提前执行,但前面Store指令的地址还没有算出来,你根本不知道这个Load访存会不会和Store冲突。如果Load先执行了,结果读到的是旧数据;等Store地址算出来发现地址重叠,就晚了。

硬件上常见的解决方案是Load-Store队列(LSQ)。ALU指令可以靠旁路网络快速转发结果,访存指令则需要在LSQ里做“访存消歧”:Load在执行前,先检查之前的Store地址是否可能重叠,如果确认不重叠,可以提前访存;如果不确定,就保守等待。当Load和之前的Store地址重叠时,Store的结果通常还在存储缓冲区里没写回Cache,Load直接从Store队列里把数据取出来,这叫存储转发(Store-to-Load Forwarding)。

访存的一个关键难点是:LSQ必须有很强的地址比较能力,而且处理逻辑复杂。现代处理器里,一个接收宽发射、高主频的访存子系统是最难设计的模块之一。很多程序里Cache缺失造成的停顿比执行单元的空闲还要致命,所以超标量的威力往往要配上足够好的Cache层次才能发挥出来。

4.3 Cache带宽和其他物理限制

多发射对Cache的带宽要求也是成倍上升的。4发射处理器的数据Cache可能需要每周期支持2到4个访问,这比单端口Cache复杂得多。多端口Cache的实现方式包括多bank划分、重复读取端口,但都会带来面积、功耗和命中率之间的权衡。指令侧也一样,I-Cache的带宽必须喂得饱发射宽度,否则发射槽必然空转。

物理限制不止在Cache上。发射队列越大,每周期要做的“选w条指令发射”的仲裁逻辑越复杂,时序越难收敛;寄存器堆的端口数越多,面积和延迟增长越快,比如寄存器堆面积的增长大约与端口数的平方成正比。这也是为什么现实主流处理器很少超过6到8发射。8发射以上的乱序超标量处理器,功耗和时序代价会急剧上升,收益却有限,因为程序本身的ILP也很难支撑那么宽的发射。

5. 超标量不是唯一路线:和VLIW、多核、SIMD的对照

5.1 四类并行路线的对比

超标量是挖掘指令级并行(ILP)的一条重要路线,但不是唯一路线。拿我学习时整理的对比表来看会更清晰:

技术路线并行层次并行性由谁发现优点缺点代表
超标量指令级(ILP)硬件动态调度软件透明、二进制兼容硬件复杂、功耗高Intel Core、ARM A7x
VLIW/EPIC指令级(ILP)编译器静态调度硬件简单、功耗低兼容性差、编译器压力大Itanium、部分DSP
多核线程级(TLP)软件提升总吞吐单线程性能提升有限各种多核CPU
SIMD数据级(DLP)编译器/硬件适合数据并行只适合特定负载GPU、NEON、AVX

VLIW(超长指令字)的思路是把发现并行的任务交给编译器。编译器在编译阶段分析出哪些指令可以并行,然后打包成一条很长的指令字,硬件只需要按照指令字里的并行槽去执行就行。这套路在DSP和某些嵌入式处理器上很有价值,因为功耗低、硬件简单。但在通用计算领域,Itanium的教训非常深刻:二进制兼容困难,编译器要精确预测运行时行为和访存延迟几乎不可能,实际IPC上不去。

多核和SIMD关注的是另外两个层面的并行性。多核跑的是线程级并行,适合高并发的服务器负载;SIMD关注数据级并行,比如图像处理、矩阵运算这类一个操作要套用到大量数据上的场景。它们和超标量不是替代关系,而是互补关系。现代高性能处理器都是乱序超标量 + SIMD + 多核的组合体。

5.2 Itanium的教训:硬件和软件分工的边界

Itanium是EPIC(显式并行指令计算)路线的代表,设计者希望用超长指令字把硬件的复杂度转移到编译器上。理论上很美,但在真实负载中,访存延迟不确定、分支行为和编译器预期不一致,静态调度很难做准。结果Itanium既没有在单线程性能上打过同期的x86超标量处理器,生态也没起来,最终成了教学案例。

这个案例反映出一个深刻的权衡:硬件的活可以隐藏复杂度和运行时不确定性,但代价是面积、功耗、设计验证成本都高;把活推给软件(编译器)可以简化硬件,但前提是软件能拿到足够准确的信息去调度。通用处理器选超标量,本质上是用硬件牺牲换来了一件最宝贵的东西——软件兼容性和运行时自适应性。你不需要重新编译程序,硬件自己就能把老的、新的、诡异的各类代码的ILP尽量挖掘出来。

5.3 为什么主流PC和服务器仍是乱序超标量的天下

过去二十年,主流PC和服务器处理器几乎都是乱序超标量,原因是通用负载的多样性决定了硬件动态调度是性价比最高的方案。程序运行时的行为、Cache命中情况、分支走向都不可能被编译器提前完整预知,硬件动态调度却能实时应对。

当然,在嵌入式、低功耗场景,顺序执行或者有限宽度的超标量反而更适合。比如一些低功耗ARM内核会采用顺序双发射配合深度流水线,因为乱序执行带来的额外功耗对续航不划算。所以超标量和乱序执行不是必须绑定,选择哪种组合完全取决于应用场景:要极致单线程性能,乱序宽超标量;要低功耗低成本,顺序窄超标量;要极限能效,再配合向量化和多核。

6. 学习路径、工具和常见误区排查

6.1 推荐的入门顺序和资料清单

学习超标量有一条比较顺的路径,我自己是按这个顺序走下来的:

  1. 先彻底搞懂流水线和数据冒险,RAW/WAR/WAW是基础,前面不熟,后面全是坑。
  2. 再学超标量最基本的概念:发射宽度、IPC、多发射带来的结构冒险。
  3. 然后学寄存器重命名,重点做手推练习。
  4. 之后学Tomasulo和乱序调度,结合保留站、ROB理解执行怎么乱序、提交怎么按序。
  5. 再去学分支预测、访存队列、指令缓存带宽这些工程细节。
  6. 最后挑一个具体处理器微架构来对照学习,比如RISC-V的BOOM,或者翻主流处理器的微架构分析文章。

资料方面,以下几份是我觉得价值最高的:

  • Hennessy & Patterson《计算机体系结构:量化研究方法》,第3章是超标量核心,适合建立完整框架。
  • 姚永斌《超标量处理器设计》,偏硬件设计视角,对重命名、ROB、发射队列解释得非常细。
  • 各类处理器微架构讲解文章,比如讲Intel Golden Cove或者AMD Zen的微架构分析,能联系实际。
  • gem5模拟器文档,适合动手做实验,不过要有心理准备,它的配置选项非常多。

额外提醒一句:在搜索学习资料的时候,注意区分“体系结构”这个术语在不同领域的含义。这些年搜“isse-cmm体系结构”或者“软件设计与体系结构”这类词,搜出来很多是软件工程、系统工程方向的内容,和硬件微架构完全是两回事。别点进去之后发现自己跑偏了。

6.2 用模拟器和性能工具观察IPC

学超标量不动手验证,总觉得隔着一层纱。最方便的实验工具是gem5。用它的O3CPU模型跑一个小程序,改几个关键参数就能直观看到超标量的行为。一个示例配置大致是:

./build/X86/gem5.opt configs/example/se.py \ --cpu-type=O3CPU --caches --l2cache \ --fetch-width=4 --dispatch-width=4 \ --rob-size=192 --cacheline_size=64 \ -c ./test_program

跑完之后在输出统计里重点看simInsts和simCycles,两者一除就得到IPC。你可以把发射宽度从4改成2,或者把ROB容量从192改成64,再看IPC变化。实测下来你会发现,IPC并不是随着发射宽度翻倍而翻倍,很多程序在4发射和8发射下的IPC提升非常有限,这就是ILP天花板和结构冒险一起作用的结果。

如果手头没有gem5,用Linux自带的perf也能看自己机器上的实际IPC:

perf stat -e cycles,instructions ./your_benchmark

输出里会有instructions和cycles,两者相除就是当前程序在这颗CPU上实际跑出来的IPC。你自己可以去试一下,绝大多数通用程序的IPC都在2到3之间,很难超过4,这比任何教科书都更有说服力。

这里有个很重要的实操感悟:当你看到实际IPC离标称发射宽度差很远的时候,不要觉得是处理器设计有问题。Cache缺失、分支预测错误、数据依赖、发射槽竞争,这些都是正常开销。处理器设计的目的不是把IPC推到理论极限,而是在功耗、复杂度、成本约束下尽可能逼近ILP收益曲线的拐点。

6.3 常见误区速查表

最后把我见过最多、我自己也踩过的几个认知误区整理成一张速查表,拿走直接用:

常见误区实际澄清
超标量等于多核完全不是。超标量是一个核内部的多发射,多核是多个物理核心并行
超标量等于乱序执行不对。超标量说的是发射宽度,乱序说的是调度策略。顺序超标量也存在,比如部分嵌入式RISC核
发射宽度越大性能一定越高不一定。ILP有限,资源竞争和功耗也会增加,超过拐点反而亏
寄存器重命名可以消除RAW依赖错。重命名消除的是WAR和WAW这些名字相关,RAW是真数据依赖,只能等
分支预测错误只是浪费几个周期在深流水线宽发射面前,一次预测错误可能冲掉几十条在途指令,代价极大
IPC可以接近发射宽度现实中受各种停顿因素影响,实际IPC往往只有发射宽度的三分之一到二分之一

这几点每一个都能对应到真实的处理器设计决策上。理解这些误区,比记住一堆术语有用得多。

说实话,我第一次接触超标量的时候,被Tomasulo和寄存器重命名绕得晕头转向。后来发现一个管用的笨办法:回到具体的指令序列,拿笔一步步推,把每条指令的物理寄存器分配、保留站占用、ROB状态都画出来,几轮下来就通了。另一件事是动手跑模拟器,光看书的增益真的很有限,只有自己把发射宽度改了、ROB容量调了、看到IPC跟着变化,才算真正建立了直觉。这篇就先聊到这里,下一章我们会把这些机制落到一个具体处理器的微架构上去。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 20:20:12

如何在 QEMU 中运行 Zephyr 示例应用并检查结果输出

如何在 QEMU 中运行 Zephyr 示例应用并检查结果输出 【免费下载链接】zephyr Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures. 项目地址: https://gitcode.com/GitHub_…

作者头像 李华
网站建设 2026/9/15 20:20:08

抖音无水印视频与直播批量录制:douyin-downloader 完整上手指南

抖音无水印视频与直播批量录制:douyin-downloader 完整上手指南 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallb…

作者头像 李华
网站建设 2026/9/15 20:15:37

Zemax光学设计全流程:从需求到公差分析实战指南

接到一个镜头设计任务,客户只有一句话:“要看得清。”焦距多少、口径多大、工作在哪个波段、像面用多大探测器,统统没提。这时候如果打开Zemax就开始堆镜片,那基本等于拿大炮打蚊子转圈,折腾到半夜也得不到能用的结果。…

作者头像 李华
网站建设 2026/9/15 20:15:00

Blender粒子系统实战指南:从发射器到毛发粒子的核心技巧

做了这么多年三维内容,我越来越觉得粒子系统是Blender里最被低估的功能之一。很多人一听“粒子效果”就联想到爆炸、烟火、魔法特效,觉得那是影视级项目才用得上的东西,实际上粒子系统在Blender里承担的工作远比你想的广泛:一片树…

作者头像 李华