【CPU微架构设计】利用Verilog设计基于饱和计数器和BTB的分支预测器

  在基于流水线(pipeline)的微处理器中,分支预测单元(Branch Predictor Unit)是一个重要的功能部件,它负责收集和分析分支/跳转指令的参数和执行结果,当处理新的分支/跳转指令时,BPU将根据已有的统计结果和当前分支跳转指令的参数,预测其执行结果,为流水线取指提供决策依据,进而提高流水线效率。

  下面讨论提出分支预测机制的主要原因和实际意义:

  在流水线处理分支跳转指令时,目标地址往往需要推迟到指令的执行阶段才能运算得出,在此之前处理器无法及时得知下一条指令的取指地址,因此无法继续取指。一种解决方法是在识别分支指令后,令取指流水级及相关的流水级暂停(stall),等待分支目标地址计算完成后再继续取指。这将浪费若干流水线时钟周期,从而降低性能。采用这种方法的流水线暂停效果示意图如下:

(附图:经典的四级流水线中分支指令引发的流水线暂停示意图,坐上紫色方块代表分支指令。由于采用简单的理想流水线,分支指令目标地址在执行阶段即可得出,这将浪费一个流水线时钟周期)

  为改进以上方法, 我们考虑引进一种静态分支预测机制,即预测分支跳转指令一定不跳转(not taken),则上述情况将成为:默认分支跳转指令之后的指令也流入pipeline,在若干流水级后,分支指令的地址将被计算得出,此时才判断之前流入流水线的指令是否为实际目标地址所指向的指令,若真,流水线可以继续运行而不必暂停;但若假,则之前流入的指令都无效,相关流水级将被冲刷(flush),处理器只能重新从正确的地址开始取值,这将同样降低流水线的效率。

  可以看到,采用静态预测后,在处理分支/跳转指令时,流水线在一定概率下将不会因分支而暂停,这就降低了出现流水线气泡周期的可能性。然而,在对性能要求较高的场合,此方法仍旧不能令人满意。

  为进一步提高效率,我们考虑动态分支预测机制。动态预测基于对分支历史的记录统计,预测出分支跳转的“方向”和“目标地址”。若处理器按照预测结果取指,则一旦预测结果与实际跳转结果相同,之前流入流水线的指令将完全有效,流水线将维持运行。处理器按照预测出的“方向”和“目标地址”进行取值的行为称为预测取值(Speculative Fetch),执行按照预测结果取出的指令的行为称为预测执行(Speculative Execution)

  随着预测算法的不断改进,当前分支预测的准确率不断向1逼近,分支预测技术有效提高了流水线的运行效率,被大量运用到主流微处理器中。

一、分支预测需要解决的问题

  (1)、预测分支是否发生,即预测“方向”的问题;

  (2)、预测分支指令设置的取值地址,即预测“目标地址”的问题。

二、分支预测单元的设计实现

  常见的分支预测机制主要可分为一级结构和两级结构。对于两级预测器,常见的算法包括gsharegselect算法,这种算法考虑到分支指令的上下文执行历史,精度相对较高,但实现相对复杂,本文不予讨论。对于一级预测器,其设计是将多个饱和计数器和BPU组织成一维向量表,利用分支/跳转指令PC值的hash映射值寻址一维向量表。这种预测器结构最为简单,本文将针对这种结构做详细的讨论。

 2.1 分支方向的预测

  本文采用2bit的饱和计数器,用于寄存4种状态。根据预测结果和实际执行结果,计数器的值将按照如下所示状态机转移图转移。

  图中跳转(taken)和不跳转(not taken)两种状态分别被进一步细分为强(strong)和弱(weak)共四种状态,并规定strongly taken和weakly taken为“跳转”、strongly not taken和weakly not taken为“不跳转”,且每当预测出错后,计数器会以相反方向更改状态,这种做法的本质其实是一种“阻尼式”的切换。

 2.2 分支目标地址的预测

  为了简化设计,本文主要讨论基于分支目标缓存(Branch Target Buffer)技术的预测器。BTB使用容量有限的缓存寄存最近执行的分支指令的目标地址。对于后续分支指令,预测时直接取出对应表项中寄存的地址作为目标地址预测值。当分支指令被执行后,将实际的目标地址回写入BTB中,为下次预测提供依据。

  本设计中,使用使用分支指令PC值的hash映射值寻址BTB表项,使得每条分支跳转指令都能与BTB表项建立起映射关系。

  其中,我们定义PC值的hash映射规则如下:

  ∫ V(PC) → V(hash), f(p) , f(p) = p & 1111111111b  (即取出PC值的低10位作为对应的hash映射值)

 2.3 设计总体框架

  综上所述,分支预测器的总体结构如下,可以看出,该预测器具有极其简单的结构:

