手把手代码实现五级流水线CPU——第一篇:初级顺序流水线


指令系统

在这里插入图片描述

编码格式

在这里插入图片描述

一、基础:顺序结构

1.取值阶段:

  • 根据icode还可以判断当前指令是否包含寄存器指示符字节(Need regids);以及是否包含常数字节(Need valC),由此计算出指令的长度,进而计算下一条地址

  • 当need_regids等于0时,表示这条指令没有寄存器指示符,rA和rB置为0xF;当指令中只含有一个寄存器操作数时,同样另一个字段置为0xF

  • 当need_regids等于0时,第1个字节到第8个表示常数字段valC,1时,2~9

2.译码阶段

  • 产生寄存器ID值,需要指令代码icode和rA、rB读取寄存器的数据,rA用于pop(call、ret)指令指针值

3.执行阶段

  • ALU根据指令功能(ifun)来判断对输入的操作数进行何种运算,都会产生条件码信号,但对于计算内存引用地址以及栈操作时,不必设置条件码,通过设置setCC,可根据icode来控制是否要更新条件码寄存器CC;标号为cond的硬件单元会根据指令功能和条件码寄存器产生一个cnd信号
  • 对于跳转指令,如果cnd=1,执行跳转,否则不跳转

4.访存阶段

  • 就是从内存中读数据或者将数据写入内存中,根据信号计算状态码Stat
    读控制块,写控制块,产生内存地址和输入数据的控制块

5.写回阶段

  • 将数据写入寄存器文件
    两个写端口分别为M和E,对应的地址输入为dstE和dstM。当执行条件传送指令(cmov)时,写入操作还需根据执行阶段计算出的cnd信号;当不满足条件时,可以将目的寄存器设置为0xF来禁止写入寄存器文件

6.更新PC阶段

  • call指令
    常数字段
  • ret指令
    内存(栈)中读出返回地址
  • jxx跳转指令
    满足cnd,常数字段;否则,与其他一样,加上当前指令长度

详细硬件结构

在这里插入图片描述

指令在各个阶段完成的操作

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
更多指令操作请查找:Y86指令集

C代码实现

#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		//0x000 : irmovq  $9,   %rdx
								  ,0x30,0xf3,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00		//0x00a	: irmovq  $21,  %rbx
								  ,0x61,0x23												//0x014	: subq   %rdx,  %rbx
								  ,0x30,0xf4,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00		//0x016	: irmovq  $128, %rsp
								  ,0x40,0x43,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00		//0x020	: rmmovq %rsp,  100(%rbx)
								  ,0xa0,0x2f												//0x02a	: pushq  %rdx 
								  ,0xb0,0x0f												//0x02c	: popq   %rax  
								  ,0x73,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00				//0x02e	: je done
								  ,0x80,0x41,0x03,0x00,0x00,0x00,0x00,0x00,0x00				//0x037	: call proc
	//0x040	: done:
