Cache三种映射以及LRU策略C语言实现

头文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
#include<math.h>
#include<stdbool.h>
#define MAX_CACHE_LINE 65536
//映射方式
enum associativity_way {
    
    
	direct_mapped = 1,
	set_associative,
	full_associative
};
//替换策略
enum replacement_way {
    
    
	none,
	FIFO = 1,
	LRU,
	LFU,
	Random
};
//写策略
enum write_way{
    
    
	write_through = 1,
	write_back
};

typedef enum associativity_way ASSOC;
typedef enum replacement_way REPLACE;
typedef enum write_way WRITE;

extern char i_type;							//指令类型

extern unsigned int long i_cache_size;		//cache 大小
extern unsigned int long i_cache_line_size; //cacheline 大小
extern unsigned int long i_cache_set;		//cache 组大小

extern unsigned int long i_num_line;		//cache 的行数(块数)
extern unsigned int long i_num_set;			//cache 的组数

extern ASSOC t_assoc;						//associativity method
extern REPLACE t_replace;					//replacement policy
extern WRITE t_write;						//write policy

extern short unsigned int bit_block;		//字块内地址所占位数
extern short unsigned int bit_line;			//cache字块地址
extern short unsigned int bit_tag;			//主存字块标记
extern short unsigned int bit_set;			//组地址

extern int cache_item[MAX_CACHE_LINE][32];	//[31]:valid [30]:hit [29]:dirty [28]-[0]:data
extern unsigned long int LRU_priority[MAX_CACHE_LINE];//LRU 策略的优先级
extern unsigned long int current_line;		//正在处理的行号
extern unsigned long int current_set;		//正在处理的组号
extern unsigned long int i, j;				//循环变量
extern unsigned long int temp;				//空变量
//.c文件有详细函数讲解
bool GetHitNum(char *address,char i_type);	
bool IsHit(char* address);
void GetReplace(char* address);
void GetRead(char* address);
void GetWrite();

void LruHitProcess();
void LruUnhitSpace();
void LruUnhitUnspace();

.c 文件

#include "base.h"

char i_type = 's';
unsigned int long i_cache_size = 0;
unsigned int long i_cache_line_size = 0;
unsigned int long i_cache_set = 0;

unsigned int long i_num_line = 0;
unsigned int long i_num_set = 0;

ASSOC t_assoc = direct_mapped;				//默认直接映射
REPLACE t_replace = none;					//默认随机替换
WRITE t_write = write_back;						//默认回写

short unsigned int bit_block = 0;		//字块内地址所占位数
short unsigned int bit_line = 0;			//cache字块地址
short unsigned int bit_tag = 0;			//主存字块标记
short unsigned int bit_set = 0;			//组地址

int cache_item[MAX_CACHE_LINE][32];	//[31]:valid [30]:hit [29]:dirty [28]-[0]:data
unsigned long int LRU_priority[MAX_CACHE_LINE];//LRU 策略的优先级
unsigned long int current_line = 0;		//正在处理的行号
unsigned long int current_set = 0;		//正在处理的组号
unsigned long int i = 0, j = 0;			//循环变量
unsigned long int temp = 0;				//空变量