三、硬件描述语言实现

  通过以上讨论,容易使用Verilog HDL实现分支预测器。

  值得注意的是,这里仅对饱和计数器进行非溢出的递增或递减,利用计数值的最高位判断是否发生跳转,1为taken,0为not taken。

 1 module bpu
 2 #(
 3    parameter PCW = 30, // The width of valid PC
 4    parameter BTBW = 10, // The width of btb address
 5 )
 6 (/*AUTOARG*/
 7    // Outputs
 8    pre_taken_o, pre_target_o,
 9    // Inputs
10    clk, rst_n, pc_i, set_i, set_pc_i, set_taken_i, set_target_i
11    );
12
13    // Ports
14    input             clk;
15    input             rst_n;
16    input [PCW-1:0]   pc_i; // PC of current branch instruction
17    input             set_i;
18    input [PCW-1:0]   set_pc_i;
19    input             set_taken_i;
20    input [PCW-1:0]   set_target_i;
21    output reg        pre_taken_o;
22    output reg [PCW-1:0] pre_target_o;
23
24    // Local Parameters
25    localparam SCS_STRONGLY_TAKEN = 2‘b11;
26    localparam SCS_WEAKLY_TAKEN = 2‘b10;
27    localparam SCS_WEAKLY_NOT_TAKEN = 2‘b01;
28    localparam SCS_STRONGLY_NOT_TAKEN = 2‘b00;
29
30    wire bypass;
31    wire [BTBW-1:0] tb_entry;
32    wire [BTBW-1:0] set_tb_entry;
33
34    // PC Address hash mapping
35    assign tb_entry = pc_i[BTBW-1:0];
36    assign set_tb_entry = set_pc_i[BTBW-1:0];
37    assign bypass = set_i && set_pc_i == pc_i;
38
39    // Saturating counters
40    reg [1:0]   counter[(1<<BTBW)-1:0];
41    generate begin :counter
42       integer               entry;
43       always @(posedge clk or negedge rst_n)
44          if(!rst_n)
45             for(entry=0; entry < (1<<BTBW); entry=entry+1) // reset BTB entries
46                counter[entry] <= 2‘b00;
47          else if(set_i && set_taken_i && counter[set_tb_entry] != SCS_STRONGLY_TAKEN) begin
48             counter[set_tb_entry] <= counter[set_tb_entry] + 2‘b01;
49          else if(set_i && !set_taken_i && counter[set_tb_entry] != SCS_STRONGLY_NOT_TAKEN) begin
50             counter[set_tb_entry] <= counter[set_tb_entry] - 2‘b01;
51          end
52    endgenerate
53
54    always @(posedge clk)
55       pre_taken_o <= bypass ? set_taken_i : counter[tb_entry][1];
56
57    // BTB vectors
58    reg [PCW-1:0] btb[(1<<BTBW)-1:0];
59
60    generate begin :btb_rst
61       integer               entry;
62       always @(posedge clk or negedge rst_n)
63          if(!rst_n)
64             for(entry=0; entry < (1<<BTBW); entry=entry+1) begin // reset BTB entries
65                btb[entry] <= {PCW{1‘b0}};
66             end
67    endgenerate
68
69    always @(posedge clk)
70       pre_target_o <= bypass ? set_pc_i : btb[tb_entry];
71
72    always @(posedge clk)
73       if( set_i )
74          btb[set_tb_entry] <= set_target_i;
75
76 endmodule

