CSE 141L Lab4. Cache Similulator. Due Sunday December 4th. As stated many times in lab and lecture THIS IS AN INDIVIDUAL ASSIGNMENT!

In this assignment you will write a cache simulator in your favorite programming language (mine is C).

Here is a very simple cache simulator in C

#include stdio.h
#include assert.h
#define CACHE_SIZE 8192 /* size of cache in cache in cache lines, the real size of the cache in bytes is 8192 times 32 because there are 8 words (32 bytes) per cache line in the example */
#define BLOCK_SHIFT 5
/* the first 2 bits are the byte offset within a 4 byte word, the next 3 bits are the word offset within a cache-line (possible values are 0-7 for 8 different word positions) */
long tags[CACHE_SIZE];
/* We don't care about the data, just the tags for the simulator */
long references, misses;
/* You will need to keep track of L1 and L2 references and misses */

void Reference(long address) {
int index = (address >> BLOCK_SHIFT) & (CACHE_SIZE-1);
/* in the line above we want the "middle bits" that say where the block goes */
long tag = address >> BLOCK_SHIFT; /* the high order bits are the tag */
/* in the line above we want the high bits (can include index bits) that uniquely identify the contents of a cache-block */
if (tags[index] != tag) {/* we compare to see if this is our data or other data mapped to the same location in cache */
misses++;
tags[index] = tag;
}
references++;
}
void main () {
long addr;
FILE * pFile;

pFile = fopen ("addressfile.txt","r+");
while (fscanf(pFile,"%x",&addr) != EOF) {
Reference(addr);
}

printf("This address stream had %d references and %d misses\n",references,misses);
}
Here's a small example addressfile.txt

0xffffff00
0xffffffff
0xffffffff
0xffffffff
0xffffffff
0xffffffff
Here is sample output
This address stream had 6 references and 2 misses
Here is a large test file
This simple cache simulator models an 8192 cache-line direct-mapped cache where each cache-line holds 32 bytes. Your assignement is to model a system with two levels of cache; 1) a 32768 TOTAL cache-lines, two-way set associative L1 cache and 2) a 65536 TOTAL cache-lines 4 way set associative cache. Both have round-robin replacement policies. Your cache-line size is 64 bytes = 16 32-bit words.

Here is a test to see if yours is working
0x00000000 (L1 miss L2 miss because both are empty to start)
0x11100030 (misses both and goes in 2nd assoc set of row zero on both L1 & L2)
0x10000020 (misses both replaces 0x00000000 in L1 goes in 3rd assoc set of row zero in L2)
0x11000010 (misses both replaces 0x11100030 in L1 goes in 4th assoc set of row zero in L2)
0x00000000 (again, miss in L1 replaces 0x10000020, hits in L2)
0x11100030 (again, miss in L1 replaces 0x11000010, hits in L2)
0x00000000 (again, hits in both moves victim pointer away from itself in L1)
0xFFF00030 (miss in both replaces 0x11100030 in both)
0x00000000 (again, hit in both) L1 has contents 0x00000000, 0xFFF00030, L2 has contents 0x00000000,0xFFF00030,0x10000020,0x11000010)
L1 hits = 2
L2 hits = 4
Memory references 9

Round robin means you keep a "victim pointer" to the next location to be replaced (a separate one for each row). When there is a miss the victim pointer is advanced by one modulo the associativity size. But, if there is a hit on an address and the victim pointer currently point at it, then the victim pointer is also advanced.

Both caches are round-robin. But you should preserve inclusion i.e. the contents of L1 should always be a subset of L2 (L2 has everything in L1). That means if there is a miss on both L1 and L2 you should select the victim in L1, replace it, then look for THE SAME VICTIM in L2 and replace it as well. (So that isn't exactly round-robin on L2 on a miss on both). But have a valid bit so you fill all 4 rows of L2 before trying to find victims. This is actually a pretty poor cache replacement policy. Implement it and a better one of your own invention and show why yours is better for extra credit!

What to turn in - you must email me source file, makefile, instructions for making and running your program. Your program must run on one of my machine (I have a UNIX box and an NT box). It must be in a language I have a compiler for (C, C++, Java, Perl, Fortran). The program must be well commented (not like the example!). It must be easy for me to compile and test your program. Additionally you will email me the output of your program on the large testfile (raw.trace) above. You may report just L1 misses and L2 misses as well as total memory references OR total L1 hits and total L2 hits and total memory references. If you report hits you must state whether you count an L1 hit as also an L2 hit. It's a matter of semantics. I don't care if you call an L1 hit also an L2 hit (becuase it is also in L2) or if you count as an L2 hit only things that were a MISS in L1 becuase that is when you actually check L2 just as long as it is clear (and correct) according to your definition. Here is acceptable output (but the numbers are left out)

L1 misses = xxx
L2 misses = xxx (also L1 misses)
Total memory references = xxx