/*
* 关于一致性:
* 写操作放入cache后需要将dirty=1,因为没有写入内存,下次需要替换时,需要保存到主存里
* 读操作不需要设置dirty,因为读始终和主存保持一致性
* 先通过Ishit()得到当前行命中情况
* 
命中:
	读操作:
		1.读数据即可
		2.进入LruHitProcess()更新lru表
	写操作:
		1.写入数据即可(修改cache_item[curremt][date部分])
		2.设置dirty=1
		3.进入LruHitProcess()更新lru表

没命中:
	直接映射:
		读操作:进入GetRead()取数据(从主存拿数据),然后放入cache行:
			该行hit=0,无数据(空闲):
				1.(放数据)直接修改cache行:data和tag以及hit
			该行hit=1,有数据:
				1.进入GetRePlace(),无策略,直接考虑dirty,决定旧数据的去留
				2.修改cache行:data和tag以及hit
				-----退出GetRepalce()
		-----退出GetRead()
		执行LruUnhitSpace()更新lru表格

		写操作:和读操作相同,只是数据来源不同,直接有数据
				需要设置dirty=1
	组相联和全相联映射:
		读操作:进入GetRead()取数据
			hit=0,有空闲:
				1.(放数据)修改cache行:data和tag以及hit
				2.LruUnhitSpace()更新lru表格
			hit=1,无空闲:
				1.进入GetRePlace()
					1.通过LruUnhitUnsapce(),得到要替换的行
					2.如果此行dirty=1,执行GetWrite()写入内存
					3.此时,该行设置为空闲,dirty、hit=0
					4.(放数据)修改cache行:data和tag以及hit
				2.退出GetRePlace()
		-----退出GetRead()
		执行LruUnhitSpace()更新lru表格

		写操作:设置dirty=1
*/
bool GetHitNum(char* address,char i_type)
{
    
    
	bool is_store = false;
	bool is_load = false;
	bool is_space = false;
	bool hit = false;
	
	switch (i_type) 
	{
    
    
	case's':
		is_store = true;
		break;
	case'l':
		is_load = true;
		break;
	case'\0':
		is_space = true;
		break;
	default:
		printf("The i_type is %c\n",&i_type);
		printf("ERROR IN JUDGE\n");
		return false;
	}
	hit = IsHit(address);	//得到了命中行号

	if (hit && is_load)		//命中,读操作
	{
    
    
		printf("Loading\n");
		printf("Hit\n");
		printf("Read from Cache!\n");

		if (t_replace == LRU)
		{
    
    
			LruHitProcess();
		}
	}
	else if (hit && is_store)//命中,写操作
	{
    
    
		printf("Storing\n");
		printf("Hit\n");
		printf("write to Cache!\n");

		cache_item[current_line][29]= 1;//设置dirty为true

		if (t_replace == LRU)
		{
    
    
			LruHitProcess();
		}
	}
	else if ((!hit) && is_load)//没命中,读操作
	{
    
    
		printf("Loading\n");
		printf("Not Hit\n");
		printf("read from memory!\n");
		GetRead(address);

		if (t_replace == LRU)
		{
    
    
			LruUnhitSpace();
		}
	}
	else if ((!hit) && is_store)//没命中,写操作
	{
    
    
		printf("Storing\n");
		printf("Not Hit\n");
		printf("write to memory!\n");
		GetRead(address);
		cache_item[current_line][29]= 1;//设置dirty为true

		if (t_replace == LRU)
		{
    
    
			LruUnhitSpace();
		}
	}
	else
	{
    
    
		printf("something ERROR\n");
		return false;
	}
	return true;
}
/*先判断hit位的值
* 若hit位=1,说明有数据,可能命中,再比较Tag才确定是否命中
*否则为空行,肯定不命中
* 
直接映射可直接利用bit_line得到行号,再比较tag,才确定行号
全相连需要遍历,且依次比较tag,才确定行号
组相联可直接得到组号,再遍历比较,才确定行号
*/

