A Simple Cache Simulator

Jeremy Johnson

This worksheet provides a simple cache simulator, which takes three cache design parameters [size, associativity, and block size] and a sequence of addresses and returns the number of cache misses.  The simulator only simulates a single level unified cache [the address sequence does not distinguish reads, writes or instructions vs. data].  The least recently used (lru) strategy is used when a cache line needs to be replaced.

Create a data structure for the Cache simulator.  An array, indexed by the cache index and set, is returned.  Each entry in the array stores the tag and a clock tick, which is used to keep track of the time [index into the address list that is passed to the simulator] that the element is accessed.  A zero entry in the clock field indicates that the cache entry is invalid.  The clock information is used to implement the lru replacement strategy.

>    Cache := proc(C,A,B)

>      local i, j, cache, slots;

>      slots := C/(B*A);  

>      cache := array(0..slots-1,0..A-1);

>      for i from 0 to slots-1 do

>        for j from 0 to A-1 do

>          cache[i,j] := table([tag=0,clock=0]);

>        od;

>      od;

>      return eval(cache);

>    end;

>      

Cache := proc (C, A, B) local i, j, cache, slots; slots := C/B/A; cache := array(0 .. slots-1,0 .. A-1); for i from 0 to slots-1 do for j from 0 to A-1 do cache[i,j] := table([tag = 0, clock = 0]) end ...
Cache := proc (C, A, B) local i, j, cache, slots; slots := C/B/A; cache := array(0 .. slots-1,0 .. A-1); for i from 0 to slots-1 do for j from 0 to A-1 do cache[i,j] := table([tag = 0, clock = 0]) end ...
Cache := proc (C, A, B) local i, j, cache, slots; slots := C/B/A; cache := array(0 .. slots-1,0 .. A-1); for i from 0 to slots-1 do for j from 0 to A-1 do cache[i,j] := table([tag = 0, clock = 0]) end ...
Cache := proc (C, A, B) local i, j, cache, slots; slots := C/B/A; cache := array(0 .. slots-1,0 .. A-1); for i from 0 to slots-1 do for j from 0 to A-1 do cache[i,j] := table([tag = 0, clock = 0]) end ...
Cache := proc (C, A, B) local i, j, cache, slots; slots := C/B/A; cache := array(0 .. slots-1,0 .. A-1); for i from 0 to slots-1 do for j from 0 to A-1 do cache[i,j] := table([tag = 0, clock = 0]) end ...
Cache := proc (C, A, B) local i, j, cache, slots; slots := C/B/A; cache := array(0 .. slots-1,0 .. A-1); for i from 0 to slots-1 do for j from 0 to A-1 do cache[i,j] := table([tag = 0, clock = 0]) end ...
Cache := proc (C, A, B) local i, j, cache, slots; slots := C/B/A; cache := array(0 .. slots-1,0 .. A-1); for i from 0 to slots-1 do for j from 0 to A-1 do cache[i,j] := table([tag = 0, clock = 0]) end ...

>    cache := Cache(8,1,1);

