09 · 旧期中扩展:处理器体系结构
**不在当前日程所示第一次阶段测验第 1~8 讲内。**为覆盖旧期中真题补充,主线对应教材第 4 章。不同年份有 Y86-32 与 Y86-64,必须先确认字长、寄存器和编码长度。
Y86-64 程序员模型#
15 个 64 位通用寄存器(x86-64 的 r15 不在教材 Y86-64 的普通寄存器集合),PC,ZF/SF/OF,字节寻址内存,状态码 AOK/HLT/ADR/INS。RNONE(0xF)表示不使用寄存器,不是实际寄存器。
| 指令 | 功能 | 教材常见长度 |
|---|---|---|
| halt / nop / ret | 停止 / 空操作 / 返回 | 1 字节 |
| rrmovq / cmovXX、OPq、pushq/popq | 寄存器/条件传送、算逻、入栈出栈 | 2 字节 |
| irmovq / rmmovq / mrmovq | 立即数传送、存内存、取内存 | 10 字节 |
| jXX / call | 条件或无条件跳转、调用 | 9 字节 |
首字节含 icode/ifun,可能再有 rA/rB 字节、8 字节小端 valC。Y86 的 jXX/call 使用题设定义的目标编码,不要套 x86 相对偏移的规则。Y86-64 没有完整 x86 指令集,不能凭空用硬件未支持的乘除或寻址形式。
组合逻辑、状态与 HCL#
组合电路输出由当前输入决定;时序电路含寄存器、存储器等状态。时钟周期必须容纳关键组合路径加寄存器开销。位与逻辑布尔、字比较、集合包含和多路选择器是 HCL 的基础。
word value = [
condition1 : expression1;
condition2 : expression2;
1 : default_expression;
];
从上到下选第一个成立条件,不是“所有分支并行赋值”。x in {A,B} 表示比较集合成员。控制逻辑描述硬件选择,不是带无限临时存储的普通 C 程序。
SEQ 的六个逻辑阶段#
F 取指:读 icode/ifun、寄存器字段、常数、算 valP;D 译码:读源寄存器 valA/valB;E 执行:ALU 得 valE、判断条件并可能更新 CC;M 访存:读得 valM 或写内存;W 写回:写 dstE、dstM;更新 PC:选 valP、valC 或 valM。SEQ 在一个较长周期内完成一条指令的这些逻辑工作。
| 指令 | 执行/访存核心 | 写回 | next PC |
|---|---|---|---|
| OPq rA,rB | valE=R[rB] op R[rA],设置 CC | rB←valE | valP |
| irmovq V,rB | valE=V | rB←valE | valP |
| rmmovq rA,D(rB) | 地址 R[rB]+D,写 R[rA] | 无 | valP |
| mrmovq D(rB),rA | 地址 R[rB]+D,读 valM | rA←valM | valP |
| pushq rA | valE=rsp-8,M8[valE]=valA | rsp←valE | valP |
| popq rA | valE=rsp+8,valM=M8[旧 rsp] | rsp←valE,rA←valM | valP |
| call Dest | rsp-8;把 valP 写新栈顶 | rsp←valE | valC |
| ret | 读旧栈顶返回地址;rsp+8 | rsp←valE | valM |
| cmovXX | 条件成立才给有效 dstE | 条件成立写 rB | valP |
| jXX | 计算 Cnd | 无 | Cnd?valC:valP |
popq %rsp 同时涉及两路写回同一寄存器,按教材优先级处理,不是任意顺序都等价。设计新指令时必须列出每阶段读写、资源是否够用、条件码时机、异常行为和 PC。
流水线的吞吐与延迟#
k 级流水线、n 条理想指令,从第一条进入 F 到最后一条离开 W 需 n+k-1 周期。实际还要加停顿和错误路径处罚,避免漏灌入/排空。时间=周期数×周期时长。
若各阶段组合延迟 tᵢ、寄存器开销 r,流水线时钟至少 max(tᵢ)+r;单条延迟约 k 个周期,吞吐可近似每周期一条。分级不均匀、寄存器开销、分支与数据冒险使加速达不到 k 倍。算频率时 ps 与 ns 换算不可漏掉 r。
数据冒险与前递#
后续指令要读前面尚未写回的寄存器,形成 RAW 数据依赖。前递把新结果送到使用位置,优先采用程序顺序上最近的生产者。教材 PIPE 的译码前递常用优先级:e_valE → M 阶段加载的 m_valM → M_valE → W_valM → W_valE → 寄存器文件。
D 阶段的 call/jXX 所需 valA 是 D_valP,须优先处理。条件传送不成立时 e_dstE 应为 RNONE,避免转发不存在的更新。不能只比较 E_dstE 而忽略条件。
load/use:紧邻 mrmovq/popq 的消费者在下一周期 E 阶段需要值,但加载到 M 阶段末才可得,教材默认前递仍需一个停顿:F stall、D stall、E bubble,前面的加载继续向 M/W 前进。
L = E_icode in {IMRMOVQ, IPOPQ}
&& E_dstM in {d_srcA, d_srcB}
2024 题加了 M→E 的 store-data 前递,可消除“加载值仅用作 push/store 写入数据”的某些停顿;若加载结果是 store 的地址基址,地址生成仍在 E 需要它,不能同样消除。
控制冒险与 PIPE 控制#
教材 PIPE 常预测 jXX 跳转;在 E 得知不该跳转时冲刷错误路径。ret 的目标来自内存,要等待返回地址,不能像直接 jmp 提前知道。
R = IRET in {D_icode,E_icode,M_icode}
B = E_icode==IJXX && !e_Cnd
F_stall = L || R
D_stall = L
D_bubble = B || (!L && R)
E_bubble = B || L
这里是教材普通 PIPE 模型的关键部分;完整实现还包括异常的 M/W 控制、CC 更新门控、预测 PC 选择等。异常指令后面的指令不能提交可见副作用。题目修改分支决策阶段、加载延迟或返回机制后,重新画时空图,不硬背固定处罚。
stall 保持该流水线寄存器,bubble 注入空操作,normal 接受下一组值;二者不是同义词。同周期既要 stall 又 bubble 的冲突必须由逻辑消除。
新指令设计通用答题法#
- 写出不可歧义的 ISA 语义:旧值/新值、内存宽度、条件失败行为。
- 标注编码、长度与 valP;确认所需 rA/rB/valC。
- 为 F/D/E/M/W/PC 分别列信号;检查一次内存访问和两个写回端口是否足够。
- 判断结果产生阶段、消费者使用阶段,补充前递、暂停和冲刷。
- 用别名寄存器(尤其 rsp)、条件失败、异常、相邻依赖做边界推演。
RISC/CISC 与性能拓展#
RISC 常强调较简单指令和寻址、load/store 结构;CISC 常有复杂指令与多种编码。但“RISC 所有指令固定长”“RISC 必比 CISC 短/快”不是普遍定理。现代实现可能把指令拆为内部操作,ISA 标签不能直接预测性能。
自检:能独立填写 push/pop/call/ret 六阶段表、推导 load/use、画五级时空图、计总周期、说明新指令为何需要某条额外数据通路。