-
Notifications
You must be signed in to change notification settings - Fork 0
/
cache.v
242 lines (212 loc) · 8.86 KB
/
cache.v
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
module cache(
/* General inputs */
input clk, input rst,
/* Read interface */
input RE, input rByte, input [proc.ARCH_BITS-1:0] rAddr, output [proc.ARCH_BITS-1:0] rData, output rValid,
/* Write interface */
input WE, input wByte, input [proc.ARCH_BITS-1:0] wAddr, input [proc.ARCH_BITS-1:0] wData, output wAck,
/* Memory interface */
output [proc.ARCH_BITS-1:0] readMemAddr, output readMemReq, input [proc.MEMORY_LINE_BITS-1:0] readMemData, input readMemLineValid,
output [proc.ARCH_BITS-1:0] writeMemAddr, output [proc.MEMORY_LINE_BITS-1:0] writeMemLine, output writeMemReq, input writeMemAck
);
parameter CACHE_LINES = 4,
CACHE_LINE_SIZE = 128;
// proc.ARCH_BITS ->
// OFFSET = Log2(CACHE_LINE_SIZE/8), 8 means 8bits per byte
// OFFSET_W_BITS = Log2(CACHE_LINE_SIZE/proc.ARCH_BITS)
// OFFSET_B_BITS = OFFSET - OFFSET_W_BITS
// LINE_BITS = Log2(CACHE_LINES)
// TAG = proc.ARCH_BITS - OFFSET - LINE_BITS
parameter OFFSET_B_BITS = 2,
OFFSET_W_BITS = 2,
LINE_BITS = 2,
TAG_BITS = 26;
integer i;
// Cache lines, tags, valid bits and dirty bits
reg [CACHE_LINE_SIZE-1:0] lines[CACHE_LINES-1:0];
reg [TAG_BITS-1:0] tags[CACHE_LINES-1:0];
reg validBits[CACHE_LINES-1:0];
reg dirtyBits[CACHE_LINES-1:0];
wire eviction;
// Read handling variables
// Info extracted from rAddr
wire [TAG_BITS-1:0] rTag;
wire [LINE_BITS-1:0] rLine;
wire [OFFSET_W_BITS-1:0] rOffsetW;
wire [OFFSET_B_BITS-1:0] rOffsetB;
// Info currently in cache
wire [CACHE_LINE_SIZE-1:0] rCurrentLine;
wire [TAG_BITS-1:0] rCurrentTag;
wire [proc.ARCH_BITS-1:0] rCurrentWord, rCurrentByteExtended;
wire readMiss;
// Write handling variables
reg _WE, _wByte;
reg [proc.ARCH_BITS-1:0] _wAddr;
reg [proc.ARCH_BITS-1:0] _wData;
// Info extracted from _wAddr
wire [TAG_BITS-1:0] wTag;
wire [LINE_BITS-1:0] wLine;
wire [OFFSET_W_BITS-1:0] wOffsetW;
wire [OFFSET_B_BITS-1:0] wOffsetB;
// Info currently in cache
wire [CACHE_LINE_SIZE-1:0] wCurrentLine;
wire [TAG_BITS-1:0] wCurrentTag;
wire [proc.ARCH_BITS-1:0] wCurrentWord;
wire writeMiss;
// MemInterface
wire [LINE_BITS-1:0] readMemLine;
wire [TAG_BITS-1:0] readMemTag;
always @(posedge clk)
begin
// Initialization
if(rst)
begin
_WE <= 1'b0;
for( i = 0; i < CACHE_LINES; i=i+1 )
begin
validBits[i] = 0;
dirtyBits[i] = 0;
end
end
else
begin
// Handle incoming data from memory
if (readMemReq && readMemLineValid && !eviction)
begin
lines[readMemLine] <= readMemData;
tags[readMemLine] <= readMemTag;
validBits[readMemLine] <= 1'b1;
dirtyBits[readMemLine] <= 1'b0;
end
else if(eviction && writeMemAck)
begin
validBits[readMemLine] <= 0;
dirtyBits[readMemLine] <= 0;
end
// Handle incoming write
_WE <= WE;
_wByte <= wByte;
_wAddr <= wAddr;
_wData <= wData;
end
end
always @(negedge clk)
begin
//Handle writes
if(_WE && !writeMiss)
begin: writes
integer offset, offsetB;
offset = (wOffsetW+1)*proc.ARCH_BITS-1;
offsetB = _wByte ? (proc.ARCH_BITS-1)-((wOffsetB+1)*proc.BYTE_BITS-1) : 0;
if(_wByte)
lines[wLine][(offset-offsetB)-:proc.BYTE_BITS] = _wData[proc.BYTE_BITS-1:0];
else
lines[wLine][offset-:proc.ARCH_BITS] = _wData[proc.ARCH_BITS-1:0];
dirtyBits[wLine] = 1;
end
end
assign rTag = rAddr[proc.ARCH_BITS-1:proc.ARCH_BITS-TAG_BITS];
assign rLine = rAddr[proc.ARCH_BITS-TAG_BITS-1:proc.ARCH_BITS-TAG_BITS-LINE_BITS];
assign rOffsetW = rAddr[proc.ARCH_BITS-TAG_BITS-LINE_BITS-1:proc.ARCH_BITS-TAG_BITS-LINE_BITS-OFFSET_W_BITS];
assign rOffsetB = rAddr[proc.ARCH_BITS-TAG_BITS-LINE_BITS-OFFSET_W_BITS-1:0];
assign rCurrentTag = tags[rLine];
assign rCurrentLine = lines[rLine];
assign rCurrentWord = rCurrentLine[(rOffsetW+1)*proc.ARCH_BITS-1-:proc.ARCH_BITS];
assign rCurrentByteExtended = $signed( rCurrentWord[(rOffsetB+1)*proc.BYTE_BITS-1-:proc.BYTE_BITS] );
assign readMiss = RE && ((rCurrentTag != rTag) || (!validBits[rLine]));
assign wTag = _wAddr[proc.ARCH_BITS-1:proc.ARCH_BITS-TAG_BITS];
assign wLine = _wAddr[proc.ARCH_BITS-TAG_BITS-1:proc.ARCH_BITS-TAG_BITS-LINE_BITS];
assign wOffsetW = _wAddr[proc.ARCH_BITS-TAG_BITS-LINE_BITS-1:proc.ARCH_BITS-TAG_BITS-LINE_BITS-OFFSET_W_BITS];
assign wOffsetB = _wAddr[proc.ARCH_BITS-TAG_BITS-LINE_BITS-OFFSET_W_BITS-1:0];
assign wCurrentTag = tags[wLine];
assign wCurrentLine = lines[wLine];
assign wCurrentWord = wCurrentLine[(wOffsetW+1)*proc.ARCH_BITS-1-:proc.ARCH_BITS];
assign writeMiss = _WE && ((wCurrentTag != wTag) || (!validBits[wLine]));
//Handle misses
// We assume that a read and a write miss never will happen at the same time
assign readMemAddr = (_WE && writeMiss) ? _wAddr : rAddr;
assign readMemReq = (RE && readMiss) || (_WE && writeMiss);
assign readMemLine = readMemAddr[proc.ARCH_BITS-TAG_BITS-1:proc.ARCH_BITS-TAG_BITS-LINE_BITS];
assign readMemTag = readMemAddr[proc.ARCH_BITS-1:proc.ARCH_BITS-TAG_BITS];
// There is no need to check tag because it is checked either in rValid or wAck, included
// in readMemReq.
assign eviction = readMemReq && validBits[readMemLine] && dirtyBits[readMemLine];
assign rData = rByte ? rCurrentByteExtended : rCurrentWord;
// if miss, go to memory and make it valid after receiving data
assign rValid = RE && !readMiss;
assign wAck = _WE && !writeMiss;
// Assuming aligned writes
assign writeMemAddr = (tags[readMemLine] << proc.ARCH_BITS-TAG_BITS) +
(readMemLine << (OFFSET_W_BITS+OFFSET_B_BITS)) +
0;
assign writeMemLine = lines[readMemLine];
assign writeMemReq = eviction;
endmodule
module cacheIns(
/* General inputs */
input clk, input rst,
/* Read interface */
input RE, input [proc.ARCH_BITS-1:0] rAddr, output [proc.ARCH_BITS-1:0] rData, output rValid,
/* Memory interface */
output [proc.ARCH_BITS-1:0] readMemAddr, output readMemReq, input [proc.MEMORY_LINE_BITS-1:0] readMemData, input readMemLineValid
);
wire [proc.ARCH_BITS-1:0] nullAddr;
wire [proc.MEMORY_LINE_BITS-1:0] nullLine;
wire nullReq;
wire writeAck;
cache cacheInsInterface(
clk, rst,
RE, 1'b0 /*rByte*/, rAddr, rData, rValid,
1'b0 /*WE*/, 1'b0 /*wByte*/, 32'hffffffff, 32'hffffffff, writeAck,
readMemAddr, readMemReq, readMemData, readMemLineValid, nullAddr, nullLine, nullReq, 1'b0 /*WriteMemAck*/
);
endmodule
module cacheData(
/* General inputs */
input clk, input rst,
/* Read interface */
input RE, input rByte, input [proc.ARCH_BITS-1:0] rAddr, output [proc.ARCH_BITS-1:0] rData, output rValid,
/* Write interface */
input WE, input wByte, input [proc.ARCH_BITS-1:0] wAddr, input [proc.ARCH_BITS-1:0] wData, output wAck,
/* Memory interface */
output [proc.ARCH_BITS-1:0] readMemAddr, output readMemReq, input [proc.MEMORY_LINE_BITS-1:0] readMemData, input readMemLineValid,
output [proc.ARCH_BITS-1:0] writeMemAddr, output [proc.MEMORY_LINE_BITS-1:0] writeMemLine, output writeMemReq, input writeMemAck
);
parameter STB_DATA_BITS = proc.ARCH_BITS + 1 /* Type of write */;
wire [proc.ARCH_BITS-1:0] _rDataCache, _rDataSTB_idem, _rDataSTB_ww_rb;
wire [STB_DATA_BITS-1:0] _wData;
wire [STB_DATA_BITS-1:0] _rDataSTB;
wire _rHitSTB, _rMatchSTB_idem, _rMatchSTB_ww_rb, _rValidCache;
wire _wReqSTB;
wire [STB_DATA_BITS-1:0] _wDataSTB;
wire [proc.ARCH_BITS-1:0] _wAddrSTB, _rAddrSTB;
wire _wAckSTB;
wire _wByteCache;
wire [proc.ARCH_BITS-1:0] _wDataCache;
/* Store buffer for input writes */
stb storeBufferCache(clk, rst, 1'b0 /*clear*/, WE, wAddr, _wData, wAck, RE, rAddr, _rDataSTB, _rAddrSTB, _rHitSTB,
_wReqSTB, _wDataSTB, _wAddrSTB, _wAckSTB);
defparam storeBufferCache.DATA_BITS = STB_DATA_BITS;
/* DataCache */
cache cacheDataInterface(
clk, rst,
RE, rByte, rAddr, _rDataCache, _rValidCache,
_wReqSTB, _wByteCache, _wAddrSTB, _wDataCache, _wAckSTB,
readMemAddr, readMemReq, readMemData, readMemLineValid, writeMemAddr, writeMemLine, writeMemReq, writeMemAck
);
/* Writes to STB */
assign _wData = { wData, wByte };
/* Writes from STB to Cache */
assign _wByteCache = _wDataSTB[0:0];
assign _wDataCache = _wDataSTB[STB_DATA_BITS-1:1];
/* Handle reads that hit in the STB */
// Write in STB matches the read type
assign _rMatchSTB_idem = ( _rHitSTB && (_rDataSTB[0:0] == rByte) && (rAddr == _rAddrSTB) );
assign _rDataSTB_idem = _rDataSTB[0:0] ? $signed( _rDataSTB[proc.BYTE_BITS:1] ) : _rDataSTB[STB_DATA_BITS-1:1];
// Write in STB is WORD and read is BYTE
assign _rMatchSTB_ww_rb = ( _rHitSTB && rByte && !_rDataSTB[0:0] );
assign _rDataSTB_ww_rb = $signed( _rDataSTB[(rAddr[1:0]+1)*proc.BYTE_BITS-:proc.BYTE_BITS] );
assign rData = _rMatchSTB_idem ? _rDataSTB_idem : ( _rMatchSTB_ww_rb ? _rDataSTB_ww_rb : _rDataCache );
// When read is WORD and STB has BYTE writes we need to wait
assign rValid = _rMatchSTB_idem || _rMatchSTB_ww_rb || ( _rValidCache && !_rHitSTB );
endmodule