📄 bpred.c
字号:
bp_entry2->counter++;
}
bp_entry2 = bp_entry2->next;
}
bp_entry->counter = 0;
}
*entry = bp_entry;
}
ASSERT(*entry != NULL);
return ;
}
//******************************************************************************
//进行分支地址的预测
/*
(1)函数名:
(2)接收参数:
bp_addr : 分支地址预测器
source_addr : 源地址,分支指令地址
result_addr : 目标地址,即预测的分支跳转地址
(3)返回值:
void
(4)函数过程说明:
进行分支地址的预测,这个是在取指令周期调用的
如果在BTB中找到对应的指令地址,则得到对应的目标地址
如果没有找到,返回的目标地址是0xffffffff
这个处理方法不是很好!
2005-9-20 11:21
今天修改,得到返回值,即:没有在BTB中找到目的地址,将返回FALSE
(5)修改于:
2005-8-28 10:35
(6)作者:
(sha)fish
*/
bool_t
bpred_addr_pred( struct bpred_addr_t* bp_addr,
addr_t source_addr,
addr_t* result_addr
)
{
struct bpred_btb_entry_t* entry = NULL;
bool_t result = 0;
//获取相应的entry
bpred_read_btb_entry(bp_addr, source_addr, &entry);
//如果找到了指令地址对应的entry
if(entry)
{
result = 1;
*result_addr = entry->target_addr;
}
else
{
result = 0;
*result_addr = 0xffffffff;
}
return result;
}
//******************************************************************************
//进行分支方向的预测
/*
(1)函数名:
(2)接收参数:
bp_dir : 分支方向预测器
source_addr : 分支指令地址
dir_result : 方向预测结果
(3)返回值:
(4)函数过程说明:
这个是在第二个周期即译码和发射周期调用的
根据分支指令的地址,查找PHT表进行预测,得到预测结果
对于2lev和gshare,预测的结果是00\01\10\11
对于neural,预测的结果则有可能是正数或负数
最后在得到结果后,要进行处理:跳转为1;不跳转为-1
在最后,还要处理,即跳转为“1”,不跳转为“-1”
(5)修改于:
2005-8-28 13:27
(6)作者:
(sha)fish
*/
void
bpred_dir_pred( struct bpred_dir_t* bp_dir,
addr_t source_addr,
long* dir_result
)
{
struct bpred_hreg_t* bp_reg;
struct bpred_pht_t* bp_pht;
word_t tag;
byte_t* data;
word_t reg;
//首先根据指令地址选择某一个分支历史寄存器
bp_reg = bp_dir->hreg + ((source_addr>>2)&(bp_dir->hreg_num-1));
//然后选择模式历史表
bp_pht = bp_dir->pht + ((source_addr>>2)&(bp_dir->pht_num-1));
switch(bp_dir->type)
{
//一起处理了啊,简单点
case BPRED_2LEV:
case BPRED_GSHARE:
{
//根据分支历史寄存器中的值选取模式历史表的一个二位饱和计数器
//首先得到分支历史寄存器中的值,gshare类型的要做一个XOR
if(bp_dir->type == BPRED_GSHARE)
tag = source_addr ^ (bp_reg->reg);
else
tag = bp_reg->reg;
//然后选择其中的某个二位饱和计数器
tag = tag & (bp_dir->pht_entry-1);
*((byte_t*)dir_result) = *(bp_pht->data + tag);
//最后进行转化
if( (*dir_result) >=2 )
*dir_result = 1;
else
*dir_result = 0;
break;
}
case BPRED_NEURAL:
{
//此时需要利用指令地址选择PHT表中的某一个向量
tag = (bp_dir->hreg_width)*((source_addr>>2)&(bp_dir->pht_entry-1));
data = bp_pht->data + tag;
*dir_result = 0;
reg = bp_reg->reg;
for(tag=0; (word_t)tag<bp_dir->hreg_width; tag++)
{
//这儿需要做正负数的变换
if((reg&1)==1)
*dir_result += (signed long) (*(data+tag));
else
*dir_result -= (signed long) (*(data+tag));
reg = reg>>1;
}
if( (*dir_result) >= 0)
*dir_result = 1;
else
*dir_result = 0;
break;
}
default:
{
ASSERT(-1);
break;
}
}
if(*dir_result == 1)
{
bp_dir->pred_taken++;
}
else if(*dir_result == 0)
{
bp_dir->pred_ntaken++;
}
return;
}
//******************************************************************************
//分支预测的更新工作
/*
(1)函数名:
(2)接收参数:
bp_dir : 分支方向预测器
bp_addr : 分支地址预测器
source_addr : 正在更新的分支指令的地址
result_addr : 正在更新的分支指令的目的地址
(3)返回值:
void
(4)函数过程说明:
分支预测的更新工作包括更新二个部分:
(1)更新BTB表
首先在BTB表中寻找是不是有这条分支指令对应的项
※如果有,则利用这个新的跳转地址更新这个项
※如果没有,则找一个地方,安排这条分支指令住下来
(2)更新PHT表以及分支历史寄存器
首先根据分支指令地址和分支历史寄存器找到PHT表的表项,
然后更新分支历史寄存器,以及PHT表中的内容
(5)修改于:
2005-9-1 21:44
(6)作者:
(sha)fish
*/
void
bpred_update( struct bpred_dir_t* bp_dir,
struct bpred_addr_t* bp_addr,
addr_t source_addr,
addr_t result_addr
)
{
struct bpred_btb_entry_t* btb_entry = NULL;
struct bpred_hreg_t* bp_reg = NULL;
struct bpred_pht_t* bp_pht = NULL;
word_t tag;
bool_t branch_taken;
long dir_result;
byte_t* data = NULL;
unsigned long reg = 0;
ASSERT( (bp_dir!=NULL) && (bp_addr!=NULL) );
//先看看这条分支指令有没有跳转成功
if( (source_addr+4) == result_addr )
{
branch_taken = 0;
bp_dir->actual_ntaken++;
}
else
{
branch_taken = 1;
bp_dir->actual_taken++;
}
//更新BTB表,首先得到BTB中被替换出去的块,
bpred_replaced_entry( bp_addr, source_addr, &btb_entry );
btb_entry->valid = 1;
//进行信息统计
if( (btb_entry->source_addr == source_addr)
&& (btb_entry->target_addr == result_addr)
)
{
bp_addr->pred_hits++;
}
//然后在这个entry中写入分支指令地址和跳转地址
else
{
btb_entry->source_addr = source_addr;
btb_entry->target_addr = result_addr;
}
//之后是更新分支历史寄存器和PHT表
//首先根据指令地址选择某一个分支历史寄存器
bp_reg = bp_dir->hreg + ((source_addr>>2)&(bp_dir->hreg_num-1));
//然后选择模式历史表
bp_pht = bp_dir->pht + ((source_addr>>2)&(bp_dir->pht_num-1));
switch(bp_dir->type)
{
//一起处理了啊,简单点
case BPRED_2LEV:
case BPRED_GSHARE:
{
//根据分支历史寄存器中的值选取模式历史表的一个二位饱和计数器
if(bp_dir->type == BPRED_GSHARE)
tag = source_addr ^ (bp_reg->reg);
else
tag = bp_reg->reg;
tag = tag & (bp_dir->pht_entry-1);
//得到的dir_result 有可能是四个值:00/01/10/11
dir_result = *(bp_pht->data + tag);
//如果跳转
if(branch_taken == 1)
{
if(dir_result<=2)
*(bp_pht->data + tag) = dir_result + 1;
}
else
{
if(dir_result>0)
*(bp_pht->data + tag) = dir_result - 1;
}
break;
}
case BPRED_NEURAL:
{
//此时需要利用指令地址选择PHT表中的某一个向量
tag = (bp_dir->hreg_width)*((source_addr>>2)&(bp_dir->pht_entry-1));
data = bp_pht->data + tag;
dir_result = 0;
reg = bp_reg->reg;
for(tag=0; (unsigned long)tag<bp_dir->hreg_width; tag++)
{
if((reg&1)==1) //即原来的跳转
{
if(branch_taken==1)
(*(data+tag))
= (((signed long) (*(data+tag))+1)>BPRED_NEURAL_MAX_EDGE)?
((signed long) (*(data+tag))) : ((signed long) (*(data+tag))+1) ;
else if(branch_taken==0)
(*(data+tag))
= (((signed long) (*(data+tag))-1)<BPRED_NEURAL_MIN_EDGE)?
((signed long) (*(data+tag))) : ((signed long) (*(data+tag))-1) ;
}
else if((reg&1)==0)
{
if(branch_taken==0)
(*(data+tag))
= (((signed long) (*(data+tag))+1)>BPRED_NEURAL_MAX_EDGE)?
((signed long) (*(data+tag))) : ((signed long) (*(data+tag))+1) ;
else if(branch_taken==1)
(*(data+tag))
= (((signed long) (*(data+tag))-1)<BPRED_NEURAL_MIN_EDGE)?
((signed long) (*(data+tag))) : ((signed long) (*(data+tag))-1) ;
}
reg = reg>>1;
}
break;
}
default:
{
ASSERT(-1);
break;
}
} //switch branch type
//然后就是更新分支历史寄存器
if(branch_taken==1)
bp_reg->reg = (bp_reg->reg<<1)+1;
else
bp_reg->reg = (bp_reg->reg<<1);
return;
}
//******************************************************************************
//分支预测的初始化
/*
(1)函数名:
(2)接收参数:
void
(3)返回值:
void
(4)函数过程说明:
没有特殊的过程,初始化系统中的分支地址预测和分支方向预测
(5)修改于:
2005-9-20 11:36
(6)作者:
(sha)fish
*/
void bpred_init(void)
{
printf("%s\n", "branch prediction init>>>>>>>>>>");
SYS_bpred_addr = bpred_addr_create( BPRED_BTB_ENTRY,
BPRED_BTB_ASSOCIATIVE,
BPRED_BTB_REPLACEMENT
);
SYS_bpred_dir = bpred_dir_create( BPRED_PREDICTION_TYPE,
BPRED_HISTORY_NUM,
BPRED_HISTORY_WIDTH,
BPRED_PHT_NUM,
BPRED_PHT_ENTRY
);
return;
}
//******************************************************************************
//分支处理的结束
/*
(1)函数名:
(2)接收参数:
void
(3)返回值:
void
(4)函数过程说明:
没有特殊的过程,释放系统中的空间
(5)修改于:
2005-9-20 11:36
(6)作者:
(sha)fish
*/
void bpred_uninit(void)
{
struct bpred_btb_set_t* btb_set = NULL;
struct bpred_btb_set_t* btb_set2 = NULL;
struct bpred_btb_entry_t* btb_entry = NULL;
struct bpred_btb_entry_t* btb_entry2 = NULL;
unsigned long set = 0;
unsigned long entry = 0;
unsigned long k = 0;
struct bpred_pht_t* pht = NULL;
ASSERT(SYS_bpred_addr);
ASSERT(SYS_bpred_dir);
//释放分支地址预测
btb_set = SYS_bpred_addr->btb->set;
for(set=1; set<=SYS_bpred_addr->btb->nsets; set++)
{
btb_set2 = btb_set + 1;
btb_entry = btb_set->head;
for(entry=1; entry<=SYS_bpred_addr->btb->associative; entry++)
{
btb_entry2 = btb_entry->next;
free(btb_entry);
btb_entry = btb_entry2;
}
btb_set = btb_set2;
}
free(SYS_bpred_addr->btb->set);
free(SYS_bpred_addr->btb);
free(SYS_bpred_addr);
//释放分支方向预测
pht = SYS_bpred_dir->pht;
for(k=1; k<=SYS_bpred_dir->pht_num; k++ , pht+=1)
free(pht->data);
free(SYS_bpred_dir->pht);
free(SYS_bpred_dir->hreg);
free(SYS_bpred_dir);
return;
}
//******************************************************************************
//统计系统中的信息
/*
(1)函数名:
(2)接收参数:
bp_dir : 系统中的分支方向预测器
bp_addr : 系统中的分支地址预测器
(3)返回值:
void
(4)函数过程说明:
统计一下信息而已,主要是统计命中次数和预测正确率
当然,也可以统计其他信息,暂时没想到呢
(5)修改于:
2005-9-20 11:42
(6)作者:
(sha)fish
*/
void bpred_statistic( struct bpred_dir_t* bp_dir,
struct bpred_addr_t* bp_addr
)
{
ASSERT(bp_dir && bp_addr);
printf("\n%s\n","BRANCH PREDICTION STATISTIC:");
printf("%s\n","branch address prediction:");
printf(" %s : %d\n","look up times ", bp_addr->lookups);
printf(" %s : %d\n","addr hit times", bp_addr->addr_hits);
printf(" %s : %d\n","pred hit times", bp_addr->pred_hits);
printf("%s\n","branch direction prediction:");
printf(" %s : %d\n","pred taken times ", bp_dir->pred_taken);
printf(" %s : %d\n","atcual taken times ", bp_dir->actual_taken);
printf("========END========\n");
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -