cache行为模型

来源:互联网 发布:淘宝客推广链接代码 编辑:程序博客网 时间:2024/06/06 08:42

贴一段自己写的cache行为仿真代码, 针对ARM Cortex A5核,未经过严格验证

/* * This is a simulation program * for the ARM Cortex-A5 L1 DCache * * Cache Structure Description: * 4-way set L1 data cache, total size = 32KB, with each cache data line = 8 words */#include <stdio.h>#include <stdlib.h>typedef     unsigned char       UINT8;typedef     unsigned short      UINT16;typedef     unsigned int        UINT32;typedef     unsigned long       UINT64;// L1 DCache parameters of ARM Cortex-A5#define DATA_CACHE_SIZE         32*1024     // 32KB#define DATA_LINE_SIZE          8           // 8 words(= 32 bytes)#define CACHE_WAYS_NUM          4#define CACHE_LINE_EACH_WAY     (DATA_CACHE_SIZE/(DATA_LINE_SIZE*CACHE_WAYS_NUM*sizeof(UINT32)))// cacheline bit masks#define     CACHE_LINE_SIZE         (DATA_LINE_SIZE+1)      // words#define     VALID_BIT               (1 << 1)#define     DIRTY_BIT               (1 << 0)// address bit masks#define     ADDR_TAGS               13#define     TAGS_BITS               (0xfffe << ADDR_TAGS)#define     ADDR_INDEX              5#define     INDEX_BITS              (0xff << ADDR_INDEX)#define     ADDR_WORD               2#define     WORD_BITS               (0x7 << ADDR_WORD)#define     ADDR_BYTE               (0x3 << 0)/* simulated L1 DCache Topology * index*CACHE_LINE_SIZE = the tag/v/d of one cacheline * the followd 8 words are data registers * LSW(the least significant word): dirty bit * MSW(the most significant word): valid bit */UINT32 CacheTopology[CACHE_WAYS_NUM][CACHE_LINE_SIZE*CACHE_LINE_EACH_WAY];/* * simulated DRAM Topology */#define     DRAM_SIZE       0x10000     // dram size = 64K Words = 256K Bytes#define     DRAM_BASE       0x0000      // dram address = DRAM_BASE + offset in DramTopologyUINT32 DramTopology[DRAM_SIZE] = {0};// cache policy configuration#define READ_ALLOC_MODE     (0x00)#define RDWT_ALLOC_MODE     (0x01)#define WRITE_THROUGH       (0x00)#define WRITE_BACK          (0x01)static void do_allocation();static void do_replacement(void);static void do_write(void);static void do_readhit(void);static void do_writehit(void);static UINT8 findCmdIndex(UINT8 *);typedef static void (*func_t)(void);/* * rdwr tells whether it is a read or write * 0 = read, 1 = write * * hit: whether this operation hit or miss the cache * 0 = miss, 1 = hit * * lineIndex: cacheline index in a way * * lineWay: cacheline index in a set * * hit: hit/miss flag of DCache * 0 = miss, 1 = hit * * valid: valid flag of DCache * 0 = not valid, 1 = valid * * allocation mode * 0 = read allocation, 1 = normal * */struct cache_sts {    UINT32 rdwr;    UINT32 lineWord;    UINT32 lineIndex;    UINT32 lineTag;    UINT32 lineWay;    UINT32 hit;    UINT32 valid;    UINT32 dirty;    UINT32 alloc_mode;    UINT32 write_mode;    UINT32 addr;    UINT32 data;} cache_sts_t = {        .rdwr = 0,        .hit = 0,        .alloc_mode = READ_ALLOC_MODE,};/* * fullfill a cacheline on a read or flush on a write */static void do_cacheline_fill_flush(UINT32 *cacheline_base){    switch (cache_sts_t.rdwr) {        case 0:            // do cacheline fill on a read            memcpy(cacheline_base, &DramTopology[DRAM_BASE+cache_sts_t.addr], CACHE_LINE_SIZE*sizeof(UINT32));            break;        case 1:            // do cacheline flush on a write            memcpy(&DramTopology[DRAM_BASE+cache_sts_t.addr], cacheline_base, CACHE_LINE_SIZE*sizeof(UINT32));            break;        default:            printf("Unknown operation.\n");            break;    }}/* * CACHE Allocation Policy: * READ ALLOCATION POLICY: cache allocation and linefill only happens * on a read. If a write misses the cache, it goes to the next level of * hierarchy with no effect on cache. * WRITE ALLOCATION POLICY: cache allocation and linefill happens both * on read and write, so it might be more accurately called read-write * cache allocation policy * */static void do_allocation(){    UINT32 i;    UINT32 lineIndex = cache_sts_t.lineIndex;    switch(cache_sts_t.alloc_mode) {    case READ_ALLOC_MODE:    {        switch (cache_sts_t.rdwr) {            case 0:                // alloc a cacheline                for (i = 0; i < CACHE_WAYS_NUM; ++i) {                    if (!(CacheTopology[i][lineIndex] & VALID_BIT)) {                        // alloc this invalidated line                        printf("alloc a invalidated cacheline as a new line.\n");                        CacheTopology[i][lineIndex*CACHE_LINE_SIZE] &= ~(cache_sts_t.lineTag << ADDR_TAGS);                        CacheTopology[i][lineIndex*CACHE_LINE_SIZE] |= (cache_sts_t.lineTag << ADDR_TAGS);                        printf("read data from DRAM into this new line.\n");                        do_cacheline_fill_flush(&CacheTopology[i][lineIndex*CACHE_LINE_SIZE+1]);                        cache_sts_t.data = CacheTopology[i][lineIndex*CACHE_LINE_SIZE+1+cache_sts_t.lineWord];                        return;                    }                break;            case 1:                printf("write data in read allocation mode.\n");                DramTopology[DRAM_BASE+cache_sts_t.addr] = cache_sts_t.data;                break;            default:                break;                }        }    }        break;    case RDWT_ALLOC_MODE:        /*         * always allocate a cacheline first if data misses in cache.         */        break;    }}/* * select one(called victim) of the cache lines in the set. * Strategies: * 1. Round-Robin/Cyclic    * * 2. Pseudo-random * 3. Last Recently Used(LRU) */static void do_replacement(){}/* * Two policies: * Write-Through or Write-Back * */static void do_write(){}static UINT8 findCmdIndex(UINT8 *cmd){    UINT8 *cmdlist[] = {            "rd",            "wd"            "\0"    };    UINT8 cmdindex;    for (cmdindex = 0; cmdindex < sizeof(cmdlist)/sizeof(UINT8 *); cmdindex += 1)        if (!strcmp(cmd, cmdlist[cmdindex]))            return cmdindex;    return -1;}/* cache hit on a read * V/D = * 10: return dcache value; 11: same as 10 except data is dirty * 00: read data from main memory into dcache, do validation and return new data * 01: as 00 * */static void do_readhit(){    switch (cache_sts_t.valid) {        case 0:            printf("update dcache value from main memory.\n");            break;        case 1:            printf("get value in the dcache.\n");            cache_sts_t.data = cache_sts_t.lineWord;            break;        default:            printf("Unsupported Status.\n");            break;    }}/* * cache hit on a write * V/D = * 10: if write through, just write data to dcache and dram; if write back, just update to dcache. * 11: clean cache data, then write data into dcache in write back mode. In write through mode, do as 10 * 00:  if write-through, write data to dcache and flush, do validation *      if write-back, write data to dcache, do validation, set dirty * 01: as 00 * */static void do_writehit(){    switch (cache_sts_t.valid) {        case 0:        {            printf("write data to dcache.\n");            //TODO: do validation            if (cache_sts_t.write_mode == WRITE_THROUGH) {                printf("write data to dram.\n");                return;            }            //TODO: set dirty        }            break;        case 1:        {            switch (cache_sts_t.dirty) {                case 1:                    printf("clean dcache data.\n");                case 0:                    printf("update data to dcache.\n");                    if (cache_sts_t.write_mode == WRITE_THROUGH)                        printf("write data to dram.\n");                    break;                default:                    printf("unsupported status.\n");                    break;            }        }            break;        default:            break;    }}static void do_lookup(UINT32 addr){    UINT32 lineIndex = (addr & INDEX_BITS) >> ADDR_INDEX;    UINT32 lineIndex = cache_sts_t.lineIndex = (addr & INDEX_BITS) >> ADDR_INDEX;    UINT32 lineTag = cache_sts_t.lineTag = (addr & TAGS_BITS) >> ADDR_TAGS;    // search the cache set    UINT32 i;    for (i = 0; i < CACHE_WAYS_NUM; i++)        //find the cacheline in the set        if ((CacheTopology[i][lineIndex] & TAGS_BITS) >> ADDR_TAGS == lineTag) {            cache_sts_t.hit = 1;            cache_sts_t.lineWay = i;            cache_sts_t.dirty = CacheTopology[i][lineIndex] & DIRTY_BIT;            if (CacheTopology[i][lineIndex] & VALID_BIT) {                cache_sts_t.valid = 1;                //TODO: should return the cached data            }            else {                /* not valid                 * TODO: allocate this line                 * read data from next hierarchy of memory                 */                cache_sts_t.valid = 0;            }        }    {   // if not hit accordong to the lineTag        cache_sts_t.hit = 0;    }    switch (cache_sts_t.hit) {        case 0:            /* cache miss             */            do_allocation();            break;        case 1:        {            switch (cache_sts_t.rdwr) {                case 0: do_readhit();                    break;                case 1: do_writehit();                    break;                default:                    printf("Unknown operation.\n");                    break;            }        }            break;        default:            printf("Error Condition.\n");            break;    }}/* * read the data address, three part of cache operation as follows: * 1. do_allocation * 2. do_replacement * 3. do_write * This address is from the output of MMU as ARM Cortes-A5 uses PIPT scheme * * address bit fields: * bits[31:13] = Tag * bits[12:5] = Set(=index) * bits[4:2] = Word * bits[1:0] = Byte */int main(int argc, char *argv[]){    UINT32  address;    UINT32  value;    UINT8   *cmd, index;    UINT32  i,j;    for (i = 0; i < CACHE_WAYS_NUM; i+=1)        for (j = 0; j < CACHE_LINE_EACH_WAY; j++) {            // clean and invalidate dcache            CacheTopology[i][j] &= ~DIRTY_BIT;            CacheTopology[i][j] |= VALID_BIT;        }    while (1) {        cmd = argv[1];        index = findCmdIndex(cmd);        switch (index) {        case 0:     if (argc != 3) {printf("parameter error while reading.\n"); return -1;}                    else {cache_sts_t.rdwr = 0; address = atoi(argv[2]);}        break;        case 1:     if (argc != 4) {printf("parameter error while writing.\n"); return -1;}                    else {cache_sts_t.rdwr = 1; address = atoi(argv[2]); value = atoi(argv[3]);}        break;        default:            printf("parameter not supported.\n");            exit(-1);        }        printf("%s on address 0x%x\n", cmd, address);        do_lookup(address);    }    return 0;}
0 0
原创粉丝点击