/*************************************************************************** * Name: cache_get_first_invalid_block * * Desc: Returns the first free (invalid) block for a set. * * Params: * tagstore ptr to the cache tagstore * line ptr to the decoded cache line * * Returns: int32_t * ID of the frist available (invalid) block * CAHCE_RV_ERR if no such block is available **************************************************************************/ int32_t cache_get_first_invalid_block(cache_tagstore_t *tagstore, cache_line_t *line) { int32_t block_id = 0; uint32_t num_blocks = 0; uint32_t tag_index = 0; cache_tag_data_t *tag_data = NULL; #ifdef DBG_ON cache_generic_t *cache = NULL; #endif /* DBG_ON */ if ((!tagstore) || (!line)) { cache_assert(0); goto error_exit; } #ifdef DBG_ON cache = (cache_generic_t *) tagstore->cache; #endif /* DBG_ON */ num_blocks = tagstore->num_blocks_per_set; tag_index = (line->index * num_blocks); tag_data = &tagstore->tag_data[tag_index]; for (block_id = 0; block_id < num_blocks; ++block_id) { if (!tag_data[block_id].valid) { #ifdef DBG_ON dprint_info("index %u, invalid block %u selected from %s\n", line->index, block_id, CACHE_GET_NAME(cache)); #endif /* DBG_ON */ return block_id; } } error_exit: return CACHE_RV_ERR; }
/******************************************************************* Program Main ******************************************************************/ main() { int i; // define an integer j to serve as a loop counter //display variables char *strPtr, *scrollStrPtr; int dpos; short scroll; //program variables int lastSwitchVal; long timeStamp,st; char line1[17]; char *rssServer,*rssPage; //display init scroll=1; dprint_init_ports(); dprint_init(); printf("LCD display initialized.\n"); //print a welcome message dprint_clear(); dprint_move_to(0,0); dprint("iDisplay"); dprint_move_to(0,12); dprint("v0.1"); dprint_move_to(1,0); dprint("initializing..."); //network init strPtr=""; if(init_DHCP()) { dprint_info(); strPtr = "success!"; } else { strPtr = "** nework initialization error!"; } //program init timeStamp = SEC_TIMER; //set up the timing for refreshing the data... lastSwitchVal = 1234; //random, so first time it grabs RSS memset(headlines,0,sizeof(headlines)); //just to be safe... //example message scrollStrPtr = strPtr; dpos = 15; while(1){ costate{ //grab the headlines after 5 mins, or on a switch change if((lastSwitchVal != BitRdPortI(PBDR,2)) || (SEC_TIMER > timeStamp+RSS_REFRESH_DELAY) ){ scroll=0; dprint_clear(); dprint_move_to(1,0); dprint("Loading data..."); if (lastSwitchVal){ rssServer=RSS_BBC_SERVER; rssPage=RSS_BBC_PAGE; strcpy(line1,"BBC News"); } else { rssServer=RSS_CNN_SERVER; rssPage=RSS_CNN_PAGE; strcpy(line1,"CNN"); } if(get_headlines(rssServer,rssPage)) strPtr = headlines; else { strPtr = "** unable to connect to Internet!"; strcpy(line1,"Error"); } scrollStrPtr = strPtr; //be friendly and leave strPtr untouched lastSwitchVal = BitRdPortI(PBDR,2); timeStamp = SEC_TIMER; dprint_move_to(0,0); //print the data source dprint(line1); sprint_time(line1); //now print the time dprint_move_to(0,11); dprint(line1); scroll=1; } } costate{ //scroll a message across the screen if(scroll==1){ dprint_move_to(1,0); for(i=0;i<dpos;i++) dprint_char(' '); if(dpos > 0) dpos--; if(dpos == 0) scrollStrPtr++; dprint(scrollStrPtr); if(*scrollStrPtr==0) { //end of str scrollStrPtr = strPtr; dpos = 15; } waitfor(DelayMs(150)); } } costate{ //debugging if (BitRdPortI(PBDR, 3)==0){ while(BitRdPortI(PBDR, 3)==0); //debounce scroll=0; dprint_info(); } } } //while true } // end program
/*************************************************************************** * Name: cache_evict_and_add_tag * * Desc: Core processing routine. It does one (and only one) of the * following for every memory reference: * 1. If the tag is already present, we are done here. Might have to * write thru for a write request if the write policy is set to * WTNA. * 2. If a free block is available, place the tag in that block. * 3. Evict a block (based on the eviction policy set), do a write * back (if evicted block is dirty) and place the incoming tag * on the block. * * For all three operations above, we need to update read/write, * miss/hit counters, valid, dirty (for writes) and age for the block. * * Params: * in_cache ptr to cache * mem_ref ptr to the memory reference (type and address) * * Returns: Nothing. **************************************************************************/ void cache_evict_and_add_tag(cache_generic_t *cache, mem_ref_t *mref, uint16_t *latency) { uint8_t read_flag = FALSE; int32_t block_id = 0; uint32_t tag_index = 0; uint32_t *tags = NULL; uint64_t curr_age; cache_line_t line; cache_tag_data_t *tag_data = NULL; cache_tagstore_t *tagstore = NULL; if ((!cache) || (!mref)) { cache_assert(0); goto exit; } tagstore = cache->tagstore; /* Fetch the current time to be used for tag age (for LRU). */ curr_age = util_get_curr_time(); /* Decode the memmory reference to the current cache's cache line. */ memset(&line, 0, sizeof(line)); cache_util_decode_mem_addr(tagstore, mref->ref_addr, &line); /* Fetch the appropriate set within the tagstore. */ tag_index = (line.index * tagstore->num_blocks_per_set); tags = &tagstore->tags[tag_index]; tag_data = &tagstore->tag_data[tag_index]; read_flag = (IS_MEM_REF_READ(mref) ? TRUE : FALSE); if (read_flag) cache->stats.num_reads += 1; else cache->stats.num_writes += 1; /* * Notes * ===== * * Victim cache will only contain entries that were missed in * L1. There can be no entires in victim cache that weren't missed * by L1 at any given time. * * Possible Operations * =================== * a.) L1 hit: * * Update counters and fetch next mref. * * b.) L1 miss: * * If there are invalid blocks in L1, take an invalid block and * fetch the data directly from next memory level. VC is not * involved in this case. * * If there are no invalid blocks, check in VC: * - If VC hit, swap the required tag (which is present in VC now) * with an LRU tag from L1. Carry forward the Dbit in both * directions. * - If VC miss, evict the LRU block in L1 and place it in VC with * Dbit info. If required, allocate block in VC by writing the * LRU block to next level, if the LRU block is dirty. * * c.) L2 miss: * * All requests to L2 should either come from VC (VC miss or VC LRU * evict) or from L1 during cache init load. * * If L2 hit, update the counters and return to previous level. * * If L2 miss, get a block ID (invalid blocks or LRU evict block), * read the data from memory into the newly created block, update * the counters and return to previous level. */ if (CACHE_RV_ERR != (block_id = cache_does_tag_match(tagstore, &line))) { /* * Cache hit! * Tag is already present. Just update the counters and go fetch the * next memory reference. * * Life is good! */ /* Update the latency based on the cache type. */ if (CACHE_LEVEL_1 == cache->level) *latency = (CACHE_L1_HIT_LATENCY); else if (CACHE_LEVEL_2 == cache->level) *latency = (CACHE_L2_HIT_LATENCY); dprint_dbg("HIT %s\n", CACHE_GET_NAME(cache)); dprint_info("cache hit for cache %s, tag 0x%x at index %u, block %u\n", CACHE_GET_NAME(cache), line.tag, line.index, block_id); tag_data[block_id].valid = 1; tag_data[block_id].age = curr_age; tag_data[block_id].ref_count += 1; if (read_flag) { cache->stats.num_read_hits += 1; } else { cache->stats.num_write_hits += 1; /* Set the block to be dirty only for WBWA write policy. */ if (CACHE_WRITE_PLCY_WBWA == CACHE_GET_WRITE_POLICY(cache)) { tag_data[block_id].dirty = 1; } else { cache->stats.num_blk_mem_traffic += 1; } } } else { cache_generic_t *next_cache = NULL; /* * Cache miss! * Well, life is not always so good.. * * In multi level caches, do the following in case of a cache miss: * 1. If the next level in hierarchy is a cache, check if the * requested data is present there. If so, bring in the block * and follow steps 2/3 for placing the block. i.e., find a * free block or go for replacement. * 2. If the next level is not a cache (i.e., for last level of * caches, the next level would be main memory), check if there * are any free blocks. If so, use those blocks for new data. * 3. If there are no free blocks and if the cache is the last level, * go for cache replacement. * * For all three cases, first find a block to place the to-be-feched * data block. */ if (CACHE_IS_L1(cache)) dprint_dbg("MISS %s\n", CACHE_GET_NAME(cache)); dprint_dp("MISS %s, TAG %x\n", CACHE_GET_NAME(cache), line.tag); dprint_info("cache miss for cache %s, tag 0x%x @ index %u\n", CACHE_GET_NAME(cache), line.tag, line.index); next_cache = cache->next_cache; dprint_info("cache %s, index %u, block %d selected for tag 0x%x\n", CACHE_GET_NAME(cache), line.index, block_id, line.tag); /* * If VC is present, L1 + VC acts as a single entity to the next memory * level. So, some ugly cache specific code.. which I don't like! */ if (CACHE_IS_L1(cache)) { if (cache_util_is_victim_present()) { int32_t vc_block_id = CACHE_RV_ERR; cache_line_t vc_line; cache_generic_t *vc = NULL; cache_tagstore_t *vc_ts = NULL; cache_stats_t *vc_stats = NULL; vc = cache_util_get_vc(); vc_ts = vc->tagstore; vc_stats = &vc->stats; memset(&vc_line, 0, sizeof(vc_line)); cache_util_decode_mem_addr(vc_ts, mref->ref_addr, &vc_line); vc_block_id = cache_does_tag_match(vc_ts, &vc_line); if (CACHE_RV_ERR != vc_block_id) { uint8_t tmp_l1_dirty = 0; uint32_t vc_tag_index = 0; uint32_t *vc_tags; mem_ref_t l1_old_ref; cache_line_t l1_old_line; cache_line_t vc_tmp_line; cache_tag_data_t *vc_tag_data; dprint_dbg("HIT %s, SWAP\n", CACHE_GET_NAME(vc)); /* * Find a block to place the to-be-fetcheed data. Go for * LRU block (don't evict, as we are just going to swap it * with VC), if no free blocks are available. */ block_id = cache_get_first_invalid_block(tagstore, &line); if (CACHE_RV_ERR == block_id) block_id = cache_util_get_lru_block_id(cache->tagstore, &line); vc_tag_index = (vc_line.index * vc_ts->num_blocks_per_set); vc_tags = &vc_ts->tags[vc_tag_index]; vc_tag_data = &vc_ts->tag_data[vc_tag_index]; /* * Convert the current L1 tag (to be swapped) to * VC's line. */ memset(&l1_old_line, 0, sizeof(l1_old_line)); l1_old_line.tag = tags[block_id]; l1_old_line.index = line.index; cache_util_encode_mem_addr(tagstore, &l1_old_line, &l1_old_ref); cache_util_decode_mem_addr(vc_ts, l1_old_ref.ref_addr, &vc_tmp_line); dprint_info("victim cache hit.. swap\n"); dprint_info("%s, to swap: T %x, I %u, B %d, D %u\n", CACHE_GET_NAME(cache), tags[block_id], line.index, block_id, tag_data[block_id].dirty); dprint_info("%s, to swap: T %x, I %u, B %d, D %u\n", CACHE_GET_NAME(vc), vc_tags[vc_block_id], vc_tmp_line.index, vc_block_id, vc_tag_data[vc_block_id].dirty); dprint_dp("addr %x, l1 tag %x, vc tag %x\n", l1_old_ref.ref_addr, l1_old_line.tag, vc_tmp_line.tag); /* Swap tag data and dirty bits. */ tags[block_id] = line.tag; vc_tags[vc_block_id] = vc_tmp_line.tag; tmp_l1_dirty = tag_data[block_id].dirty; tag_data[block_id].dirty = vc_tag_data[vc_block_id].dirty; vc_tag_data[vc_block_id].dirty = tmp_l1_dirty; if (!read_flag) tag_data[block_id].dirty = 1; curr_age = util_get_curr_time(); tag_data[block_id].valid = 1; tag_data[block_id].age = curr_age; vc_tag_data[vc_block_id].valid = 1; vc_tag_data[vc_block_id].age = curr_age; #ifdef DBG_ON dprint_info("print cache conntents start\n"); cache_print_tags(cache, &line); cache_print_tags(vc, &vc_tmp_line); dprint_info("print cache conntents end\n"); #endif /* DBG_ON */ vc_stats->num_swaps += 1; if (read_flag) vc_stats->num_read_hits += 1; else vc_stats->num_write_hits += 1; goto exit; } else { /* VC miss. Set next cache to L2, if available. */ dprint_dbg("MISS %s\n", CACHE_GET_NAME(vc)); dprint_dp("MISS %s, TAG %x\n", CACHE_GET_NAME(vc), vc_line.tag); next_cache = (cache_util_is_l2_present()) ? cache_util_get_l2() : NULL; if (read_flag) vc_stats->num_read_misses += 1; else vc_stats->num_write_misses += 1; } } else { /* VC not present. Set next_cache to L2 if available. */ next_cache = (cache_util_is_l2_present()) ? cache_util_get_l2() : NULL; } } /* Check next level cache, if available. */ if (next_cache) { mem_ref_t read_ref; /* * Find a block to place the to-be-fetcheed data. Go for * block eviction, if no free blocks are available. */ block_id = cache_get_first_invalid_block(tagstore, &line); if (CACHE_RV_ERR == block_id) block_id = cache_evict_tag(cache, mref, &line); /* * For cache misses, issues a read reference for that address * to the next cache level. */ memset(&read_ref, 0, sizeof(read_ref)); memcpy(&read_ref, mref, sizeof(read_ref)); read_ref.ref_type = MEM_REF_TYPE_READ; dprint_dp("%s, READ FROM %s %x, %x\n", CACHE_GET_NAME(cache), CACHE_GET_NAME(next_cache), read_ref.ref_addr, line.tag); cache_evict_and_add_tag(next_cache, &read_ref, latency); tags[block_id] = line.tag; cache->stats.num_blk_mem_traffic += 1; tag_data[block_id].valid = 1; tag_data[block_id].age = curr_age; tag_data[block_id].ref_count = (util_get_block_ref_count(tagstore, &line) + 1); if (read_flag) { cache->stats.num_read_misses += 1; } else { cache->stats.num_write_misses += 1; /* Set the block to be dirty only for WBWA write policy. */ if (CACHE_WRITE_PLCY_WBWA == CACHE_GET_WRITE_POLICY(cache)) tag_data[block_id].dirty = 1; } dprint_info("%s, tag 0x%x added to index %u, block %u\n", CACHE_GET_NAME(cache), line.tag, line.index, block_id); } else { /* If we are here, we are at a total loss for latency. No matter * L1 miss or L2 miss. */ *latency = CACHE_TOTAL_MISS_LATENCY; /* * Find a block to place the to-be-fetcheed data. Go for * block eviction, if no free blocks are available. */ block_id = cache_get_first_invalid_block(tagstore, &line); if (CACHE_RV_ERR == block_id) block_id = cache_evict_tag(cache, mref, &line); /* * We are at the last cache and currently handling a miss. * Read from memory and place it the previouly found block. */ tags[block_id] = line.tag; cache->stats.num_blk_mem_traffic += 1; tag_data[block_id].valid = 1; tag_data[block_id].age = curr_age; tag_data[block_id].ref_count = (util_get_block_ref_count(tagstore, &line) + 1); dprint_dp("%s, READ FROM MEMORY %x, %x\n", CACHE_GET_NAME(cache), mref->ref_addr, line.tag); if (read_flag) { cache->stats.num_read_misses += 1; } else { cache->stats.num_write_misses += 1; /* Set the block to be dirty only for WBWA write policy. */ if (CACHE_WRITE_PLCY_WBWA == CACHE_GET_WRITE_POLICY(cache)) tag_data[block_id].dirty = 1; } dprint_info("%s, tag 0x%x added to index %u, block %u\n", CACHE_GET_NAME(cache), line.tag, line.index, block_id); } /* End of last level cache processing */ } /* End of cache miss processing */ exit: #ifdef DBG_ON cache_print_tags(cache, &line); #endif /* DBG_ON */ return; }
/*************************************************************************** * Name: cache_evict_tag * * Desc: Responsible for tag eviction (based on the replacement poliy set) * and to write back the block, if the selected eviction block * happens to be dirty. * * Params: * tagstore ptr to the cache tagstore * line ptr to the decoded cache line * * Returns: int32_t * ID of the block on a match is found * CACHE_RV_ERR if no match is found **************************************************************************/ int32_t cache_evict_tag(cache_generic_t *cache, mem_ref_t *mref, cache_line_t *line) { int32_t block_id = 0; uint32_t tag_index; cache_tagstore_t *tagstore = NULL; if ((!cache) || (!mref) || (!line)) { cache_assert(0); goto error_exit; } tagstore = cache->tagstore; tag_index = (line->index * tagstore->num_blocks_per_set); switch (CACHE_GET_REPLACEMENT_POLICY(cache)) { case CACHE_REPL_PLCY_LRU: block_id = cache_get_lru_block(tagstore, mref, line); if (CACHE_RV_ERR == block_id) goto error_exit; break; case CACHE_REPL_PLCY_LFU: block_id = cache_get_lfu_block(tagstore, mref, line); if (CACHE_RV_ERR == block_id) goto error_exit; /* * According to LFU policy, the row ref count should be set to * the ref count of the block being evicted and the evicted block * ref count should be reset. */ tagstore->set_ref_count[line->index] = tagstore->tag_data[tag_index + block_id].ref_count; tagstore->tag_data[tag_index + block_id].ref_count = 0; #ifdef DBG_ON printf("set_ref_count %u, tag_ref_count %u\n", tagstore->set_ref_count[line->index], tagstore->tag_data[tag_index + block_id].ref_count); #endif /* DBG_ON */ break; default: cache_assert(0); goto error_exit; } dprint_dp("LRU EVICT FROM %s, INDEX %u, BLOCK %d, DIRTY %u\n", CACHE_GET_NAME(cache), line->index, block_id, cache_util_is_block_dirty(tagstore, line, block_id)); dprint_info("LRU evict: %s, index %u , block %d, dirty %u\n", CACHE_GET_NAME(cache), line->index, block_id, cache_util_is_block_dirty(tagstore, line, block_id)); /* * If victim is present, all evictions from L1 should goto victim cache. * Force write those evictions to victim cache here, */ if (CACHE_IS_L1(cache) && (cache_util_is_victim_present())) { dprint_dp("%s, index %u, block %u, force write " \ "from %s to %s due to eviction\n", CACHE_GET_NAME(cache), line->index, block_id, CACHE_GET_NAME(cache), CACHE_GET_NAME(cache->next_cache)); dprint_info("%s, index %u, block %u, writing non-dirty block " \ "from %s to %s due to eviction\n", CACHE_GET_NAME(cache), line->index, block_id, CACHE_GET_NAME(cache), CACHE_GET_NAME(cache->next_cache)); cache_handle_dirty_tag_evicts(cache, mref, block_id); goto ret_id; } /* If the block to be evicted is dirty, write it back if required. */ if (cache_util_is_block_dirty(tagstore, line, block_id)) { dprint_info("selected a dirty block to evict in index %u, block %d\n", line->index, block_id); cache_handle_dirty_tag_evicts(cache, mref, block_id); } ret_id: return block_id; error_exit: return CACHE_RV_ERR; }
/*************************************************************************** * Name: cache_handle_dirty_tag_evicts * * Desc: Handles dirty tag evicts from the cache. If the write policy is * set to write back, writes the block to next level of memory. * * Params: * cache ptr to the cache containing the dirty block * mem_ref incoming memory reference * block_id ID of the block within the set which has to be evicted * * Returns: Nothing **************************************************************************/ void cache_handle_dirty_tag_evicts(cache_generic_t *cache, mem_ref_t *mem_ref, uint32_t block_id) { uint16_t latency = 0; uint32_t tag_index = 0; uint32_t *tags = NULL; cache_line_t line; cache_tagstore_t *tagstore = NULL; cache_tag_data_t *tag_data = NULL; if ((!cache) || (!mem_ref)) { cache_assert(0); goto exit; } tagstore = cache->tagstore; /* Decode the memmory reference to the current cache's cache line. */ memset(&line, 0, sizeof(line)); cache_util_decode_mem_addr(tagstore, mem_ref->ref_addr, &line); tag_index = (line.index * tagstore->num_blocks_per_set); tags = &tagstore->tags[tag_index]; tag_data = &tagstore->tag_data[tag_index]; /* * If there's another level of cache, write the dirty block to the next * available cache. */ if ((cache->next_cache) && (CACHE_WRITE_PLCY_WBWA == cache->write_plcy)) { mem_ref_t write_ref; cache_line_t write_line; /* * To write the dirty block to next cache, issue a write request to * the next cache by encoding the dirty tag to a memory ref addr and * the ref type as write. */ memset(&write_line, 0, sizeof(write_line)); memset(&write_ref, 0, sizeof(write_ref)); write_line.tag = tags[block_id];; write_line.index = line.index; cache_util_encode_mem_addr(tagstore, &write_line, &write_ref); write_ref.ref_type = MEM_REF_TYPE_WRITE; if (CACHE_IS_VC(cache->next_cache)) { boolean dirty = FALSE; dirty = tag_data[block_id].dirty; cache_write_to_victim(cache->next_cache, &write_ref, dirty); tag_data[block_id].dirty = 0; goto exit; } dprint_dp("LRU WRITE TO %s, TAG %x, INDEX %u, BLOCK %d, DIRTY %u\n", CACHE_GET_NAME(cache->next_cache), line.tag, line.index, block_id, cache_util_is_block_dirty(tagstore, &line, block_id)); dprint_info("%s writing dirty block [%u, %d] to next level due " \ "to eviction", CACHE_GET_NAME(cache), line.index, block_id); cache_evict_and_add_tag(cache->next_cache, &write_ref, &latency); } else { dprint_dp("LRU WRITE TO MEMORY, INDEX %u, BLOCK %d, DIRTY %u\n", line.index, block_id, cache_util_is_block_dirty(tagstore, &line, block_id)); dprint_info("%s writing dirty block [%u, %d] to memory due to eviction", CACHE_GET_NAME(cache), line.index, block_id); } /* Update the write back counter and clear the dirty bit on the block. */ cache->stats.num_write_backs += 1; cache->stats.num_blk_mem_traffic += 1; tag_data[block_id].dirty = 0; exit: return; }
/*************************************************************************** * Name: cache_init * * Desc: Init code for cache. It sets up the cache parameters based on * the user given cache configuration. * * Params: * l1_cache ptr to the L1 cache * vic_cache ptr to the victim cache * l2_cache ptr to the L2 cache * num_args # of input arguments * input ptr to input list * * Returns: Nothing **************************************************************************/ void cache_init(cache_generic_t *l1_cache, cache_generic_t *vic_cache, cache_generic_t *l2_cache, int num_args, char **input) { char *trace_file = NULL; uint8_t arg_iter = 0; uint32_t blk_size = 0; uint32_t l1_size = 0; uint16_t l1_set_assoc = 0; uint32_t l2_size = 0; uint16_t l2_set_assoc = 0; uint32_t victim_size = 0; if ((!l1_cache) || (!l2_cache) || (!input)) { cache_assert(0); goto exit; } memset(l1_cache, 0, sizeof(*l1_cache)); memset(l2_cache, 0, sizeof(*l2_cache)); /* Input for caches is of the form: * ... <block-size> <l1-cache-size> <l1-set-assoc> * <l2-cache-size> <l2-set-assoc> ... */ g_victim_present = FALSE; blk_size = atoi(input[arg_iter++]); l1_size = atoi(input[arg_iter++]); l1_set_assoc = atoi(input[arg_iter++]); l2_size = atoi(input[arg_iter++]); g_l2_present = (l2_size ? TRUE : FALSE); l2_set_assoc = atoi(input[arg_iter++]); trace_file = input[arg_iter++]; /* Init L1 cache. */ strncpy(l1_cache->name, g_l1_name, (CACHE_NAME_LEN - 1)); strncpy(l1_cache->trace_file, trace_file, (CACHE_TRACE_FILE_LEN - 1)); l1_cache->size = l1_size; l1_cache->level = CACHE_LEVEL_1; l1_cache->set_assoc = l1_set_assoc; l1_cache->blk_size = blk_size; l1_cache->repl_plcy = CACHE_REPL_PLCY_LRU; l1_cache->write_plcy = CACHE_WRITE_PLCY_WBWA; l1_cache->victim_size = victim_size; l1_cache->stats.cache = l1_cache; dprint_info("%s init successful\n", CACHE_GET_NAME(l1_cache)); /* Init victim cache. */ if (cache_util_is_victim_present()) { strncpy(vic_cache->name, g_vic_name, (CACHE_NAME_LEN - 1)); strncpy(vic_cache->trace_file, trace_file, (CACHE_TRACE_FILE_LEN - 1)); vic_cache->size = victim_size; vic_cache->level = CACHE_LEVEL_L1_VICTIM; vic_cache->blk_size = blk_size; vic_cache->repl_plcy = CACHE_REPL_PLCY_LRU; vic_cache->write_plcy = CACHE_WRITE_PLCY_WBWA; vic_cache->stats.cache = vic_cache; vic_cache->set_assoc = /* VC is a fully associative cache. */ (vic_cache->size / vic_cache->blk_size); dprint_info("%s init successful\n", CACHE_GET_NAME(vic_cache)); } /* Init L2 cache. */ if (cache_util_is_l2_present()) { strncpy(l2_cache->name, g_l2_name, (CACHE_NAME_LEN - 1)); l2_cache->size = l2_size; l2_cache->level = CACHE_LEVEL_2; l2_cache->set_assoc = l2_set_assoc; l2_cache->blk_size = blk_size; l2_cache->victim_size = 0; /* No victim cache for L2 */ l2_cache->repl_plcy = CACHE_REPL_PLCY_LRU; l2_cache->write_plcy = CACHE_WRITE_PLCY_WBWA; l2_cache->stats.cache = l2_cache; dprint_info("%s init successful\n", CACHE_GET_NAME(l2_cache)); } /* Set the previous and next caches. */ if (cache_util_is_victim_present()) { l1_cache->prev_cache = NULL; l1_cache->next_cache = vic_cache; vic_cache->prev_cache = l1_cache; vic_cache->next_cache = NULL; if (cache_util_is_l2_present()) { vic_cache->next_cache = l2_cache; l2_cache->prev_cache = vic_cache; l2_cache->next_cache = NULL; } } else if (cache_util_is_l2_present()) { l1_cache->prev_cache = NULL; l1_cache->next_cache = l2_cache; l2_cache->prev_cache = l1_cache; l2_cache->next_cache = NULL; } exit: return; }
/*************************************************************************** * Name: cache_tagstore_init * * Desc: Init code for a tagstore. Does the following: * 1. Calculates all the cache parameters based on the user * given specifications. * 2. Allocated memory for tags and tag_data. This will be a * contiguous allocation and the data should be accessed bu * either 2D indices or by linearizing the 2D index to an 1D * index. * 1D_index = block_index + (set_index * blocks_per_set) * * blocks--> * 0 1 2 3 * +------+------+------+------+ * 0 | | | | | s * | | | | | e * +------+------+------+------+ t * 1 | | | * | | s * | | | | | | * +------+----- +------+------+ | * 2 | | | | | v * | | | | | * +------+------+------+------+ * * To get to the * block, 2D index would be [1][2] * eg., 1D_index = 2 + (1 * 4) = 6 * * Params: * cache ptr to the actual cache * tagstore ptr to the tagstore to be assoicated with the cache * * Returns: Nothing **************************************************************************/ void cache_tagstore_init(cache_generic_t *cache, cache_tagstore_t *tagstore) { uint8_t tag_bits = 0; uint8_t index_bits = 0; uint8_t blk_offset_bits = 0; uint32_t num_sets = 0; uint32_t num_blocks_per_set = 0; uint32_t iter = 0; if ((!cache) || (!tagstore)) { cache_assert(0); goto exit; } /* * # of tags that could be accomodated is same as the # of sets. * # of sets = (cache_size / (set_assoc * block_size)) */ tagstore->num_sets = num_sets = ((cache->size) / (cache->set_assoc * cache->blk_size)); /* * blk_offset_bits = log_b2 (blk_size) * index_bits = log_b2 (# of sets) * tag_bits = addr_bits - index_bits - blk_offset_bits * num_blocks = num_sets * set_assoc */ tagstore->num_offset_bits = blk_offset_bits = util_log_base_2(cache->blk_size); tagstore->num_index_bits = index_bits = util_log_base_2(num_sets); tagstore->num_tag_bits = tag_bits = (CACHE_ADDR_32BIT_LEN - index_bits - blk_offset_bits); tagstore->num_blocks_per_set = num_blocks_per_set = cache->set_assoc; tagstore->num_blocks = num_sets * num_blocks_per_set; /* Allocate memory to store indices, tags and tag data. */ tagstore->lru_block_id = calloc(1, num_sets * sizeof(uint8_t)); tagstore->index = calloc(1, (num_sets * sizeof(uint32_t))); tagstore->tags = calloc(1, (num_sets * num_blocks_per_set * sizeof (uint32_t))); tagstore->tag_data = calloc(1, (num_sets * num_blocks_per_set * sizeof (*(tagstore->tag_data)))); tagstore->set_ref_count = calloc(1, (num_sets * sizeof(uint32_t))); if ((!tagstore->index) || (!tagstore->tags) || (!tagstore->tag_data)) { dprint("Error: Unable to allocate memory for cache %s tagstore.\n", CACHE_GET_NAME(cache)); cache_assert(0); goto fatal_exit; } /* Initialize indices. */ for (iter = 0; iter < num_sets; ++iter) tagstore->index[iter] = iter; /* Assoicate the tagstore to the given cache and vice-versa. */ cache->tagstore = tagstore; tagstore->cache = cache; #ifdef DBG_ON dprint_info("printing ts data for %s\n", CACHE_GET_NAME(cache)); cache_print_tagstore(cache); #endif /* DBG_ON */ dprint_info("%s, tagstore init successful\n", CACHE_GET_NAME(cache)); exit: return; fatal_exit: /* Fatal exit. Quit the program. */ exit(-1); }