直接映射Cache模拟器

直接映射是Cache中结构最简单的一种。

一、Cache的大小和结构

直接映射Cache的结构如下:(因为每组只有一行,所以下文中行、组代表相同含义)


代码如下:

本实验采用总容量16KB,每一组(行)64字节,则共256组(行)

typedef unsigned char      UINT8;
typedef unsigned short     UINT16;
typedef unsigned int       UINT32;
typedef int                INT32;
typedef unsigned long long UINT64;                                          // 数字表示数据的位数
#define DCACHE_SIZE 16384                                                   // 总大小16KB
#define DCACHE_DATA_PER_LINE 64                                             // 每行64字节
#define DCACHE_DATA_PER_LINE_ADDR_BITS GET_POWER_OF_2(DCACHE_DATA_PER_LINE) // 2^6=64,即64字节需要6位地址
#define DCACHE_SET (DCACHE_SIZE / DCACHE_DATA_PER_LINE)                     // 256行
#define DCACHE_SET_ADDR_BITS GET_POWER_OF_2(DCACHE_SET)                     // 2^8=256,即256行需要8位地址

定义一个DCache数组,每个元素表示一行(组)的结构:

struct DCACHE_LineStruct
{UINT8 Valid;                     // 只要从主存加载过数据到该行,Valid变为1UINT8 Dirty;                    // 标识该行是否被修改过(写回策略)UINT64 Tag;                        // 行标记,用于区分映射到该行的不同地址的数据UINT8 Data[DCACHE_DATA_PER_LINE]; // 数据块,每个1字节,共64字节
} DCache[DCACHE_SET];

DCache的初始化:

