第二讲:CPU微架构入门
指令集架构(ISA)与微架构的区别
很多刚入行的同学,容易把指令集架构和微架构搞混。我当年也犯过这个错。
简单来说,指令集架构(ISA)是程序员看到的计算机。它定义了CPU能执行哪些指令、寄存器怎么用、内存怎么访问。而微架构是硬件工程师怎么实现这个ISA。同一个ISA,可以有完全不同的微架构。
举个例子。x86指令集,Intel和AMD都在用。但Intel的Core微架构和AMD的Zen微架构,内部设计天差地别。你想想看,它们跑同样的程序,结果一样,但速度、功耗完全不同。这就是ISA和微架构的区别。
核心区别一句话:ISA是“做什么”,微架构是“怎么做”。
我在项目中遇到过一件事。有个同事非要自己设计一套ISA,觉得这样更酷。我劝他别这么干。为什么?因为没有软件生态支持。你设计个新ISA,编译器要重写、操作系统要适配、应用软件要重新编译。这工作量,一个团队几年都搞不定。
所以,工业界的主流做法是:用成熟的ISA(比如ARM、RISC-V),然后在微架构上做创新。这才是正道。
经典5级流水线
流水线这个概念,说白了就是“分工合作”。
想象一下洗车。一个人洗车,要完成:冲水→打泡沫→擦洗→冲净→擦干。如果只有一个人,他得按顺序做完所有步骤。但如果五个人各负责一步,那效率就上来了。第一辆车冲完水,第二辆车就可以开始冲水了。这就是流水线。
经典的5级流水线,把一条指令的执行分成5个阶段:
| 阶段 | 英文 | 做什么 |
|---|---|---|
| 取指 | IF | 从内存中取出指令 |
| 译码 | ID | 解析指令,读取寄存器 |
| 执行 | EX | ALU计算或地址计算 |
| 访存 | MEM | 访问数据内存(仅load/store指令需要) |
| 写回 | WB | 将结果写回寄存器 |
每个阶段用一个时钟周期完成。理想情况下,每个时钟周期都能完成一条指令。这就是CPI=1的由来。
嗯,这里要注意。流水线不是免费的午餐。它带来了三个问题:结构冒险、数据冒险、控制冒险。我们重点讲后两个。
数据冒险
数据冒险,说白了就是指令之间有数据依赖。
看个例子:
add x1, x2, x3 // x1 = x2 + x3
sub x4, x1, x5 // x4 = x1 - x5
第二条指令要用x1,但第一条指令还没把结果写回寄存器。这就出问题了。
我刚开始做CPU设计时,就踩过这个坑。当时写了个简单的RISC-V处理器,跑测试程序时发现结果总是不对。查了两天才发现,是数据冒险没处理好。
解决数据冒险,有三种常用方法:
- 插入气泡(Stall):让流水线停几个周期,等数据准备好。简单但性能差。
- 转发(Forwarding):把计算结果直接送到需要它的地方,不用等写回寄存器。这是最常用的方法。
- 编译器调度:让编译器重新排列指令顺序,减少数据依赖。
我的建议:转发逻辑一定要做全。我见过有些设计只做了部分转发,结果遇到某些指令组合还是出错。与其后期打补丁,不如一开始就把所有转发路径都实现。
控制冒险
控制冒险,就是分支指令带来的问题。
你想想看,CPU取指时,下一条指令的地址取决于分支指令的结果。但分支指令还在流水线里跑着,结果还没出来。这时候该取哪条指令?
这就是控制冒险的根源。
常见的处理方法:
- 分支预测:猜一个方向,先取指令执行。猜对了就继续,猜错了就清空流水线。
- 延迟槽:在分支指令后面放一条一定会执行的指令。MIPS架构用过这个办法。
- 静态预测:简单的预测策略,比如“向后跳转预测为真,向前跳转预测为假”。
我曾经在一个项目里,分支预测器做得太简单,导致预测准确率只有70%。结果流水线经常被清空,性能还不如没有流水线。后来换了个两比特饱和计数器,准确率提升到90%以上,效果立竿见影。
避坑指南:分支预测器的设计,一定要结合你的应用场景。如果是控制密集型的程序(比如操作系统),分支预测的准确率直接影响性能。如果是计算密集型的程序(比如矩阵运算),分支预测就没那么重要。我曾经见过有人不管三七二十一,上来就搞了个复杂的预测器,结果面积和功耗都上去了,性能提升却微乎其微。
小结
这一讲我们聊了三个核心概念:
- ISA是接口,微架构是实现。两者要分开理解。
- 5级流水线是经典设计,每个阶段各司其职。
- 数据冒险靠转发解决,控制冒险靠分支预测解决。
下一讲,我们会深入流水线的控制逻辑,看看怎么用Verilog把这些东西实现出来。到时候我会分享一些具体的代码和调试经验。
公众号:蓝海资料掘金营,微信deep3321