-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcache.c
More file actions
296 lines (247 loc) · 9.07 KB
/
cache.c
File metadata and controls
296 lines (247 loc) · 9.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
#include "cache.h"
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdint.h>
#define MEMORY_SIZE 64 * 1024 //64KB
#define CACHE_SIZE 16 * 1024 //16KB
#define BLOCK_SIZE 64 //64B
#define CACHE_WAYS 8
#define CACHE_METADATA 16
#define CACHE_SET CACHE_SIZE / (BLOCK_SIZE * CACHE_WAYS)
#define SIZE_SET_BITS 5
#define SIZE_OFFSET_BITS 6
#define SIZE_TAG_BITS 5
#define MAX_ADDRESS 65535
#define MASK_TAG 0x3E00
#define MASK_VALID 0x8000
#define MASK_OFFSET 0x003F
#define MASK_COUNTER 0x01FF
#define MASK_DIRTY 0x4000
/* ******************************************************************
* STRUCT CACHE ADT DEFINITION
* *****************************************************************/
//Main memory
//Size: 64KB
//Block Size: 16B
unsigned char MAIN_MEMORY[MEMORY_SIZE / BLOCK_SIZE][BLOCK_SIZE];
struct cache {
//Cache memory - 8-WSA
//Size: 16KB
//Block Size: 64B
unsigned char cache_memory[CACHE_WAYS][CACHE_SET][BLOCK_SIZE];
//Metadata
//First bit: Valid
//Second bit: Dirty
//3,4,5,6,7 bits: Tag
//Rest : counter
uint16_t cache_metadata[CACHE_WAYS][CACHE_SIZE / (BLOCK_SIZE * CACHE_WAYS)];
//Miss rate
float access;
float misses;
}cache;
cache_t CACHE;
/* *****************************************************************
* AUXILIAR FUNCTIONS
* *****************************************************************/
// Write in main memory the value in the address
void write_in_main_memory(unsigned int address, unsigned char value)
{
unsigned int set = address / BLOCK_SIZE;
unsigned int offset = address % BLOCK_SIZE;
MAIN_MEMORY[set][offset] = value;
}
//Ads 1 to all way's set counter except new_way
void add_1_to_counter(unsigned int set, unsigned int new_way)
{
uint16_t metadata;
unsigned int valid;
for(size_t way = 0; way < CACHE_WAYS; way++) {
if(way != new_way) {
metadata = CACHE.cache_metadata[way][set];
valid = metadata & MASK_VALID;
if(valid) {
metadata++; //Only adds 1 to those blocks containing something
}
}
}
}
void _write_in_cache(unsigned int way, unsigned int set, unsigned int offset, unsigned char value, unsigned int tag) {
CACHE.cache_memory[way][set][offset] = value;
CACHE.cache_metadata[way][set] |= MASK_VALID; // set byte valid with all ones
CACHE.cache_metadata[way][set] |= (tag << 9); // set tag in metadata
add_1_to_counter(set, way);
}
//Returns 1 if it's valid, 0 if it isn't
int address_is_valid(unsigned int address) {
return (address <= MAX_ADDRESS) ? 1 : 0;
}
/* ******************************************************************
* CACHE FUNCTIONS
* *****************************************************************/
//Initializes:
//Main memory to 0
//Cache lines as invalid
//Miss rate to 0
void init(void){
memset(MAIN_MEMORY, 0, sizeof(MAIN_MEMORY)); //Main memory initialized to 0
memset(CACHE.cache_metadata, 0, sizeof(CACHE.cache_metadata)); //Valid, Dirty, Counter and Tag and counter initialized to 0
}
//Returns the byte's offset of the memory block to which the address maps
unsigned int get_offset (unsigned int address){
unsigned int mask = pow(2,SIZE_OFFSET_BITS) - 1; //loads 1 in 6 bits less significatives
unsigned int offset = address & mask;
return offset;
}
//Returns the number of the cache set to which the address maps
unsigned int find_set(unsigned int address)
{
unsigned int mask = pow(2,SIZE_SET_BITS) - 1; //load ones in five bits less significatives
unsigned int adress_desplazed = address >> SIZE_SET_BITS; //right shift
return (adress_desplazed & mask); //return only five bits less significatives
}
//Returns the tag of the memory block to which the address maps
unsigned int get_tag(unsigned int address)
{
unsigned int mask = pow(2,SIZE_TAG_BITS) - 1;
unsigned int tag = (address >> (SIZE_SET_BITS + SIZE_OFFSET_BITS)) & mask;
return tag;
}
//Returns the way containing the oldest block inside the set 'setnum'
unsigned int select_oldest(unsigned int setnum)
{
unsigned int oldest_block = 0;
unsigned int oldest_way = 0;
int16_t metadata, counter_metadata;
for (int way = 0; way < CACHE_WAYS; way++)
{
metadata = CACHE.cache_metadata[way][setnum]; //we check de metadata of a specific block
counter_metadata = (metadata & MASK_COUNTER);
if (counter_metadata > oldest_block)
{
oldest_block = counter_metadata;
oldest_way = way;
}
}
return oldest_way;
}
// Write in cache the value only if the address is found in some block of cache.
void write_in_cache(unsigned int address, unsigned char value)
{
// values are from the adress
unsigned int set = find_set(address);
unsigned int offset = get_offset(address);
unsigned int tag = get_tag(address);
uint16_t metadata;
unsigned int tag_in_cache;
for (int way = 0; way < CACHE_WAYS; way++)
{
metadata = CACHE.cache_metadata[way][set];
tag_in_cache = (metadata & MASK_TAG) >> 9; //the 9 bits less significatives are droped (counter ones).
if (tag_in_cache == tag) // the address match with the adress in cache metadata. The address i
{
if(!(metadata & MASK_VALID)) {
continue;
}
if (metadata & MASK_DIRTY) // checks if we need to write that block in memory (write back politics)
{
write_tomem(CACHE.cache_memory[way][set][offset], address / BLOCK_SIZE, address % BLOCK_SIZE, value);
CACHE.cache_metadata[way][set] &= ~MASK_DIRTY; // we set the dirty byte in 0
}
_write_in_cache(way, set, offset, value, tag);
return;
}
}
//If the block is not on the cache, is a miss
CACHE.misses++;
//Seeks for an empty block
for (int way = 0; way < CACHE_WAYS; way++) {
metadata = CACHE.cache_metadata[way][set];
if (!(metadata & MASK_VALID)) {
_write_in_cache(way, set, offset, value, tag);
return;
}
}
//If there isn't an empty block, replaces one
unsigned int oldest_one = select_oldest(set);
_write_in_cache(oldest_one, set, offset, value, tag);
}
//Reads the block 'blocknum' from memory and
//stores it on the specified way and set on cache memory
void read_tocache(unsigned int blocknum, unsigned int way, unsigned int set)
{
for (int offset = 0; offset < BLOCK_SIZE; offset++)
{
CACHE.cache_memory[way][set][offset] = MAIN_MEMORY[blocknum][offset];
}
CACHE.cache_metadata[way][set] |= MASK_VALID; //if its load the block in cache, its need to refresh metadata
}
unsigned char read_byte(unsigned int address)
{
if (!address_is_valid(address))
{
return 0;
}
unsigned int set = find_set(address);
unsigned int offset = get_offset(address);
unsigned int tag = get_tag(address);
uint16_t metadata;
unsigned int tag_in_cache;
CACHE.access++;
for (int way = 0; way < CACHE_WAYS; way++)
{
metadata = CACHE.cache_metadata[way][set];
tag_in_cache = (metadata & MASK_TAG) >> 9; // //the 9 bits less significatives are droped (counter ones).
if (tag_in_cache == tag) { // the address matches with the address in cache metadata.
if(!(metadata & MASK_VALID)) {
continue;
}
return CACHE.cache_memory[way][set][offset];
}
}
// If none of the ways containts the tag then the address is not in cache
CACHE.misses++;
//Seeks for an empty block
for (int way = 0; way < CACHE_WAYS; way++) {
metadata = CACHE.cache_metadata[way][set];
if (!(metadata & MASK_VALID)) {
read_tocache(address/BLOCK_SIZE, way, set);
CACHE.cache_metadata[way][set] |= (tag << 9);
return CACHE.cache_memory[way][set][offset];
}
}
//If there isn't an empty block, replaces one
unsigned int oldest_one = select_oldest(set);
read_tocache(address/BLOCK_SIZE, oldest_one, set);
CACHE.cache_metadata[oldest_one][set] |= (tag << 9);
return CACHE.cache_memory[oldest_one][set][offset];
}
//Writes the value on main memory on the address given
//and on cache memory
//If the block is not on the cache, it brings it back from memory and then, writes it
void write_byte(unsigned int address, unsigned char value)
{
if (!address_is_valid(address))
{
return;
}
CACHE.access++;
//writing in main memory.
write_in_main_memory(address, value);
//writin in cache memory.
write_in_cache(address, value);
}
//Updates the blocknum in the 'set' and the in the 'offset' of main memory
void write_tomem(unsigned int blocknum, unsigned int set, unsigned int offset, unsigned char value)
{
MAIN_MEMORY[set][offset] = blocknum;
}
//Returns miss rate
float get_miss_rate(void) {
float miss_rate = CACHE.misses/CACHE.access;
return miss_rate;
}
//Releases ADT cache
void release(void){
//do nothing
}