bool IsHit(char* address)
{
    
    
	bool ret = false;

	if (t_assoc == direct_mapped)
	{
    
    
		int num_line = 0;//空变量//判断在cache多少行
		for (j=1,i = 31 - (bit_block); i >31 - (bit_block + bit_line); i--,j++)
		{
    
    
			num_line += address[i]*pow(2,j);
		}
		current_line = num_line;
		if (cache_item[current_line][30] == true)//判断hit位是否为真
		{
    
    
			ret = true;
			for ( i = 31, j = 28; i > (31 - bit_tag); i--,j--)
			{
    
    
				if(address[i]!=cache_item[current_line][j])
				{
    
    
					ret = false;
					break;
				}
			}
		}
	}
	else if (t_assoc == full_associative)
	{
    
    
		for ( temp = 0; temp < i_num_line; temp++)//遍历所有行
		{
    
    
			if (cache_item[temp][30] == true)//判断hit位是否为真
			{
    
    
				ret = true;
				for (i = 31, j = 28; i > (31 - bit_tag); i--, j--)
				{
    
    
					if (address[i] != cache_item[current_line][j])
					{
    
    
						ret = false;
						break;
					}
				}
			}
			if (ret == true)
			{
    
    
				current_line = temp;
				break;
			}
		}
	}
	else if (t_assoc == set_associative)
	{
    
    
		int num_set = 0;//空变量//判断在cache多少行
		for (j = 1, i = 31 - (bit_block); i > 31 - (bit_block + bit_set); i--, j++)
		{
    
    
			num_set += address[i] * pow(2, j);
		}
		current_set = num_set;
		for ( temp = (current_set*i_cache_set); temp < ((current_set+1)*i_cache_set); temp++)//遍历该组所有行
		{
    
    
			if (cache_item[temp][30] == true)//判断hit位是否为真
			{
    
    
				ret = true;
				for (i = 31, j = 28; i > (31 - bit_tag); i--, j--)
				{
    
    
					if (address[i] != cache_item[current_line][j])
					{
    
    
						ret = false;
						break;
					}
				}
			}
			if (ret == true)
			{
    
    
				current_line = temp;
				break;
			}
		}
	}
	return ret;
}
/*传数据在此刻进行
没命中时
* 所填入的行无数据,直接放数据,修改TAG,,修改hit
* 有数据(hit),进行替换(是否使用策略),考虑dirty
* 
* 直接映射,位置固定,不需要找空闲,直接对该行判断,不涉及替换算法
* 
* 组相联和全相连需要先判断是否有空闲
* 有空闲(hit = 0):直接放入(tag),进入LruUnhitSapce()
* 否则执行 LruUnhitUnspace()
* 
*/
void GetRead(char* address)
{
    
    
	if (t_assoc == direct_mapped)
	{
    
    
		if(cache_item[current_line][30] == false)//hit is false
		{
    
    
			printf("Read from Main Memory to Cache\n");
			//----将主存内容放入cache中,再更改tag
			for (i=31,j=28;i>(31-bit_tag);i--,j--)
			{
    
    
				cache_item[current_line][j] = address[i];
			}
			cache_item[current_line][30] = 1;//设置hit位为true
		}
		else
		{
    
    
			GetReplace(address);
		}
		
	}
	else if (t_assoc == full_associative)
	{
    
    
		bool space = false;
		for (temp = 0; temp < i_num_line; temp++)
		{
    
    
			if (cache_item[temp][30] == false) //find a space line
			{
    
    
				space = true;
				break;
			}
		}
		if (space == true)
		{
    
    
			current_line = temp;// 此处,temp不需减1,因为一旦发现空行,上面for循环会break,此时temp尚未++
			printf("Read from Main Memory to Cache\n");
			//----数据传递,将主存内容放入cache中,再更改tag
			for (i = 31, j = 28; i > (31 - bit_tag); i--, j--)
			{
    
    
				cache_item[current_line][j] = address[i];
			}
			cache_item[current_line][30] = 1;//设置hit位为true
			if (t_replace == LRU)
			{
    
    
				LruUnhitSpace();
			}
		}
		else
		{
    
    
			GetReplace(address);
		}
	}
	else if (t_assoc == set_associative)
	{
    
    
		bool space = false;
		for (temp = (current_set * i_cache_set); temp < ((current_set + 1) * i_cache_set); temp++)
		{
    
    
			if (cache_item[temp][30] == false) //find a space line
			{
    
    
				space = true;
				break;
			}
		}

		if (space == true)
		{
    
    
			current_line = temp; // 此处,temp不需减1,因为一旦发现空行,上面for循环会break,此时temp尚未++
			for (i = 31, j = 28; i > (31ul - bit_tag); i--, j--) //设置标记
			{
    
    
				cache_item[current_line][j] = address[i];
				assert(j > 0);
			}

			cache_item[current_line][30] = true; //设置hit位为true.

			if (t_replace == LRU)
			{
    
    
				LruUnhitSpace();
			}
		}
		else
		{
    
    
			GetReplace(address);
		}
	}
}

