Files
csapp2025/branchPrediction.c
2025-04-17 23:02:23 +08:00

654 lines
19 KiB
C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "common.h"
// 饱和计数器加1
static inline UINT32 SatIncrement(UINT32 x, UINT32 max)
{
if (x<max) return x + 1;
return x;
}
// 饱和计数器减1
static inline UINT32 SatDecrement(UINT32 x)
{
if (x>0) return x - 1;
return x;
}
#define BITS_OF_PC 13 // 选择13位的PC作为索引
#define STATE_MAX 3
#define STATE_INIT 2
UINT32 *State; // 状态数组用于保存分支指令的状态机实际只使用最低2位
UINT64 StateArraySize;
void PREDICTOR_init(void)
{
StateArraySize = (1 << BITS_OF_PC); // 状态数组项数
State = (UINT32 *)malloc(StateArraySize * sizeof(UINT32));
// *********** 你需要在下面书写代码 ***********
// 将状态数组全部初始化为STATE_INIT
for(UINT32 i = 0; i < StateArraySize; i++)
{
State[i] = 2;
}
// *********** 你需要在上面书写代码 ***********
}
// 2位状态的分支预测器预测部分
char GetPrediction(UINT64 PC)
{
// *********** 你需要在下面书写代码 ***********
// 将PC的低13位去索引状态数组State得到对应的饱和状态
// 如果该状态的值超过一半,则预测跳转
// 如果该状态的值低于一半,则预测不跳转
UINT32 index = PC>>2 & 0x1fff;
if(State[index] == 0 || State[index] == 1) return NOT_TAKEN;
return TAKEN;
//return TAKEN;
//return NOT_TAKEN;
// *********** 你需要在上面书写代码 ***********
}
// 2位状态的分支预测器更新部分
void UpdatePredictor(UINT64 PC, OpType opType, char resolveDir, char predDir, UINT64 branchTarget)
{
// *********** 你需要在下面书写代码 ***********
// 根据分支指令实际执行结果,来更新对应的饱和计数器
// 如果结果为跳转,则对应的饱和计数器+1
// 如果结果为不跳转,则对应的饱和计数器-1
UINT32 index = PC>>2 & 0x1fff;
if(resolveDir == 'T')
{
State[index] = SatIncrement(State[index], 3);
}
else
{
State[index] = SatDecrement(State[index]);
}
// *********** 你需要在上面书写代码 ***********
}
void PREDICTOR_free(void)
{
free(State);
}
#include "common.h"
// 饱和计数器加1
static inline UINT32 SatIncrement(UINT32 x, UINT32 max)
{
if (x<max) return x + 1;
return x;
}
// 饱和计数器减1
static inline UINT32 SatDecrement(UINT32 x)
{
if (x>0) return x - 1;
return x;
}
#define BITS_OF_PC 13 // 选择13位的PC作为索引
#define STATE_MAX 7
#define STATE_INIT 3
UINT32 *State; // 状态数组用于保存分支指令的状态机实际只使用最低3位
UINT64 StateArraySize;
void PREDICTOR_init(void)
{
StateArraySize = (1 << BITS_OF_PC); // 状态数组项数
State = (UINT32 *)malloc(StateArraySize * sizeof(UINT32));
// *********** 你需要在下面书写代码 ***********
// 将状态数组全部初始化为STATE_INIT
for(UINT64 i = 0; i <= StateArraySize; i++)
{
State[i] = STATE_INIT;
}
// *********** 你需要在上面书写代码 ***********
}
// 2位状态的分支预测器预测部分
char GetPrediction(UINT64 PC)
{
// *********** 你需要在下面书写代码 ***********
// 将PC的低13位去索引状态数组State得到对应的饱和状态
// 如果该状态的值超过一半,则预测跳转
// 如果该状态的值低于一半,则预测不跳转
UINT64 index = (PC>>2) & 0x1fff;
if(State[index] == 0 || State[index] == 1 || State[index] == 2 || State[index] == 3) return NOT_TAKEN;
return TAKEN;
//return TAKEN;
//return NOT_TAKEN;
// *********** 你需要在上面书写代码 ***********
}
// 2位状态的分支预测器更新部分
void UpdatePredictor(UINT64 PC, OpType opType, char resolveDir, char predDir, UINT64 branchTarget)
{
// *********** 你需要在下面书写代码 ***********
// 根据分支指令实际执行结果,来更新对应的饱和计数器
// 如果结果为跳转,则对应的饱和计数器+1
// 如果结果为不跳转,则对应的饱和计数器-1
UINT64 index = (PC>>2) & 0x1fff;
if(resolveDir == 'T')
{
State[index] = SatIncrement(State[index], 7);
}
else
{
State[index] = SatDecrement(State[index]);
}
// *********** 你需要在上面书写代码 ***********
}
void PREDICTOR_free(void)
{
free(State);
}
#include "common.h"
// 饱和计数器加1
static inline UINT32 SatIncrement(UINT32 x, UINT32 max)
{
if (x < max) return x + 1;
return x;
}
// 饱和计数器减1
static inline UINT32 SatDecrement(UINT32 x)
{
if (x > 0) return x - 1;
return x;
}
#define BITS_OF_PC 10 // 选择10位的PC作为索引
#define LOCAL_HIST_LEN 3 // 局部历史长度3位
#define LOCAL_HIST_MASK ~(~0 << LOCAL_HIST_LEN)
#define STATE_MAX 3
#define STATE_INIT 2
UINT32* pht; // pattern history table 模式历史表
UINT32 phtArraySize; // pht数组项数
UINT32* State; // 状态数组用于保存分支指令的状态机实际只使用最低2位
UINT64 StateArraySize;
void PREDICTOR_init(void)
{
StateArraySize = (1 << (BITS_OF_PC + LOCAL_HIST_LEN)); // 状态数组项数
State = (UINT32*)malloc(StateArraySize * sizeof(UINT32));
phtArraySize = (1 << BITS_OF_PC); // pht数组项数
pht = (UINT32*)malloc(phtArraySize * sizeof(UINT32));
// *********** 你需要在下面书写代码 ***********
// 将状态数组全部初始化为STATE_INIT
// 将模式历史表pht全部初始化为0
for(UINT64 i = 0; i < StateArraySize; i++)
{
State[i] = STATE_INIT;
}
for(UINT32 i = 0; i < phtArraySize; i++)
{
pht[i] = 0;
}
// *********** 你需要在上面书写代码 ***********
}
// 2位状态的分支预测器预测部分
char GetPrediction(UINT64 PC)
{
// *********** 你需要在下面书写代码 ***********
// 将PC的低10位去索引模式历史表pht得到对应的3位历史信息
UINT32 index1 = (PC>>2) & 0x3ff;
// 将PC的低10位与3位历史信息进行拼接形成一个13位的状态数组索引拼接需要使用C语言的移位、与、或等运算
//UINT64 index2 = (index1<<3) | (pht[index1]);
//UINT64 index2 = (index1) | (pht[index1]<<10);
UINT64 index2 = (index1 & 0x3ff) | (pht[index1]<<10 & 0x1c00);
// 用13位去索引状态数组得到对应的饱和状态
if(State[index2] == 0 || State[index2] == 1) return NOT_TAKEN;
return TAKEN;
// 如果该状态的值超过一半,则预测跳转
// 如果该状态的值低于一半,则预测不跳转
//return TAKEN;
// return NOT_TAKEN;
// *********** 你需要在上面书写代码 ***********
}
// 2位状态的分支预测器更新部分
void UpdatePredictor(UINT64 PC, OpType opType, char resolveDir, char predDir, UINT64 branchTarget)
{
// *********** 你需要在下面书写代码 ***********
// 根据分支指令实际执行结果,来更新对应的饱和计数器
// 如果结果为跳转,则对应的饱和计数器+1
// 如果结果为不跳转,则对应的饱和计数器-1
// 更新pht中的最近3次分支历史信息使用移位寄存器来更新
// 将其更新到pht中
UINT32 index1 = (PC>>2) & 0x3ff;
//UINT64 index2 = (index1<<3) | (pht[index1]);
//UINT64 index2 = (index1) | (pht[index1]<<10);
UINT64 index2 = (index1 & 0x3ff) | (pht[index1]<<10 & 0x1c00);
if(resolveDir == 'T')
{
State[index2] = SatIncrement(State[index2], 3);
pht[index1] = (pht[index1]<<1) | 0x1;
}
else
{
State[index2] = SatDecrement(State[index2]);
pht[index1] = (pht[index1]<<1);
}
// *********** 你需要在上面书写代码 ***********
}
void PREDICTOR_free(void)
{
free(State);
free(pht);
}
#include "common.h"
// 饱和计数器加1
static inline UINT32 SatIncrement(UINT32 x, UINT32 max)
{
if (x < max) return x + 1;
return x;
}
// 饱和计数器减1
static inline UINT32 SatDecrement(UINT32 x)
{
if (x > 0) return x - 1;
return x;
}
#define BITS_OF_PC 9 // 选择9位的PC作为索引
#define LOCAL_HIST_LEN 4 // 局部历史长度4位
#define LOCAL_HIST_MASK ~(~0 << LOCAL_HIST_LEN)
#define STATE_MAX 3
#define STATE_INIT 2
UINT32* pht; // pattern history table 模式历史表
UINT32 phtArraySize; // pht数组项数
UINT32* State; // 状态数组用于保存分支指令的状态机实际只使用最低2位
UINT64 StateArraySize;
void PREDICTOR_init(void)
{
StateArraySize = (1 << (BITS_OF_PC + LOCAL_HIST_LEN)); // 状态数组项数
State = (UINT32*)malloc(StateArraySize * sizeof(UINT32));
phtArraySize = (1 << BITS_OF_PC); // pht数组项数
pht = (UINT32*)malloc(phtArraySize * sizeof(UINT32));
// *********** 你需要在下面书写代码 ***********
// 将状态数组全部初始化为STATE_INIT
// 将模式历史表pht全部初始化为0
for(UINT64 i = 0; i < StateArraySize; i++)
{
State[i] = STATE_INIT;
}
for(UINT32 i = 0; i < phtArraySize; i++)
{
pht[i] = 0;
}
// *********** 你需要在上面书写代码 ***********
}
// 2位状态的分支预测器预测部分
char GetPrediction(UINT64 PC)
{
// *********** 你需要在下面书写代码 ***********
// 将PC的低10位去索引模式历史表pht得到对应的3位历史信息
// 将PC的低10位与3位历史信息进行拼接形成一个13位的状态数组索引拼接需要使用C语言的移位、与、或等运算
// 用13位去索引状态数组得到对应的饱和状态
// 如果该状态的值超过一半,则预测跳转
// 如果该状态的值低于一半,则预测不跳转
UINT32 index1 = (PC>>2) & 0x1ff;
UINT64 index2 = (index1 & 0x1ff) | (pht[index1]<<9 & 0x1e00);
if(State[index2] == 0 || State[index2] == 1) return NOT_TAKEN;
return TAKEN;
//return TAKEN;
// return NOT_TAKEN;
// *********** 你需要在上面书写代码 ***********
}
// 2位状态的分支预测器更新部分
void UpdatePredictor(UINT64 PC, OpType opType, char resolveDir, char predDir, UINT64 branchTarget)
{
// *********** 你需要在下面书写代码 ***********
// 根据分支指令实际执行结果,来更新对应的饱和计数器
// 如果结果为跳转,则对应的饱和计数器+1
// 如果结果为不跳转,则对应的饱和计数器-1
// 更新pht中的最近3次分支历史信息使用移位寄存器来更新
// 将其更新到pht中
UINT32 index1 = (PC>>2) & 0x1ff;
UINT64 index2 = (index1 & 0x1ff) | (pht[index1]<<9 & 0x1e00);
if(resolveDir == 'T')
{
State[index2] = SatIncrement(State[index2], 3);
pht[index1] = (pht[index1]<<1) | 0x1;
}
else
{
State[index2] = SatDecrement(State[index2]);
pht[index1] = (pht[index1]<<1);
}
// *********** 你需要在上面书写代码 ***********
}
void PREDICTOR_free(void)
{
free(State);
free(pht);
}
#include "common.h"
// 饱和计数器加1
static inline UINT32 SatIncrement(UINT32 x, UINT32 max)
{
if (x < max) return x + 1;
return x;
}
// 饱和计数器减1
static inline UINT32 SatDecrement(UINT32 x)
{
if (x > 0) return x - 1;
return x;
}
#define GLOBAL_HIST_LEN 13 // 全局历史长度13位
#define GLOBAL_HIST_MASK ~(~0 << GLOBAL_HIST_LEN)
#define STATE_MAX 3
#define STATE_INIT 2
UINT32 GHR; // Global History Register全局历史寄存器
UINT32* State; // 状态数组用于保存分支指令的状态机实际只使用最低2位
UINT64 StateArraySize;
void PREDICTOR_init(void)
{
StateArraySize = (1 << GLOBAL_HIST_LEN); // 状态数组项数
State = (UINT32*)malloc(StateArraySize * sizeof(UINT32));
// *********** 你需要在下面书写代码 ***********
// 将状态数组全部初始化为STATE_INIT
// 将全局历史寄存器GHR初始化为0
for(UINT64 i = 0; i < StateArraySize; i++)
{
State[i] = STATE_INIT;
}
GHR = 0;
// *********** 你需要在上面书写代码 ***********
}
// Gshare分支预测器预测部分
char GetPrediction(UINT64 PC)
{
// *********** 你需要在下面书写代码 ***********
// 用13位的GHR去索引状态数组得到对应的饱和状态
// 如果该状态的值超过一半,则预测跳转
// 如果该状态的值低于一半,则预测不跳转
UINT64 index = GHR & 0x1fff;
if(State[index] == 0 || State[index] == 1) return NOT_TAKEN;
return TAKEN;
// return TAKEN;
// return NOT_TAKEN;
// *********** 你需要在上面书写代码 ***********
}
// Gshare分支预测器更新部分
void UpdatePredictor(UINT64 PC, OpType opType, char resolveDir, char predDir, UINT64 branchTarget)
{
// *********** 你需要在下面书写代码 ***********
// 根据分支指令实际执行结果,来更新对应的饱和计数器
// 如果结果为跳转,则对应的饱和计数器+1
// 如果结果为不跳转,则对应的饱和计数器-1
// 更新GHR中的最近1次分支历史信息使用移位寄存器来更新
UINT64 index = GHR & 0x1fff;
if(resolveDir == 'T')
{
State[index] = SatIncrement(State[index], 3);
GHR = GHR << 1 | 0x1;
}
else
{
State[index] = SatDecrement(State[index]);
GHR = GHR << 1;
}
// *********** 你需要在上面书写代码 ***********
}
void PREDICTOR_free(void)
{
free(State);
}
#include "common.h"
// 饱和计数器加1
static inline UINT32 SatIncrement(UINT32 x, UINT32 max)
{
if (x < max) return x + 1;
return x;
}
// 饱和计数器减1
static inline UINT32 SatDecrement(UINT32 x)
{
if (x > 0) return x - 1;
return x;
}
#define BITS_OF_PC 3 // 选择3位的PC作为索引
#define GLOBAL_HIST_LEN 10 // 全局历史长度10位
#define STATE_INDEX_MASK ~(~0 << (BITS_OF_PC + GLOBAL_HIST_LEN))
#define STATE_MAX 3
#define STATE_INIT 2
UINT32 GHR; // Global History Register全局历史寄存器
UINT32* State; // 状态数组用于保存分支指令的状态机实际只使用最低2位
UINT64 StateArraySize;
void PREDICTOR_init(void)
{
StateArraySize = (1 << (BITS_OF_PC +GLOBAL_HIST_LEN)); // 状态数组项数
State = (UINT32*)malloc(StateArraySize * sizeof(UINT32));
// *********** 你需要在下面书写代码 ***********
// 将状态数组全部初始化为STATE_INIT
// 将全局历史寄存器GHR初始化为0
for(UINT64 i = 0; i < StateArraySize; i++)
{
State[i] = STATE_INIT;
}
GHR = 0;
// *********** 你需要在上面书写代码 ***********
}
// Gshare分支预测器预测部分
char GetPrediction(UINT64 PC)
{
// *********** 你需要在下面书写代码 ***********
// 将PC的低3位与10位GHR进行拼接形成一个13位的状态数组索引
// 用13位去索引状态数组得到对应的饱和状态
// 如果该状态的值超过一半,则预测跳转
// 如果该状态的值低于一半,则预测不跳转
UINT64 index = (((PC>>2 & 0x7) << 10) & 0x1c00) | (GHR & 0x3ff);
if(State[index] == 0 || State[index] == 1) return NOT_TAKEN;
return TAKEN;
// return TAKEN;
// return NOT_TAKEN;
// *********** 你需要在上面书写代码 ***********
}
// Gshare分支预测器更新部分
void UpdatePredictor(UINT64 PC, OpType opType, char resolveDir, char predDir, UINT64 branchTarget)
{
// *********** 你需要在下面书写代码 ***********
// 根据分支指令实际执行结果,来更新对应的饱和计数器
// 如果结果为跳转,则对应的饱和计数器+1
// 如果结果为不跳转,则对应的饱和计数器-1
// 更新GHR中的最近1次分支历史信息使用移位寄存器来更新
UINT64 index = (((PC>>2 & 0x7) << 10) & 0x1c00) | (GHR & 0x3ff);
if(resolveDir == 'T')
{
State[index] = SatIncrement(State[index], 3);
GHR = GHR << 1 | 0x1;
}
else
{
State[index] = SatDecrement(State[index]);
GHR = GHR << 1;
}
// *********** 你需要在上面书写代码 ***********
}
void PREDICTOR_free(void)
{
free(State);
}
#include "common.h"
// 饱和计数器加1
static inline UINT32 SatIncrement(UINT32 x, UINT32 max)
{
if (x < max) return x + 1;
return x;
}
// 饱和计数器减1
static inline UINT32 SatDecrement(UINT32 x)
{
if (x > 0) return x - 1;
return x;
}
#define GLOBAL_HIST_LEN 13 // 全局历史长度13位
#define GLOBAL_HIST_MASK ~(~0 << GLOBAL_HIST_LEN)
#define STATE_MAX 3
#define STATE_INIT 2
UINT32 GHR; // Global History Register全局历史寄存器
UINT32* State; // 状态数组用于保存分支指令的状态机实际只使用最低2位
UINT64 StateArraySize;
void PREDICTOR_init(void)
{
StateArraySize = (1 << GLOBAL_HIST_LEN); // 状态数组项数
State = (UINT32*)malloc(StateArraySize * sizeof(UINT32));
// *********** 你需要在下面书写代码 ***********
// 将状态数组全部初始化为STATE_INIT
// 将全局历史寄存器GHR初始化为0
for(UINT64 i = 0; i < StateArraySize; i++)
{
State[i] = STATE_INIT;
}
GHR = 0;
// *********** 你需要在上面书写代码 ***********
}
// Gshare分支预测器预测部分
char GetPrediction(UINT64 PC)
{
// *********** 你需要在下面书写代码 ***********
// 将PC的低13位与13位GHR进行异或形成一个13位的状态数组索引
// 用13位去索引状态数组得到对应的饱和状态
// 如果该状态的值超过一半,则预测跳转
// 如果该状态的值低于一半则预测不跳转7]
UINT64 nPC = (PC) & 0x1fff;
UINT64 index = nPC ^ (GHR & 0x1fff);
if(State[index] == 0 || State[index] == 1) return NOT_TAKEN;
return TAKEN;
// return TAKEN;
// return NOT_TAKEN;
// *********** 你需要在上面书写代码 ***********
}
// Gshare分支预测器更新部分
void UpdatePredictor(UINT64 PC, OpType opType, char resolveDir, char predDir, UINT64 branchTarget)
{
// *********** 你需要在下面书写代码 ***********
// 根据分支指令实际执行结果,来更新对应的饱和计数器
// 如果结果为跳转,则对应的饱和计数器+1
// 如果结果为不跳转,则对应的饱和计数器-1
// 更新GHR中的最近1次分支历史信息使用移位寄存器来更新
UINT64 nPC = (PC) & 0x1fff;
UINT64 index = nPC ^ (GHR & 0x1fff);
if(resolveDir == 'T')
{
State[index] = SatIncrement(State[index], 3);
GHR = GHR << 1 | 0x1;
}
else
{
State[index] = SatDecrement(State[index]);
GHR = GHR << 1;
}
// *********** 你需要在上面书写代码 ***********
}
void PREDICTOR_free(void)
{
free(State);
}