⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bpred.h

📁 这是一个32位微处理器的模拟程序
💻 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 + -