📄 bpred.h
字号:
//==============================================================================
//写文件的人: (sha)fish
//联系方式: wahaha_nescafe@hotmail.com
//
//系统说明: 这是一个32位微处理器的模拟程序,属于原型,实现的功能有限。
// 参考了MIPSR10000、POWPC620处理器的结构,以及体系结构
// 中的圣经《计算机体系结构——量化研究方法》。
// 实现了指令的4发射、乱序执行。
//版权说明: Copyright (C) 2004-2005 by (sha)fish
// All Rights Not Reserved!
// (没有版权,随便折腾——不能用于商业目的)
//==============================================================================
#ifndef BPRED_H
#define BPRED_H
//******************************************************************************
//整个分支预测的说明
//在这儿将实现三种类型的分支预测:
// two_level : 二级分支预测
// gshare : gshare分支预测
// neural : 基于神经网络的分支预测
//整个分支预测的分支配置 N, W, M, V
// N : 分支历史寄存器的个数
// W : 分支历史寄存器的长度
// M : 模式表的个数
// V : 每个模式表的表项数
// 注意:一般情况下,V = 2^W
//
// 对于下列几种情况的配置说明:
// GAg (一个分支历史寄存器,一个PHT表) : 1, W, 1, V
// GAp (一个分支历史寄存器,多个PHT表) : 1, W, M, V
// PAg (多个分支历史寄存器,一个PHT表) : N, W, 1, V
// PAp (多个分支历史寄存器,多个PHT表) : N, W, M, V
//
//CPU利用分支预测的方法:
// 在取指阶段,利用BTB进行分支地址的预测
// 在译码阶段,进行分支方向的预测
// 这两种预测算法之间没有必然的联系
// 如果在译码阶段发现利用BTB预测的是错误的,则译码阶段有最高权利
//实现的是两段分支预测方法(模仿了PowPC620)
//******************************************************************************
#include "config.h"
#include "system.h"
//******************************************************************************
//以下定义分支预测的类型
enum BPRED_TYPE
{
BPRED_2LEV = 1,
BPRED_GSHARE = 2,
BPRED_NEURAL = 3
};
//******************************************************************************
//以下定义BTB的结构
//先定义BTB表的替换策略
enum BPRED_BTB_POLICY
{
//利用计数器方法实现的LRU替换方法:
//每一块都设置一个计数器,计数器的操作规则是:
// (1) 在调入或者替换出去一个块时, 其计数器清“0”,而其它的计数器则加“1”。
// (2) 当访问命中时,所有块的计数值与命中块的计数值要进行比较,
// 如果计数值小于命中块的计数值, 则该块的计数值加“1”;
// 如果块的计数值大于命中块的计数值,则数值不变。最后将命中块的计数器清为0。
// (3) 需要替换时,则选择计数值最大的块被替换。
BTB_LRU = 1,
//利用计数器方法实现的FIFO的替换方法:
//每一块都设置一个计数器,计数器的操作规则是:
// (1) 在调入一个块时,其计数器清“0”,而其他的计数器加“1”。
// (2) 在访问命中时,不进行操作。
// (3) 需要替换时,选择计数器最大的块进行替换。
BTB_FIFO = 2,
BTB_RANDOM = 3
};
//******************************************************************************
//定义BTB表中的各个表项
struct bpred_btb_entry_t
{
bool_t valid; //该表项是不是有效
addr_t source_addr; //分支指令的地址
addr_t target_addr; //分支目标指令的地址
counter_t counter; //计数器,主要是用于BTB替换时处理的
struct bpred_btb_entry_t *next; //各个表项的链接指针
};
//定义BTB表中一个组的结构
struct bpred_btb_set_t
{
struct bpred_btb_entry_t* head; //形成表项的头指针
struct bpred_btb_entry_t* tail; //形成表项的尾指针,几乎没用
};
//定义整个BTB表
struct bpred_btb_t
{
struct bpred_btb_set_t* set; //BTB中的组
enum BPRED_BTB_POLICY policy; //BTB中的组的块使用的替换策略
word_t associative; //BTB的相联度
word_t nsets; //BTB的组数
};
//分支地址预测器的结构
struct bpred_addr_t
{
struct bpred_btb_t* btb; //指向BTB表的指针
counter_t addr_hits; //找到相应地址的次数(找到的不一定是正确的)
counter_t lookups; //查找BTB表的次数(不一定能找到相应的表项)
counter_t pred_hits; //预测正确的次数
};
//******************************************************************************
//以下为获取指令地址在BTB中组的宏
#define BPRED_GET_BTB_SET(btb, addr) ( ((addr)>>2) & ((btb->nsets)-1) )
//******************************************************************************
//以下定义分支模式历史表的结构
//分支历史寄存器的结构
struct bpred_hreg_t
{
word_t reg; //分支历史寄存器存放分支历史的地方
};
//分支模式历史表的结构
struct bpred_pht_t
{
byte_t* data;
};
//分支方向预测器的结构
struct bpred_dir_t
{
enum BPRED_TYPE type;
struct bpred_hreg_t* hreg; //指向分支历史寄存器
word_t hreg_num; //分支历史寄存器的个数
word_t hreg_width; //分支历史寄存器的长度
struct bpred_pht_t* pht; //指向模式历史表
word_t pht_num; //模式历史表的个数
word_t pht_entry; //每个模式历史表的入口个数
counter_t pred_taken; //预测跳转的次数
counter_t actual_taken; //实际跳转的次数
counter_t pred_ntaken; //预测不跳转的次数
counter_t actual_ntaken; //实际不跳转的次数
};
//******************************************************************************
//创建分支方向预测器和分支地址预测器
//创建分支方向预测器
struct bpred_dir_t* bpred_dir_create (
enum BPRED_TYPE type, //预测的类型
word_t hreg_num, //分支历史寄存器的个数
word_t history_width, //分支历史寄存器的长度
word_t pht_num, //PHT表的个数
word_t pht_entry_num //PHT表表项的个数
);
//创建一个分支地址预测器
struct bpred_addr_t* bpred_addr_create(
word_t btb_entry_num, //分支地址预测器中的btb表项的数目
word_t btb_associative, //BTB的相联度
enum BPRED_BTB_POLICY policy //BTB的替换方法
);
//******************************************************************************
//以下为读取BTB中的某个entry
//如果该entry正好命中,则读出来,否则为NULL
static void bpred_read_btb_entry( struct bpred_addr_t*, //分支地址预测器
addr_t addr, //搜寻的指令地址
struct bpred_btb_entry_t** entry //表项
);
//******************************************************************************
//以下为在BTB中的某个set中选择将要被替换出来的entry
static void bpred_replaced_entry( struct bpred_addr_t*, //分支地址预测器
addr_t addr, //搜寻的指令地址
struct bpred_btb_entry_t** entry //表项
);
//******************************************************************************
//以下为进行分支地址的预测
bool_t bpred_addr_pred(
struct bpred_addr_t* bp_addr, //接受的分支方向预测器
addr_t source_addr, //进行分支方向预测的分支指令地址
addr_t* result_addr //分支地址预测的结果
//如果在BTB表中找到了对应的分支指令地址,则说明
//这次分支是要跳转的,然后查看当前的表项是不是有效
//有效就取出预测结果地址,作为下一条PC
);
//******************************************************************************
//以下为进行分支方向的预测
void bpred_dir_pred(
struct bpred_dir_t* bp_dir, //接受的分支方向预测器
addr_t source_addr, //进行分支方向预测的分支指令地址
long* dir_result //分支方向预测的结果
//对于二级分支预测,结果不外呼:00/01/10/11
//对于神经网络,则有可能是正负数
);
//******************************************************************************
//以下为分支预测失效后的分支部件的恢复
void bpred_update( struct bpred_dir_t* bp_dir, //分支方向预测器
struct bpred_addr_t* bp_addr, //分支地址预测器
addr_t source_addr, //该条分支指令的地址
addr_t result_addr //该条分支指令的目的地址
);
//******************************************************************************
//以下为分支预测的初始化
void bpred_init(void);
//******************************************************************************
//分支预测的结束处理
void bpred_uninit(void);
//******************************************************************************
//分支预测的统计信息
void bpred_statistic( struct bpred_dir_t* bp_dir,
struct bpred_addr_t* bp_addr
);
#endif //BPRED_H
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -