经过三次重写,和合计30多个小时的开发,终于把这个简单的逻辑做完了。(自己太笨)
因为刚刚接触C,写的代码实现方式肯定有不对的地方,逻辑上可能也有疏漏,如果有看官发现问题还望及时给予指正,谢谢。
一、整体概括:
1.1目标:
维护一个单独的缓存空间,该空间是低一级存储的缓存。缓存的大小比低级存储的大小要小很多,通过一个逻辑将底层存储的数据抽到缓存中的一个位置。
1.2 实现思路:
通过阅读《深入理解计算机系统》一书,了解低级存储与缓存之间关联规则是基于存储地址的,通过一个地址映射的规则,将低级存储的地址映射到缓存的制定位置。
1.2.1 存储:
存储是由一个个位构成的,每个位都有一个对应的地址,地址的大小取决于计算机的字长。
1.2.2 低级存储:
在这次的设计中低级存储只是一个抽象概念,实际上就是内存中的一块空间,只不过我通过映射值将低级存储的地址改为从F000开始的地址。
1.2.3 缓存:
缓存是比低级存储小得多的集合,因为存储越大寻址的时间越长,所以需要一个小的缓存来存储处理器近期使用到的数据。
这次设计中的缓存也只是一个抽象概念,也是内存的一块空间,也是通过映射值将缓存的地址改为A000开始的地址。
如何将低级存储的地址映射到缓存——缓存模型:
缓存模型主要分——组、行、缓存单元
1.2.3.1 组
在逻辑上没有体现,知识对地址进行切割并划分了一个范围,是在映射逻辑上有关,在实际内存中不会存储。
1.2.3.2 行
也是一个逻辑体现,主要是为了更好的提升缓存的寻址效率而设置的思想。
1.2.3.3 缓存单元:
实际存储数据的对象,其中包含了标识、是否加载、以及字节块。
标识:标识是地址的一部分根据规则截取出来的,通过地址另一部分找到对应的组以后就会对其中的行进行遍历,根据标识找到对应的行。
是否加载:用来标识该缓存是否已经加载数据。
字节块:用来存储缓存数据。(大小可设置)
1.2.3.4 总结
通过上述的几个对象,我们将缓存组织成了一个三层的结构,第一层是组、第二层是行、第三层是存储单元。一个缓存可以有S个组,可以有E个行,每行只能有一个缓存单元。
1.2.4 全相连高速缓存、组相连高速缓存、直接映射高速缓存
全相连高速缓存就是缓存中只有一个组,有E个行的方式实现。
组相连高速缓存就是一个缓存中有S个组,E个行的实现方式。
直接映射高速缓存就是一个缓存中有S个组,1个行和1个缓存单元的实现方式。
1.2.5 缓存各项指标的设置:
组数、行数、缓存数据块的大小的设置直接影响缓存的效率但也要根据实际情况,大小对不同的情况有不同的策略。
二、具体实现:
2.1 公共常量:
计算机字长:MemAddrLength
2.2 几个核心对象:
2.2.1 硬件控制器:HWController
属性:
存储空间大小
1)写方法(Write):传入一个虚拟硬件地址(自己映射的,从F000开始)和一个长度。映射后写入数据到内存。
2)读方法(Read):传入一个虚拟硬件地址和一个长度。映射后从内存读出数据,并写到一个新的内存空间并返回该指针。
2.2.2 缓存控制器:CacheController
1)缓存单元查询器(CacheFinder):
2)读方法(Read):传入一个硬件虚拟地址和长度,在缓存中查找对应的单元,如果找不到从硬件中读取数据写到缓存,并将数据写到内存新的空间中、返回该指针。
3)写方法(Write):传入一个硬件虚拟地址和长度,将数据写入到硬件中再写到缓存里(实际上缓存会有多种策略、直写/不直写等等)。
4)取下一个(Next):将传入缓存单元指针移动到相邻的下一个缓存单元,如果超出缓存范围则返回0x00。
2.3 执行结果概述
返回四大部分:
1)总体介绍部分,会将地址空间、缓存的S、E、B、t几个主要参数值显示出来。
2)内存查看部分,会将初始化后虚拟硬件存储和缓存存储的值都写出来。
3)缓存大小显示
4)缓存读值测试
下面的集合是所有缓存单元的参数和右侧缓存单元字节块中的数据。
上面的集合是根据指令从缓存中读取出来的数据内容。
通过这两个集合可以验证读取数据是否正确。
剩下没解决的问题:
在写缓存的时候,如果该组所有缓存单元都已经初始化了,就需要通过一个科学的方式选择一个块覆盖或驱逐,目前是用随机数,不太合理。
抽象不够,没有悟透和语言不熟导致很多复用问题比较多,有问题望指出。后续有时间我会继续完善。
说不定有BUG,如果有客观指正。
三、代码
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <math.h> 4 #include <unistd.h> 5 6 /* 7 * 基本设定初始化 8 */ 9 const unsigned int _memSize = 1024; //内存大小(字节) 10 const unsigned int _memAddrLength = 16;//地址长度 11 const unsigned int _cacheSize = 256;//缓存大小 12 13 /* 14 * 硬件控制器 15 */ 16 typedef struct HWController{ 17 unsigned long _memStartAddr; //start addr 0XF0 18 unsigned char* _memAddr; 19 unsigned long _memOffset; 20 21 unsigned char* (*Read)(unsigned long memOffset, unsigned long addr, unsigned long length); 22 unsigned char (*Write)(unsigned long memOffset, unsigned long addr, unsigned char *data, unsigned long length); 23 }; 24 25 /* 26 * 缓存控制器: 27 * 1)缓存单元集合指针 CacheUnitArrayPtr 28 * 2)缓存查询函数 CacheFinder 29 * 3)缓存读函数 Read 30 * 4)缓存写函数 Write 31 */ 32 typedef struct CacheController { 33 unsigned int _s; 34 unsigned long _sMask; 35 unsigned int _S; 36 unsigned int _E; 37 unsigned int _b; 38 unsigned long _bMask; 39 unsigned int _B; 40 unsigned int _t; 41 unsigned long _tMask; 42 unsigned int _C; 43 44 unsigned long _unitCount; 45 unsigned long _unitSize; 46 47 unsigned long _cacheSize; 48 unsigned long _cacheStartAddr; 49 unsigned char* _cacheMemAddr; 50 unsigned long _cacheOffset; 51 struct CacheUnit* CacheUnitArrayPtr; 52 53 struct CacheUnit* (*Next)(struct CacheController *ctrl,struct CacheUnit *unit); 54 struct CacheUnit* (*CacheFinder)(struct CacheController *ctrl,unsigned long Addr); 55 unsigned char* (*Read)(struct CacheController *ctrl,struct HWController *hwctrl,unsigned long addr, unsigned long length); 56 unsigned char (*Write)(struct CacheController *ctrl,struct HWController *hwctrl,unsigned long addr, unsigned char *data, unsigned long length); 57 }; 58 59 /* 60 * 缓存单元 61 * 1)数据块集合指针 BlockArrayPtr; 62 * 2)t标志位 tCode; 63 * 3)热标识位 hot; 64 */ 65 typedef struct CacheUnit { 66 unsigned char* BlockArrayPtr; 67 unsigned long tCode; 68 unsigned char Hot; 69 }; 70 71 //HWController 72 unsigned char _hwWrite(unsigned long memOffset, unsigned long addr, unsigned char *data, unsigned long length){ 73 unsigned char* ptr = (unsigned char*)(memOffset + addr); 74 while(length--){ 75 *ptr = *data; 76 ptr++; 77 data++; 78 } 79 return 1; 80 } 81 unsigned char* _hwRead(unsigned long memOffset, unsigned long addr, unsigned long length){ 82 unsigned char *ptr = (unsigned char*)(memOffset + addr); 83 unsigned char *retPtr = malloc(length); 84 unsigned char *loopPtr = retPtr; 85 while(length--){ 86 *loopPtr = *ptr; 87 ptr++; 88 loopPtr++; 89 } 90 91 return retPtr; 92 } 93 struct HWController* GetHWCtroller(){ 94 struct HWController *ctrl = malloc(sizeof(struct HWController)); 95 void *rPtr = malloc(_memSize);//get ptr point to Memory Space. 96 (*ctrl)._memStartAddr = 0xF000; 97 (*ctrl)._memOffset = (unsigned long) (rPtr - (*ctrl)._memStartAddr); 98 (*ctrl)._memAddr = rPtr; 99 (*ctrl).Write = _hwWrite; 100 (*ctrl).Read = _hwRead; 101 102 unsigned char *ptr = rPtr; 103 int i = 0; 104 while( i < _memSize ){ 105 *ptr = i + 1000; 106 ptr++; 107 i++; 108 } 109 110 printf("==>Memory: startAddr:%X,offset:%X",(unsigned int)(*ctrl)._memStartAddr,(unsigned int)((*ctrl)._memOffset )); 111 112 return ctrl; 113 } 114 115 //CacheController 116 struct CacheUnit* _next(struct CacheController *ctrl,struct CacheUnit *unit){ 117 unit = (struct CacheUnit *)((unsigned long)unit + ctrl->_unitSize); 118 return unit >= (ctrl->_cacheSize + ctrl->_cacheMemAddr) ? 0x00 : unit; 119 } 120 struct CacheUnit* _cacheFinder(struct CacheController *ctrl,unsigned long addr){ 121 unsigned long _tBit = (addr&(*ctrl)._tMask)>>((*ctrl)._b+(*ctrl)._s); 122 unsigned long _sBit = (addr&(*ctrl)._sMask)>>((*ctrl)._b); 123 unsigned long _bBit = (addr&(*ctrl)._bMask); 124 125 // printf(" ====>Find Addr:%X tMask:%X,tVal:%X sMask:%X,sVal:%X bMask:%X,bVal:%X",addr,(*ctrl)._tMask,_tBit,(*ctrl)._sMask,_sBit,(*ctrl)._bMask,_bBit); 126 127 struct CacheUnit* _unit = (struct CacheUnit*)((*ctrl)._cacheStartAddr + ctrl->_cacheOffset + _sBit * ((*ctrl)._E * ctrl->_unitSize)); 128 int e = (*ctrl)._E; 129 while ( e-- ) 130 { 131 if((*_unit).tCode == _tBit){ 132 return _unit; 133 } 134 _unit = (struct CacheUnit *)(((unsigned long)_unit)+ ctrl->_unitSize); 135 } 136 return 0; 137 } 138 unsigned char* _cacheRead(struct CacheController *ctrl,struct HWController *hwctrl,unsigned long addr, unsigned long length){ 139 struct CacheUnit *unit = ctrl->CacheFinder(ctrl,addr); 140 //todo: 找时间把Loader抽象出来或者其他方式优化复用。 141 if(!unit || !(*unit).Hot){ 142 unsigned char *read = hwctrl->Read(hwctrl->_memOffset,addr,length); 143 ctrl->Write(ctrl,hwctrl,addr,read,length); 144 unit = ctrl->CacheFinder(ctrl,addr); 145 if(!unit || !(*unit).Hot){ 146 printf(" ERROR::can not load cache by %X !!!! " ,(unsigned int)addr); 147 exit(0); 148 } 149 } 150 unsigned char *memPtr = malloc(length); 151 unsigned char *memLoopPtr = memPtr; 152 unsigned char *blockPtr = (*unit).BlockArrayPtr + (ctrl->_bMask & addr); 153 unsigned long i = 0; 154 while(i < length){ 155 *memLoopPtr = *blockPtr; 156 memLoopPtr++; 157 blockPtr++; 158 if(blockPtr >= (*unit).BlockArrayPtr + (*ctrl)._B){ 159 unit = ctrl->CacheFinder(ctrl,addr + i + 1); 160 if(!unit || !(*unit).Hot){ 161 printf(" ERROR::can not load cache by %X !!!! " ,(unsigned int)(addr + i)); 162 exit(0); 163 } 164 blockPtr = unit->BlockArrayPtr; 165 } 166 i++; 167 } 168 return memPtr; 169 } 170 unsigned char _cacheWrite(struct CacheController *ctrl,struct HWController *hwctrl,unsigned long addr, unsigned char *data, unsigned long length){ 171 //写入底层内存先。 172 hwctrl->Write(hwctrl->_memOffset,addr,data,length); 173 //写入缓存 174 unsigned char *ptr = data; 175 unsigned long i = 0; 176 177 while(i<length){ 178 struct CacheUnit *unit = ctrl->CacheFinder(ctrl,addr + i); 179 if(!unit||!unit->Hot) 180 { 181 unsigned long startAddr = (unsigned long)(ctrl->_cacheMemAddr + (((ctrl->_sMask & (addr + i)) >> ((*ctrl)._b)) * ctrl->_E) * ctrl->_unitSize) ; 182 unsigned long endAddr = (unsigned long)(ctrl->_cacheMemAddr + (((ctrl->_sMask & (addr + i)) >> ((*ctrl)._b)) * ctrl->_E)) + ctrl->_E * ctrl->_unitSize; 183 unit = (struct CacheUnit *)startAddr; 184 int hit = 0; 185 while(unit){ 186 if(!unit->Hot) 187 { 188 hit=1; 189 break; 190 } 191 unit = ctrl->Next(ctrl,unit); 192 if((unsigned long)unit >= endAddr){ 193 break; 194 } 195 } 196 if(!hit) 197 { 198 printf(" nhit!!! "); 199 int rm = rand() % ( ctrl->_E ); 200 unit = startAddr + rm * ctrl->_unitSize; 201 } 202 unit->tCode = ((addr + i) & ctrl->_tMask) >> ((*ctrl)._b+(*ctrl)._s); 203 unit->Hot = 1; 204 } 205 unsigned char *blockPtr = unit->BlockArrayPtr + ((addr+i)&ctrl->_bMask); 206 *blockPtr = *ptr; 207 ptr++; 208 i++; 209 } 210 } 211 struct CacheController* GetCacheController(unsigned int _memAddrLength, unsigned int cacheSize, unsigned int blockSize,unsigned int E){ 212 struct CacheController *cache = malloc(sizeof(struct CacheController)); 213 (*cache)._b = (unsigned int)log2(blockSize); 214 (*cache)._B = blockSize; 215 (*cache)._bMask = (unsigned long) pow(2,(*cache)._b) - 1; 216 217 (*cache)._E = E; 218 219 (*cache)._S = cacheSize / (*cache)._B / (*cache)._E; 220 (*cache)._s = (unsigned int)log2((*cache)._S); 221 (*cache)._sMask = (unsigned long) pow(2,((*cache)._b + (*cache)._s)) - (*cache)._bMask - 1; 222 223 (*cache)._C = (*cache)._B * (*cache)._E * (*cache)._S; 224 225 (*cache)._t = _memAddrLength - (*cache)._s - (*cache)._b; 226 (*cache)._tMask = (unsigned long) pow(2,_memAddrLength) - (*cache)._bMask - (*cache)._sMask - 1; 227 228 (*cache)._unitCount = (*cache)._E * (*cache)._S; 229 (*cache)._unitSize = sizeof(struct CacheUnit) + (*cache)._B; 230 231 (*cache)._cacheSize = (*cache)._unitSize * (*cache)._unitCount; 232 //apply mem 233 (*cache)._cacheMemAddr = malloc((*cache)._cacheSize); 234 (*cache)._cacheStartAddr = 0xA000; 235 (*cache)._cacheOffset = (unsigned long)((*cache)._cacheMemAddr - cache->_cacheStartAddr); 236 237 unsigned long counter = (*cache)._unitCount; 238 struct CacheUnit *unit = (struct CacheUnit*)(*cache)._cacheMemAddr; 239 240 while(counter){ 241 (*unit).Hot = 0x00; 242 (*unit).tCode = counter; 243 (*unit).BlockArrayPtr = (unsigned char *)(((unsigned long)unit) + sizeof(struct CacheUnit)); 244 int x; 245 for(x = 0;x < cache->_B ; x++){ 246 *(unit->BlockArrayPtr + x) = (unsigned char)x; 247 } 248 unit = (struct CacheUnit*)((*unit).BlockArrayPtr + (*cache)._B); 249 counter--; 250 } 251 (*cache).Next = _next; 252 (*cache).CacheFinder = _cacheFinder; 253 (*cache).Read = _cacheRead; 254 (*cache).Write = _cacheWrite; 255 256 printf(" ==>CacheSize: MemAddrLength = %d. C = %d, S = %d, E = %d, B = %d; s = %d, b = %d, t = %d",_memAddrLength,(*cache)._C,(*cache)._S,(*cache)._E,(*cache)._B,(*cache)._s,(*cache)._b,(*cache)._t); 257 printf(" cacheAddr:%X,cacheStartAddr:%X, cacheOffset:%X, cacheSize:%d",(unsigned int)(*cache)._cacheMemAddr,(unsigned int)(*cache)._cacheStartAddr,(unsigned int)(*cache)._cacheOffset,(unsigned int) (*cache)._cacheSize); 258 printf(" bMask:%x,sMask:%x,tMask:%x",(unsigned int)(*cache)._bMask,(unsigned int)(*cache)._sMask,(unsigned int)(*cache)._tMask); 259 260 return cache; 261 } 262 263 //utility 264 void PrintMem(char* title, unsigned long addr, unsigned long length,int split){ 265 printf(" =====> title::%s:: Printing Mem %X,Length:%d <======= ",title,(unsigned int)addr,(unsigned int)length); 266 unsigned char *ptr = (unsigned char *)addr; 267 268 int i = 0; 269 while(i < length){ 270 if( i % 16 == 0){ 271 printf(" %d %X ",i,(unsigned int)ptr); 272 } 273 else if( i > 0 && i % 4 == 0){ 274 printf(" "); 275 } 276 printf(" %X",*ptr); 277 ptr++; 278 i++; 279 } 280 } 281 void PrintCache(char* title, struct CacheController* ctrl){ 282 printf(" =====> title::%s:: Printing Mem %X,Length:%d <======= ",title,(unsigned int)(ctrl->_cacheStartAddr + ctrl->_cacheOffset),(unsigned int)ctrl->_unitCount); 283 284 struct CacheUnit *unit = ( struct CacheUnit *)(ctrl->_cacheStartAddr + ctrl->_cacheOffset); 285 unsigned char *blockPtr = unit->BlockArrayPtr; 286 int i = 0; 287 int j = 0; 288 while(i < ctrl->_unitCount){ 289 printf(" --Unit%d[[tCode:%d,BlockPtr:%X,Hot:%d]] Blocks: ",i+1,(unsigned int)unit->tCode,(unsigned int)unit->BlockArrayPtr,(unsigned int)unit->Hot); 290 j = 0; 291 while(j < ctrl->_B){ 292 printf(" %X",(unsigned int)*blockPtr); 293 blockPtr++; 294 j++; 295 } 296 unit = (struct CacheUnit *)(((unsigned long)unit) + sizeof(struct CacheUnit) + ctrl->_B); 297 blockPtr = unit->BlockArrayPtr; 298 i++; 299 } 300 } 301 int main() { 302 printf("Hello, World! "); 303 struct HWController hwCtrl = *GetHWCtroller(); 304 struct CacheController cacheCtrl = *GetCacheController(_memAddrLength,_cacheSize,32,2); 305 306 //HW Unit Test 307 // PrintMem("",(unsigned long)hwCtrl._memAddr,16,0); 308 // unsigned char temp = 0xAA; 309 // unsigned char *data = &temp; 310 // hwCtrl.Write(hwCtrl._memOffset,0XF002,data,1); 311 // PrintMem(" HWMEM 0~16 ",(unsigned long)hwCtrl._memAddr,16,0); 312 // unsigned char *retData = hwCtrl.Read(hwCtrl._memOffset,0XF002,1); 313 // PrintMem(" HWMEM 0XF002 ",(unsigned long)retData,1,0); 314 // unsigned char *retData = hwCtrl.Read(hwCtrl._memOffset,0XF002,1); 315 PrintMem(" HWMEM ALL ",(unsigned long)hwCtrl._memAddr,_memSize,0); 316 317 318 //Cache Unit Test 319 PrintMem(" CACHE ALL ",(unsigned long)cacheCtrl._cacheMemAddr,cacheCtrl._cacheSize,0); 320 321 322 //struct test 323 struct CacheUnit cu = { 324 0x00, 325 0x00, 326 0x00 327 }; 328 printf(" ============>> CacheUnitTypeSize %d ",sizeof(struct CacheUnit)); 329 printf(" ============>> CacheUnitSize %d ",sizeof(cu)); 330 printf(" ============>> CacheUnitSize.Hot %d ",sizeof(cu.Hot)); 331 printf(" ============>> CacheUnitSize.tCode %d ",sizeof(cu.tCode)); 332 printf(" ============>> CacheUnitSize ptr %d ",sizeof(cu.BlockArrayPtr)); 333 334 //ReadCacheTest 335 PrintMem("",cacheCtrl.Read(&cacheCtrl,&hwCtrl,0XF038,16),16,0); 336 PrintCache("",&cacheCtrl); 337 return 0; 338 }