Rocket-chip-Cache

关于cache的知识,大家可以看以下链接:
https://zhuanlan.zhihu.com/p/102293437?utm_source=qq

下面为验证rocket-chip icache和dcache的代码。
在这里我只验证cache起到的作用,不会分析直接映射缓存、多路组相缓存和全相连缓存在rocket-chip上的差异,也不会分析具体的miss/hit情况,也不会分析其分配策略,如果后面有做相关测试,会再补充内容。

测试代码如下:

#include "encoding.h"
#include "L1Dcache.h"

#define U32 *(volatile unsigned int *)
#define DEBUG_SIG   0x70000000
#define DEBUG_VAL   0x70000004
#define DATA_SIZE   100

int input1_data[DATA_SIZE] =
{
   41, 833, 564, 187, 749, 350, 132, 949, 584, 805, 621,   6, 931, 890, 392, 694, 961, 110, 116, 296,
  426, 314, 659, 774, 319, 678, 875, 376, 474, 938, 539, 569, 203, 280, 759, 606, 511, 657, 195,  81,
  267, 229, 337, 944, 902, 241, 913, 826, 933, 985, 195, 960, 566, 350, 649, 657, 181, 111, 859,  65,
  288, 349, 141, 905, 886, 264, 576, 979, 761, 241, 478, 499, 403, 222, 444, 721, 676, 317, 224, 937,
  288, 119, 615, 606, 389, 351, 455, 278, 367, 358, 584,  62, 985, 403, 346, 517, 559, 908, 775, 255
};

int input2_data[DATA_SIZE] =
{
  454, 335,   1, 989, 365, 572,  64, 153, 216, 140, 210, 572, 339, 593, 898, 228,  12, 883, 750, 646,
  500, 436, 701, 812, 981, 150, 696, 564, 272, 258, 647, 509,  88, 703, 669, 375, 551, 936, 592, 569,
  952, 800, 584, 643, 368, 489, 328, 313, 592, 388, 543, 649, 979, 997, 814,  79, 208, 998, 629, 847,
  704, 997, 253, 715, 430, 415, 538, 700,   4, 494, 100, 864, 693, 416, 296, 285, 620,  78, 351, 540,
  646, 169, 527, 289, 796, 801, 720, 758, 745,  92, 989, 271, 853, 788, 531, 222, 461, 241, 358, 332
  };

//--------------------------------------------------------------------------
// handle_trap function

void handle_trap()
{
    asm volatile ("nop");
    while(1);
}

//--------------------------------------------------------------------------
// cache function

void cache( int n, int a[], int b[])
{
    int i;

    for ( i = 0; i < n; i++ )
        U32(0x80001000+4*i) = a[i] + b[i];

    for ( i = 0; i < n; i++ )
        U32(0x60001000+4*i) = U32(0x80001000+4*i);

    FLUSH_D_REG(0x80001000);

    FLUSH_D_ALL();

    for ( i = 0; i < n; i++ )
        U32(0x60001000+4*i) = U32(0x80001000+4*i);
}

//--------------------------------------------------------------------------
// clock gating function

void clock_gating()
{
    U32(0x60000000) = read_csr(0x7C1);
    write_csr(0x7C1,read_csr(0x7C1) & 0xFFFFFFF0);
}

//--------------------------------------------------------------------------
// Main

void main()
{
    cache(DATA_SIZE, input1_data, input2_data);
    clock_gating();
    //U32(DEBUG_SIG) = 0xFF;
    while(1) {asm volatile ("wfi");}
}

先看elf dump出来的反汇编文件。
第一个红色箭头:代码运行的起始地址,开始的操作是将32个通用寄存器清零。
第二个红色箭头:main函数的开始位置,0x8000_0194,main函数后面(0x8000_01b4后面)就是数据段,也就是input1_data和input2_data的存储地方。
第三个红色箭头:main函数的结束位置,0x8000_01b4,这里是一个死循环,再次跳转至0x8000_01b0,执行wfi(等待中断)的指令。
看反汇编文件的目的是确定运行代码的长度,就是0x8000_0000-0x8000_01b4这么长。
在这里插入图片描述
然后是看icache仿真波形。
第一个蓝色箭头:是rocket-chip icache模块往外求数据的总线接口。
第二个蓝色箭头:是分割线,左边是icache有请求数据的动作,右边是没有再往外请求数据。
红色箭头:rocket-chip core向icache请求指令数据的总线接口。
黄色箭头:icache miss的信号。
白色箭头:icache hit的信号。
绿色箭头:哪条cache line存在于icache中的标志。
rocket-chip指令请求的顺序(存在icache的情况):
1)core向icache请求执行指令数据。
2)icache若存在请求的执行指令,则返回给core;若不存在,则往外部memory请求指令。
3)若指令不存在于icache,icache会产生miss信号,若存在则会产生hit信号。
4)外部返回的指令数据会存入icache中,并修改vb_array相应的bit。
5)然后icache将刚存入的指令数据传给core,这次不再产生miss信号,而是产生hit信号。
6)完成一次core指令数据的请求,跳至步骤1)再次等待core请求数据。
7)如果运行期间,cpu执行了icache flush操作,那么之前存入icache的指令数据都会被刷掉,core想再次请求的话,icache需要再次往外请求数据。
在这里插入图片描述
接下来看dcache的仿真波形。
红色箭头:memory数据的总线接口,只有ar和r这两组接口,memory只关心读的情况,不关心写的情况。
蓝色箭头:mmio数据的总线接口,只有aw和w这两组接口,mmio只关心写的情况,不关心读的情况。
第一个黄色箭头:左边是将数据从memory中读入dcache中,右边是将数据输出到mmio端口上。

	for ( i = 0; i < n; i++ )
    	U32(0x80001000+4*i) = a[i] + b[i];
	for ( i = 0; i < n; i++ )
    	U32(0x60001000+4*i) = U32(0x80001000+4*i);

第二个黄色箭头:左边是将数据输出到mmio端口上,右边存在一个操作没有在波形上体现出来,那就是将dcache中的数据全部flush掉。

    for ( i = 0; i < n; i++ )
        U32(0x60001000+4*i) = U32(0x80001000+4*i);
	FLUSH_D_ALL();

第三个黄色箭头:左边是将dcache中的全部数据flush掉,右边是在dcache中没有预存数据的情况下,将memory的数据搬到mmio端口上。

	FLUSH_D_ALL();
    for ( i = 0; i < n; i++ )
        U32(0x60001000+4*i) = U32(0x80001000+4*i);

第三个黄金箭头可以看到,每次从memory端口中读取一次数据,然后分多次写到mmio端口上,这是因为memory是以一条cache line的长度来读写数据的,而mmio则是以单word的长度来读写数据的,所以配置寄存器的行为必须是采用mmio的总线端口,而不能采用memory总线端口。
在这里插入图片描述

下图是第一个黄色箭头右边的一小段波形。可以看到往0x6000_1000位置输出数据的时候,是不需要利用memory端口请求数据的。
在这里插入图片描述

下图是第三个黄色箭头右边的一小段波形。可以看到蓝色箭头是往0x6000_1000位置输出数据的时候,在输出数据前需要在更早的时间使用memory端口向内存请求0x8000_1000的相关数据。同时可以看到,memory端口读写数据是以一条cache line为单位的,而mmio端口读写数据是以一个word为单位的。
在这里插入图片描述

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值