对该实现需要做如下说明:

(1)、BPU在每个时钟周期内完成预测和更新。pc_i端口输入待预测的指令PC值,set_i端口指示是否在下一个时钟周期到来时更新预测器。

(2)、考虑到特殊的指令流情况,该实现添加了旁路(bypass)机制。对于具体的处理器实现,可能永远不会触发旁路,因此可以去掉这部分实现。

(3)、对于在BTB中没有记录的分支指令,BPU默认预测目标地址输出为0(BTB在此之前进行过置零复位)。对于具体的处理器实现,可考虑将分支指令的下一条指令的PC值作为目标地址的预测值。

四、总结

  通过讨论,我们提出了基于饱和计数器和BTB的分支预测单元的设计思路,并最终利用Verilog实现了该分支预测器的原型。该实现在面积上具有一定优势,可运用于微处理器实验和验证等方面;同时,该设计也存在一些不足之处:

  (1)、在求PC值的hash映射值时,仅简单地取PC低10bit的数据作为BTB的索引,这将导致PC值高位相同的分支指令的记录状态互相混淆,从而降低预测精度;

  (2)、该设计仅考虑分支指令的全局状态,而没有跟踪分支指令具体的上下文环境;

  (3)、对于带条件判断的分支指令、或寄存器直接/间接寻址的跳转指令,由于其操作数保存在寄存器中,而寄存器的值往往是不断变化的,这将导致对分支目标地址的预测精度降低。

===================================================

本博文仅供参考,难免有错误或疏漏之处,欢迎提出宝贵意见。

原文地址:https://www.cnblogs.com/sci-dev/p/9817676.html

时间: 2024-10-29 04:02:50

【CPU微架构设计】利用Verilog设计基于饱和计数器和BTB的分支预测器的相关文章

【CPU微架构设计】分布式多端口(4写2读)寄存器堆设计

寄存器堆(Register File)是微处理的关键部件之一.寄存器堆往往具有多个读写端口,其中写端口往往与多个处理单元相对应.传统的方法是使用集中式寄存器堆,即一个集中式寄存器堆匹配N个处理单元.随着端口数量的增加,集中式寄存器堆的功耗.面积.时序均会呈幂增长,进而可能降低处理器总体性能. 下图所示为传统的集中式寄存器堆结构: 本文讨论一种基于分布存储和面积与时序互换原则的多端口寄存器堆设计,我们暂时称之为"分布式寄存器堆".该种寄存器从端口使用上,仍与集中式寄存器堆完全兼容,但该寄

ARM架构--CPU的微架构

网上确实有说ARM架构的,但是此架构泛指用ARM指令系统的CPU,而不是CPU的微架构.,硬件电路上,要用ARM指令集系统,必然硬件设计电路上要要遵循,ARM指令的特点和寻址方式,所以说高通和苹果的CPU是ARM架构是可以的. ,但CPU的微架构就要复杂太多了,CPU微架构包括缓存管理,缓存设计,乱序执行,超标量,超流水线,内存控制,分支预测等众多的极其复杂的电路,这些结构的电路的效率是直接决定CPU性能的. 高通和苹果是自主设计的这些电路,所以说是自主的CPU架构,只是用了ARM的指令系统和寻

微架构设计:微博计数器的设计

作者:@cydu 来源: http://qing.weibo.com/1639780001/61bd0ea133002460.html http://qing.weibo.com/1639780001/61bd0ea1330025sq.html 背景:  每一条微博的转发和评论背后都是一串串说不完的故事,但是今天主要讲的是 计数服务,计数服务详尽地记录着每条微博 被评论的次数 和 被转发的次数,当然也还有更多的喜怒哀乐都记录于此. 数据量:   微博总数量:  千亿级 而且每秒都在飞速增长中.每

