系列文章目录
第一篇:初级顺序流水线
第二篇:分支预测流水线
文章目录
- 系列文章目录
- 一、控制逻辑
- 二、具体操作
- 1.判断暂停
- 2.控制冒险
- 3.跳转问题
- 4.实现
- 代码
一、控制逻辑
通过暂停和插入气泡来动态调整流水线的状态
二、具体操作
1.判断暂停
-
识别:
指令在译码阶段读取寄存器时,通过读取寄存器的id值来分别与执行阶段、访存阶段以及写回阶段所执行指令的目的寄存器进行对比如果存在寄存器id值相等的情况,就说明指令之间存在数据相关,那么该指令就要在译码阶段等待
-
方式:
通过插入气泡来代替暂停的指令气泡不会改变寄存器、内存、条件码以及程序状态
-
用途:
解决数据冒险
基于这种机制实现的流水线性能并不高,频繁暂停,降低流水线的吞吐量
-
优化:
直接将运算结果进行传递,数据转发,但对于访存指令,数据比较靠后,必须使用暂停再转发
使得流水线不用暂停就可以处理大多数情况的数据冒险
2.控制冒险
-
问题:
由于需要每一次取值操作后,必须马上确定下一条指令的地址当取出指令为ret时,下一条指令需要从栈中读出,因此必须等到访存操作结束后才能确定下一条指令的地址 当取到的指令是分支条件指令时,流水线无法立即进行立即判断是否进行跳转,通过执行阶段后才能确定跳转
-
方式:
暂停执行新指令
3.跳转问题
-
策略:
预测分支总是跳转或者总是不跳转 -
解决方式:
对于需要冲刷的第一条指令,在执行阶段插入气泡,对于第二条,在译码阶段插入气泡,还要取出跳转指令后面的指令
4.实现
-
为每个流水线寄存器引入两个控制信号,分别为暂停信号和气泡信号
-
当需要暂停时,将暂停信号设为 1,寄存器就会保持以前的状态,就实现指令阻塞在流水线的某个阶段中
-
当需要插入气泡时,寄存器的状态会设置成某个固定的复位配置,复位配置等效于指令nop的状态
代码
#include<stdio.h>
#include<stdint.h>
#include<string.h>
/*
寄存器编号
*/
enum Reg {
rax = 0,
rcx = 1,
rdx = 2,
rbx = 3,
rsp = 4,
rbp = 5,
rsi = 6,
rdi = 7,
r8 = 8,
r9 = 9,
r10 = 0xA,
r11 = 0xB,
r12 = 0xC,
r13 = 0xD,
r14 = 0xE,
No_regisEer = 0xF,
};
const uint8_t PC_memory[32768] = { 0x30,0xf2,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00 //1 0x000 : irmovq $9, %rdx
,0x30,0xf3,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00 //2 0x00a : irmovq $21, %rbx
,0x61,0x23 //3 0x014 : subq %rdx, %rbx
,0x30,0xf4,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00 //4 0x016 : irmovq $128, %rsp
,0x40,0x43,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00 //5 0x020 : rmmovq %rsp, 100(%rbx)
,0xa0,0x2f //6 0x02a : pushq %rdx
,0xb0,0x0f //7 0x02c : popq %rax
,0x73,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00 //8 0x02e : je done
,0x80,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00 //9 0x037 : call proc
//10 0x040 : done:
,0x00 // 0x040 : halt
//11 0x041 : proc:
,0x90 }; // 0x041 : ret
struct FReg {
int predPC;
};
struct SelectPC { //PC选择逻辑单元,预测与纠错
int predpc; //经过predicatePC单元,判断jxx,call跳转 还是 其他顺序执行PCinc单元(valp),预测
int cnd; //执行jxx valc的限制条件,默认跳转,cnd=0 顺序执行valp ,修正jxx
int M_valA; //通过selectA将valp放入valA里了
int M_icode;
int W_valM; //ret默认顺序执行valp,待从栈Datamemory中读地址后更新 ,修正ret
int W_icode;
};
struct F_DReg {
int bubble;
int stall;
int stat;
int icode;
int ifuc;
int rA;
int rB;
int valC;
int valP;
};
struct D_EReg {
int bubble;
int stall;
int stat;
int icode;
int ifuc;
int valC;
int valA;
int valB;
int dstE;
int dstM;
int srcA;
int srcB;
};
struct Cache {
int valid;
int Tag;
int Cache_block;
}Set[16];
struct Address {
int Tag;
int Set_index;
}Address;
struct FwdB {
int register_B;
int srcB;
int E_dstE;
int E_valE;
int M_dstE;
int M_valE;
int M_dstM;
int M_valM;
int W_dstM;
int W_valM;
int W_dstE;
int W_valE;
int valB;
};
struct SelectA_and_FwdA {
int register_A;
int srcA;
int valP;
int E_dstE;
int E_valE;
int M_dstE;
int M_valE;
int M_dstM;
int M_valM;
int W_dstM;
int W_valM;
int W_dstE;
int W_valE;
int valA;
};
struct E_MReg {
int bubble;
int stall;
int stat;
char icode;
int Cnd;
int valE;
int valA;
int dstE;
int dstM;
};
struct CC {
int ZF;
int SF;
int OF;
};
struct M_WReg {
int bubble;
int stall;
int stat;
int icode;
int valE;
int valM;
int dstE;
int dstM;
};
struct Inst {
int icode;
int ifunct;
int rA_id;
int rB_id;
int valC;
int valP;
int len;
};
struct Inst inst = { 0,0,0,0,0,0,0 };
struct F_DReg f_dReg = { 0,0,1,0,0,0,0,0,0 };
struct D_EReg d_eReg = { 0,0,1,0,0,0,0,0,0,0,0,0 };
struct E_MReg e_mReg = { 0,0,1,0,0,0,0,0,0 };
struct M_WReg m_wReg = { 0,0,1,0,0,0,0xF,0xF };
struct F_DReg f_dRegNew = { 0,0,1,0,0,0,0,0,0 };
struct D_EReg d_eRegNew = { 0,0,1,0,0,0,0,0,0,0,0,0 };
struct E_MReg e_mRegNew = { 0,0,1,0,0,0,0,0,0 };
struct M_WReg m_wRegNew = { 0,0,1,0,0,0,0xF,0xF };
int Register_file[16] = { 0 };
int Datamemory[32768] = { 0 };
struct CC cc = { 0 };
struct FReg fReg = { 0 };
struct SelectPC selectpc = { 0,1,0,0,0,0 };
struct FwdB fwdb = { 0 };
struct SelectA_and_FwdA sel_fwda = { 0 };
/*
1.用暂停来避免冒险
只要一条指令的源操作数会被流水线后面某个阶段中的指令产生,处理器就会通过将指令阻塞在解码阶段来避免数据冒险
2.用转发来避免冒险-----》不需要暂停,但与存储器读有关的指令,是在流水线较后面发生的,仍需暂停
如mr 0(%edx),%eax 指令后紧接着add %ebx,&eax ;add的%eax需要在译码阶段得到值,而mr最早到访存阶段才能转发
显然已经来不及,所以不得不先暂停后转发
3.暂停+转发
将解码阶段中的指令暂停一个周期,导致执行阶段中插入一个气泡,同时暂停,使得F和D状态不变
需要解决的控制逻辑:插入气泡
1.加载使用冒险:1个气泡
在一条从存储器中读出一个值的指令和一条使用该值的指令之间,流水线必须暂停一个周期
2. ret:3个气泡
流水线必须暂停直到ret指令到达写回阶段
3. 预测错误的分支:两个气泡
在分支逻辑发现不应该选择分支之前(执行阶段才发现),分支目标处的几条指令已经进入流水线了。
必须从流水线中去掉这些指令。
此时第一条指令已经执行到译码阶段,第二条指令刚开始取指。
具体实现:
定义F_DReg 和F_DRegNew D_EReg 和D_ERegNew E_MReg 和E_MRegNew M_WReg 和M_WRegNew
执行过程中:
F:输入pc 输出 F_DRegNew;正常情况下需要更新 将F_DRegNew---->F_DReg,否则不变
D:输入F_DReg 输出 D_ERegNew;
E: 输入D_EReg 输出 E_MRegNew;
M: 输入E_MReg 输出 M_WRegNew
W: 输入M_WReg
每次执行完需要判断:
需要暂停,就使用原状态F_DReg
正常情况,每次执行完一个周期需要更新
F_DReg = F_DRegNew
*/
//分支预测
void Select_PC() {
if (selectpc.W_icode == 9) { //ret生效
printf("ret生效\n");
selectpc.predpc = selectpc.W_valM;
printf("selectpc.predpc =%d \n", selectpc.predpc);
}
else if (selectpc.W_icode == 7) {
if (selectpc.cnd == 0) { //跳转失败
selectpc.predpc = selectpc.M_valA;
}
}
}
//取值阶段
int Predict_PC(int icode, int valc, int valp) {
if (icode == 7 || icode == 8) {
return valc;
}
else {
return valp;
}
}
int PC_inc(int len, int pc) {
return len + pc;
}
int iValC(int valC_start, int valC_end) {
int i, j, valc = 0;
for (j = 0, i = valC_start; i <= valC_end; i++, j = j + 2)
{
valc += PC_memory[i] << j;
}
return valc;
}
void Align(int pc,int Need_regids, int Need_valC) {
int valC_start;
int valC_end;
if (Need_regids == 0) {
inst.rA_id = 0xF;
inst.rB_id = 0xF;
if (Need_valC) { //无寄存器、有常数 如jxx、call
valC_start = pc + 1;
valC_end = pc + 8;
inst.len = 1 + (valC_end - pc);
inst.valC = iValC(valC_start, valC_end);
}
else { //无寄存器、无常数 如halt、nop、ret
inst.len = 1;
}
}
if (Need_regids == 1) {
inst.rA_id = 0xF;
inst.rB_id = PC_memory[pc + 1] & 0x0F;
if (Need_valC) { //只有寄存器rB、有常数 如irmovq
valC_start = pc + 2;
valC_end = pc + 9;
inst.len = 1 + (valC_end - pc);
inst.valC = iValC(valC_start, valC_end);
}
//只有寄存器rB、无常数 此情况无
}
if (Need_regids == 2) {
inst.rA_id = PC_memory[pc + 1] >> 4;
inst.rB_id = 0xF;
//只有寄存器rA、有常数 此情况无
if (!Need_valC) { //有寄存器rA、无常数 如pushq、popq
inst.len = 2;
}
}
if (Need_regids == 3) {
inst.rA_id = PC_memory[pc + 1] >> 4;
inst.rB_id = PC_memory[pc + 1] & 0x0F;
if (Need_valC) { //都有寄存器、有常数 如rrmovq、rmmovq、mrmovq
valC_start = pc + 2;
valC_end = pc + 9;
inst.len = 1 + (valC_end - pc);
inst.valC = iValC(valC_start, valC_end);
}
else {
// 都有寄存器、无常数 如addq、subq、andq、xorq、rrmovq、rrmovq、cmovle、cmovl、cmove、cmovne、cmovge、cmovg
inst.len = 2;
}
}
}
void Split(int pc) {
int Need_valC;
int Need_regids; //0:都为空;1:rA为空;2:rB为空;3:都不为空
uint8_t code = PC_memory[pc];
uint8_t reg = PC_memory[pc + 1];
inst.icode = (uint8_t)(code >> 4);
inst.ifunct = code & 0x0F;
if (inst.icode == 0 && inst.ifunct == 0) {
Need_regids = 0;
Need_valC = 0;
Align(pc,Need_regids, Need_valC);
}
if (inst.icode == 1 && inst.ifunct == 0) {
Need_valC = 0;
Need_regids = 0;
Align(pc,Need_regids, Need_valC);
}
if (inst.icode == 2) {
Need_valC = 0;
Need_regids = 3;
Align(pc,Need_regids, Need_valC);
}
if (inst.icode == 3 && inst.ifunct == 0) {
Need_valC = 1;
Need_regids = 1;
Align(pc, Need_regids, Need_valC);
}
if (inst.icode == 4 && inst.ifunct == 0) {
Need_valC = 1;
Need_regids = 3;
Align(pc,Need_regids, Need_valC);
}
if (inst.icode == 5 && inst.ifunct == 0) {
Need_valC = 1;
Need_regids = 3;
Align(pc, Need_regids, Need_valC);
}
if (inst.icode == 6) {
Need_valC = 0;
Need_regids = 3;
Align(pc, Need_regids, Need_valC);
}
if (inst.icode == 7) {
Need_valC = 1;
Need_regids = 0;
Align(pc,Need_regids, Need_valC);
}
if (inst.icode == 8 && inst.ifunct == 0) {
Need_valC = 1;
Need_regids = 0;
Align(pc,Need_regids, Need_valC);
}
if (inst.icode == 9 && inst.ifunct == 0) {
Need_valC = 0;
Need_regids = 0;
Align(pc,Need_regids, Need_valC);
}
if (inst.icode == 0xA && inst.ifunct == 0) {
Need_valC = 0;
Need_regids = 2;
Align(pc, Need_regids, Need_valC);
}
if (inst.icode == 0xB && inst.ifunct == 0) {
Need_valC = 0;
Need_regids = 2;
Align(pc, Need_regids, Need_valC);
}
if (!(inst.icode >= 0 && inst.icode <= 11)) {
f_dReg.stat = 0;
}
}
void Fetch(int pc) {
Split(pc);
inst.valP = PC_inc(inst.len, pc);
fReg.predPC = Predict_PC(inst.icode, inst.valC, inst.valP);
selectpc.predpc = fReg.predPC;
f_dRegNew.bubble = 0;
f_dRegNew.stall = 0;
f_dRegNew.icode = inst.icode;
f_dRegNew.ifuc = inst.ifunct;
f_dRegNew.rA = inst.rA_id;
f_dRegNew.rB = inst.rB_id;
f_dRegNew.valC = inst.valC;
f_dRegNew.valP = inst.valP;
}
//译码阶段
/*
1.不是所以指令都需要数据转发,而且数据转发阶段也不同:(不需要回写寄存器的指令,不需要转发)
执行阶段:(ALU计算结果) valE: 3irmov 6opq 2rrmov(有条件) Apush Bpop 8call 9ret(注意:回写valE到SP寄存器)
访存前: (对寄存器写入端口E还没有进行写入的数据)valE: 就是执行阶段的指令
访存后有:(内存的输出数据) valM: 5mrmov(有点晚) Bpop (从Datememory中读出数据后才回写)
写回阶段:(对寄存器写入端口E还没进行写入的数据) valE:就是执行阶段的指令
(对寄存器写入端口M还没有进行写入的数据)valM: 就是访存后指令
2.rB寄存器作为源寄存器时,需要与rB作为目的寄存器匹配验证的指令很少。有指令:
opq: rA,rB->rB
mrmov:D(rB),rA
3.rA寄存器作为源寄存器时,需要与rA作为目的寄存器匹配验证。rA源寄存器有指令:
特别注意:jxx和call指令要经过selectA,选出的是valP,不是来自寄存器的ra值,所以不需要匹配验证
mr指令也不需要
*/
//数据转发
void SelectA_and_FwdA() {
if (sel_fwda.srcA == 0xF) {
sel_fwda.valA = sel_fwda.valP;
}
else {
if (sel_fwda.srcA == sel_fwda.E_dstE) {
sel_fwda.valA = sel_fwda.E_valE;
}
else if (sel_fwda.srcA == sel_fwda.M_dstE) {
sel_fwda.valA = sel_fwda.M_valE;
}
else if (sel_fwda.srcA == sel_fwda.M_dstM) {
sel_fwda.valA = sel_fwda.M_valE;
}
else if (sel_fwda.srcA == sel_fwda.W_dstE) {
sel_fwda.valA = sel_fwda.W_valE;
}
else if (sel_fwda.srcA == sel_fwda.W_dstM) {
sel_fwda.valA = sel_fwda.W_valM;
}
else {
sel_fwda.valA = sel_fwda.register_A;
}
}
}
void FwdB() {
if (fwdb.srcB == fwdb.E_dstE) {
fwdb.valB = fwdb.E_valE;
}
else if (fwdb.srcB == fwdb.M_dstE) {
fwdb.valB = fwdb.M_valE;
}
else if (fwdb.srcB == fwdb.M_dstM) {
fwdb.valB = fwdb.M_valE;
}
else if (fwdb.srcB == fwdb.W_dstE) {
fwdb.valB = fwdb.W_valE;
}
else if (fwdb.srcB == fwdb.W_dstM) {
fwdb.valB = fwdb.W_valM;
}
else {
fwdb.valB = fwdb.register_B;
}
}
void Decode(int Register_file[]) {
if (f_dReg.stall) {
printf("Decode: Stall\n");
//调整pc=pc-inst.len
inst.valP = inst.valP - inst.len;
printf("跳出译码阶段\n");
return;
}
if (f_dReg.bubble) {
printf("Decode: Bubble\n");
d_eRegNew.bubble = 1;
}
printf("进入译码阶段\n");
d_eRegNew.stall = 0;
d_eRegNew.stat = f_dReg.stat;
d_eRegNew.icode = f_dReg.icode;
d_eRegNew.valC = f_dReg.valC;
d_eRegNew.ifuc = f_dReg.ifuc;
if (f_dReg.icode == 0 || f_dReg.icode == 1) {
;
}
if (f_dReg.icode == 2) { //rr
d_eRegNew.srcA = f_dReg.rA;
sel_fwda.srcA = f_dReg.rA;
sel_fwda.register_A = Register_file[f_dReg.rA];
SelectA_and_FwdA(&sel_fwda);
d_eRegNew.valA = sel_fwda.valA;
d_eRegNew.srcB = f_dReg.rB;
d_eRegNew.valB = 0;
d_eRegNew.dstE = f_dReg.rB; //将结果valE写回寄存器rB
}
if (f_dReg.icode == 3) { //ir
d_eRegNew.srcA = f_dReg.rA;
d_eRegNew.srcB = f_dReg.rB;
d_eRegNew.valB = 0;
d_eRegNew.dstE = f_dReg.rB; //将ALU结果valE写回寄存器rB
}
if (f_dReg.icode == 4) { //rm rA,D(rB) 不需要写回寄存器
d_eRegNew.srcA = f_dReg.rA;
sel_fwda.srcA = f_dReg.rA;
sel_fwda.register_A = Register_file[f_dReg.rA];
SelectA_and_FwdA();
d_eRegNew.valA = sel_fwda.valA;
d_eRegNew.srcB = f_dReg.rB; //对rB去寄存器取基地址
fwdb.srcB = f_dReg.rB;
fwdb.register_B = Register_file[f_dReg.rB];
FwdB();
d_eRegNew.valB = fwdb.valB;
}
if (f_dReg.icode == 5) { //mr D(rB),rA 需要验证
d_eRegNew.srcB = f_dReg.rB; //对rB去寄存器取基地址
fwdb.srcB = f_dReg.rB;
fwdb.register_B = Register_file[f_dReg.rB];
FwdB(&fwdb);
d_eRegNew.valB = fwdb.valB;
d_eRegNew.dstM = f_dReg.rA; //将Datamemory结果valM写回寄存器rA
}
if (f_dReg.icode == 6) { //OPq rA,rB 需要验证
sel_fwda.srcA = f_dReg.rA;
sel_fwda.register_A = Register_file[f_dReg.rA];
SelectA_and_FwdA(&sel_fwda);
d_eRegNew.valA = sel_fwda.valA;
fwdb.srcB = f_dReg.rB;
fwdb.register_B = Register_file[f_dReg.rB];
FwdB(&fwdb);
d_eRegNew.valB = fwdb.valB;
d_eRegNew.dstE = f_dReg.rB; //将ALU结果valE写回寄存器rB
}
if (f_dReg.icode == 7) { //jxx
sel_fwda.srcA = f_dReg.rA;
sel_fwda.register_A = Register_file[f_dReg.rA];
SelectA_and_FwdA();
d_eRegNew.valA = sel_fwda.valA;
}
if (f_dReg.icode == 8) { //call
d_eRegNew.srcA = 4;
sel_fwda.srcA = 4;
sel_fwda.register_A = Register_file[f_dReg.rA];
SelectA_and_FwdA();
d_eRegNew.valA = sel_fwda.valA;
fwdb.srcB = 4;
fwdb.register_B = Register_file[f_dReg.rB];
FwdB();
d_eRegNew.valB = fwdb.valB;
d_eRegNew.dstE = 4; //将ALU结果valE写回寄存器sp
}
if (f_dReg.icode == 9) { //ret
d_eRegNew.srcA = 4; //对sp去寄存器取数据
sel_fwda.srcA = 4;
sel_fwda.register_A = Register_file[f_dReg.rA];
SelectA_and_FwdA();
d_eRegNew.valA = sel_fwda.valA;
d_eRegNew.srcB = 4;
fwdb.srcB = 4;
fwdb.register_B = Register_file[f_dReg.rB];
FwdB();
d_eRegNew.valB = fwdb.valB;
d_eRegNew.dstE = 4; //将ALU结果valE写回寄存器sp
}
if (f_dReg.icode == 0xA) {//push
d_eRegNew.srcA = f_dReg.rA;
sel_fwda.srcA = f_dReg.rA; //对rA去寄存器取数据
sel_fwda.register_A = Register_file[f_dReg.rA];
SelectA_and_FwdA();
d_eRegNew.valA = sel_fwda.valA;
d_eRegNew.srcB = 4;
fwdb.srcB = 4;
fwdb.register_B = Register_file[f_dReg.rB];
FwdB();
d_eRegNew.valB = fwdb.valB;
d_eRegNew.dstE = 4; //将ALU结果valE写回寄存器sp
}
if (f_dReg.icode == 0xB) {//popq
d_eRegNew.srcA = 4; //对sp去寄存器取数据
sel_fwda.srcA = 4;
sel_fwda.register_A = Register_file[f_dReg.rA];
SelectA_and_FwdA();
d_eRegNew.valA = sel_fwda.valA;
d_eRegNew.srcB = 4; //对sp去寄存器取数据
fwdb.srcB = 4;
fwdb.register_B = Register_file[f_dReg.rB];
FwdB();
d_eRegNew.valB = fwdb.valB;
d_eRegNew.dstE = 4; //将ALU结果valE写回寄存器sp
d_eRegNew.dstM = f_dReg.rA; //将Datamemory结果valM写回寄存器rA
}
}
//执行阶段
void setCC(int a, int b, int result, int op) {
if (op == 1) { //OF=1 两个同符号数相加(正数+正数 或 负数+负数),结果符号与其相反。
if ((a >= 0 && b >= 0) && result < 0) {
cc.OF = 1;
}
else if ((a < 0 && b < 0) && result >= 0) {
cc.OF = 1;
}
else {
cc.OF = 0;
}
}
if (op == 2) { //OF=1 两数符号相反(正数-负数,或负数-正数),而结果符号与减数相同。
if ((a >= 0 && b < 0) && result >= 0) {
cc.OF = 1;
}
else if ((a < 0 && b >= 0) && result < 0) {
cc.OF = 1;
}
else {
cc.OF = 0;
}
}
if (op == 3 || op == 4) {
cc.OF = 0;
}
if (result < 0) {
cc.SF = 1;
}
else {
cc.SF = 0;
}
if (result) {
cc.ZF = 1;
}
else {
cc.ZF = 0;
}
}
int ALU(int alu_a, int alu_b, int op) {
if (op == 1)
return alu_a + alu_b;
else if (op == 2)
return alu_a - alu_b;
else if (op == 2)
return alu_a & alu_b;
else
return alu_a ^ alu_b;
}
int Cond(int ifunc) {
if (ifunc == 1) {
return (cc.SF ^ cc.OF) | cc.ZF;
}
if (ifunc == 2) {
return cc.SF ^ cc.OF;
}
if (ifunc == 3) {
return cc.ZF;
}
if (ifunc == 4) {
return ~cc.ZF;
}
if (ifunc == 5) {
return ~(cc.SF ^ cc.OF);
}
if (ifunc == 6) {
return ~(cc.SF ^ cc.OF) & ~cc.ZF;
}
return 1;
}
void Excecute() {
int ALU_A;
int ALU_B;
if (d_eReg.stall) {
printf("Execute: Stall\n");
e_mRegNew.bubble = 1; \
return;
}
if (d_eReg.bubble) {
printf("Execute: Bubble\n");
e_mRegNew.bubble = 1;
}
e_mRegNew.stat = d_eReg.stat;
e_mRegNew.icode = d_eReg.icode;
e_mRegNew.valA = d_eReg.valA;
e_mRegNew.dstM = d_eReg.dstM;
int op = 1;//1:add,2:sub,3:and,4:xor
if (d_eReg.icode == 0) {// 不提供数据转发
e_mRegNew.dstE = 0xF;
}
if (d_eReg.icode == 1) {// 不提供数据转发
e_mRegNew.dstE = 0xF;
}
if (d_eReg.icode == 2) {//rr 如果条件满足才提供数据转发
ALU_A = d_eReg.valA;
ALU_B = d_eReg.valB;
op = 1;
e_mRegNew.valE = ALU(ALU_A, ALU_B, op);
fwdb.E_valE = ALU(ALU_A, ALU_B, op);
sel_fwda.E_valE = ALU(ALU_A, ALU_B, op);
if (d_eReg.ifuc == 0) {
e_mRegNew.Cnd = 1;
}
if (d_eReg.ifuc == 1) {
e_mRegNew.Cnd = Cond(d_eReg.ifuc);
}
if (d_eReg.ifuc == 2) {
e_mRegNew.Cnd = Cond(d_eReg.ifuc);
}
if (d_eReg.ifuc == 3) {
e_mRegNew.Cnd = Cond(d_eReg.ifuc);
}
if (d_eReg.ifuc == 4) {
e_mRegNew.Cnd = Cond(d_eReg.ifuc);
}
if (d_eReg.ifuc == 5) {
e_mRegNew.Cnd = Cond(d_eReg.ifuc);
}
if (d_eReg.ifuc == 6) {
e_mRegNew.Cnd = Cond(d_eReg.ifuc);
}
if (e_mRegNew.Cnd) {
e_mRegNew.dstE = d_eReg.dstE;
fwdb.E_dstE = d_eReg.dstE;
sel_fwda.E_dstE = d_eReg.dstE;
}
else {
e_mRegNew.dstE = 0xF;
fwdb.E_dstE = 0xF;
sel_fwda.E_dstE = 0xF;
}
}
if (d_eReg.icode == 3) {//ir 提供数据转发
op = 1;
ALU_A = d_eReg.valC;
ALU_B = d_eReg.valB;
printf("执行立即数加法\n");
e_mRegNew.valE = ALU(ALU_A, ALU_B, op);
fwdb.E_valE = ALU(ALU_A, ALU_B, op);
sel_fwda.E_valE = ALU(ALU_A, ALU_B, op);
fwdb.E_dstE = d_eReg.dstE;
sel_fwda.E_dstE = d_eReg.dstE;
e_mRegNew.dstE = d_eReg.dstE;
}
if (d_eReg.icode == 4) {//rm 不提供数据转发
op = 1;
ALU_A = d_eReg.valC;
ALU_B = d_eReg.valB;
e_mRegNew.valE = ALU(ALU_A, ALU_B, op);
e_mRegNew.dstE = 0xF;
}
if (d_eReg.icode == 5) {//mr 只有访存后才数据转发
op = 1;
ALU_A = d_eReg.valC;
ALU_B = d_eReg.valB;
e_mRegNew.valE = ALU(ALU_A, ALU_B, op);
e_mRegNew.dstE = d_eReg.dstE;
f_dRegNew.stall = 2;
d_eRegNew.stall = 2;
e_mRegNew.bubble = 1;
}
if (d_eReg.icode == 6) {//Opq rr 提供数据转发
ALU_A = d_eReg.valA;
ALU_B = d_eReg.valB;
e_mRegNew.dstE = d_eReg.dstE;
if (d_eReg.ifuc == 0) {
op = 1;
}
if (d_eReg.ifuc == 1) {
op = 2;
}
if (d_eReg.ifuc == 2) {
op = 3;
}
if (d_eReg.ifuc == 3) {
op = 4;
}
e_mRegNew.valE = ALU(ALU_A, ALU_B, op);
fwdb.E_valE = ALU(ALU_A, ALU_B, op);
fwdb.E_dstE = d_eReg.dstE;
fwdb.E_valE = ALU(ALU_A, ALU_B, op);
fwdb.E_dstE = d_eReg.dstE;
sel_fwda.E_valE = ALU(ALU_A, ALU_B, op);
sel_fwda.E_dstE = d_eReg.dstE;
setCC(ALU_A, ALU_B, e_mRegNew.valE, op);
}
if (d_eReg.icode == 7) {//jxx 不提供数据转发
if (d_eReg.ifuc == 0) { //jmp
e_mRegNew.Cnd = 1;
}
if (d_eReg.ifuc == 1) { //jle (SF ^ OF) | ZF
e_mRegNew.Cnd = Cond(d_eReg.ifuc);
}
if (d_eReg.ifuc == 2) { //jl SF ^ OF
e_mRegNew.Cnd = Cond(d_eReg.ifuc);
}
if (d_eReg.ifuc == 3) { //je ZF
e_mRegNew.Cnd = Cond(d_eReg.ifuc);
}
if (d_eReg.ifuc == 4) { //jne ~ZF
e_mRegNew.Cnd = Cond(d_eReg.ifuc);
}
if (d_eReg.ifuc == 5) { //jge ~(SF ^ OF)
e_mRegNew.Cnd = Cond(d_eReg.ifuc);
}
if (d_eReg.ifuc == 6) { //jg ~(SF ^ OF) & ~ZF
e_mRegNew.Cnd = Cond(d_eReg.ifuc);
}
f_dRegNew.bubble = 1;
d_eRegNew.bubble = 1;
}
if (d_eReg.icode == 8 || d_eReg.icode == 0xA) { //call push valB=R[%rsp] 提供数组转发
ALU_B = d_eReg.valB;
ALU_A = -4; //-8
op = 1;
e_mRegNew.valE = ALU(ALU_A, ALU_B, op);
e_mRegNew.dstE = d_eReg.dstE;
fwdb.E_valE = ALU(ALU_A, ALU_B, op);
fwdb.E_dstE = d_eReg.dstE;
sel_fwda.E_valE = ALU(ALU_A, ALU_B, op);
sel_fwda.E_dstE = d_eReg.dstE;
}
if (d_eReg.icode == 9) { //ret valB=R[%rsp] 提供数组转发给fwda
ALU_B = d_eReg.valB;
ALU_A = 4;
op = 1;
e_mRegNew.valE = ALU(ALU_A, ALU_B, op);
e_mRegNew.dstE = d_eReg.dstE;
fwdb.E_valE = ALU(ALU_A, ALU_B, op);
fwdb.E_dstE = d_eReg.dstE;
sel_fwda.E_valE = ALU(ALU_A, ALU_B, op);
sel_fwda.E_dstE = d_eReg.dstE;
f_dRegNew.bubble = 1;
d_eRegNew.bubble = 1;
e_mRegNew.bubble = 1;
}
if (d_eReg.icode == 0xB) { //pop valB=R[%rsp] 提供数组转发 1.执行阶段valB=R[%rsp] 2.访存后 valM
ALU_B = d_eReg.valB;
ALU_A = 4;
op = 1;
e_mRegNew.valE = ALU(ALU_A, ALU_B, op);
e_mRegNew.dstE = d_eReg.dstE;
fwdb.E_valE = ALU(ALU_A, ALU_B, op);
fwdb.E_dstE = d_eReg.dstE;
sel_fwda.E_valE = ALU(ALU_A, ALU_B, op);
sel_fwda.E_dstE = d_eReg.dstE;
}
selectpc.cnd = e_mRegNew.Cnd;
selectpc.M_icode = e_mRegNew.icode;
e_mRegNew.bubble = 0;
e_mRegNew.stall = 0;
}
//访存阶段
void DataMemory(int addr, int Data, int* Datamemory, int MemoryControl) {
if (MemoryControl == 1) {
Address.Set_index = addr &0x0F;
Address.Tag = addr & 0xFF;
if (Set[Address.Set_index].valid && Set[Address.Set_index].Tag == Address.Tag) {
m_wRegNew.valM = Set[Address.Set_index].Cache_block;
}
else {
Set[Address.Set_index].valid = 1;
Set[Address.Set_index].Tag = Address.Tag;
Set[Address.Set_index].Cache_block = Datamemory[addr];
m_wRegNew.valM = Set[Address.Set_index].Cache_block;
}
}
else if (MemoryControl == 2) { //写穿透
Address.Set_index = addr &0x0F;
Address.Tag = addr &0xFF;
Datamemory[addr] = Data;
Set[Address.Set_index].valid = 1;
Set[Address.Set_index].Tag = Address.Tag;
Set[Address.Set_index].Cache_block = Data;
}
}
void MemoryAccess() {
int MemoryControl = -1; //0:不读不写;1:读有效,输入地址输出valM;2:写有效,输入地址数据
int Addr = -1;
int Data = -1;
if (e_mReg.stall) {
printf("Execute: Stall\n");
return;
}
if (e_mReg.bubble) {
printf("Execute: Bubble\n");
m_wRegNew.bubble = 1;
}
m_wRegNew.icode = e_mReg.icode;
m_wRegNew.stat = e_mReg.stat;
m_wRegNew.valE = e_mReg.valE;
m_wRegNew.dstE = e_mReg.dstE;
m_wRegNew.dstM = e_mReg.dstM;
if (e_mReg.icode == 0 || e_mReg.icode == 1 || e_mReg.icode == 2 || e_mReg.icode == 3) {
MemoryControl = 0;
}
if (e_mReg.icode == 4 || e_mReg.icode == 0xA) { //rm push M[valE] = valA
MemoryControl = 2;
Addr = e_mReg.valE;
Data = e_mReg.valA;
}
if (e_mReg.icode == 8) { //call M[valE] = valP
MemoryControl = 2;
Addr = e_mReg.valE;
// Data = e_mReg.valA;
Data = f_dReg.valP;
}
if (e_mReg.icode == 5) { //mr
MemoryControl = 1;
Addr = e_mReg.valE;
}
if (e_mReg.icode == 0xB) { //pop M[valE] = valA
MemoryControl = 1;
Addr = e_mReg.valA;
}
if (e_mReg.icode == 9 ) { //ret valP = M[valE]
MemoryControl = 1;
Addr = e_mReg.valA;
}
//数据传递
if (e_mReg.icode == 2 || e_mReg.icode == 3 || e_mReg.icode == 6 || e_mReg.icode == 8 || e_mReg.icode == 9
|| e_mReg.icode == 0xA || e_mReg.icode == 0xB) {
fwdb.M_valE = e_mReg.valE;
fwdb.M_dstE = e_mReg.dstE;
sel_fwda.M_valE = e_mReg.valE;
sel_fwda.M_dstE = e_mReg.dstE;
}
DataMemory(Addr, Data, Datamemory, MemoryControl);
if (e_mReg.icode == 5 || e_mReg.icode == 0xB) {
fwdb.M_valM = m_wRegNew.valM;
fwdb.M_dstM = e_mReg.dstM;
sel_fwda.M_valM = m_wRegNew.valM;
sel_fwda.M_dstM = e_mReg.dstM;
}
selectpc.M_valA = e_mReg.valA;
m_wRegNew.bubble = 0;
m_wRegNew.stall = 0;
}
//写回阶段
void writeBack() {
if (m_wReg.stall) {
printf("WriteBack: stall\n");
return;
}
if (m_wReg.bubble) {
printf("WriteBack: Bubble\n");
return;
}
if (m_wReg.dstE != 0xF)
Register_file[m_wReg.dstE] = m_wReg.valE;
if (m_wReg.dstM != 0xF)
Register_file[m_wReg.dstM] = m_wReg.valM;
if (m_wReg.icode == 2 || m_wReg.icode == 3 || m_wReg.icode == 6 || m_wReg.icode == 8 || m_wReg.icode == 9
|| m_wReg.icode == 0xA || m_wReg.icode == 0xB) {
fwdb.M_valE = m_wReg.valE;
fwdb.M_dstE = m_wReg.dstE;
sel_fwda.M_valE = m_wReg.valE;
sel_fwda.M_dstE = m_wReg.dstE;
}
if (m_wReg.icode == 5 || m_wReg.icode == 0xB) {
fwdb.M_valM = m_wReg.valM;
fwdb.M_dstM = m_wReg.dstM;
sel_fwda.M_valM = m_wReg.valM;
sel_fwda.M_dstM = m_wReg.dstM;
}
selectpc.W_valM = m_wReg.valM;
printf("selectpc.W_valM=%d\n", selectpc.W_valM);
selectpc.W_icode = m_wReg.icode;
printf("selectpc.W_icode=%d\n", selectpc.W_icode);
}
void initCache() {
for (int i = 0; i < 16; i++)
{
Set[i].valid = 0;
}
}
void test_cache() {
for (int i = 0; i < 16; i++)
{
if (Set[i].valid) {
printf("Set[%d].Cache_block:%d\n",i, Set[i].Cache_block);
}
}
}
//主函数
int main() {
int i = 11;
initCache();
while (i--) {
printf("第%d条指令开始执行", 11 - i);
printf("开始预测\n");
Select_PC();
printf("PC = %d\n", selectpc.predpc);
Fetch(selectpc.predpc);
if (!f_dReg.stall) {
f_dReg = f_dRegNew;
}
else {
f_dReg.stall--;
}
Decode(&Register_file);
if (!d_eReg.stall) {
d_eReg = d_eRegNew;
}
else {
d_eReg.stall--;
}
Excecute();
e_mReg = e_mRegNew;
MemoryAccess();
m_wReg = m_wRegNew;
writeBack();
printf("Datamemory[%d]=%d\n", Register_file[4], Datamemory[Register_file[4]]);
memset(&f_dRegNew, 0, sizeof(f_dRegNew));
memset(&d_eRegNew, 0, sizeof(d_eRegNew));
memset(&e_mRegNew, 0, sizeof(e_mRegNew));
memset(&m_wRegNew, 0, sizeof(m_wRegNew));
}
printf("Datamemory[124]=%d", Datamemory[124]);
//test_cache();
return 0;
}