//////////////////////////////////////////////////////////////////////////////// // // // This function is called by the cache after every cache hit/miss // // The arguments are: the set index, the physical way of the cache, // // the pointer to the physical line (should contestants need access // // to information of the line filled or hit upon), the thread id // // of the request, the PC of the request, the accesstype, and finall // // whether the line was a cachehit or not (cacheHit=true implies hit) // // // //////////////////////////////////////////////////////////////////////////////// void CACHE_REPLACEMENT_STATE::UpdateReplacementState( UINT32 setIndex, INT32 updateWayID, const LINE_STATE *currLine, UINT32 tid, Addr_t PC, UINT32 accessType, bool cacheHit ) { // What replacement policy? if( replPolicy == CRC_REPL_LRU ) { UpdateLRU( setIndex, updateWayID ); } else if( replPolicy == CRC_REPL_RANDOM ) { // Random replacement requires no replacement state update } else if( replPolicy == CRC_REPL_CONTESTANT ) { if (cacheHit) { } } }
/*============================================================================ ** ** Function Name: Read ** ** Visibility: Public ** ** Description: Read data from the cache. On a miss, ** identifies LRU and evicts the data prior to reading data ** from next lower level memory. ** ** Invocation: By the CPU of adjecent memory hierarchy. ** ** Input Parameters: const UINT32 address, ** ** Return Values: UINT8 data ** **==========================================================================*/ UINT8 CCacheWriteThru::Read(const UINT32 address) { // Separate tag, index and offset bits UINT32 offset = GetOffsetBits(address); UINT32 index = GetIndexBits(address); UINT32 tag = GetTagBits(address); UINT32 way_to_read = WAY_INVALID; // The byte to be returned UINT8 data = 0xFF; // Starting address of a line. // Useful for reading a line from next memory hierarchy. UINT32 line_start_add; #ifdef __debug__ std::cout << std::endl << "--------------------------------------------------------" << std::endl; std::cout << " Address = " << std::hex << address << std::dec << " Set No = " << index << std::endl; #endif // Make sure sets exists if(m_sets) { // All is well way_to_read = MatchTagBits(m_sets[index], tag); if(WAY_INVALID != way_to_read) { // Cache Read hit. Yay! // Do nothing m_hits++; #ifdef __debug__ std::cout << "Cache Read Hit. " << " Way to read = " << way_to_read << std::endl; #endif } else { UINT32 empty_way = GetEmptyWay(m_sets[index]); if(empty_way != WAY_INVALID) { // The set is not full, an empty way has been found m_misses++; way_to_read = empty_way; #ifdef __debug__ std::cout << "Cache miss. Set not full. " << " Way to read = " << way_to_read << std::endl; #endif } else { // The set is full // Cache read miss m_misses++; UINT32 way_lru = GetLRU(m_sets[index]); way_to_read = way_lru; } // if(empty_way == WAY_INVALID) // Need to read new cache line from L2 (Common to Is there an empty way, Conflict / Compulsory misses) line_start_add = (m_sets[index].lines[way_to_read].tag << (m_num_offset_bits + m_num_index_bits)) | (index << m_num_offset_bits); for(UINT32 item_offset = 0; item_offset < m_line_size; item_offset++) { m_sets[index].lines[way_to_read].line_data[item_offset] = m_next_mem->Read(line_start_add + item_offset); } } // if(WAY_INVALID == way_to_read) // Get the requested byte and update the state bits data = m_sets[index].lines[way_to_read].line_data[offset]; m_sets[index].lines[way_to_read].valid = 1; m_sets[index].lines[way_to_read].tag = tag; m_num_reads++; UpdateLRU(m_sets[index],way_to_read); #ifdef __debug__ printf("Data Read = %x\n", data); std::cout << std::dec << "Stats: Total Reads = " << m_num_reads << " Total Writes = " << m_num_writes << std::endl; std::cout << "Stats: Total Hits = " << m_hits << " Total Misses = " << m_misses << std::endl; for(UINT32 item_offset = 0; item_offset < m_line_size; item_offset++) { printf("\n Line data %d = %x ", item_offset, m_sets[index].lines[way_to_read].line_data[item_offset]); } #endif } else { // Sets not allocated!! SERIOUS ERROR!!! } return data; }
/*============================================================================ ** ** Function Name: Write ** ** Visibility: Public ** ** Description: Write data into the cache. Writes through to second ** level memory to maintain inclusivity. On a miss, ** identifies LRU and evicts the data prior to reading data ** from next lower level memory ** ** Invocation: By the CPU or adjecent memory hierarchy. ** ** Input Parameters: const UINT32 address, const UINT8 data ** ** Return Values: CACHE_HM // Cache hit or miss info ** **==========================================================================*/ CACHE_HM CCacheWriteThru::Write(const UINT32 address, const UINT8 data) { CACHE_HM hm_type = CACHE_HIT; // Separate Tag, index, offset bits UINT32 offset = GetOffsetBits(address); UINT32 index = GetIndexBits(address); UINT32 tag = GetTagBits(address); UINT32 way_to_write = WAY_INVALID; // Starting address of a line. // Useful for reading a line from next memory hierarchy. UINT32 line_start_add; #ifdef __debug__ std::cout << std::endl << "--------------------------------------------------------" << std::endl; std::cout << " Address = " << std::hex << address << " Data = " << data << std::dec << " Set No = " << index << std::endl; #endif // Make sure sets exists if(m_sets) { // All is well way_to_write = MatchTagBits(m_sets[index], tag); if(WAY_INVALID != way_to_write) { // Cache write hit // Do nothing m_hits++; hm_type = CACHE_HIT; #ifdef __debug__ std::cout << "Cache Hit. " << " Way to write = " << way_to_write << std::endl; #endif } else { UINT32 empty_way = GetEmptyWay(m_sets[index]); if(empty_way != WAY_INVALID) { // The set is not full m_misses++; hm_type = CACHE_MISS; way_to_write = empty_way; #ifdef __debug__ std::cout << "Cache miss. Set not full. " << " Way to write = " << way_to_write << std::endl; #endif } else { // The set is full // Cache write miss m_misses++; hm_type = CACHE_MISS; UINT32 way_lru = GetLRU(m_sets[index]); way_to_write = way_lru; }// if(WAY_INVALID == way_to_write) // Need to read new cache line from L2. Common to compuslory and confilct misses line_start_add = (m_sets[index].lines[way_to_write].tag << (m_num_offset_bits + m_num_index_bits)) | (index << m_num_offset_bits); for(UINT32 item_offset = 0; item_offset < m_line_size; item_offset++) { m_sets[index].lines[way_to_write].line_data[item_offset] = m_next_mem->Read(line_start_add + item_offset); } } m_sets[index].lines[way_to_write].line_data[offset] = data; // Need to write to next memeory hierarchy (L2) to maintain inclusivity line_start_add = (m_sets[index].lines[way_to_write].tag << (m_num_offset_bits + m_num_index_bits)) | (index << m_num_offset_bits); // No need to write the whole line, since we write only one byte at time. m_next_mem->Write(address, data); m_sets[index].lines[way_to_write].valid = 1; m_sets[index].lines[way_to_write].tag = tag; m_num_writes++; UpdateLRU(m_sets[index],way_to_write); #ifdef __debug__ std::cout << "Stats: Total Reads = " << m_num_reads << " Total Writes = " << m_num_writes << std::endl; std::cout << "Stats: Total Hits = " << m_hits << " Total Misses = " << m_misses << std::endl; for(UINT32 item_offset = 0; item_offset < m_line_size; item_offset++) { printf("\n Line data %d = %x ", item_offset, m_sets[index].lines[way_to_write].line_data[item_offset]); } #endif } else { // Sets not allocated!! SERIOUS ERROR!!! hm_type = hm_type; } return hm_type; }