pipeline 概念

发布于:2025-05-09 ⋅ 阅读:(16) ⋅ 点赞:(0)

基础知识

  • 流水线(pipeline)
1.(机器)周期()cpu
2.(机器)周期()()流水线()cpu
	// 将一条指令的执行过程 划分为 多个 小过程(stage), stage 与 stage 之间加latch 
	// 可以简单认为 : N 周期 对应了 N 个stage(N级流水线) 
	// 5 级流水线(5-stage pipeline) 
	// 其实 大多数的stage都是一个机器周期 , 部分 stage 的 机器周期不定
3.(机器)周期()()流水线()cpu // 
  • 流水线中的latch
流水线 中 , 每个 stage 之间,都要
	1. 有 latch , 一组寄存器(pipeline register)来暂存当前阶段的结果 . 这些寄存器在时钟上升沿更新 ⇒ 就叫做“流水寄存器”或“阶段间寄存器”
	2. 打一拍 // 举例 : 将 Fetch(取指)阶段的输出 打一拍(打一拍 = 通过寄存器延迟一个周期),再送给 Decode(译码)模块使用。
		// IF 阶段每个周期会取出一些指令、PC、预测信息等;
		// 这些信号通过 流水线寄存器(你看到的这段代码),在 clk 上升沿锁存下来;
		// 锁存后的信号称为 *_if,然后在下一个周期供 ID 阶段使用。
  • 前端与后端
不管 pipeline 实现如何,  一般 都有前端 和 后端
前端 一般是 取指译码
后端 一般是 执行,...

前端与后端有接口
  • 超标量
注意 : 这里说的几个 , 一般是 在 rtl(流水线顶层) 代码中 实例化 几次
取指单元 译码单元 执行 写回
简单超标量 1(个) 1(个) N(个) 1(个)
复杂超标量 N(2/3/4/6/8/更多) N N N
SMT N(典型值为2/4/8) N 1 1
前后端的参数
  • 前后端的 stage
一条流水线 的 stage 可以分属21. 分属前端的stage
	2. 分属后端的stage

对于 ridecore 来讲
IF →  ID →  DP →           SW →  EX →  COM
↑前端 ↑前端 ↑前端           ↑后端  ↑后端 ↑后端

Ridecore 的前端是 2-way、3-stage 前端管线
Ridecore 的后端是支持最多 5 条指令同时 issue 的 3-stage 后端管线
  • 前后端的界限
在传统流水线中,发射(issue)常常被视为前后端的交界点,因为它既包含了指令的准备(前端的部分)也涉及了指令的执行调度(后端的部分)。

在复杂的动态调度流水线中,发射(issue) 主要属于后端,因为它涉及到执行单元的选择、调度以及执行顺序等任务。
  • 前端的way
前端重点是 Fetch/Decode 的宽度(way)

如果流水线 前端与后端的接口侧
	前端一次发送给后端1条指令 : 1-way
	前端一次"最多"发送给后端2条指令 : 2-way // Dual-Issue
		// 最多的意思是,  不是所有的指令对都能够被双发射的
  • 后端中的issue 即 N-issue
后端重点是 issue/execution 的吞吐能力(issue width)
后端设计中
	发射模块一次最多发送给 执行单元的 指令个数
		1: 1 issue
		2: 2 issue
		4: 4 issue // 4-issue:后端每周期最多可以发射(issue)4条指令;
部分 用词建议 说明
前端 “2-way fetch/decode” 表示同时处理两条指令
后端 “5-issue width” 表示支持每周期最多 issue 5 条指令
从多个层面看前后端
层面 前后端是一体 前后端分离
单条指令生命周期 ✅ 是连续的
多条指令并行处理 ✅ 逻辑功能和性能上分离
性能分析角度 ✅ 可能受限或瓶颈不同
设计角度 ✅ 逻辑功能上明确分离的
✅ 在设计架构时,不以“一条指令的完整生命周期”为主线,而是:
  • 将整条流水线拆解成多个功能模块(fetch、decode、rename、issue、execute、writeback、commit)。

  • 各模块各司其职,分别负责处理“指令流的一段阶段”。

  • 前后端的设计团队各自优化自己负责的区域,例如前端专注于:

    • 高带宽的 fetch
    • 精确的分支预测
    • 快速的 decode & rename

    后端专注于:

    • 高效的调度(issue logic)
    • 多发射(multiple execution units)
    • 精确提交(retire/commit)
    • ROB、RS、LSQ 等资源管理