,0x00														//0x040	:     halt
//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 stat;
	int icode;
	int ifuc;
	int rA;
	int rB;
	int valC;
	int valP;
};
struct D_EReg {
	int stat;
	int icode;
	int ifuc;
	int valC;
	int valA;
	int valB;
	int dstE;
	int dstM;
	int srcA;
	int srcB;
};

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

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(struct SelectPC* selectpc) {
	if (selectpc->W_icode == 9) {	//ret生效
		selectpc->predpc = selectpc->W_valM;
	}
	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,struct Inst* inst,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, struct Inst* inst, struct F_DReg* f_dReg) {
	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,inst, Need_regids, Need_valC);
	}
	if (inst->icode == 1 && inst->ifunct == 0) {
		Need_valC = 0;
		Need_regids = 0;
		Align(pc, inst, Need_regids, Need_valC);
	}
	if (inst->icode == 2) {
		Need_valC = 0;
		Need_regids = 3;
		Align(pc, inst, Need_regids, Need_valC);
	}
	if (inst->icode == 3 && inst->ifunct == 0) {
		Need_valC = 1;
		Need_regids = 1;
		Align(pc, inst, Need_regids, Need_valC);
	}
	if (inst->icode == 4 && inst->ifunct == 0) {
		Need_valC = 1;
		Need_regids = 3;
		Align(pc, inst, Need_regids, Need_valC);
	}
	if (inst->icode == 5 && inst->ifunct == 0) {
		Need_valC = 1;
		Need_regids = 3;
		Align(pc, inst, Need_regids, Need_valC);
	}
	if (inst->icode == 6) {
		Need_valC = 0;
		Need_regids = 3;
		Align(pc, inst, Need_regids, Need_valC);
	}
	if (inst->icode == 7) {
		Need_valC = 1;
		Need_regids = 0;
		Align(pc, inst, Need_regids, Need_valC);
	}
	if (inst->icode == 8 && inst->ifunct == 0) {
		Need_valC = 1;
		Need_regids = 0;
		Align(pc, inst, Need_regids, Need_valC);
	}
	if (inst->icode == 9 && inst->ifunct == 0) {
		Need_valC = 0;
		Need_regids = 0;
		Align(pc, inst, Need_regids, Need_valC);
	}
	if (inst->icode == 0xA && inst->ifunct == 0) {
		Need_valC = 0;
		Need_regids = 2;
		Align(pc, inst, Need_regids, Need_valC);
	}
	if (inst->icode == 0xB && inst->ifunct == 0) {
		Need_valC = 0;
		Need_regids = 2;
		Align(pc, inst, Need_regids, Need_valC);
	}
	if (!(inst->icode >= 0 && inst->icode <= 11)) {
		f_dReg->stat = 0;
	}
}
void Fetch(struct F_DReg* f_dReg,int pc){
	struct Inst inst = {0,0,0,0,0,0,0};
	Split(pc,&inst, f_dReg);
	inst.valP = PC_inc(inst.len, pc);
	fReg.predPC = Predict_PC(inst.icode, inst.valC, inst.valP);
	selectpc.predpc = selectpc.predpc;
	f_dReg->icode = inst.icode;
	f_dReg->ifuc = inst.ifunct;
	f_dReg->rA = inst.rA_id;
	f_dReg->rB = inst.rB_id;
	f_dReg->valC = inst.valC;
	f_dReg->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(struct SelectA_and_FwdA* sel_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(struct FwdB* 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(struct F_DReg f_dReg, struct D_EReg* d_eReg, int* Register_file) {
	d_eReg->stat = f_dReg.stat;
	d_eReg->icode = f_dReg.icode;
	d_eReg->valC = f_dReg.valC;
	d_eReg->ifuc = f_dReg.ifuc;
	if (f_dReg.icode == 0 || f_dReg.icode == 1) {
		;
	}
	if (f_dReg.icode == 2) {	//rr
		d_eReg->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_eReg->valA = sel_fwda.valA;

		d_eReg->srcB = f_dReg.rB;
		d_eReg->valB = 0;

		d_eReg->dstE = f_dReg.rB;		//将结果valE写回寄存器rB
	}
	if (f_dReg.icode == 3) {	//ir
		d_eReg->srcA = f_dReg.rA;
		d_eReg->srcB = f_dReg.rB;
		d_eReg->valB = 0;
		d_eReg->dstE = f_dReg.rB;		//将ALU结果valE写回寄存器rB
	}
	if (f_dReg.icode == 4) {	//rm  rA,D(rB)  不需要写回寄存器
		d_eReg->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_eReg->valA = sel_fwda.valA;

		d_eReg->srcB = f_dReg.rB;  //对rB去寄存器取基地址
		fwdb.srcB = f_dReg.rB;
		fwdb.register_B = Register_file[f_dReg.rB];
		FwdB(&fwdb);
		d_eReg->valB = fwdb.valB;
	}
	if (f_dReg.icode == 5) {	//mr  D(rB),rA   需要验证
		d_eReg->srcB = f_dReg.rB;		//对rB去寄存器取基地址
		fwdb.srcB = f_dReg.rB;
		fwdb.register_B = Register_file[f_dReg.rB];
		FwdB(&fwdb);
		d_eReg->valB = fwdb.valB;


		d_eReg->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_eReg->valA = sel_fwda.valA;

		fwdb.srcB = f_dReg.rB;
		fwdb.register_B = Register_file[f_dReg.rB];
		FwdB(&fwdb);
		d_eReg->valB = fwdb.valB;

		d_eReg->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(&sel_fwda);
		d_eReg->valA = sel_fwda.valA;
	}
	if (f_dReg.icode == 8) {	//call
		d_eReg->srcA = 4;

		sel_fwda.srcA = 4;
		sel_fwda.register_A = Register_file[f_dReg.rA];
		SelectA_and_FwdA(&sel_fwda);
		d_eReg->valA = sel_fwda.valA;

		fwdb.srcB = 4;
		fwdb.register_B = Register_file[f_dReg.rB];
		FwdB(&fwdb);
		d_eReg->valB = fwdb.valB;

		d_eReg->dstE = 4;		//将ALU结果valE写回寄存器sp
	}
	if (f_dReg.icode == 9) {	//ret
		d_eReg->srcA = 4;				//对sp去寄存器取数据 
		sel_fwda.srcA = 4;
		sel_fwda.register_A = Register_file[f_dReg.rA];
		SelectA_and_FwdA(&sel_fwda);
		d_eReg->valA = sel_fwda.valA;

		d_eReg->srcB = 4;
		fwdb.srcB = 4;
		fwdb.register_B = Register_file[f_dReg.rB];
		FwdB(&fwdb);
		d_eReg->valB = fwdb.valB;

		d_eReg->dstE = 4;		//将ALU结果valE写回寄存器sp
	}
	if (f_dReg.icode == 0xA) {//push
		d_eReg->srcA = f_dReg.rA;

		sel_fwda.srcA = f_dReg.rA;		//对rA去寄存器取数据
		sel_fwda.register_A = Register_file[f_dReg.rA];
		SelectA_and_FwdA(&sel_fwda);
		d_eReg->valA = sel_fwda.valA;

		d_eReg->srcB = 4;
		fwdb.srcB = 4;
		fwdb.register_B = Register_file[f_dReg.rB];
		FwdB(&fwdb);
		d_eReg->valB = fwdb.valB;

		d_eReg->dstE = 4;		//将ALU结果valE写回寄存器sp
	}
	if (f_dReg.icode == 0xB) {//popq
		d_eReg->srcA = 4;				//对sp去寄存器取数据 
		sel_fwda.srcA = 4;
		sel_fwda.register_A = Register_file[f_dReg.rA];
		SelectA_and_FwdA(&sel_fwda);
		d_eReg->valA = sel_fwda.valA;

		d_eReg->srcB = 4;				//对sp去寄存器取数据
		fwdb.srcB = 4;
		fwdb.register_B = Register_file[f_dReg.rB];
		FwdB(&fwdb);
		d_eReg->valB = fwdb.valB;

		d_eReg->dstE = 4;		//将ALU结果valE写回寄存器sp
		d_eReg->dstM = f_dReg.rA;		//将Datamemory结果valM写回寄存器rA
	}
}
//执行阶段
void setCC(struct CC* cc, 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(struct CC cc, 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;
	}
}
void Excecute(struct D_EReg d_eReg, struct E_MReg* e_mReg) {
	int ALU_A;
	int ALU_B;
	e_mReg->stat = d_eReg.stat;
	e_mReg->icode = d_eReg.icode;
	e_mReg->valA = d_eReg.valA;
	e_mReg->dstM = d_eReg.dstM;
	int op = 1;//1:add,2:sub,3:and,4:xor
	if (d_eReg.icode == 0) {//				不提供数据转发
		e_mReg->dstE = 0xF;
	}
	if (d_eReg.icode == 1) {//				不提供数据转发
		e_mReg->dstE = 0xF;
	}
	if (d_eReg.icode == 2) {//rr		如果条件满足才提供数据转发
		ALU_A = d_eReg.valA;
		ALU_B = d_eReg.valB;
		op = 1;
		e_mReg->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_mReg->Cnd = 1;
		}
		if (d_eReg.ifuc == 1) {
			e_mReg->Cnd = Cond(cc, d_eReg.ifuc);
		}
		if (d_eReg.ifuc == 2) {
			e_mReg->Cnd = Cond(cc, d_eReg.ifuc);
		}
		if (d_eReg.ifuc == 3) {
			e_mReg->Cnd = Cond(cc, d_eReg.ifuc);
		}
		if (d_eReg.ifuc == 4) {
			e_mReg->Cnd = Cond(cc, d_eReg.ifuc);
		}
		if (d_eReg.ifuc == 5) {
			e_mReg->Cnd = Cond(cc, d_eReg.ifuc);
		}
		if (d_eReg.ifuc == 6) {
			e_mReg->Cnd = Cond(cc, d_eReg.ifuc);
		}
		if (e_mReg->Cnd) {
			e_mReg->dstE = d_eReg.dstE;
			fwdb.E_dstE = d_eReg.dstE;
			sel_fwda.E_dstE = d_eReg.dstE;
		}
		else {
			e_mReg->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_mReg->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_mReg->dstE = d_eReg.dstE;
	}
	if (d_eReg.icode == 4) {//rm			不提供数据转发
		op = 1;
		ALU_A = d_eReg.valC;
		ALU_B = d_eReg.valB;
		e_mReg->valE = ALU(ALU_A, ALU_B, op);
		e_mReg->dstE = 0xF;
	}
	if (d_eReg.icode == 5) {//mr			只有访存后才数据转发
		op = 1;
		ALU_A = d_eReg.valC;
		ALU_B = d_eReg.valB;
		e_mReg->valE = ALU(ALU_A, ALU_B, op);
		e_mReg->dstE = d_eReg.dstE;
	}
	if (d_eReg.icode == 6) {//Opq rr		提供数据转发
		ALU_A = d_eReg.valA;
		ALU_B = d_eReg.valB;
		e_mReg->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_mReg->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(&cc, ALU_A, ALU_B, e_mReg->valE, op);
	}
	if (d_eReg.icode == 7) {//jxx			不提供数据转发
		if (d_eReg.ifuc == 0) {				//jmp
			e_mReg->Cnd = 1;
		}
		if (d_eReg.ifuc == 1) {				//jle  (SF ^ OF) | ZF
			e_mReg->Cnd = Cond(cc, d_eReg.ifuc);
		}
		if (d_eReg.ifuc == 2) {				//jl   SF ^ OF
			e_mReg->Cnd = Cond(cc, d_eReg.ifuc);
		}
		if (d_eReg.ifuc == 3) {				//je   ZF
			e_mReg->Cnd = Cond(cc, d_eReg.ifuc);
		}
		if (d_eReg.ifuc == 4) {				//jne  ~ZF
			e_mReg->Cnd = Cond(cc, d_eReg.ifuc);
		}
		if (d_eReg.ifuc == 5) {				//jge   ~(SF ^ OF)
			e_mReg->Cnd = Cond(cc, d_eReg.ifuc);
		}
		if (d_eReg.ifuc == 6) {				//jg    ~(SF ^ OF) & ~ZF
			e_mReg->Cnd = Cond(cc, d_eReg.ifuc);
		}
	}
	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_mReg->valE = ALU(ALU_A, ALU_B, op);
		e_mReg->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_mReg->valE = ALU(ALU_A, ALU_B, op);
		e_mReg->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 == 0xB) {	//pop  valB=R[%rsp]   提供数组转发  1.执行阶段valB=R[%rsp] 2.访存后 valM
		ALU_B = d_eReg.valB;
		ALU_A = 4;
		op = 1;
		e_mReg->valE = ALU(ALU_A, ALU_B, op);
		e_mReg->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_mReg->Cnd;
	selectpc.M_icode = e_mReg->icode;
}
//访存阶段
void DataMemory(int addr, int Data, int* Datamemory, int MemoryControl, struct M_WReg* m_wReg) {
	if (MemoryControl == 1) {
		m_wReg->valM = Datamemory[addr];
	}
	else if (MemoryControl == 2) {
		Datamemory[addr] = Data;
	}
}
void MemoryAccess(struct E_MReg e_mReg, struct M_WReg* m_wReg) {
	int MemoryControl = -1;	//0:不读不写;1:读有效,输入地址输出valM;2:写有效,输入地址数据
	int Addr = -1;
	int Data = -1;
	m_wReg->icode = e_mReg.icode;
	m_wReg->stat = e_mReg.stat;
	m_wReg->valE = e_mReg.valE;
	m_wReg->dstE = e_mReg.dstE;
	m_wReg->dstM = e_mReg.dstM;
	if (e_mReg.icode == 0 || e_mReg.icode == 1 || e_mReg.icode == 2) {
		MemoryControl = 0;
	}
	if (e_mReg.icode == 3 || e_mReg.icode == 8 || e_mReg.icode == 0xA) {	//rm push M[valE] = valA
		MemoryControl = 2;
		Addr = e_mReg.valE;
		Data = e_mReg.valA;
	}
	if (e_mReg.icode == 5) {	//mr
		MemoryControl = 1;
		Addr = e_mReg.valE;
	}
	if (e_mReg.icode == 9 || e_mReg.icode == 0xB) {	//ret pop M[valE] = valA
		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, m_wReg);
	if (e_mReg.icode == 5 || e_mReg.icode == 0xB) {
		fwdb.M_valM = m_wReg->valM;
		fwdb.M_dstM = e_mReg.dstM;
		sel_fwda.M_valM = m_wReg->valM;
		sel_fwda.M_dstM = e_mReg.dstM;
	}
	selectpc.M_valA = e_mReg.valA;
}
//写回阶段
void writeBack(struct M_WReg m_wReg) {
	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;
	selectpc.W_icode = m_wReg.icode;
}

//主函数
int main() {
	int i = 5;
	struct F_DReg f_dReg = { 1,0,0,0,0,0,0 };
	struct D_EReg d_eReg = { 1,0,0,0,0,0,0,0,0,0 };
	struct E_MReg e_mReg = { 1,0,0,0,0,0,0 };
	struct M_WReg m_wreg = { 1,0,0,0,0xF,0xF };

	while (i--) {
		if (!selectpc.predpc) {
			Select_PC(&selectpc);
		}
		Fetch(&f_dReg, selectpc.predpc);
		printf("取指阶段-------------------\n");
		printf("f_dReg.icode = %d\n", f_dReg.icode);
		printf("f_dReg.ifun = %d\n", f_dReg.ifuc);
		printf("f_dReg.rA = %d\n", f_dReg.rA);
		printf("f_dReg.rB = %d\n", f_dReg.rB);
		printf("f_dReg.valC = %d\n", f_dReg.valC);

		Decode(f_dReg, &d_eReg, &Register_file);
		printf("译码阶段-------------------\n");
		printf("d_eReg.icode = %d\n", d_eReg.icode);
		printf("d_eReg.ifun = %d\n", d_eReg.ifuc);
		printf("d_eReg.srcA = %d\n", d_eReg.srcA);
		printf("d_eReg.valA = %d\n", d_eReg.valA);
		printf("d_eReg.srcB = %d\n", d_eReg.srcB);
		printf("d_eReg.valB = %d\n", d_eReg.valB);
		printf("d_eReg.dstE = %d\n", d_eReg.dstE);
		printf("d_eReg.dstM = %d\n", d_eReg.dstM);
		printf("d_eReg.valC = %d\n", d_eReg.valC);

		Excecute(d_eReg, &e_mReg);
		printf("执行阶段--------------------\n");
		printf("e_mReg->valE = %d\n", e_mReg.valE);
		printf("e_mReg->dstE = %d\n", e_mReg.dstE);

		MemoryAccess(e_mReg, &m_wreg);
		printf("访存阶段----------------------\n");
		writeBack(m_wreg);
		printf("写回阶段----------------------\n");
		printf("rbx = %d\n", Register_file[3]);
	}


	return 0;
}

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 很高兴听到您对RISC-V处理器的兴趣。设计CPU是一项复杂的任务,需要深入的计算机体系结构知识和硬件设计技能。以下是一些基本步骤,可以帮助您开始设计RISC-V处理器: 1.了解RISC-V架构:RISC-V是一种开放源代码指令集架构,它的设计旨在简化处理器的设计和实现。您需要了解RISC-V的指令集、寄存器、内存管理和异常处理等方面的基本知识。 2.选择设计工具:设计CPU需要使用硬件描述语言(HDL),如Verilog或VHDL。您需要选择一个合适的设计工具,如Xilinx Vivado或Altera Quartus等。 3.设计处理器核心:处理器核心是CPU的主要组成部分,它包括指令译码、执行单元、寄存器文件和数据通路等。您需要根据RISC-V架构的要求设计处理器核心。 4.实现内存管理单元:内存管理单元(MMU)是处理器的重要组成部分,它负责管理内存访问和虚拟地址转换等。您需要实现MMU以支持RISC-V的内存管理功能。 5.测试和验证:设计CPU后,您需要进行测试和验证以确保其正确性和性能。您可以使用仿真工具进行测试,或者使用FPGA进行验证。 以上是设计RISC-V处理器的基本步骤,但这只是一个简单的概述。设计CPU需要深入的计算机体系结构知识和硬件设计技能,需要不断学习和实践。希望这些信息能够帮助您开始设计RISC-V处理器。 ### 回答2: RISC-V处理器是一款开源的指令集架构,目前被广泛应用于各种类型的芯片设计中,如移动设备、网络设备、服务器等。在学习如何设计RISC-V处理器之前,我们需要先了解一些基本的概念和技术。 首先,指令集架构(ISA)是处理器硬件和软件之间通信的接口规范,决定了处理器可以解释和执行哪些指令。在RISC-V处理器中,指令集被分为不同的“指令集扩展”模块,包括基本指令集、乘除运算指令集、浮点运算指令集等。每个扩展模块都包含一组相关的指令,为定制和优化处理器提供了灵活性。 其次,流水线技术是处理器设计中常用的性能优化手段。流水线是一个分阶段的处理器执行单元,每个阶段依次执行指令的不同部分,从而实现指令并行执行。然而,流水线可能会遇到数据相关性和控制相关性等问题,需要使用一些技术来解决。 最后,硬件描述语言(HDL)是描述数字电路和系统的语言,可以使用HDL来描述处理器的逻辑电路和功能实现。常见的HDL包括Verilog和VHDL,可以使用这些语言来实现RISC-V处理器的功能模块。 接下来,我们可以手把手教你如何设计RISC-V处理器: 第一步,定义指令集。定义指令集是设计处理器的第一步,需要确定基本指令集并考虑扩展模块的需求。 第二步,确定处理器流水线架构。处理器流水线架构的设计涉及指令的分阶段执行和数据通路的设计,需要考虑处理器性能和复杂度的平衡。 第三步,实现处理器的逻辑电路。通过HDL语言来实现RISC-V处理器的逻辑电路和功能模块,包括控制单元、寄存器文件和运算单元等。 第四步,进行仿真和验证。仿真和验证是测试处理器功能和性能的关键步骤,可以使用EDA工具来进行仿真和验证。 第五步,进行物理设计。物理设计涉及到处理器芯片的物理规划、布图和布线等步骤,需要协同进行。 以上是大致的设计流程,实际上,RISC-V处理器设计需要考虑的因素还有很多,例如内存管理、中断处理等等。不过,只要按照步骤逐步设计,加上充分的沟通和协作,基本上都能够顺利完成设计任务。 ### 回答3: RISC-V是一个完全开源的指令集架构,可以自由使用和修改,非常适合自己设计CPU。以下是手把手教你设计CPU-RISC-V处理器篇。 第一步:确定CPU体系结构和指令集 首先,需要确定CPU的体系结构和指令集。RISC-V提供了多个不同级别的指令集,每个级别的指令集都有不同的指令数量、复杂度和性能。根据自己的需要和能力,选择适合自己的指令集。 第二步:设计CPU数据通路 设计CPU的数据通路需要确定如何实现指令的执行和数据的传输。可以使用硬件描述语言(例如Verilog)来描述数据通路。对于RISC-V处理器,需要实现以下基本单元:ALU(算术逻辑单元)、寄存器文件、存储器控制器和指令解码器。 第三步:测试CPU 设计完成后,需要对CPU进行测试。可以使用模拟器来模拟CPU的运行,也可以将CPU制成芯片进行实际测试。在测试期间,可以使用不同的指令和数据来验证CPU的正确性和性能。 第四步:优化CPU 一旦确认CPU能够正确运行,就可以开始优化CPU的性能。可以使用一些技术来提高CPU的性能和功效,例如通过流水线、分支预测、数据缓存等方式提高数据传输和处理效率。 总结: 设计RISC-V处理器需要确定体系结构和指令集,设计数据通路,测试和优化。这个过程需要深厚的计算机体系结构和数字电路设计的知识,同时要有足够的耐心和毅力。通过这个过程,可以获得极为满足和有成就感的终极收获。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Strive_LiJiaLe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值