#include #include #include "memory.h" /* Return the memory index that corresponds to the given address. */ int toIndex (unsigned int address) { return (address-BASE_ADDRESS)/4; } /* Retrieve the contents of memory at the given address. First consult the cache. */ int contents(Memory mipsMem, unsigned int address) { if (cacheContains(mipsMem->cache, address)) { return cacheContents (mipsMem->cache, address); } else { int contents = mipsMem->ram[toIndex(address)]; addEntry (mipsMem->cache, mipsMem, address); return contents; } } /* Store the given contents at the given address, and add a corresponding entry in the cache. */ void store(Memory mipsMem, unsigned int address, int contents) { /* write-through */ mipsMem->ram[toIndex(address)] = contents; if (cacheContains(mipsMem->cache, address)) { updateCacheContents (mipsMem->cache, address, contents); } else { addEntry (mipsMem->cache, mipsMem, address); } } /* Return a pointer to an initialized data structure representing a computer memory. maxNumInstrs is the maximum number of words allowed for instructions. maxNumData is the maximum number of words allowed for data. numRows, blockSize, and associativity are cache parameters (see above). printingMemory, printingCache, and debugging govern the production of output. */ struct memory * newMemory (int maxNumInstrs, int maxNumData, int associativity, int nsets, int blocksize, bool printingMemory, bool printingCache, bool debugging) { struct memory * mem; mem = (struct memory *) malloc (sizeof(struct memory)); mem->ram = (int *) calloc (maxNumInstrs+maxNumData, sizeof(int)); mem->maxNumInstrs = maxNumInstrs; mem->maxNumData = maxNumData; mem->printingMemory = printingMemory; mem->debugging = debugging; mem->cache = newCache (associativity, nsets, blocksize, printingCache, debugging); return mem; } /* Print the contents of the memory and cache. */ void printMemory(Memory mipsMem, int changedMem) { int addr; if (!mipsMem->printingMemory && changedMem == -1) { printf ("No memory location was updated.\n"); } else if (!mipsMem->printingMemory) { printf ("Updated memory at address %8.8x to %8.8x\n", changedMem, contents (mipsMem, changedMem)); } else { printf ("Nonzero memory\n"); printf ("ADDR CONTENTS\n"); for (addr = BASE_ADDRESS+(mipsMem->maxNumInstrs << 2); addr < 0x00400000+((mipsMem->maxNumInstrs+mipsMem->maxNumData) << 2); addr = addr+4) { int contents = mipsMem->ram[toIndex(addr)]; if (contents != 0) printf ("%8.8x %8.8x\n", addr, contents); } } printf ("\n"); Cache cache = mipsMem->cache; if (cache->printingCache || (changedMem != -1)) printCache(cache); int set, way; for (set = 0; set < cache->nsets; set++) { for (way = 0; way < cache->associativity; way++) { int * pCache = cache->sets[set].blocks[way].words; if ((pCache >= mipsMem->ram) && (pCache < (mipsMem->ram + mipsMem->maxNumInstrs + mipsMem->maxNumData))) { printf("Cache block pointed into memory array! Set %d, Way %d\n", set, way); printf("Stop trying to cheat the assignment, and store your cache blocks separately from your memory!\n"); exit(1); } } } } /* A shadow copy of the cache contents for checking... */ struct set * cacheShadowSets = NULL; /* Print the contents of the cache. */ void printCache(Cache cache) { int set, way, word; if (!cache->printingCache) { if (cacheShadowSets == NULL) { // If we've never been called before create a copy of the cache! // Copy each set.... cacheShadowSets = (struct set *)malloc(sizeof(struct set) * cache->nsets); for (set = 0; set < cache->nsets; set++) { cacheShadowSets[set].blocks = (struct block *) malloc (cache->associativity * sizeof(struct block)); // Copy each way within the set... for (way = 0; way < cache->associativity; way++) { cacheShadowSets[set].blocks[way].lastUsedTime = cache->sets[set].blocks[way].lastUsedTime; cacheShadowSets[set].blocks[way].isValid = cache->sets[set].blocks[way].isValid; cacheShadowSets[set].blocks[way].tag = cache->sets[set].blocks[way].tag; cacheShadowSets[set].blocks[way].words = (int *) malloc (cache->blocksize * sizeof(int)); // Copy each word within the block for (word = 0; word < cache->blocksize; word++) { cacheShadowSets[set].blocks[way].words[word] = cache->sets[set].blocks[way].words[word]; } } } } else { // We have a previous copy of the cache, so print out all the differences // For each set... for (set = 0; set < cache->nsets; set++) { // For each way within the set for (way = 0; way < cache->associativity; way++) { // Determine if the block has changed at all bool blockChanged = FALSE; blockChanged = blockChanged || (cacheShadowSets[set].blocks[way].lastUsedTime != cache->sets[set].blocks[way].lastUsedTime); blockChanged = blockChanged || (cacheShadowSets[set].blocks[way].isValid != cache->sets[set].blocks[way].isValid); blockChanged = blockChanged || (cacheShadowSets[set].blocks[way].tag != cache->sets[set].blocks[way].tag); for (word = 0; word < cache->blocksize; word++) { blockChanged = blockChanged || (cacheShadowSets[set].blocks[way].words[word] != cache->sets[set].blocks[way].words[word]); } // The block changed, so print it out and update our copy if (blockChanged) { /* // Print the old version printf ("| old set %8.8x way %8.8x tag %8.8x, used %8.8x, valid? %1d ", set, way, cacheShadowSets[set].blocks[way].tag, cacheShadowSets[set].blocks[way].lastUsedTime, cacheShadowSets[set].blocks[way].isValid); for (word=0; word < cache->blocksize; word++) { printf (": %8.8x ", cacheShadowSets[set].blocks[way].words[word]); } printf ("|\n"); // Print the new version printf ("| new set %8.8x way %8.8x tag %8.8x, used %8.8x, valid? %1d ", set, way, cache->sets[set].blocks[way].tag, cache->sets[set].blocks[way].lastUsedTime, cache->sets[set].blocks[way].isValid); for (word=0; word < cache->blocksize; word++) { printf (": %8.8x ", cache->sets[set].blocks[way].words[word]); } printf ("|\n"); */ // Update our copy for the next printout cacheShadowSets[set].blocks[way].lastUsedTime = cache->sets[set].blocks[way].lastUsedTime; cacheShadowSets[set].blocks[way].isValid = cache->sets[set].blocks[way].isValid; cacheShadowSets[set].blocks[way].tag = cache->sets[set].blocks[way].tag; for (word = 0; word < cache->blocksize; word++) { cacheShadowSets[set].blocks[way].words[word] = cache->sets[set].blocks[way].words[word]; } } } } } } else { // Just print out the cache contents, to make debugging easier for (set = 0; set < cache->nsets; set++) { for (way = 0; way < cache->associativity; way++) { //printf ("| set %8.8x way %8.8x tag %8.8x, used %8.8x, valid? %1d ", //set, way, cache->sets[set].blocks[way].tag, //cache->sets[set].blocks[way].lastUsedTime, //cache->sets[set].blocks[way].isValid); printf ("| set %8.8x way %8.8x tag %8.8x, valid? %1d ", set, way, cache->sets[set].blocks[way].tag, cache->sets[set].blocks[way].isValid); for (word=0; word < cache->blocksize; word++) { printf (": %8.8x ", cache->sets[set].blocks[way].words[word]); } printf ("|\n"); } } printf ("\n"); } }