Hand-in-hand code to realize five-stage pipeline CPU——Part 3: Pipeline control logic

Series Article Directory

Part 1: Primary Sequential Pipeline
Part 2: Branch Prediction Pipeline



1. Control logic

Dynamically adjust the state of the pipeline by pausing and inserting bubbles
insert image description here

2. Concrete operation

insert image description here

1. Judgment timeout

  • Identification:
    When the instruction reads the register in the decoding stage, the id value of the read register is compared with the destination register of the instruction executed in the execution stage, the memory access stage, and the write-back stage.

     如果存在寄存器id值相等的情况,就说明指令之间存在数据相关,那么该指令就要在译码阶段等待
    
  • Method:
    By inserting bubbles to replace paused instructions

     气泡不会改变寄存器、内存、条件码以及程序状态
    
  • use:

    Addressing Data Risks

     基于这种机制实现的流水线性能并不高,频繁暂停,降低流水线的吞吐量
    
  • optimization:

    Directly transfer the operation result and forward the data, but for the memory access instruction, the data is relatively late, so you must use pause and then forward

     使得流水线不用暂停就可以处理大多数情况的数据冒险
    

2. Take control of the adventure

  • Problem:
    Since each value fetch operation is required, the address of the next instruction must be determined immediately

     当取出指令为ret时,下一条指令需要从栈中读出,因此必须等到访存操作结束后才能确定下一条指令的地址
     当取到的指令是分支条件指令时,流水线无法立即进行立即判断是否进行跳转,通过执行阶段后才能确定跳转
    
  • Method:
    suspend the execution of new instructions

3. Jump problem

  • Strategy:
    predictive branch always jumps or never jumps

  • Solution:
    For the first instruction that needs to be flushed, insert bubbles in the execution phase; for the second instruction, insert bubbles in the decoding phase, and take out the instruction after the jump instruction

4. Realize

  • Introduce two control signals for each pipeline register, namely the pause signal and the bubble signal

  • When a pause is required, set the pause signal to 1, and the register will maintain the previous state, and the instruction will be blocked in a certain stage of the pipeline.

  • When a bubble needs to be inserted, the state of the register will be set to a fixed reset configuration, which is equivalent to the state of the instruction nop

insert image description here

the code

#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;
}

Guess you like

Origin blog.csdn.net/Strive_LiJiaLe/article/details/128519372