📄 cache.c
字号:
{ if (item->lru != 0 && item->lru < tag->lru) ++item->lru; ++item; } tag->lru = 0; /* Mark as least recently used. */}/* Find the line containing the given address and load it if it is not already loaded. Returns the tag of the requested line. */static FRV_CACHE_TAG *find_or_retrieve_cache_line (FRV_CACHE *cache, SI address){ /* See if this data is already in the cache. */ FRV_CACHE_TAG *tag; int found = get_tag (cache, address, &tag); /* Fill the line from memory, if it is not valid. */ if (! found) { /* The tag could be NULL is all ways in the set were used and locked. */ if (tag == NULL) return tag; fill_line_from_memory (cache, tag, address); tag->dirty = 0; } /* Update the LRU information for the tags in this set. */ set_most_recently_used (cache, tag); return tag;}static voidcopy_line_to_return_buffer (FRV_CACHE *cache, int pipe, FRV_CACHE_TAG *tag, SI address){ /* A cache line was available for the data. Copy the data from the cache line to the output buffer. */ memcpy (cache->pipeline[pipe].status.return_buffer.data, tag->line, cache->line_size); cache->pipeline[pipe].status.return_buffer.address = address & ~(cache->line_size - 1); cache->pipeline[pipe].status.return_buffer.valid = 1;}static voidcopy_memory_to_return_buffer (FRV_CACHE *cache, int pipe, SI address){ address &= ~(cache->line_size - 1); read_data_from_memory (cache->cpu, address, cache->pipeline[pipe].status.return_buffer.data, cache->line_size); cache->pipeline[pipe].status.return_buffer.address = address; cache->pipeline[pipe].status.return_buffer.valid = 1;}static voidset_return_buffer_reqno (FRV_CACHE *cache, int pipe, unsigned reqno){ cache->pipeline[pipe].status.return_buffer.reqno = reqno;}/* Read data from the given cache. Returns the number of cycles required to obtain the data. */intfrv_cache_read (FRV_CACHE *cache, int pipe, SI address){ FRV_CACHE_TAG *tag; if (non_cache_access (cache, address)) { copy_memory_to_return_buffer (cache, pipe, address); return 1; } tag = find_or_retrieve_cache_line (cache, address); if (tag == NULL) return 0; /* Indicate non-cache-access. */ /* A cache line was available for the data. Copy the data from the cache line to the output buffer. */ copy_line_to_return_buffer (cache, pipe, tag, address); return 1; /* TODO - number of cycles unknown */}/* Writes data through the given cache. The data is assumed to be in target endian order. Returns the number of cycles required to write the data. */intfrv_cache_write (FRV_CACHE *cache, SI address, char *data, unsigned length){ int copy_back; /* See if this data is already in the cache. */ SIM_CPU *current_cpu = cache->cpu; USI hsr0 = GET_HSR0 (); FRV_CACHE_TAG *tag; int found; if (non_cache_access (cache, address)) { write_data_to_memory (cache, address, data, length); return 1; } found = get_tag (cache, address, &tag); /* Write the data to the cache line if one was available and if it is either a hit or a miss in copy-back mode. The tag may be NULL if all ways were in use and locked on a miss. */ copy_back = GET_HSR0_CBM (GET_HSR0 ()); if (tag != NULL && (found || copy_back)) { int line_offset; /* Load the line from memory first, if it was a miss. */ if (! found) fill_line_from_memory (cache, tag, address); line_offset = address & (cache->line_size - 1); memcpy (tag->line + line_offset, data, length); tag->dirty = 1; /* Update the LRU information for the tags in this set. */ set_most_recently_used (cache, tag); } /* Write the data to memory if there was no line available or we are in write-through (not copy-back mode). */ if (tag == NULL || ! copy_back) { write_data_to_memory (cache, address, data, length); if (tag != NULL) tag->dirty = 0; } return 1; /* TODO - number of cycles unknown */}/* Preload the cache line containing the given address. Lock the data if requested. Returns the number of cycles required to write the data. */intfrv_cache_preload (FRV_CACHE *cache, SI address, USI length, int lock){ int offset; int lines; if (non_cache_access (cache, address)) return 1; /* preload at least 1 line. */ if (length == 0) length = 1; offset = address & (cache->line_size - 1); lines = 1 + (offset + length - 1) / cache->line_size; /* Careful with this loop -- length is unsigned. */ for (/**/; lines > 0; --lines) { FRV_CACHE_TAG *tag = find_or_retrieve_cache_line (cache, address); if (lock && tag != NULL) tag->locked = 1; address += cache->line_size; } return 1; /* TODO - number of cycles unknown */}/* Unlock the cache line containing the given address. Returns the number of cycles required to unlock the line. */intfrv_cache_unlock (FRV_CACHE *cache, SI address){ FRV_CACHE_TAG *tag; int found; if (non_cache_access (cache, address)) return 1; found = get_tag (cache, address, &tag); if (found) tag->locked = 0; return 1; /* TODO - number of cycles unknown */}static voidinvalidate_return_buffer (FRV_CACHE *cache, SI address){ /* If this address is in one of the return buffers, then invalidate that return buffer. */ address &= ~(cache->line_size - 1); if (address == cache->pipeline[LS].status.return_buffer.address) cache->pipeline[LS].status.return_buffer.valid = 0; if (address == cache->pipeline[LD].status.return_buffer.address) cache->pipeline[LD].status.return_buffer.valid = 0;}/* Invalidate the cache line containing the given address. Flush the data if requested. Returns the number of cycles required to write the data. */intfrv_cache_invalidate (FRV_CACHE *cache, SI address, int flush){ /* See if this data is already in the cache. */ FRV_CACHE_TAG *tag; int found; /* Check for non-cache access. This operation is still perfromed even if the cache is not currently enabled. */ if (non_cache_access (cache, address)) return 1; /* If the line is found, invalidate it. If a flush is requested, then flush it if it is dirty. */ found = get_tag (cache, address, &tag); if (found) { SIM_CPU *cpu; /* If a flush is requested, then flush it if it is dirty. */ if (tag->dirty && flush) write_line_to_memory (cache, tag); set_least_recently_used (cache, tag); tag->valid = 0; tag->locked = 0; /* If this is the insn cache, then flush the cpu's scache as well. */ cpu = cache->cpu; if (cache == CPU_INSN_CACHE (cpu)) scache_flush_cpu (cpu); } invalidate_return_buffer (cache, address); return 1; /* TODO - number of cycles unknown */}/* Invalidate the entire cache. Flush the data if requested. */intfrv_cache_invalidate_all (FRV_CACHE *cache, int flush){ /* See if this data is already in the cache. */ int elements = cache->sets * cache->ways; FRV_CACHE_TAG *tag = cache->tag_storage; SIM_CPU *cpu; int i; for(i = 0; i < elements; ++i, ++tag) { /* If a flush is requested, then flush it if it is dirty. */ if (tag->valid && tag->dirty && flush) write_line_to_memory (cache, tag); tag->valid = 0; tag->locked = 0; } /* If this is the insn cache, then flush the cpu's scache as well. */ cpu = cache->cpu; if (cache == CPU_INSN_CACHE (cpu)) scache_flush_cpu (cpu); /* Invalidate both return buffers. */ cache->pipeline[LS].status.return_buffer.valid = 0; cache->pipeline[LD].status.return_buffer.valid = 0; return 1; /* TODO - number of cycles unknown */}/* --------------------------------------------------------------------------- Functions for operating the cache in cycle accurate mode. ------------------------------------------------------------------------- *//* Convert a VLIW slot to a cache pipeline index. */static intconvert_slot_to_index (int slot){ switch (slot) { case UNIT_I0: case UNIT_C: return LS; case UNIT_I1: return LD; default: abort (); } return 0;}/* Allocate free chains of cache requests. */#define FREE_CHAIN_SIZE 16static FRV_CACHE_REQUEST *frv_cache_request_free_chain = NULL;static FRV_CACHE_REQUEST *frv_store_request_free_chain = NULL;static voidallocate_new_cache_requests (void){ int i; frv_cache_request_free_chain = xmalloc (FREE_CHAIN_SIZE * sizeof (FRV_CACHE_REQUEST)); for (i = 0; i < FREE_CHAIN_SIZE - 1; ++i) { frv_cache_request_free_chain[i].next = & frv_cache_request_free_chain[i + 1]; } frv_cache_request_free_chain[FREE_CHAIN_SIZE - 1].next = NULL;}/* Return the next free request in the queue for the given cache pipeline. */static FRV_CACHE_REQUEST *new_cache_request (void){ FRV_CACHE_REQUEST *req; /* Allocate new elements for the free chain if necessary. */ if (frv_cache_request_free_chain == NULL) allocate_new_cache_requests (); req = frv_cache_request_free_chain; frv_cache_request_free_chain = req->next; return req;}/* Return the given cache request to the free chain. */static voidfree_cache_request (FRV_CACHE_REQUEST *req){ if (req->kind == req_store) { req->next = frv_store_request_free_chain; frv_store_request_free_chain = req; } else { req->next = frv_cache_request_free_chain; frv_cache_request_free_chain = req; }}/* Search the free chain for an existing store request with a buffer that's large enough. */static FRV_CACHE_REQUEST *new_store_request (int length){ FRV_CACHE_REQUEST *prev = NULL; FRV_CACHE_REQUEST *req; for (req = frv_store_request_free_chain; req != NULL; req = req->next) { if (req->u.store.length == length) break; prev = req; } if (req != NULL) { if (prev == NULL) frv_store_request_free_chain = req->next; else prev->next = req->next; return req; } /* No existing request buffer was found, so make a new one. */ req = new_cache_request (); req->kind = req_store; req->u.store.data = xmalloc (length); req->u.store.length = length; return req;}/* Remove the given request from the given pipeline. */static voidpipeline_remove_request (FRV_CACHE_PIPELINE *p, FRV_CACHE_REQUEST *request){ FRV_CACHE_REQUEST *next = request->next; FRV_CACHE_REQUEST *prev = request->prev; if (prev == NULL) p->requests = next; else prev->next = next; if (next != NULL) next->prev = prev;}/* Add the given request to the given pipeline. */static voidpipeline_add_request (FRV_CACHE_PIPELINE *p, FRV_CACHE_REQUEST *request){ FRV_CACHE_REQUEST *prev = NULL; FRV_CACHE_REQUEST *item; /* Add the request in priority order. 0 is the highest priority. */ for (item = p->requests; item != NULL; item = item->next) { if (item->priority > request->priority) break; prev = item; } request->next = item; request->prev = prev; if (prev == NULL) p->requests = request; else prev->next = request; if (item != NULL) item->prev = request;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -