import java.util.ListIterator; /** Cache.java - This file defines a cache for our cache simulation. * We'll assume a simple model. Direct mapped (each program line has exactly * one place to go) and having 8 lines and 4 words per line. The number of * bits for the tag, line # and word # can be derived from the cache dimensions. */ public class Cache { private int linesInCache; private int wordsPerLine; private int tagBits; private int lineBits; private int wordBits; private int [] tag; private int [][] contents; private int numHits; private int numMisses; private static final int EMPTY = -1; private int fetchNumber; // for output public Cache() { linesInCache = 8; wordsPerLine = 4; numHits = 0; numMisses = 0; fetchNumber = 0; // allocate space for arrays tag = new int [linesInCache]; contents = new int [linesInCache][wordsPerLine]; for (int i = 0; i < linesInCache; ++i) { tag[i] = EMPTY; for (int j = 0; j < wordsPerLine; ++j) contents[i][j] = EMPTY; } // The method calcBits() will determine the field sizes for the // number of bits in the tag, line number and word number. // We assume the byte number is represented by the rightmost 2 bits. calcBits(linesInCache, wordsPerLine); System.out.printf("tag bits = %d\n", tagBits); System.out.printf("line bits = %d\n", lineBits); System.out.printf("word bits = %d\n", wordBits); } // calcBits - determine field sizes based on cache dimensions. // Note that we use numLines and numWords as local names so we don't // inadvertently change the actual size of the cache here. // *** You need to finish this method. public void calcBits(int numLines, int numWords) { tagBits = 0; lineBits = 0; wordBits = 0; } // run - Simulate the cache on a set of address references given in the // Program object called p. Keep tract of hits and misses, as well as the // current state of the cache. We should also print the cache "contents" // every time it changes (i.e. on a miss). // See down below the section that you need to finish. public void run(Program p) { ListIterator it = p.listIterator(); while(it.hasNext()) { ++fetchNumber; System.out.printf("fetch # %d\n", fetchNumber); int address = Integer.parseInt((String) it.next(), 16); // Now it's time to play cache! Find the tagnum, linenum, wordnum, // see if it's in cache, and if not put the whole line in. // Keep track of total hits and misses! // And print out the state of the cache when there is a miss. // *** You need to add your code here. if (true) System.out.println(this); } } public void printResults() { System.out.printf("Number of hits = %d ", numHits); System.out.printf("Number of misses = %d ", numMisses); System.out.printf("miss rate = %.1f %%\n", 100.0 * numMisses / numMisses / (numHits + numMisses)); } // Carefully create the String that represents what's in cache. public String toString() { StringBuilder sb = new StringBuilder(); sb.append(justify("tags", 17 + 9 * wordsPerLine) + "\n"); for (int i = 0; i < linesInCache; ++i) { sb.append("line " + justify(i, 2) + ":"); for (int j = 0; j < wordsPerLine; ++j) if (contents[i][j] == EMPTY) sb.append(justify("...", 9)); else sb.append(justify(contents[i][j], 9)); if (tag[i] == EMPTY) sb.append(justify("...", 11) + "\n"); else sb.append(justify(tag[i], 11) + "\n"); } return sb.toString(); } // Create a string showing the integer n in HEX, right justified // n a field width of 'width'. Treat 0 as an ordinary number. public String justify(int n, int width) { StringBuilder sb = new StringBuilder(); String numberString = Integer.toHexString(n); for (int i = 0; i < width - numberString.length(); ++i) sb.append(" "); sb.append(numberString); return sb.toString(); } // We need a similar function for strings in general. public String justify(String s, int n) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < n - s.length(); ++i) sb.append(" "); sb.append(s); return sb.toString(); } }