Skip to content

Lec 17 实现流水线:模块接口 & 并发

Lec 15/Lec 16 从“数据通路”角度讲了流水线与冒险;Lec 21 开始用模块实现流水线处理器。但一旦多个流水级在同一周期都活跃,我们就必须正面回答一个问题:多个原子规则如何在一个周期内并发执行、又保持正确? 本讲讲清这套并发语义,它是后面 Lec 23 旁路/EHR 的基础。

Outline

  • 用模块接口连接流水级
  • 守卫原子动作(rule)回顾
  • 一次一规则(one-rule-at-a-time)语义
  • 并发执行与规则冲突
  • 普通寄存器的同周期通信障碍
  • 模块化细化:换接口不改其它阶段

用模块接口连接流水级

流水线处理器 = 若干阶段模块 + 连接它们的状态元件

  • 阶段之间用 FIFO 传递(如 fetch→decode 的 f2d、decode→execute 的 d2e……),靠 enq/deq/first 的守卫握手(见 Lec 7 弹性流水线);
  • 共享状态:寄存器堆(decode 读、writeback 写)、PC(fetch 读写、execute 重定向)、指令/数据存储器。

每个阶段写成一条 rule:满足守卫(输入 FIFO 非空、输出 FIFO 不满)时触发,做本阶段的事、把结果 enq 给下游。因为阶段只通过接口通信,整张流水线就是一组并发活动的模块。

守卫原子动作(rule)回顾

回顾 Lec 8:rule 是守卫原子动作(guarded atomic action)

  • 原子(atomic):一条 rule 内对各状态的更新要么全发生、要么全不发生;
  • 读看旧值、写到周期末生效:rule 内读到的是“本周期开始时”的状态,<= 的新值下周期才可见。

一次一规则(one-rule-at-a-time)语义

理解并发的“黄金模型”:系统的行为,等价于每个周期只挑一条就绪的 rule、原子地执行,如此一条接一条。这给了我们一个简单、可推理的语义——无论编译器实际让多少条 rule 并行,最终效果必须等价于某个一次一条的串行顺序

但“每周期只跑一条 rule”太慢(5 级流水线岂不退化成 5 周期一条指令?)。所以实际实现里,编译器会让多条互不冲突的 rule 在同一周期并发触发,只要总效果仍等价于某个串行顺序即可。

并发执行与规则冲突

两条 rule 能否同周期并发,取决于它们对共享状态的访问是否冲突(conflict)

  • 都只读同一状态:不冲突,可并发;
  • 一读一写、或都写同一状态:冲突,不能无条件同周期执行——否则“谁的值算数”就不确定了。

冲突的两条 rule 同周期最多只能触发一条,另一条被推迟(相当于 Lec 16 的 stall)。冲突越多 → 能并发的 rule 越少 → 吞吐越低。 因此实现高吞吐流水线的关键,是尽量减少阶段间的冲突、或让冲突的访问能在一个周期内“有序地”共存。

每对方法/规则之间的关系可以用冲突矩阵刻画(CF=不冲突、C=冲突、/=有先后次序),详见 Lec 23

普通寄存器的同周期通信障碍

这正是问题的核心。用普通寄存器作共享状态时,无法在同一个周期(同一原子动作内)完成下列通信

  • 两个方法之间;
  • 两条规则之间;
  • 一条规则与一个方法之间。

为什么? 寄存器是时钟边沿触发的:本周期写入的值要到下个周期才出现在输出端。所以生产者 rule 这周期写、消费者 rule 这周期读——消费者只能读到旧值,拿不到“刚算出来的新值”。

后果:流水线里“前一条指令刚算出结果、后一条指令本周期就想用”的旁路需求,用普通寄存器实现不了,只能 stall。要在同一周期内先写再读、且读到新值,就需要一种新原语——EHR(Ephemeral History Register),它“记得本周期已经写过什么”,从而支持同周期通信与旁路。EHR 的语义、冲突矩阵与用它构建的并发/流水线/旁路 FIFO,见 Lec 23

模块化细化:换接口不改其它阶段

模块接口带来的最大好处是模块化细化(modular refinement):因为阶段之间只通过 FIFO 的 enq/deq 守卫接口通信,我们可以只替换某个 FIFO 的实现来改变并发行为,而不动其它阶段的代码

  • 普通 FIFO → 入队的值同周期内出队看不到,阶段间完全解耦(但可能要多停一拍);
  • 流水线 FIFO(pipeline FIFO) → 满时若同周期有 deq 腾位,则允许 enq
  • 旁路 FIFO(bypass FIFO) → 空时若同周期有 enq,则允许 deq,新值直接“绕过”存储送到出队口——这正是旁路在模块层面的体现。

换言之,“stall 还是 bypass”可以归结为“给这条流水线用哪种 FIFO”,而接口不变保证了正确性不被破坏。这就是用接口 + 并发语义实现流水线的威力:性能可调、正确性可控。(三种 EHR-FIFO 的细节见 Lec 23。)