cache := ARRAY([0 .. 7, 0 .. 0],[(0, 0) = TABLE([clock = 0, tag = 0]), (1, 0) = TABLE([clock = 0, tag = 0]), (2, 0) = TABLE([clock = 0, tag = 0]), (3, 0) = TABLE([clock = 0, tag = 0]), (4, 0) = TABLE([...
cache := ARRAY([0 .. 7, 0 .. 0],[(0, 0) = TABLE([clock = 0, tag = 0]), (1, 0) = TABLE([clock = 0, tag = 0]), (2, 0) = TABLE([clock = 0, tag = 0]), (3, 0) = TABLE([clock = 0, tag = 0]), (4, 0) = TABLE([...
cache := ARRAY([0 .. 7, 0 .. 0],[(0, 0) = TABLE([clock = 0, tag = 0]), (1, 0) = TABLE([clock = 0, tag = 0]), (2, 0) = TABLE([clock = 0, tag = 0]), (3, 0) = TABLE([clock = 0, tag = 0]), (4, 0) = TABLE([...
cache := ARRAY([0 .. 7, 0 .. 0],[(0, 0) = TABLE([clock = 0, tag = 0]), (1, 0) = TABLE([clock = 0, tag = 0]), (2, 0) = TABLE([clock = 0, tag = 0]), (3, 0) = TABLE([clock = 0, tag = 0]), (4, 0) = TABLE([...
cache := ARRAY([0 .. 7, 0 .. 0],[(0, 0) = TABLE([clock = 0, tag = 0]), (1, 0) = TABLE([clock = 0, tag = 0]), (2, 0) = TABLE([clock = 0, tag = 0]), (3, 0) = TABLE([clock = 0, tag = 0]), (4, 0) = TABLE([...
cache := ARRAY([0 .. 7, 0 .. 0],[(0, 0) = TABLE([clock = 0, tag = 0]), (1, 0) = TABLE([clock = 0, tag = 0]), (2, 0) = TABLE([clock = 0, tag = 0]), (3, 0) = TABLE([clock = 0, tag = 0]), (4, 0) = TABLE([...
cache := ARRAY([0 .. 7, 0 .. 0],[(0, 0) = TABLE([clock = 0, tag = 0]), (1, 0) = TABLE([clock = 0, tag = 0]), (2, 0) = TABLE([clock = 0, tag = 0]), (3, 0) = TABLE([clock = 0, tag = 0]), (4, 0) = TABLE([...
cache := ARRAY([0 .. 7, 0 .. 0],[(0, 0) = TABLE([clock = 0, tag = 0]), (1, 0) = TABLE([clock = 0, tag = 0]), (2, 0) = TABLE([clock = 0, tag = 0]), (3, 0) = TABLE([clock = 0, tag = 0]), (4, 0) = TABLE([...
cache := ARRAY([0 .. 7, 0 .. 0],[(0, 0) = TABLE([clock = 0, tag = 0]), (1, 0) = TABLE([clock = 0, tag = 0]), (2, 0) = TABLE([clock = 0, tag = 0]), (3, 0) = TABLE([clock = 0, tag = 0]), (4, 0) = TABLE([...
cache := ARRAY([0 .. 7, 0 .. 0],[(0, 0) = TABLE([clock = 0, tag = 0]), (1, 0) = TABLE([clock = 0, tag = 0]), (2, 0) = TABLE([clock = 0, tag = 0]), (3, 0) = TABLE([clock = 0, tag = 0]), (4, 0) = TABLE([...

CacheSim implements the simulator.  

>    # Cache Simulator

>    # Inputs:

>    #   addr : a list of addresses

>    #      C : Cache size

>    #      A : Associativity

>    #      B : Block size

>    #  TRACE : boolean flag.  If TRACE is true, each address in the trace is printed along

>    #          with a message indicating whether the cache access was a hit or not.

>    # Output:

>    #  misses : the number of cache misses that would occur using the specified cache design

>    #           on the given sequence of addresses.       

>    CacheSim := proc(addr,C,A,B,TRACE)

>      local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses;

>      cache := Cache(C,A,B);  slots := C/(A*B);  misses := 0;

>      printf("Cache size = %d, Associativity = %d, Block size = %d\n",C,A,B);

>      printf("Number of slots = %d\n",slots);

>      n := nops(addr);

>      for i from 1 to n do  

>        block := floor(addr[i]/B);  offset := addr[i] mod B;

>        index := block mod slots;  found := false;

>        if TRACE then printf("%d-th address = %d -> %d\n",i,addr[i],index); fi;

>        for j from 0 to A-1 do

>          if block = cache[index,j][tag] and cache[index,j][clock] > 0 then

>             found := true;  cache[index,j][clock] := i;  

>             if TRACE then printf("hit\n"); fi;

>          fi;

>        od;

>        if not found then

>          if TRACE then printf("miss\n"); fi;

>          misses := misses + 1; minclock := n+1;  

>          for j from 0 to A-1 do       

>            if cache[index,j][clock] < minclock then  

>              minclock := cache[index,j][clock];  rep := j;

>            fi;

>          od;

>          cache[index,rep][tag] := block;

>          cache[index,rep][clock] := i;

>        fi;

>      od;

>      return misses;

>    end;

CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(
CacheSim := proc (addr, C, A, B, TRACE) local cache, slots, i, j, n, block, offset, index, found, rep, minclock, misses; cache := Cache(C,A,B); slots := C/A/B; misses := 0; printf(

>    T1 := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 2, 4, 6, 8, 10, 12, 14, 0, 4, 8, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15, 1, 5, 9, 13, 3, 7, 11, 15];

T1 := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 2, 4, 6, 8, 10, 12, 14, 0, 4, 8, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15, 1, 5, 9, 13, 3, 7, 11, 15]

>    nops(T1);

48

>    CacheSim(T1,8,1,1,false);

Cache size = 8, Associativity = 1, Block size = 1

Number of slots = 8

48

>    CacheSim(T1,8,1,2,false);

Cache size = 8, Associativity = 1, Block size = 2

Number of slots = 4

40

>    CacheSim(T1,8,2,1,false);

Cache size = 8, Associativity = 2, Block size = 1

Number of slots = 4

48

>    T2 := [0, 1, 2, 3, 4, 5, 6, 7, 0, 4, 1, 5, 2, 6, 3, 7, 8, 9, 10, 11, 12, 13, 14, 15, 8, 12, 9, 13, 10, 14, 11, 15, 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15];

T2 := [0, 1, 2, 3, 4, 5, 6, 7, 0, 4, 1, 5, 2, 6, 3, 7, 8, 9, 10, 11, 12, 13, 14, 15, 8, 12, 9, 13, 10, 14, 11, 15, 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15]

>    CacheSim(T2,8,1,1,false);

Cache size = 8, Associativity = 1, Block size = 1

Number of slots = 8

32

>    CacheSim(T2,8,1,2,false);

Cache size = 8, Associativity = 1, Block size = 2

Number of slots = 4

24

>    CacheSim(T2,8,2,1,true);

Cache size = 8, Associativity = 2, Block size = 1

Number of slots = 4

1-th address = 0 -> 0

miss

2-th address = 1 -> 1

miss

3-th address = 2 -> 2

miss

4-th address = 3 -> 3

miss

5-th address = 4 -> 0

miss

6-th address = 5 -> 1

miss

7-th address = 6 -> 2

miss

8-th address = 7 -> 3

miss

9-th address = 0 -> 0

hit

10-th address = 4 -> 0

hit

11-th address = 1 -> 1

hit

12-th address = 5 -> 1

hit

13-th address = 2 -> 2

hit

14-th address = 6 -> 2

hit

15-th address = 3 -> 3

hit

16-th address = 7 -> 3

hit

17-th address = 8 -> 0

miss

18-th address = 9 -> 1

miss

19-th address = 10 -> 2

miss

20-th address = 11 -> 3

miss

21-th address = 12 -> 0

miss

22-th address = 13 -> 1

miss

23-th address = 14 -> 2

miss

24-th address = 15 -> 3

miss

25-th address = 8 -> 0

hit

26-th address = 12 -> 0

hit

27-th address = 9 -> 1

hit

28-th address = 13 -> 1

hit

29-th address = 10 -> 2

hit

30-th address = 14 -> 2

hit

31-th address = 11 -> 3

hit

32-th address = 15 -> 3

hit

33-th address = 0 -> 0

miss

34-th address = 8 -> 0

miss

35-th address = 1 -> 1

miss

36-th address = 9 -> 1

miss

37-th address = 2 -> 2

miss

38-th address = 10 -> 2

miss

39-th address = 3 -> 3

miss

40-th address = 11 -> 3

miss

41-th address = 4 -> 0

miss

42-th address = 12 -> 0

miss

43-th address = 5 -> 1

miss

44-th address = 13 -> 1

miss

45-th address = 6 -> 2

miss

46-th address = 14 -> 2

miss

47-th address = 7 -> 3

miss

48-th address = 15 -> 3

miss

32

>    T3 := [0,8,0,8];

T3 := [0, 8, 0, 8]

>    CacheSim(T3,8,1,1,true);

Cache size = 8, Associativity = 1, Block size = 1

Number of slots = 8

1-th address = 0 -> 0

miss

2-th address = 8 -> 0

miss

3-th address = 0 -> 0

miss

4-th address = 8 -> 0

miss

4

>    CacheSim(T3,4,2,1,true);

Cache size = 4, Associativity = 2, Block size = 1

Number of slots = 2

1-th address = 0 -> 0

miss

2-th address = 8 -> 0

miss

3-th address = 0 -> 0

hit

4-th address = 8 -> 0

hit

2

>