来不及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;
}