void InitDataCache()
{UINT32 i;for (i = 0; i < DCACHE_SET; i++){DCache[i].Valid = 0; // 最初从未从主存加载过数据,Valid=0DCache[i].Dirty = 0; // 最初数据未被修改过,Dirty=0}
}

二、Cache对读、写操作的处理

参数:Address主存地址;
operation操作类型,'R’读’W’写;
DataSize数据的大小(字节数);
StoreValue: 当执行写操作的时候,需要写入的数据;
LoadResult: 当执行读操作的时候,从Cache读出的数据

首先要对地址进行切分,得到标记、行号、块偏移

 CacheLineAddress = (Address >> DCACHE_DATA_PER_LINE_ADDR_BITS) % DCACHE_SET;   // Cache的行号,在直接映射中,就是组号(每组1行)BlockOffset = Address % DCACHE_DATA_PER_LINE;                                     // 块偏移,数据起始字节所在的位置AddressTag = (Address >> DCACHE_DATA_PER_LINE_ADDR_BITS) >> DCACHE_SET_ADDR_BITS; // 地址去掉DCACHE_SET、DCACHE_DATA_PER_LINE,剩下的作为Tag

根据行号索引到对应组,再根据有效位和标记判断是否命中

(一)命中时

即满足两个条件:索引到的行有效,且标记位与AddressTag相同

1. 读操作

根据需要的字节数直接读取即可
注意要对齐到相应字节边界,如4字节:BlockOffset & 0xFC,即把最后2位设置为0,一定为4的倍数

         ReadValue = 0;switch (DataSize){case 1: // 1个字节ReadValue = DCache[CacheLineAddress].Data[BlockOffset + 0];break;case 2:                                // 2个字节BlockOffset = BlockOffset & 0xFE; // 需对齐到2字节边界ReadValue = DCache[CacheLineAddress].Data[BlockOffset + 1];ReadValue = ReadValue << 8;ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 0];break;case 4:                                // 4个字节BlockOffset = BlockOffset & 0xFC; // 需对齐到4字节边界ReadValue = DCache[CacheLineAddress].Data[BlockOffset + 3];ReadValue = ReadValue << 8;ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 2];ReadValue = ReadValue << 8;ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 1];ReadValue = ReadValue << 8;ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 0];break;case 8:                                // 8个字节BlockOffset = BlockOffset & 0xF8; // 需对齐到8字节边界ReadValue = DCache[CacheLineAddress].Data[BlockOffset + 7];ReadValue = ReadValue << 8;ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 6];ReadValue = ReadValue << 8;ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 5];ReadValue = ReadValue << 8;ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 4];ReadValue = ReadValue << 8;ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 3];ReadValue = ReadValue << 8;ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 2];ReadValue = ReadValue << 8;ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 1];ReadValue = ReadValue << 8;ReadValue |= DCache[CacheLineAddress].Data[BlockOffset + 0];break;}*LoadResult = ReadValue;

2.写操作

由于修改了Cache的值,涉及到要不要修改相应主存地址的值,有两种策略:写直达和写回。
一般采用效率更高的写回
即先不修改主存内的数据,一直用Cache中的那个,直到其将要被驱逐时,再修改主存的值。
实现起来需要引入Dirty标记,逻辑为:新加载到Cache一行时,其Dirty设置为0,表示未被修改。当用写操作修改了Cache中这行的数据后,其Dirty设置为1,表示其已经和主存的值不同了。如果要驱逐这行,驱逐前要把这行修改过的块存到它原来所在的地址。

         switch (DataSize){case 1: // 1个字节DCache[CacheLineAddress].Data[BlockOffset + 0] = StoreValue & 0xFF;break;case 2:                               // 2个字节BlockOffset = BlockOffset & 0xFE; // 需对齐到2字节边界DCache[CacheLineAddress].Data[BlockOffset + 0] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 1] = StoreValue & 0xFF;break;case 4:                               // 4个字节BlockOffset = BlockOffset & 0xFC; // 需对齐到4字节边界DCache[CacheLineAddress].Data[BlockOffset + 0] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 1] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 2] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 3] = StoreValue & 0xFF;break;case 8:                                 // 8个字节BlockOffset = BlockOffset & 0xF8; // 需对齐到8字节边界DCache[CacheLineAddress].Data[BlockOffset + 0] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 1] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 2] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 3] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 4] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 5] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 6] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 7] = StoreValue & 0xFF;break;}DCache[CacheLineAddress].Dirty = 1;//由于写入后数据被修改,Dirty设为1

(二)未命中

需要从主存中加载数据到Cache中。
在此之前,根据写回策略,如果这一行已经被修改(Dirty=1),需要先倒推出其在主存的地址,并存回去。

     if (DCache[CacheLineAddress].Dirty){UINT64 OldAddress;                  // 计算原地址,OldAddress = > (Tag,Set,0000)OldAddress = ((DCache[CacheLineAddress].Tag << DCACHE_SET_ADDR_BITS) << DCACHE_DATA_PER_LINE_ADDR_BITS) | ((UINT64)CacheLineAddress << DCACHE_DATA_PER_LINE_ADDR_BITS); // 从Tag中恢复旧的地址StoreDataCacheLineToMemory(OldAddress, CacheLineAddress);DCache[CacheLineAddress].Dirty = 0; // 将新加载一行,Dirty设为1}

再加载数据,设置有效位和标记

     LoadDataCacheLineFromMemory(Address, CacheLineAddress);DCache[CacheLineAddress].Valid = 1;DCache[CacheLineAddress].Tag = AddressTag;

1.读操作

不用读了

2.写操作

写回策略一般搭配写分配,即加载到Cache后只修改Cache中的数据,主存不变
和命中时的写一样

         switch (DataSize){case 1: // 1个字节DCache[CacheLineAddress].Data[BlockOffset + 0] = StoreValue & 0xFF;break;case 2:                               // 2个字节BlockOffset = BlockOffset & 0xFE; // 需对齐到2字节边界DCache[CacheLineAddress].Data[BlockOffset + 0] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 1] = StoreValue & 0xFF;break;case 4:                               // 4个字节BlockOffset = BlockOffset & 0xFC; // 需对齐到4字节边界DCache[CacheLineAddress].Data[BlockOffset + 0] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 1] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 2] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 3] = StoreValue & 0xFF;break;case 8:                                 // 8个字节BlockOffset = BlockOffset & 0xF8; // 需对齐到8字节边界DCache[CacheLineAddress].Data[BlockOffset + 0] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 1] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 2] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 3] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 4] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 5] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 6] = StoreValue & 0xFF;StoreValue = StoreValue >> 8;DCache[CacheLineAddress].Data[BlockOffset + 7] = StoreValue & 0xFF;break;}

(三)Load和Store函数

1.Load函数

从内存加载一块数据到Cache中

void LoadDataCacheLineFromMemory(UINT64 Address, UINT32 CacheLineAddress)
{// 一次性从Memory中将DCACHE_DATA_PER_LINE数据读入某个Data Cache行// 提供了一个函数,一次可以读入8个字节UINT32 i;UINT64 ReadData;UINT64 AlignAddress;UINT64 *pp;AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1); // 地址必须对齐到DCACHE_DATA_PER_LINE (64)字节边界pp = (UINT64 *)DCache[CacheLineAddress].Data;for (i = 0; i < DCACHE_DATA_PER_LINE / 8; i++){ReadData = ReadMemory(AlignAddress + 8LL * i);if (DEBUG)printf("[%s] Address=%016llX ReadData=%016llX\n", __func__, AlignAddress + 8LL * i, ReadData);pp[i] = ReadData;}
}

2.Store函数

从Cache中把一行存回主存

void StoreDataCacheLineToMemory(UINT64 Address, UINT32 CacheLineAddress)
{// 一次性将DCACHE_DATA_PER_LINE数据从某个Data Cache行写入Memory中// 提供了一个函数,一次可以写入8个字节UINT32 i;UINT64 WriteData;UINT64 AlignAddress;UINT64 *pp;AlignAddress = Address & ~(DCACHE_DATA_PER_LINE - 1); // 地址必须对齐到DCACHE_DATA_PER_LINE (64)字节边界pp = (UINT64 *)DCache[CacheLineAddress].Data;WriteData = 0;for (i = 0; i < DCACHE_DATA_PER_LINE / 8; i++){WriteData = pp[i];WriteMemory(AlignAddress + 8LL * i, WriteData);if (DEBUG)printf("[%s] Address=%016llX ReadData=%016llX\n", __func__, AlignAddress + 8LL * i, WriteData);}
}

直接映射Cache模拟器相关推荐

  1. cache 计算机系统实验报告,计算机组成原理实验报告-cache模拟器的实现

    计算机组成原理实验报告-cache模拟器的实现 (20页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 19.90 积分 计算机组成原理实验报告学院(系)南 ...

  2. Cache模拟器(CacheSim)

     最近写了一个Cache的模拟器,由于平时空余时间比较分散,前前后后用了一周多的时间,基本实现的Cache的模拟功能(通过读取trace文件得到相应的命中率),能够实现直接映射.全相联.组相联三种 ...

  3. ARM的cache和写缓冲器(write buffer)

    转:https://blog.csdn.net/gameit/article/details/13169445?utm_medium=distribute.pc_relevant.none-task- ...

  4. Cache相关基本概念理解

    Allocation          在CACHE中发现一个位置,并把新的cache数据存到这个位置的过程.这个处理过程可能包括evicting(驱逐)cache中已存在的数据,从而为新的数据腾出空 ...

  5. 计组—缓存Cache

    缓存 通过大量统计发现了一个访问规律:程序对存储空间90%的访问局限于存储空间的10%的区域中,另外10%的访问则分布在存储空间的90%区域中.(即:存储器10%的存储空间是高频访问区,90%的存储空 ...

  6. Linux内存管理:ARM64体系结构与编程之cache(1)

    <Linux内存管理:ARM64体系结构与编程之cache(1)> <Linux内存管理:ARM64体系结构与编程之cache(2)> <ARM SMMU原理与IOMMU ...

  7. CPU Cache Line:CPU缓存行/缓存块

    <CPU Cache Line伪共享问题的总结和分析> 以下文章来源于小林coding ,作者小林coding Table of Contents CPU Cache 有多快? CPU C ...

  8. 计算机缓存Cache以及Cache Line详解

    转载: 计算机缓存Cache以及Cache Line详解 - 围城的文章 - 知乎 https://zhuanlan.zhihu.com/p/37749443 L1,L2,L3 Cache究竟在哪里? ...

  9. C64+ cache资料集(更新中)

    1 CACHE的一些名词术语: Allocation          在CACHE中发现一个位置,并把新的cache数据存到这个位置的过程.这个处理过程可能包括evicting(驱逐)cache中已 ...

最新文章

  1. django两个服务器之间的通讯
  2. 【Linux Deploy】一、Linux Deploy安装配置使用教程
  3. fegin需要实现类_深入理解JVM(六)--虚拟机类加载机制
  4. 手把手教你使用ECharts绘制可视化图表
  5. (转)RabbitMQ学习之spring整合发送异步消息(注解实现)
  6. django html文本编辑器,django xadmin 集成DjangoUeditor富文本编辑器
  7. JavaScript学习05 定时器
  8. linux磁盘第一个扇区分析,Linux磁盘分区
  9. websocket心跳检测前后端架构
  10. Node.js入门 - 回调函数
  11. Vue源码中compiler部分逻辑梳理(内有彩蛋)
  12. 10月23日见?疑似魅族16T预热海报曝光:定位大屏娱乐旗舰
  13. JSON数据的解析方式
  14. mybatis SqlMapConfig.xml typeAliases
  15. 【非科班告诉你】前端自学从小白到入门
  16. Java-json系列(一):用GSON解析Json格式数据
  17. Snmp4j编程简介之三:Snmp
  18. WordPress采集插件-WordPress文章自动采集发布
  19. 计算机专业比较好的加州州立,美国计算机专业大学排名前十
  20. 前端数据加密(Base64、MD5、AES、RSA)

热门文章

  1. 【蓝桥杯嵌入式】比赛笔记(2)根据固件库快速配置各模块初始化
  2. Stage.1——井字棋
  3. mac地址和ip地址、子网掩码和默认网关
  4. day42-多线程与多进程
  5. 名帖352 黄庭坚 草书《浣花溪图引》
  6. Windows入侵排查
  7. php逐级审批,php 审批流程管理
  8. 【微信二狗成语接龙】
  9. 工作党福利来了!Python实现钉钉/企业微信自动打卡
  10. 常熟市杨园小学能耗管理系统的应用