手机服务器微架构设计和实现专题

9.29 开始动手看着慕课网的视频去学习手机服务器微架构实现,原因是: 现在自己想要认真地学习了解android的基本网络知识,以及其实践 一.知识准备 首先,我要了解tcp.udp和http的关系,了解自己需要在什么情况下选择哪个. 然后,就是我需要了解的是http的实现原理. 据说这个是我们面试时有可能需要考到的,其实,我需要的是弄清楚 request和accept需要做的是什么 最后,是关于http的解析过程. 二.写代码过程 接下来,就是跟着视频写代码 : 首先是设定accept soc

微服务的4个设计原则和19个解决方案

转载本文需注明出处:微信公众号EAWorld,违者必究. 微服务架构现在是谈到企业应用架构时必聊的话题,微服务之所以火热也是因为相对之前的应用开发方式有很多优点,如更灵活.更能适应现在需求快速变更的大环境. 本文将介绍微服务架构的演进.优缺点和微服务应用的设计原则,然后着重介绍作为一个"微服务应用平台"需要提供哪些能力.解决哪些问题才能更好的支撑企业应用架构. 微服务平台也是我目前正在参与的,还在研发过程中的平台产品,平台是以SpringCloud为基础,结合了普元多年来对企业应用的理

微服务的4大设计原则和19种解决方案

微服务架构现在是谈到企业应用架构时必聊的话题,微服务之所以火热也是因为相对之前的应用开发方式有很多优点,如更灵活.更能适应现在需求快速变更的大环境. 本文将介绍微服务架构的演进.优缺点和微服务应用的设计原则,然后着重介绍作为一个"微服务应用平台"需要提供哪些能力.解决哪些问题才能更好的支撑企业应用架构. 微服务平台也是我目前正在参与的,还在研发过程中的平台产品,平台是以SpringCloud为基础,结合了普元多年来对企业应用的理解和产品的设计经验,逐步孵化的一个微服务应用平台. 目录:

Redis架构之防雪崩设计:网站不宕机背后的兵法

Redis架构之防雪崩设计:网站不宕机背后的兵法 原创: 付磊,张益军 高可用架构 2017-03-24 导读:互联网系统中不可避免要大量用到缓存,在缓存的使用过程中,架构师需要注意哪些问题?本文以 Redis 为例,详细探讨了最关键的 3 个问题. 一.缓存穿透预防及优化 缓存穿透是指查询一个根本不存在的数据,缓存层和存储层都不会命中,但是出于容错的考虑,如果从存储层查不到数据则不写入缓存层,如图 11-3 所示整个过程分为如下 3 步: 缓存层不命中 存储层不命中,所以不将空结果写回缓存 返

NET架构设计、框架设计系列文章总结

NET架构设计.框架设计系列文章总结 从事.NET开发到现在已经有七个年头了.慢慢的可能会很少写.NET文章了.不知不觉竟然走了这么多年,热爱.NET热爱c#.突然想对这一路的经历进行一个总结. 是时候开始下一阶段的旅途,希望这些文章可以在发挥点价值作用. 架构设计: ElasticSearch大数据分布式弹性搜索引擎使用 (推荐) DDD实施经验分享-价值导向.从上往下进行(圈内第一个吃螃蟹DDD实施方案)(推荐) 软件工程-思考项目开发那些事(一)(推荐) SOA架构设计经验分享-架构.职责

敏捷开发下, 如何将需求分析,架构(软件)设计,开发与测试,一气呵成式的结合且高效的完成 ?

产品开发中,时常会发生类似如图中 "削马铃薯"的悲剧. 悲剧的发生,往往是由于我们只传递了 "要作什么功能"给开发人员.却缺乏了一个有效的且轻量级的实践,能在正式进入迭代开发前,确认开发人员是否真有能力,能将 "使用者的需求"转化为 "可执行的代码"? "场景树" 便是一结合Use Case, Domain Driven Design, UML 的轻量级可视化的敏捷实践. 经由场景树,可确认开发人员,是否已