乱序执行C语言实现

来不及debug了

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
struct PC 
{
    
    
	char type[20];
	int SR1_id;			//源寄存器编号
	int SR2_id;			//源寄存器编号
	int DR_id;			//目的寄存器编号
};

#define RS_size    5   //Reservation Station 保留站
#define Reg_size   5   //寄存器个数
#define P_Reg_size 16  //物理寄存器个数
#define ROB_size   5   //Re—order Buffer     重排序缓冲区
#define TYPE	   ADD
int main() 
{
    
    
	int i, j,k;				//循环变量
	//寄存器
	int Reg[Reg_size]= {
    
    1,10,20,0,0};
	//物理寄存器
	int P_Reg[P_Reg_size]= {
    
    0};
	//映射表 寄存器到物理寄存器的映射
	int map[P_Reg_size] = {
    
    0};				//P_Reg->Reg
	//每次可同时执行的指令序号,如order[0][0]=1,order[0][1]=2,说明指令1和指令2在第一周期可同时执行
	int order[ROB_size][ROB_size] ={
    
    0};
	//寄存器标记
	int flag[P_Reg_size] = {
    
     0 };
	//成功排序标记
	int success[ROB_size] = {
    
    0};
	//保留站
/*
假设指令为:
ADD R3,R1,R2       //指令1和指令2 数据相关
ADD R4,R3,R2	   //指令2和指令3 反相关
ADD R2,R1,R3	   //指令3和指令4 输出相关
ADD R2,R1,R4	   //指令4和指令5 数据相关
ADD R4,R2,R3
*/
	struct PC RS[RS_size] = {
    
     {
    
     "TYPE",1,2,3},
							  {
    
     "TYPE",3,2,4},
							  {
    
     "TYPE",1,3,2},
							  {
    
     "TYPE",1,4,2},
							  {
    
     "TYPE",2,3,4} };
	//缓冲区
	struct PC ROB[ROB_size] = RS;

//--------------------寄存器重命名------------------
// 
	//映射初始化
	for ( i = 1; i < 5; i++)
	{
    
    
		//F1->R1,F2->R2,F3->R3,F4->R4
		map[i] = i;					//map的i是物理寄存器编号  右边是寄存器编号
		P_Reg[i] = Reg[i];			//传递数据,前四个数一对一传递
	}
	//全部映射,一边映射一边更新
	//j控制ROB缓冲区的更新
	for ( i = 5,j = 0; i < P_Reg_size; i++,j++)
	{
    
    
		//目的寄存器优先重命名
		map[i] = RS[j].DR_id; //F5->R3
		
		//更新ROB缓冲区
		//倒序寻找源寄存器最新重命名
		for ( k = P_Reg_size-1; k > 0; k--)
		{
    
    
			if (RS[j].SR1_id == map[k])			 //找到源寄存器1重命名后的寄存器编号
			{
    
    
				ROB[j].SR1_id = k;
				P_Reg[k] = Reg[map[k]];			//传递数据
				break;
			}
		}
		for (k = P_Reg_size - 1; k > 0; k--)
		{
    
    
			if (RS[j].SR2_id == map[k])  //找到源寄存器2重命名后的寄存器编号
			{
    
    
				ROB[j].SR2_id = k;
				P_Reg[k] = Reg[map[k]]; //传递数据
				break;
			}
		}
		//倒序寻找目的寄存器最新重命名
		for (k = P_Reg_size - 1; k > 0; k--)
		{
    
    
			if (RS[j].DR_id == map[k])  //找到重命名后的寄存器编号
			{
    
    
				ROB[j].DR_id = k;
				P_Reg[k] = Reg[map[k]];
				break;
			}
		}
		//执行指令,存入重命名后的目的寄存器
		P_Reg[ROB[j].DR_id] = TYPE(P_Reg[ROB[j].SR1_id], P_Reg[ROB[j].SR2_id]);

	}
//--------------------寄存器重命名------------------

/*
重命名后的形式假设为:

ADD F5,F1,F2		ROB结构体形式: "TYPE",1,2,5  //指令类型,源寄存器1编号,源寄存器2编号,目的寄存器编号
ADD F6,F5,F2					   "TYPE",5,2,6
ADD F7,F1,F5					   "TYPE",1,5,7
ADD F8,F1,F6					   "TYPE",1,6,8
ADD F9,F8,F5					   "TYPE",8,5,9

假设第一条指令的源操作数已经准备好,处理器会通知所有依赖F5的指令,F5已经准备好了,指令2需要的两个源操作数F5和
F2都已准备好,它就可以被发送到指令的执行队列中去执行。同样,指令3也可以准备执行,如果处理器中有多个加法单元,
指令2和指令3就可以同时执行。指令2完成后,F6也准备好了,指令4就可以去执行,指令4执行完后,F8就准备好了,F5早
就准备好了,指令5就可以去执行。在这个调度的例子中,5条指令4个Cycle就可以完成,而使用顺序内核,则需要5个Cycle。
方法1.定义一个一维数组来标记每个寄存器数据是否准备好,然后进行扫描,如果某条指令的源寄存器数据已经准备好,则
可执行,然后将目的寄存器标记为准备好。
方法2.利用拓扑排序。
用方法1实现。
*/
	flag[ROB[0].SR1_id] = 1;
	flag[ROB[0].SR2_id] = 1;
	
	for ( i = 0, j = 0; i < ROB_size; i++)
	{
    
    
		//扫描指令
		for ( k = 0; k < ROB_size; k++)
		{
    
    
			if (success[k])
				continue;
			if (flag[ROB[k].SR1_id] && flag[ROB[k].SR2_id])
			{
    
    	//满足
				order[i][j++] = k;			//成功排序,下次循环标记
				success[k] = 1;			//下次不用验证了
			}

		}
		//检查是否可以提前结束
		for ( k = 0; k < ROB_size; k++)
		{
    
    
			if (success[k])
				;
			else
				break;
		}
		if (k == ROB_size)
			break;
		//遍历order,将成功排序的指令进行更新标记
		for ( k = 0; k < j; k++)
		{
    
    
			if(order[k])
				flag[ROB[k].DR_id] = 1;
		}
	}
	return 0;
}

int TYPE(int a, int b)
{
    
    
	return a + b;
}

猜你喜欢

转载自blog.csdn.net/Strive_LiJiaLe/article/details/127526066