顺序与乱序

什么是 序

多条指令在汇编文件中, 一条指令A在前,一条指令B在后.  如果 A后B // A后面为B
	// 这个我们可以很明确的在汇编文件 中看到 // 或者在反汇编文件中
一个指令(A/B) 在pipeline 中 被 分成多个 阶段,  每个 stage "开始执行" 的时机 为一个精确的时刻(我们称为 s1 s2 ... )
	// 这个我们可以在 rtl 中 , 仿真时, 拉信号看到
	
我们考虑顺序乱序, 只是 在考虑 在某个 stage 两条指令 是否顺序乱序
	1. 如果 100% 机率 As1 后 Bs1 , 那么 就叫做 s1 100% 顺序
	2. 如果 50%  机率 Bs2 后 As2 , 那么 就叫做 s2 乱序 (只要不能保证100%顺序,那么就叫顺序)

如果 有 1个 stage 乱序, 那么我们就叫做 这个 pipeline 乱序 , 即 Out of Order pipeline.
只要 有 1个 pipeline 乱序, 那么我们就叫做这个 cpu 乱序 

后端 执行阶段 是否乱序 是设计者决定的(使用动态调度算法,则乱序. 禁用,则顺序)

在前后端分离的CPU流水线设计中,后端执行阶段(Execution Stage)的指令到达顺序是否确定,取决于具体的设计选择。以下是关键点的分析和设计方法:


1. 指令到达顺序是否确定?

  • 默认情况下可能乱序:现代高性能CPU通常采用乱序执行(Out-of-Order Execution, OOO),后端执行阶段的指令到达顺序由动态调度逻辑(如Tomasulo算法)决定,而非程序顺序。执行顺序受以下因素影响:
    • 操作数就绪时间:数据依赖(RAW依赖)未解决的指令会等待。
    • 功能单元空闲情况:如乘法单元忙时,指令会被延迟。
    • 动态调度策略:如发射队列(Issue Queue)的优先级。
  • 顺序执行设计:如果设计为顺序执行(In-Order),则指令严格按程序顺序进入执行阶段。

2. 如何强制顺序执行?

若需保证指令按程序顺序到达执行阶段,需以下设计:

  • 禁用乱序逻辑
    • 顺序发射(In-Order Issue):仅当指令是程序顺序的下一条且操作数就绪时,才发射到执行单元。
    • 阻塞流水线:若前一条指令未完成,后续指令不进入执行阶段(类似经典5级流水线)。
  • 同步机制
    • 插入显式屏障指令(如FENCE),强制后续指令等待。
    • 通过数据依赖人为制造顺序(如用虚假寄存器依赖链)。

3. 如何实现乱序执行?

若需允许乱序执行,需以下设计:

  • 动态调度硬件
    • 保留站(Reservation Stations):指令在操作数就绪后立即执行,无需等待程序顺序。
    • 重排序缓冲区(ROB):跟踪指令状态,确保乱序执行的结果按程序顺序提交(Retire)。
  • 消除顺序约束
    • 寄存器重命名:消除虚假数据依赖(WAR/WAW依赖),释放指令并行性。
    • 多发射(Multi-Issue):允许每个周期发射多条独立指令到不同功能单元。

4. 设计示例对比

顺序执行设计
前端(取指/解码) → 顺序发射队列 → 执行单元(按序)
  • 行为:指令B必须等待指令A执行完毕,即使B的操作数已就绪。
乱序执行设计
前端(取指/解码) → 重命名/发射队列 → 保留站 → 执行单元(乱序) → ROB → 提交(按序)
  • 行为:若指令B的操作数先就绪,可先于指令A执行。

5. 关键权衡

  • 顺序执行:硬件简单(适合低功耗场景),但性能较低。
  • 乱序执行:提高IPC(指令级并行),但增加功耗和面积(复杂的调度逻辑)。

总结

  • 顺序到达:需禁用动态调度,按程序顺序发射指令。
  • 乱序到达:启用保留站、寄存器重命名和ROB,允许指令就绪后立即执行。

设计时应根据目标场景(高性能/低功耗)选择策略,并通过硬件调度逻辑控制顺序性。


网站公告

今日签到

点亮在社区的每一天
去签到