The goal of this project is to implement a set-associative cache simulator in C, capable of simulating memory accesses with realistic cache behavior. The simulator supports configurable cache size, block size, and associativity. It simulates memory operations based on a trace file and tracks cache statistics.
The simulator must:
- Accept command-line arguments for cache configuration
- Use write-back policy with LRU replacement
- Output cache contents and summary statistics after running
The simulator must accept the following arguments:
-s=<cache size>: Total cache size in bytes (valid range: 32B to 1MB)-b=<block size>: Block size in bytes (valid range: 4B to 256B)-a=<associativity>: Number of cache blocks per set (must be power of two)-f=<trace file>: Path to memory trace file
All sizes must be powers of two.
Example:
$ ./cachesim -s=64 -a=2 -b=8 -f=sample.trcArgument order is flexible.
The trace file contains memory access operations in the following format:
<Address> <R/W> <Data>
<Address>: 32-bit memory address (8 hexadecimal characters)<R/W>: Either 'R' for read or 'W' for write<Data>: Data to write (only for write operations; 32-bit decimal integer)
Example:
00010008 W 33
0001000C W 4
00010000 R
All memory accesses are 1 word (4 bytes) in size. Memory not accessed yet is initialized to 0.
- Cache is divided into multiple sets; each set holds multiple blocks (ways)
- Uses write-back policy
- Uses LRU (Least Recently Used) for eviction
- Each cache line contains:
- Tag
- Valid bit
- Dirty bit
- Block data
At the end of the simulation, the following statistics should be printed:
- Total number of hits
- Total number of misses
- Miss rate (percentage)
- Total number of dirty blocks
- Average memory access cycle
Memory access cycles:
- Hit: 1 cycle
- Miss: 200 cycles
Example output after simulation:
0: 00000001 00000001 v:1 d:1
00000002 FFFC1100 v:1 d:0
1: 00000003 00000001 v:1 d:1
0005FD04 00000001 v:1 d:0
2: 00000000 00000001 v:0 d:1
00000001 01100001 v:1 d:1
3: ABAB0022 00011111 v:1 d:0
11100001 00000001 v:1 d:1
total number of hits: 234
total number of misses: 31
miss rate: 11.7%
total number of dirty blocks: 4
average memory access cycle: 29.4
Each cache set is indexed (e.g., 0:, 1:), and each line shows 2 words per block (for 8-byte blocks). Valid and dirty bits are indicated at the end of each line.
- Memory is sparse: only modified memory locations should be stored
- Cache and memory must be initialized to zero
- Write-back: only write back to memory when evicting a dirty block
- LRU: track the least recently used block in each set
To validate the simulator, create small trace files with predictable behavior.
Start with simple cases (1-2 lines), and gradually build more complex traces once basic correctness is confirmed.
Example test trace:
00010000 W 1 // Miss
00010004 W 2 // Hit
00010008 W 3 // Miss
0001000C W 4 // Hit
00010000 R // Hit
00010004 R // Hit
00010008 R // Hit
0001000C R // Hit
Use <unistd.h> for getopt() in C:
int getopt(int argc, char *const argv[], const char *optstring);Helpful variables:
optarg: string value of option parameteroptopt: unknown option character
For options like -s 64, -b 8, -a 2, -f file, use optstring "s:b:a:f:".
For a good explanation of write-back vs write-through caching: