Question
#include #include #include int offset_bits; //number of bits in the offset int line_num_bits; //number of bits in the line number int cache[16][8]; int binToInt(char* bin)
#include
#include
#include
int offset_bits; //number of bits in the offset
int line_num_bits; //number of bits in the line number
int cache[16][8];
int binToInt(char* bin) { //converts binary number string into integer
int retVal = 0;
while(*bin) {
retVal *= 2;
if(*bin == '1')
retVal += 1;
bin++;
}
return retVal;
}
int read(char* addr) {
//called when there is a read on given address; returns whether it hit
printf("Read from address %s: ", addr);
//split address into parts
char* tag = malloc(sizeof(char) * 13);
strncpy(tag, addr, 5);
tag[5] = '\0';
char* line_num = malloc(sizeof(char) * 5);
strncpy(line_num, addr+5, 4);
line_num[4] = '\0';
char* offset = malloc(sizeof(char) * 4);
strncpy(offset, addr+9, 3);
offset[3] = '\0';
//print tag and cache line number for debugging purposes
printf("tag: %s, cache line number: %d ", tag, binToInt(line_num));
free(tag);
free(line_num);
free(offset);
return 0;
}
int write(char* addr) {
//called when there is a write on given address; returns whether it hit
printf("Write to address %s: ", addr);
//split address into parts
char* tag = malloc(sizeof(char) * 13);
strncpy(tag, addr, 5);
tag[5] = '\0';
char* line_num = malloc(sizeof(char) * 5);
strncpy(line_num, addr+5, 4);
line_num[4] = '\0';
char* offset = malloc(sizeof(char) * 4);
strncpy(offset, addr+9, 3);
offset[3] = '\0';
//print tag and cache line number for debugging purposes
printf("tag: %s, cache line number: %d ", tag, binToInt(line_num));
free(tag);
free(line_num);
free(offset);
return 0;
}
void print() {
//prints contents of cache
int num_lines = 1 << line_num_bits; //number of cache lines
int line_size = 1 << offset_bits; //size of each cache line
printf("Cache contents: ");
for(int i=0; i printf("Line %d: ", i); for(int j=0; j printf("%d ", cache[i][j]); printf(" "); } } int main() { offset_bits = 3; //line size is 2^3=8 bytes line_num_bits = 4; //2^4=16 lines char lines[30]; //to read input while(fgets(line, 30, stdin) != NULL) { char* cmd = strtok(line, " "); //command if(strcmp(cmd, "quit") == 0) break; if(strcmp(cmd, "print") == 0) print(); else if(strcmp(cmd, "read") == 0) { char* addr = strtok(NULL, " "); //address for operation if(addr) if(read(addr)) printf("Hit! "); else printf("Miss "); else printf("Missing address "); } else if(strcmp(cmd, "write") == 0) { char* addr = strtok(NULL, " "); //address for operation if(addr) if(write(addr)) printf("Hit! "); else printf("Miss "); else printf("Missing address "); } else printf("Unrecognized command: %s ", cmd); } } Expand on the cache simulator above so that it can simulate caches of different size and associativity. Specifically, it should take 3 integers from the command line when it is run. Thus, you can run the program with a command line like the following: ./cacheSim 4 3 5 Call the arguments x, y, and z. The total cache size is 2x ; x has the role of line num bits in the lab. The number of sets is 2y ; y is also the number of bits used by the middle field of the address (the set number). The third command line argument is the number of address bits that specify the offset; this is the same as offset bits in the lab. The addresses will all be 16 bits; you may assume that 16 > x y and that 16 > y + z. To read these arguments off the command line, we add arguments to the main function: int main(int argc, char** argv) Here argv is an array of strings (array of arrays of chars) representing the arguments. For example, with the command line given above, argv[1] will be 4, argv[2] will be 3 and argv[3] will be 5. argc is the number of command line arguments, including argv[0], which is the name of the executable as a string (i.e. ./cacheSim. To convert the string representation of an integer into the integer itself, use atoi (stands for ASCII to integer); for example, atoi(argv[1]) returns the integer value of the first argument (x in our case). Your simulator should support the read, write, and print methods. Beyond what is in the lab handout, the simulator should also track which cache lines are dirty (written to since they were loaded) and how many misses the cache has suffered. When the cache is printed, it should print a summary of each line, where the following are examples of an invalid line, a clean line, and a dirty line respectively: Line 0: Empty Line 1: Tag: 100011010 Line 2: Tag: 111000101 Dirty After printing a summary for all the lines, it should print the number of misses: Number of misses so far: 2 A miss should be recorded whenever a requested data block is not in the cache, i.e. writes also cause a miss unless that data block is already in the cache. When x=y, i.e. the number of lines is equal to the number of sets, the cache will be direct mapped. When they are not equal, the cache will be organized into sets of size 2x-y , each using a FCFS replacement policy within that set. I suggest that you represent the cache contents as an array with one line struct per cache line (for the tags, valid bits, and dirty bits) and also an array of integers, one per set, giving the index of the cache line within that set to replace next. In addition, when the program quits, you should free all dynamically-allocated memory (i.e. anything allocated using malloc).
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started