一、流水线实验回顾
1.1 实验进度
流水线中的组件本质上与单周期类似,主要新增的是各级之间的流水线寄存器(pipeline registers)。基础模块(单周期各组件)一定要测试好——单模块组件测试通过后,后面的连接和流水线级间寄存器就没有太多复杂的事。模块不对就没法调,没有什么能调的余地。
可以使用大模型帮助检查基础模块代码。
1.2 实验扩展支持
有同学想做额外的乘法器和除法器——不管有什么自己的想法,只要课程/lab 要求上没有也没关系,只要自己感兴趣,可以单独沟通实现要求。
二、指令集体系结构(ISA)设计
2.1 为什么要设计指令集
指令集(Instruction Set Architecture, ISA)是软件和硬件之间的契约/语言。指令集设计的好坏直接决定了 CPU 实现的难易程度。
指令集就是给 CPU 下命令的语言。如果一门语言设计得不好,CPU 就会很痛苦。新指令集不断冒出来,又有老的不断死掉——都是经过了市场选择。
指令集有两个核心要求——清晰高效。对硬件设计者来说,指令集能不能让设计电路时简单一点?第一少干点活,第二干的活尽量简单,不要来回折腾。
看着上面的应用层跑得很开心,但底层硬件才是负重前行的。设计指令集的时候,得让硬件实现也轻松一点。
2.2 自然语言 vs 严谨形式语言的讨论
一个开放性问题:大模型时代,为什么不能用自然语言直接给计算机下指令?
数学之所以要有一套严谨的表达式和公式体系,是因为自然语言不严谨。拿一个不严谨的、开放的语言来让大模型替我们完成严谨的工作,这显然是有问题的。软件工程为什么强调”给我写个文档”——落到纸面上就会慎重,条列清楚才能看懂。
vibe coding 现在很火,但到底以后会怎么发展,值得思考。
2.3 指令的基本构成
一条指令需要包含以下信息:
- 操作码(Opcode):告诉 CPU “干什么”
- 操作数地址:数据在哪里(寄存器、内存、I/O端口、指令本身中的立即数)
- 下一条指令地址:如何找到下一条指令(顺序执行或跳转)
数据和指令都存放在主存中,CPU 取指令和取数据可能产生冲突,需要仲裁机制。
2.4 指令格式:固定长度 vs 可变长度
一条指令的长度有两种策略:
- 固定长度:每条指令长度相同,简单但可能浪费空间
- 可变长度:根据指令复杂度长度可变,节省空间但解码复杂
指令格式要有足够的操作码位数预留。因为随着业务发展,新指令会不断出现。比如现在 AI 时代,英特尔发现某些 AI 算法中有些操作特别频繁,想加几条指令来支撑 AI 算法——操作码位数不够就完了,指令集就”死了”。
三、地址码与寻址方式
3.1 地址码数量
根据指令中显式指定的操作数地址个数,分为:
| 类型 | 地址码数 | 特点 | 示例 |
|---|---|---|---|
| 零地址 | 0 | 操作数位置隐式约定 | nop, push, pop |
| 一地址 | 1 | 另一个操作数默认在累加器 ACC | add R1(ACC + R1 → ACC) |
| 二地址 | 2 | 两个寄存器操作数 | add R1, R2(R1 + R2 → R1) |
| 三地址 | 3 | 两个源操作数 + 一个目标 | add R1, R2, R3(R2 + R3 → R1) |
3.2 历史演变与RISC的选择
早期硬件(电子管时代)非常昂贵,多一条指令都是要命的,所以指令集设计极度精简,能用软件解决的问题尽量不交给硬件。
现在是 RISC 风格——有钱了,就别那么抠了,指令格式规整、清清楚楚地写好,实现也简单。
x86 是从 8086 一步步发展起来的,上面承载着辉煌的历史,也承载着沉重的历史包袱。当接手一个老指令集时,”全都有”——想扔掉旧的?千万小心,一扔也许把公司就扔掉了。而 RISC-V 是白手起家,没有包袱。
RISC-V 经历了多个版本迭代(I, II, III, IV, V),到第5版才获得业界公认。RISC-V 的风格是:指令用二地址或三地址格式,寄存器-寄存器操作,load/store 单独两条指令访存,其他指令只在寄存器间操作。
四、RISC 设计原则
4.1 核心原则
- 指令尽量短小规整:固定长度,简化取指和解码
- 足够的操作码位数:为未来扩展预留空间
- Load/Store 架构:只有
load和store两条指令访问存储器,其余在寄存器间操作 - 简单就是美:硬件希望”少干点活,多拿点工资”——指令简单,电路就简单
4.2 硬件 vs 软件的权衡
| 维度 | 硬件 | 软件 |
|---|---|---|
| 复杂度代价 | 芯片面积增大 → 生产成本高 | 多写代码、熬夜加班 |
| 修改成本 | 流片后无法修改 | 随时可以更新 |
| 核心诉求 | 指令简单、固定格式 | 指令丰富、表达能力强的 |
软件工程师永远有活——硬件干完就没什么事了,但软件总在迭代。哪部分该软件辛苦一点熬夜,哪部分该硬件承担,架构师需要做权衡。因为硬件要生产——面积大就贵;软件熬两个通宵就做好了。
4.3 永远保留扩展空间
指令集设计必须为未来留空间。当 AI 算法出现后,发现某些计算模式特别频繁,能否在指令集中加入专用指令加速?如果操作码位数用尽,就只能眼巴巴看着竞争对手抢占 AI 芯片市场。