CS450 定时器
实现一个定时器,该定时器对给定的时钟周期数进行倒计数,并在计数完成时断言一个信号以指示给定持续时间已结束。实现此功能的一种良好方式是使用递减计数器,当计数值变为 0 时断言输出信号。
每个时钟周期:
- 若 load = 1,则将内部计数器加载为 10 位数据 data,该数据表示定时器在超时之前应计数的时钟周期数。计数器可在任意时刻加载,包括仍在计数且尚未到达 0 时。
- 若 load = 0,则内部计数器递减 1。
输出信号 tc(“terminal count”,即终值计数)指示内部计数器是否已达到 0。一旦内部计数器达到 0,它应保持为 0(停止计数),直到计数器再次被加载。
以下是要求定时器计数 3 个周期时的行为示例:
参考答案
/* 模块功能:带同步并行加载的10位递减倒计时计数器 核心逻辑: 1. 时钟上升沿同步判定加载信号load:load有效则载入外部data数值;无效则计数器非零时逐周期递减,零时保持静止 2. tc为终端计数标志,计数器归0时输出高电平,其余时刻输出低电平 典型用途:定时倒计时、脉冲周期控制、超时触发电路 */moduletop_module(input clk,// 系统时钟,上升沿触发计数器状态更新input load,// 同步并行加载使能,高电平有效,优先级高于递减计数input[9:0]data,// 10位并行加载输入数据,load拉高时写入计数器output tc// Terminal Count终端计数标志,计数器为0时tc=1);reg[9:0]counter;// 10位时序寄存器,存储当前倒计时数值// 同步时序逻辑块:仅时钟上升沿执行状态更新,非阻塞赋值适配寄存器建模always @(posedge clk)beginif(load)begin// 加载优先:load有效,同步载入外部给定数据,覆盖原有计数值counter<=data;endelsebegin// 加载无效,倒计时模式:数值非0则自减1;数值为0保持不变,停止递减if(counter!=10'd0)counter<=counter-1'b1;end end// 纯组合逻辑连续赋值:实时判定计数器是否归零,输出终端标志tcassign tc=(counter==10'd0);endmodule输出结果
CS450 双二进制计数器
分支方向预测器通常组织为计数器表,由程序计数器(PC)和分支历史信息联合索引。每个表项通常采用两位状态,因为单比特状态(仅记录上一次预测结果)缺乏足够的迟滞(hysteresis)特性,导致状态翻转过于频繁。
两位饱和计数器的状态图如下:四个状态分别为强/弱 取(Taken,T)和强/弱 不取(Not-Taken,NT)
一种效果良好的两位状态机是饱和计数器[1],该计数器可递增至 3(即 2’b11)或递减至 0(即 2’b00),但不会发生溢出回绕。“取”的结果使计数器加 1,“不取”的结果使计数器减 1。当计数值为 2 或 3(即 2’b1x)时,分支预测为“取”。加入一定迟滞可防止在强偏置的分支偶尔出现相反方向时,预测值发生翻转;因为此时需要在相反方向连续递增两次,预测才会被翻转。
参考文献
- R. Nair,“最佳 2 位分支预测器”,《IEEE 计算机汇刊》,第 44 卷,第 5 期,1995 年 5 月。
题目描述
构建一个两位饱和计数器。
当 train_valid = 1 且 train_taken = 1 时,计数器递增(最大到 3);当 train_valid = 1 且 train_taken = 0 时,计数器递减(最小到 0)。当不进行训练时(train_valid = 0),计数器保持原值不变。
areset 为异步复位信号,将计数器复位为弱不取(2’b01)。输出 state[1:0] 为两位计数器的计数值。
参考答案
/* 模块功能:2位饱和型分支预测状态机(经典2bit饱和计数器分支预测器) 核心机制: 1. 高电平异步复位:复位后强制进入状态2'b01(弱不预测跳转) 2. 仅训练有效(train_valid=1)时更新状态: - train_taken=1(实际发生跳转):状态+1,上限饱和锁定2'b11(强预测跳转) - train_taken=0(实际不跳转):状态-1,下限饱和锁定2'b00(强预测不跳转) 3. train_valid=0无训练时,状态保持不变;内部寄存器直接对外输出当前2位状态 应用场景:CPU流水线分支方向预测模块 */moduletop_module(input clk,// 工作时钟,上升沿触发状态更新input areset,// 高电平异步复位,优先级最高,立刻复位无需等待时钟边沿input train_valid,// 训练有效使能:高电平允许根据分支结果更新状态input train_taken,// 分支实际结果:1=跳转发生,0=未跳转output reg[1:0]state// 对外输出当前2bit预测状态);reg[1:0]state_reg;// 内部状态寄存变量,保存饱和计数值// 时序逻辑:异步高复位+时钟上升沿状态更新,非阻塞赋值适配寄存器always @(posedge clk or posedge areset)beginif(areset)begin// 异步复位触发:强制初始化为弱不跳转状态 01state_reg<=2'b01;endelsebeginif(train_valid)begin// 训练有效:按分支实际结果做饱和增减if(train_taken)begin// 分支跳转:计数递增,上限饱和到最大值11(3)不再增加if(state_reg<2'b11)state_reg<=state_reg+1'b1;endelsebegin// 分支不跳转:计数递减,下限饱和到最小值00(0)不再减小if(state_reg>2'b00)state_reg<=state_reg-1'b1;end endelsebegin// 训练无效,不更新状态,保持原有计数值state_reg<=state_reg;end end end// 组合逻辑直通输出当前状态assign state=state_reg;endmodule输出结果
CS450 历史移位寄存器
分支方向预测器通常组织为计数器表,由程序计数器(PC)和分支历史信息联合索引。分支历史是指最近若干分支的“取”或“不取”结果序列。
在硬件实现中,分支历史寄存器可实现为 N 位移位寄存器。在每个条件分支方向被预测后,其预测方向被移入该移位寄存器。因此,该移位寄存器保存了最近的 N 个分支结果。
分支历史寄存器及其周边硬件。本练习构建的是蓝色虚线矩形内的分支历史寄存器。
图中显示分支执行单元发出分支预测错误信号,但根据处理器设计的不同,该信号也可能在指令提交阶段或其他时刻发出。
由于分支预测是推测性执行的,流水线冲刷会带来额外的复杂性。当发生分支预测错误时,处理器状态需要回滚到该错误预测分支之后的紧邻状态。这包括回滚全局历史寄存器,其中可能包含了比该错误预测分支更年轻的分支所移入的预测结果,但现在需要被丢弃。
我们在此假设分支预测器外部存在硬件,用于记住预测每个分支时所使用的分支历史寄存器状态,并将其保存以供后续的分支预测器训练和流水线冲刷使用。当发生分支预测错误时,该硬件通知分支预测器:某个分支预测错误、该分支应有的实际方向、以及对应程序中该错误预测分支之前紧邻点的分支历史寄存器状态。
当然,由于处理器重新从该错误预测分支之后的点开始执行,流水线冲刷后的分支历史寄存器需要追加该错误预测分支的实际方向。
题目描述
构建一个 32 位全局历史移位寄存器,包括支持因分支预测错误导致的流水线冲刷而进行状态回滚。
当进行分支预测时(predict_valid = 1),从最低位侧移入 predict_taken,以更新该预测分支的分支历史。(predict_history[0] 表示最新分支的方向。)
当发生分支预测错误时(train_mispredicted = 1),将分支历史寄存器加载为错误预测分支完成后的历史值。该值为错误预测分支之前的历史(train_history)与分支的实际结果(train_taken)拼接而成。
若预测和预测错误同时发生,则预测错误优先,因为流水线冲刷也会将当前正在进行预测的分支冲刷掉。
predict_history 是分支历史寄存器的当前值。
areset 为异步复位信号,将历史寄存器复位为零。
参考答案
/* 模块功能:32位移位型分支历史寄存器(CPU分支预测专用历史记录模块) 核心逻辑分层优先级(从高到低): 1. 高电平异步复位:立刻清空32位历史为全0,无需等待时钟边沿 2. 预测错误修正:预测出错时,截取旧历史高31位拼接实际分支结果train_taken,覆盖更新整体历史 3. 正常预测更新:预测有效时,原有历史左移1位、最低位补本次预测结果predict_taken,实现历史滚动记录 4. 无有效操作:历史值保持不变 输出直接对外暴露完整32位分支历史快照 */moduletop_module(input clk,// 系统时钟,上升沿触发历史寄存器更新input areset,// 高电平异步全局复位,优先级最高,即时清零历史// 正常预测通路端口input predict_valid,// 本次预测有效标志,高电平允许追加预测结果到历史末尾input predict_taken,// 本次预测的分支走向:1预测跳转、0预测不跳转output[31:0]predict_history,// 实时对外输出完整32位分支历史寄存器值// 预测错误训练修正通路端口(优先级高于正常预测)input train_mispredicted,// 分支预测错误标志,高电平触发历史回滚修正input train_taken,// 分支实际最终走向,用于修正历史最低位input[31:0]train_history// 预测出错前保留的旧32位分支历史快照);reg[31:0]history;// 32位时序寄存器,循环存储最近32次分支走向记录// 异步复位+时钟上升沿时序逻辑,非阻塞赋值适配寄存器建模always @(posedge clk or posedge areset)beginif(areset)begin// 异步复位生效:清空全部历史记录,初始化为32位全0history<=32'd0;endelseif(train_mispredicted)begin// 预测出错优先修正:保留旧历史高31位,最低位替换为真实分支结果// 语法{高位片段,最低位}:拼接组合生成修正后的完整32位历史history<={train_history[30:0],train_taken};endelseif(predict_valid)begin// 正常预测滚动更新:旧历史左移1位丢弃最早记录,最低位追加本次预测结果history<={history[30:0],predict_taken};endelsebegin// 既无错误修正、也无有效预测,历史值维持不变history<=history;end end// 组合逻辑直通输出:内部历史寄存器实时对外输出assign predict_history=history;endmodule输出结果
CS450 全局共享分支预测器(gshare 分支预测算法)
分支方向预测器
分支方向预测器用于生成条件分支指令的“取”或“不取”方向预测。它位于处理器流水线的前端附近,负责引导指令沿(希望是)正确的程序执行路径进行取指。分支方向预测器通常与分支目标缓冲器(BTB)配合使用,其中BTB预测目标地址,而方向预测器则决定是跳转到目标地址还是沿顺序路径继续取指。
在流水线的稍后阶段(通常在分支执行或提交阶段),已执行分支指令的结果会被反馈回分支预测器,以通过观察过往分支行为来训练其更准确地预测未来分支。当发生分支预测错误时,也可能触发流水线冲刷。
取指阶段内的分支方向预测器。该分支预测器借助当前程序计数器与历史寄存器完成预测,预测结果会对下一个程序计数器数值产生影响。流水线后端会发送训练请求与预测错误处理请求。
在本练习中,假设分支方向预测器位于右侧图所示假想处理器流水线的取指阶段。本练习仅构建分支方向预测器,即图中蓝色虚线矩形所指示部分。
分支方向预测采用组合逻辑路径:PC寄存器用于计算“取/不取”预测,该预测影响下一PC多路选择器,从而决定下一周期的PC值。
相反,模式历史表(PHT)和分支历史寄存器的更新则在下一个时钟上升沿生效,这与触发器存储状态的预期行为一致。
Gshare预测器
分支方向预测器通常组织为计数器表,由程序计数器和分支历史联合索引。表索引是分支地址与历史的哈希值,旨在为每个分支和历史组合分配独立的表项(或至少减少冲突)。每个表项包含一个两位饱和计数器,用于记录同一分支和历史模式在过去执行时的分支方向。
此类预测器的一个典型示例是Gshare预测器[1]。在Gshare算法中,分支地址(PC)与历史位“共享”表索引位。基本Gshare算法通过将N位分支地址位与N位全局分支历史位进行异或(XOR)运算,计算出N位的PHT表索引。
该N位索引随后用于访问具有2^N个表项的两位饱和计数器表。该计数器的值提供预测结果(0或1表示不取,2或3表示取)。
训练过程以类似方式对表进行索引。训练PC和历史用于计算表索引,然后根据分支的实际结果对该索引处的两位计数器进行递增或递减。
参考文献
- S. McFarling,“组合分支预测器”,WRL技术说明TN-36,1993年6月
题目描述
构建一个Gshare分支预测器,采用7位PC和7位全局历史,通过异或(XOR)散列为7位索引。该索引访问一个包含128个表项(每个表项为两位饱和计数器)的表(类似于cs450/counter_2bc)。分支预测器应包含一个7位全局分支历史寄存器(类似于cs450/history_shift)。
分支预测器具有两组接口:一组用于预测,一组用于训练。预测接口在处理器取指阶段使用,用于请求针对当前取指指令的分支方向预测。当这些分支沿流水线前进并被执行后,分支的真实结果变得已知,此时使用实际分支方向结果对分支预测器进行训练。
当针对给定PC请求分支预测时(predict_valid = 1),分支预测器产生预测的分支方向以及用于做出该预测的分支历史寄存器状态。随后,分支历史寄存器在下一时钟上升沿针对该预测分支进行更新。
当请求对某分支进行训练时(train_valid = 1),分支预测器会被告知该分支的PC、分支历史寄存器值、实际分支结果以及是否发生预测错误(需要流水线冲刷)。更新模式历史表(PHT)以训练分支预测器,使其下次更准确地预测该分支。此外,如果被训练的分支发生预测错误,还需要将分支历史寄存器恢复至该错误预测分支执行完成后的紧邻状态。
如果同一周期内同时存在预测错误训练和对另一更年轻指令的预测请求,则两者都希望修改分支历史寄存器。此时,训练操作优先,因为被预测的分支无论如何都会被丢弃。如果同一周期内对同一PHT表项同时进行训练和预测,则预测看到的是训练前的PHT状态,因为训练仅在下一个时钟上升沿修改PHT。以下时序图展示了在同一周期内对PHT表项0同时进行训练和预测的时序:周期4的训练请求在周期5改变PHT表项状态,但周期4的预测请求输出的是周期4的PHT状态,而未考虑周期4训练请求的影响。
在同一周期内使用PHT表项0同时进行训练和预测时:
areset 为异步复位信号,将整个PHT清零为 2’b01(弱不取),同时将全局历史寄存器清零为 0。
参考答案
/* 模块:Gshare 分支预测器 功能说明:采用PC地址异或全局历史生成查表索引,基于2bit饱和计数器实现分支跳转预测; 支持正常预测滚动更新全局历史、预测错误历史回滚修正、训练阶段更新模式历史表PHT,搭配高电平异步复位完成全局初始化,适用于CPU流水线分支预测场景 逻辑优先级固定:异步复位 > PHT训练更新 > 误预测历史纠错 > 正常预测历史移位 > 保持原值,原有业务逻辑完全保留未改动 */moduletop_module(input clk,// 系统工作时钟,上升沿触发PHT数组、全局历史寄存器时序更新input areset,// 高电平异步复位,边沿触发,拉高立即执行初始化,无需等待时钟上升沿// 预测查询通路端口组input predict_valid,// 预测有效标志:高电平代表本次分支预测查询合法,可输出预测结果并后续滚动更新全局历史input[6:0]predict_pc,// 待预测分支指令7位PC地址,参与查表索引运算output predict_taken,// 分支预测结果输出:1=预测分支跳转,0=预测分支不跳转output[6:0]predict_history,// 实时输出当前7位全局分支历史寄存器快照,供给外部模块调用// 训练纠错通路端口组input train_valid,// 训练有效标志:高电平代表本次分支真实结果有效,允许更新对应PHT表项饱和计数值input train_taken,// 分支真实跳转结果:1=分支实际跳转,0=分支实际不跳转,用于PHT计数更新、误预测历史修正input train_mispredicted,// 预测错误标记:高电平表示上一轮预测出错,触发全局历史回滚纠错逻辑input[6:0]train_history,// 出错前保存的7位全局历史快照,撤销错误预测写入的无效历史记录input[6:0]train_pc// 本次训练对应的分支7位PC地址,参与PHT更新索引运算);// 内部寄存器定义reg[6:0]history;// 7bit全局分支移位寄存器,记录最近7次分支跳转走向,参与索引计算与滚动更新reg[1:0]pht[0:127];// 128项模式历史表(PHT),每项存储1个2bit饱和计数器,记录对应分支长期跳转倾向integer i;// 循环遍历整型变量,仅异步复位阶段遍历初始化全部PHT表项// 组合逻辑:实时完成查表索引计算与预测结果输出wire[6:0]pred_index=predict_pc^history;// Gshare核心算法:PC异或全局历史,融合局部PC特征、全局分支趋势生成查表索引assign predict_taken=(pht[pred_index]>=2'b10)?1'b1 : 1'b0;// 2bit饱和计数判定:计数≥10判定跳转,否则判定不跳转assign predict_history=history;// 直通输出当前全局历史快照,组合逻辑实时跟随寄存器值变化// 时序逻辑:复位初始化、PHT训练更新、全局历史更新,原有判断分支、边界约束完整保留always @(posedge clk or posedge areset)beginif(areset)begin// 异步复位执行逻辑:全局历史清零,所有PHT表项初始化为弱不跳转默认态2'b01history<=7'd0;for(i=0;i<128;i=i+1)pht[i]<=2'b01;endelsebegin// PHT训练更新分支:训练有效时按真实分支结果做饱和增减if(train_valid)begin// 训练索引与预测索引算法一致:训练PC异或出错前历史,保证查表、更新指向同一表项if(train_taken)begin// 分支实际跳转:计数值递增,上限饱和锁定2'b11,避免溢出回绕if(pht[train_pc^train_history]<2'b11)pht[train_pc^train_history]<=pht[train_pc^train_history]+1'b1;endelsebegin// 分支实际不跳转:计数值递减,下限饱和锁定2'b00,避免数值下溢if(pht[train_pc^train_history]>2'b00)pht[train_pc^train_history]<=pht[train_pc^train_history]-1'b1;end end// 全局历史更新分支:误预测回滚优先级高于正常预测移位if(train_valid&&train_mispredicted)begin// 误预测恢复逻辑:截取错误前历史高6位,拼接真实分支结果覆盖末位,撤销错误预测写入的无效记录history<={train_history[5:0],train_taken};endelseif(predict_valid)begin// 正常预测更新逻辑:旧历史左移丢弃最早记录,末位追加本次预测结果滚动存储history<={history[5:0],predict_taken};end// 无触发条件时history默认保持原值,无需额外赋值end end endmodule