//替换(随机或LRU),考虑dirty,最后设置Tag
// 直接映射只考虑dirty
//组相联和全相联此时无空闲,
void GetReplace(char* address)
{
    
    
	if (t_assoc == direct_mapped)
	{
    
    
	}
	else if (t_assoc == full_associative)
	{
    
    
		if (t_replace == Random)
		{
    
    
			current_line = rand() / (RAND_MAX / i_num_line + 1); // a random line in(0,i_num_line-1)
		}
		else if (t_replace == LRU)
		{
    
    
			LruUnhitUnspace();
		}
	}
	else if (t_assoc == set_associative) // 从本组中任选一行,进行替换
	{
    
    
		if (t_replace == Random)
		{
    
    
			temp = rand() / (RAND_MAX / i_cache_set + 1); // a random line in(0,i_cache_set-1)
			current_line = current_set * i_cache_set + temp; // a random line in current_set
		}
		else if (t_replace == LRU)
		{
    
    
			LruUnhitUnspace();
		}
	}
	//考虑dirty
	if (cache_item[current_line][29] == true) //dirty位必须为1才写入
	{
    
    
		GetWrite(); //写入内存
	}
	//----数据传递
	for (i = 31, j = 28; i > (31 - bit_tag); i--, j--) //设置标记
	{
    
    
		cache_item[current_line][j] = address[i];
		assert(j > 0);
	}

	cache_item[current_line][30] = true; //设置hit位为true
}
void GetWrite() //写入内存
{
    
    
	cache_item[current_line][29] = false; //设置dirty为false
	cache_item[current_line][30] = false; //设置hit为false
}


#include "base.h"

void LruHitProcess()
{
    
    
	if (t_assoc == full_associative)
	{
    
    
		for ( i = 0; i < i_num_line; i++)
		{
    
    
			if (LRU_priority[i] < LRU_priority[current_line] && cache_item[i][30] == true)
			{
    
    
				LRU_priority[i]++;
			}
		}
		LRU_priority[current_line] = 0;
	}
	else if (t_assoc == set_associative)
	{
    
    
		for (i = (current_set * i_cache_set); i < (current_set + 1) * i_cache_set; i++)
		{
    
    
			// 如果该行比正在访问的行计数器值小,并且该行中hit为true
			if (LRU_priority[i] < LRU_priority[current_line] && cache_item[i][30] == true)
			{
    
    
				LRU_priority[i]++;
			}
		}
		LRU_priority[current_line] = 0;
	}
}

void LruUnhitSpace() // if the replacement policy is LRU,and not hit,but there has a spaceline
{
    
    
	if (t_assoc == full_associative)
	{
    
    
		for (i = 0; i < i_num_line; i++)
		{
    
    
			if (cache_item[i][30] == true)
			{
    
    
				LRU_priority[i]++;
			}
		}
		LRU_priority[current_line] = 0;
	}
	else if (t_assoc == set_associative)
	{
    
    
		for (i = (current_set * i_cache_set); i < ((current_set + 1) * i_cache_set); i++)
		{
    
    
			if (cache_item[current_line][30] == true)
			{
    
    
				LRU_priority[i]++; // 如果该行该行中hit为true
			}
		}

		LRU_priority[current_line] = 0;
	}
}
void LruUnhitUnspace()
{
    
    
	if (t_assoc == full_associative)
	{
    
    
		temp = LRU_priority[0];

		for (i = 0; i < i_num_line; i++)
		{
    
    
			if (LRU_priority[i] >= temp)
			{
    
    
				temp = LRU_priority[i];
				j = i;
			}
		}

		current_line = j;
	}

	if (t_assoc == set_associative)
	{
    
    
		temp = LRU_priority[current_set * i_cache_set];

		for (i = (current_set * i_cache_set); i < ((current_set + 1) * i_cache_set); i++)
		{
    
    
			if (LRU_priority[i] >= temp)
			{
    
    
				temp = LRU_priority[i];
				j = i;
			}
		}

		current_line = j;
	}
}

猜你喜欢

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