资讯详情

资讯详情

流水线控制冒险优化:ID级提前判断与nop替换机制

简介这份电子科技大学2021年计算机体系结构实验四报告面向正在学习流水线CPU设计、需要攻克控制冒险难题的高校学生与Verilog初学者。报告围绕JUMP无条件跳转与BNE、BEQ条件跳转两类指令展开讲解如何在ID级提前比较寄存器值生成id_z信号、用nop部件将IF级预取指令替换为空指令并配合指令序列仿真验证方案有效性同时给出流水线结构图中新增功能部件与控制信号的标注说明。资源包共1个PDF文件约1.34MB完整收录实验原理、实验步骤、关键代码片段与电路结构图便于对照复现。该报告已有841人学习适合作为流水线CPU实验的参考范例帮助读者理解控制冒险与数据冒险叠加时的处理思路掌握Xilinx ISE平台下的Verilog实现方法。1. 控制冒险为什么一条跳转指令能让流水线“翻车”流水线 CPU 最反直觉的一点是指令还没执行完后面几条就已经被取进来了。顺序执行时这没问题可一旦遇到beq、bne、jump这类转移指令前面预取的指令可能根本不该执行。控制冒险要解决的就是这个矛盾——转移结果还没算出来流水线已经“抢跑”了。这份实验报告的价值在于它没有停在教科书式的“暂停流水线”上而是在 ID 级提前算出转移条件和目标地址用一条空指令把抢跑的那条指令顶掉把控制冒险的代价从多个周期压到最多一个周期。搞懂这套机制你才能真正理解流水线里“预测”和“废弃”这两个动作是怎么落到电路上的。2. 控制冒险的根源转移指令到底让流水线错在哪2.1 转移指令的延迟周期从哪来控制冒险也叫转移相关问题本质是程序计数器 PC 的更新时机和流水线取指节奏对不上。在顺序执行模型里PC 每取一条指令就加一个指令字长流水线各级按部就班往前推。但转移指令会改写 PC而改写 PC 所需的两个信息——转移是否发生、转移目标地址——都不是在取指阶段就能拿到的。实验报告里给了一个很关键的量化关系如果转移指令从取指到执行完毕需要 n 个周期那么有 n-1 条后续指令会受影响。这个 n-1 就是控制冒险的“罚款”。在经典的五级流水线里如果转移条件在 EX 级由 ALU 算出来那就要等三个周期罚款是两条指令如果提前到 ID 级算罚款就降到一条指令。这份实验的 CPU 把转移条件的判断和转移地址的偏移计算都放在了 ID 级所以转移指令只需要两个时钟周期就能确定下地址。代价是 IF 级已经在这两个周期里取进了一条新指令这条指令在转移发生时就是错的必须被废弃。理解这个“两个周期、一条罚款”的账是后面所有电路改动的出发点。2.2 单周期 CPU 和流水线 CPU 的判断时机差异单周期 CPU 里条件转移的判断依赖 ALU 计算后的 Z 标志控制部件拿到 Z 之后再产生rsrtequ信号一切都在一个周期内完成不存在“抢跑”问题。流水线 CPU 把一条指令拆到不同阶段Z 标志要到 EX 级甚至更晚才稳定而 IF 级不能干等着它必须继续取指。常见的实现思路有两种。第一种是暂停Z 标志没准备好就冻结 PC 和 IF/ID 寄存器一个周期等 Z 出来再决定。这种办法简单但每次条件转移都多花一个周期。第二种是提前判断在 ID 级加一个比较器直接比较寄存器堆读出的两个操作数不等 ALU 的 Z 标志。实验报告采用的正是第二种用id_z替代rsrtequ把判断时机从 EX 级前移到 ID 级。提示提前判断不是没有代价的。它需要额外的比较器硬件而且比较的是寄存器堆原始输出必须配合数据前推才能拿到最新值否则比较的就是过期数据。2.3 条件转移和无条件转移的差异处理条件转移beq、bne需要比较两个寄存器的内容判断是否相等或不等无条件转移jump则直接改写 PC不需要比较。两者在 ID 级都会算出目标地址区别在于是否要看id_z。实验报告里Control_Unit的输出pcsource承担了这个区分当 ID 级指令是转移指令且条件成立或无条件转移时pcsource输出01或10表示下地址来自转移目标否则输出00表示顺序执行。这个两比特信号同时驱动两个动作——更新 PC 和废弃 IF 级指令。把“判断”和“废弃”绑在同一个信号上是这套设计最紧凑的地方。3. ID 级提前判断比较器、id_z 和 pcsource 怎么串起来3.1 比较器的位置和 id_z 的两种写法实验在 ID 级增加了一个比较器输入是寄存器堆读出的两个值id_a和id_b输出id_z。报告给了两种等价写法// 写法一直接比较 assign id_z (id_a id_b) ? 1b1 : 1b0; // 写法二按位异或后归约或 assign id_z ~|(id_a ^ id_b);第二种写法在硬件上更自然先对两个操作数逐位异或只要有任何一位不同异或结果就不为零归约或|得到 1取反后id_z为 0全部相同则异或为零id_z为 1。这种“异或加归约”的比较结构在综合工具里通常映射成一条比较链延迟比减法器低适合放在 ID 级这种对时序敏感的位置。id_z的语义是“两个寄存器值相等”它直接替代了原来从 ALU 拿的 Z 标志。对于beq条件成立就是id_z 1对于bne条件成立是id_z 0。控制单元根据指令类型和id_z共同决定pcsource。3.2 Control_Unit 里 pcsource 的产生逻辑报告里Control_Unit的改动集中在转移指令的译码分支。用一段结构化的 Verilog 描述这个逻辑// 根据指令类型和 id_z 产生 pcsource // pcsource: 00 顺序执行, 01 条件转移成立, 10 无条件转移 always (*) begin case (op) OP_BEQ: pcsource (id_z 1b1) ? 2b01 : 2b00; OP_BNE: pcsource (id_z 1b0) ? 2b01 : 2b00; OP_JUMP: pcsource 2b10; default: pcsource 2b00; endcase end这段逻辑的关键在于pcsource不再等待 EX 级的 ALU 结果而是在 ID 级指令译码的同一个周期内就产生。beq看id_z为 1 才跳bne看id_z为 0 才跳jump无条件给10。pcsource为01或10时PC 的下一个值来自 ID 级算出的转移目标地址为00时PC 正常加四。注意pcsource的位宽和编码必须和 PC 选择逻辑严格对齐。报告里用01表示条件转移成立、10表示无条件转移这两个值在后续的 nop 部件和 PC 多路选择器里会被反复判断编码一旦写错表现就是跳转地址对但顺序指令被误废弃或者反过来。3.3 转移地址在 ID 级的计算路径转移目标地址的计算也在 ID 级完成。条件转移的地址通常是当前 PC 加上指令中的立即数偏移无条件转移则可能直接取指令中的目标字段。报告提到bpc和jpc两个目标地址信号分别对应条件转移和无条件转移。这条路径的时序压力不小ID 级要同时完成寄存器读出、比较、立即数符号扩展、地址加法然后送到 PC 多路选择器。常见的实现思路是把地址加法器独立出来不和 ALU 复用避免 ID 级和 EX 级争抢同一个加法资源。报告没有展开加法器的具体结构但从pcsource在 ID 级就影响 IF 级这一点看地址计算必须和比较器并行完成不能串行等待。4. 废弃抢跑指令nop 部件如何把 IF 级指令换成空指令4.1 if_inst 和 if_inst_org 的分工这是整套设计里最巧妙的一处。报告新增了if_inst_org信号作为 IF 级真正从指令存储器取出的原始指令而送入流水线寄存器 IR 的if_inst则经过一个选择// 当 ID 级检测到转移时用空指令替换 IF 级原始指令 assign if_inst (pcsource 2b01 || pcsource 2b10) ? 32h0 : if_inst_org;pcsource为01或10意味着 ID 级当前指令是“会跳”的转移指令此时 IF 级那条按顺序取进来的指令就是错的用32h0顶掉。32h0在全零指令编码下通常被译码成nop它流过流水线时不写寄存器、不写存储器、不改 PC等于一个无害的占位符。这个设计把“废弃”做成了“替换”而不是“清空流水线寄存器”。清空需要额外的使能控制和多路选择而替换只需要在 IF 级输出端加一个二选一改动面小时序也干净。4.2 为什么不需要封锁 WMEM 和 WREG报告里有一句容易被忽略但很关键的话转移指令只可能改变 PC不改变其它状态因此不需要封锁WMEM、WREG信号。原因是转移指令本身的译码结果里写存储器使能和写寄存器使能本来就是 0。被废弃的那条 IF 级指令虽然被换成了nop但即便它原本是一条会写寄存器的指令替换成nop之后写使能也为 0。换句话说这套方案的安全性建立在“nop 的译码结果全为无害”这个前提上。如果 nop 的编码定义不干净比如某位控制信号默认为 1那废弃动作就会引入副作用。这也是为什么报告强调用32h0而不是随便一个无效编码。4.3 空指令流过流水线时的时序从仿真波形看转移指令在 ID 级被识别的那一拍pcsource变化同一拍 IF 级输出被替换成nop。下一拍nop进入 ID 级而转移目标地址的指令进入 IF 级。再下一拍nop进入 EX 级目标指令进入 ID 级。整个过程只多了一个nop在流水线里占位没有冻结 PC也没有清空任何流水线寄存器。这种“插入气泡”的方式和暂停有本质区别暂停是让 PC 和 IF/ID 寄存器保持不动气泡是让流水线继续流动只是流进来的是无害指令。前者需要额外的使能逻辑后者只需要一个选择器。报告选择后者和它“在 ID 级提前判断”的整体思路是一致的——尽量用组合逻辑换时序而不是用控制状态机。5. 避坑与排查控制冒险实现里最容易翻车的几处5.1 现象条件转移该跳却没跳波形上 pcsource 一直是 00原因通常是id_z的比较对象不对。ID 级比较的是寄存器堆读出的id_a和id_b但如果前一条指令的结果还没写回这两个值就是旧的。报告里明确提到条件转移指令的比较寄存器与 ALU 或 LOAD 指令的目的寄存器相同时存在数据冒险必须依赖实验三建立的前推通路。解决方式是确认前推优先级EX 级 ALU 结果、MEM 级 ALU 结果、MEM 级 LOAD 结果哪一级最新就用哪一级。报告仿真里bne取的r5分别来自mem_mo、exe_alu_result、mem_alu_result三条不同前推线说明前推选择逻辑必须覆盖到 ID 级比较器的输入而不是只覆盖 ALU 输入。5.2 现象跳转发生了但跳转目标指令前面多执行了一条不该执行的指令原因是if_inst的替换条件和pcsource的更新不在同一拍生效。如果pcsource晚一拍才影响 IF 级那被废弃的指令已经写进 IR 了。报告的做法是让id_z在影响pcsource的同时影响IF_STAGE两者在同一个组合逻辑路径上。排查时看波形转移指令进入 ID 级的那一拍pcsource应该立刻变化同一拍if_inst应该变成32h0。如果if_inst晚一拍变说明替换逻辑多打了一拍寄存器需要把选择器挪到 IF 级输出端。5.3 现象无条件跳转后 PC 正确但流水线里残留了一条会写寄存器的指令这是jump的pcsource编码和 nop 替换条件没对齐。jump给的是10如果替换条件只写了01那jump后面的顺序指令就不会被顶掉。报告里替换条件是pcsource 2b01 || pcsource 2b10两个值都要覆盖。另一个容易漏的点是jump的地址计算。报告里jpc来自指令中的目标字段如果符号扩展或拼接写错PC 会跳到一个错误地址波形上表现为目标指令取错但pcsource看起来是对的。5.4 现象仿真通过上板后偶发跑飞组合逻辑路径太长是常见原因。ID 级要同时做寄存器读出、比较、地址加法、pcsource译码再送到 IF 级做指令替换这条路径如果超过一个时钟周期就会在高速时钟下出错。报告用的是仿真验证没有展开时序约束但实际实现时这条路径需要重点关注。解决思路是把地址加法和比较器并行化不要让pcsource等待地址计算完成如果仍然紧张可以把pcsource中不依赖id_z的部分比如jump的10提前译码减少关键路径上的逻辑级数。6. 设计取舍为什么把判断放在 ID 级而不是 EX 级这套方案的核心取舍是“用硬件换周期”。把比较器搬到 ID 级多了一个比较器和一条前推到 ID 级的通路换来的是转移罚款从两条指令降到一条。报告在改进建议里也提到其实还可以在 EX 级完成控制冒险处理但时间限制只做了 ID 级。这句话背后是一个真实的工程权衡ID 级方案罚款小但组合逻辑路径长、前推网络复杂EX 级方案路径短但要多废弃一条指令罚款更大。从验证角度看报告设计的指令序列很有代表性。它把条件转移和数据冒险交织在一起bne比较的r5来自 MEM 级前推beq比较的r4来自 EX 级前推最后一条bne比较的r5来自 MEM 级 ALU 前推。三类前推路径各覆盖一次等于用一条指令序列把“控制冒险 数据冒险”的交叉场景全测了。这种测试思路比单独测跳转更有说服力因为真实程序里转移指令的操作数往往就是前一条指令的结果。如果让我给这套设计提一个延伸方向我会关注转移预测。ID 级提前判断本质上还是“算出来再决定”罚款虽然降到一条但每次转移仍然有一个气泡。静态预测比如预测不跳可以在 IF 级就按顺序取指猜错了再废弃猜对了零罚款。把预测和 ID 级判断结合是流水线控制冒险从“消除”走向“隐藏”的下一步。我自己的习惯是每次改流水线控制通路先把pcsource的每一种取值和 IF 级替换条件列成真值表逐行对一遍波形再跑指令序列。控制冒险的坑大多不在逻辑本身而在“哪一拍生效”这个时序细节上。希望帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →