@@ -41,46 +41,31 @@ module VX_cache_data #(
41
41
input wire read,
42
42
input wire write,
43
43
input wire [`CS_LINE_SEL_BITS - 1 : 0 ] line_idx,
44
- input wire [NUM_WAYS - 1 : 0 ] evict_way,
44
+ input wire [`CS_WAY_SEL_WIDTH - 1 : 0 ] evict_way,
45
45
input wire [NUM_WAYS - 1 : 0 ] tag_matches,
46
46
input wire [`CS_WORDS_PER_LINE - 1 : 0 ][`CS_WORD_WIDTH - 1 : 0 ] fill_data,
47
47
input wire [`CS_WORD_WIDTH - 1 : 0 ] write_word,
48
48
input wire [WORD_SIZE - 1 : 0 ] write_byteen,
49
49
input wire [`UP (`CS_WORD_SEL_BITS )- 1 : 0 ] word_idx,
50
50
// outputs
51
- output wire [`CS_WORD_WIDTH - 1 : 0 ] read_data ,
52
- output wire line_dirty ,
53
- output wire [ `CS_LINE_WIDTH - 1 : 0 ] evict_data ,
51
+ output wire [`CS_WAY_SEL_WIDTH - 1 : 0 ] way_idx ,
52
+ output wire [ `CS_LINE_WIDTH - 1 : 0 ] read_data ,
53
+ output wire evict_dirty ,
54
54
output wire [LINE_SIZE - 1 : 0 ] evict_byteen
55
55
);
56
56
`UNUSED_PARAM (WORD_SIZE )
57
57
`UNUSED_VAR (stall)
58
58
59
- localparam BYTEENW = (WRITE_ENABLE != 0 ) ? LINE_SIZE : 1 ;
60
-
61
- wire [NUM_WAYS - 1 : 0 ][`CS_WORDS_PER_LINE - 1 : 0 ][`CS_WORD_WIDTH - 1 : 0 ] line_rdata;
62
-
63
59
if (WRITEBACK != 0 ) begin : g_writeback
64
60
localparam BYTEEN_DATAW = 1 + ((DIRTY_BYTES != 0 ) ? LINE_SIZE : 0 );
65
- wire [`LOG2UP (NUM_WAYS )- 1 : 0 ] evict_way_idx, evict_way_idx_r;
66
-
67
- VX_onehot_encoder # (
68
- .N (NUM_WAYS )
69
- ) fill_way_enc (
70
- .data_in (evict_way),
71
- .data_out (evict_way_idx),
72
- `UNUSED_PIN (valid_out)
73
- );
74
-
75
- `BUFFER_EX (evict_way_idx_r, evict_way_idx, ~ stall, 1 );
76
61
77
62
wire [NUM_WAYS - 1 : 0 ][BYTEEN_DATAW - 1 : 0 ] byteen_rdata;
78
63
wire [NUM_WAYS - 1 : 0 ][BYTEEN_DATAW - 1 : 0 ] byteen_wdata;
79
64
wire [NUM_WAYS - 1 : 0 ][BYTEEN_DATAW - 1 : 0 ] byteen_wren;
80
65
81
66
for (genvar i = 0 ; i < NUM_WAYS ; ++ i) begin : g_byteen_wdata
82
67
wire evict = fill || flush;
83
- wire evict_way_en = (NUM_WAYS == 1 ) || evict_way[i] ;
68
+ wire evict_way_en = (NUM_WAYS == 1 ) || ( evict_way == i) ;
84
69
wire dirty_data = write; // only asserted on writes
85
70
wire dirty_wren = init || (evict && evict_way_en) || (write && tag_matches[i]);
86
71
if (DIRTY_BYTES != 0 ) begin : g_dirty_bytes
@@ -121,54 +106,47 @@ module VX_cache_data #(
121
106
);
122
107
123
108
if (DIRTY_BYTES != 0 ) begin : g_line_dirty_and_byteen
124
- assign { line_dirty , evict_byteen} = byteen_rdata[evict_way_idx_r ];
109
+ assign { evict_dirty , evict_byteen} = byteen_rdata[way_idx ];
125
110
end else begin : g_line_dirty
126
- assign line_dirty = byteen_rdata[evict_way_idx_r ];
111
+ assign evict_dirty = byteen_rdata[way_idx ];
127
112
assign evict_byteen = '1 ;
128
113
end
129
114
130
- assign evict_data = line_rdata[evict_way_idx_r];
131
-
132
115
end else begin : g_no_writeback
133
116
`UNUSED_VAR (init)
134
117
`UNUSED_VAR (flush)
135
- assign line_dirty = 0 ;
136
- assign evict_data = '0 ;
118
+ assign evict_dirty = 0 ;
137
119
assign evict_byteen = '0 ;
138
120
end
139
121
140
- for (genvar i = 0 ; i < NUM_WAYS ; ++ i) begin : g_data_store
141
- wire [`CS_WORDS_PER_LINE - 1 : 0 ][`CS_WORD_WIDTH - 1 : 0 ] line_wdata;
142
- wire [BYTEENW - 1 : 0 ] line_wren;
122
+ wire [NUM_WAYS - 1 : 0 ][`CS_WORDS_PER_LINE - 1 : 0 ][`CS_WORD_WIDTH - 1 : 0 ] line_rdata;
143
123
144
- wire fill_way_en = (NUM_WAYS == 1 ) || evict_way[i];
124
+ if (WRITE_ENABLE ) begin : g_data_store
125
+ // create a single write-enable block ram to reduce area overhead
126
+ wire [NUM_WAYS - 1 : 0 ][`CS_WORDS_PER_LINE - 1 : 0 ][`CS_WORD_WIDTH - 1 : 0 ] line_wdata;
127
+ wire [NUM_WAYS - 1 : 0 ][LINE_SIZE - 1 : 0 ] line_wren;
128
+ wire line_write;
129
+ wire line_read;
145
130
146
- if (WRITE_ENABLE != 0 ) begin : g_wdata
131
+ for (genvar i = 0 ; i < NUM_WAYS ; ++ i) begin : g_wdata
132
+ wire fill_way_en = (NUM_WAYS == 1 ) || (evict_way == i);
147
133
wire [`CS_WORDS_PER_LINE - 1 : 0 ][WORD_SIZE - 1 : 0 ] write_mask;
148
134
for (genvar j = 0 ; j < `CS_WORDS_PER_LINE ; ++ j) begin : g_write_mask
149
135
wire word_en = (`CS_WORDS_PER_LINE == 1 ) || (word_idx == j);
150
136
assign write_mask[j] = write_byteen & { WORD_SIZE { word_en}} ;
151
137
end
152
- assign line_wdata = (fill && fill_way_en) ? fill_data : { `CS_WORDS_PER_LINE { write_word}} ;
153
- assign line_wren = { LINE_SIZE { fill && fill_way_en}}
154
- | ({ LINE_SIZE { write && tag_matches[i]}} & write_mask);
155
-
156
- end else begin : g_ro_wdata
157
- `UNUSED_VAR (write)
158
- `UNUSED_VAR (write_byteen)
159
- `UNUSED_VAR (write_word)
160
- `UNUSED_VAR (word_idx)
161
- assign line_wdata = fill_data;
162
- assign line_wren = fill_way_en;
138
+ assign line_wdata[i] = fill ? fill_data : { `CS_WORDS_PER_LINE { write_word}} ;
139
+ assign line_wren[i] = { LINE_SIZE { fill && fill_way_en}}
140
+ | ({ LINE_SIZE { write && tag_matches[i]}} & write_mask);
163
141
end
164
142
165
- wire line_write = fill || (write && WRITE_ENABLE );
166
- wire line_read = read || ((fill || flush) && WRITEBACK );
143
+ assign line_write = fill || (write && WRITE_ENABLE );
144
+ assign line_read = read || ((fill || flush) && WRITEBACK );
167
145
168
146
VX_sp_ram # (
169
- .DATAW (`CS_LINE_WIDTH ),
147
+ .DATAW (NUM_WAYS * `CS_LINE_WIDTH ),
170
148
.SIZE (`CS_LINES_PER_BANK ),
171
- .WRENW (BYTEENW ),
149
+ .WRENW (NUM_WAYS * LINE_SIZE ),
172
150
.OUT_REG (1 )
173
151
) data_store (
174
152
.clk (clk),
@@ -178,35 +156,46 @@ module VX_cache_data #(
178
156
.wren (line_wren),
179
157
.addr (line_idx),
180
158
.wdata (line_wdata),
181
- .rdata (line_rdata[i] )
159
+ .rdata (line_rdata)
182
160
);
161
+ end else begin : g_data_store
162
+ `UNUSED_VAR (write)
163
+ `UNUSED_VAR (write_byteen)
164
+ `UNUSED_VAR (write_word)
165
+ `UNUSED_VAR (word_idx)
166
+
167
+ // we don't merge the ways into a single block ram due to WREN overhead
168
+ for (genvar i = 0 ; i < NUM_WAYS ; ++ i) begin : g_ways
169
+ wire fill_way_en = (NUM_WAYS == 1 ) || (evict_way == i);
170
+ VX_sp_ram # (
171
+ .DATAW (`CS_LINE_WIDTH ),
172
+ .SIZE (`CS_LINES_PER_BANK ),
173
+ .OUT_REG (1 )
174
+ ) data_store (
175
+ .clk (clk),
176
+ .reset (reset),
177
+ .read (read),
178
+ .write (fill && fill_way_en),
179
+ .wren (1'b1 ),
180
+ .addr (line_idx),
181
+ .wdata (fill_data),
182
+ .rdata (line_rdata[i])
183
+ );
184
+ end
183
185
end
184
186
185
- wire [`LOG2UP (NUM_WAYS )- 1 : 0 ] hit_way_idx;
187
+ wire [`CS_WAY_SEL_WIDTH - 1 : 0 ] hit_idx;
188
+
186
189
VX_onehot_encoder # (
187
190
.N (NUM_WAYS )
188
- ) hit_idx_enc (
191
+ ) way_idx_enc (
189
192
.data_in (tag_matches),
190
- .data_out (hit_way_idx ),
193
+ .data_out (hit_idx ),
191
194
`UNUSED_PIN (valid_out)
192
195
);
193
196
194
- if (`CS_WORDS_PER_LINE > 1 ) begin : g_read_data
195
- // order the data layout to perform ways multiplexing last.
196
- // this allows converting way index to binary in parallel with BRAM read and word indexing.
197
- wire [`CS_WORDS_PER_LINE - 1 : 0 ][NUM_WAYS - 1 : 0 ][`CS_WORD_WIDTH - 1 : 0 ] transposed_rdata;
198
- VX_transpose # (
199
- .DATAW (`CS_WORD_WIDTH ),
200
- .N (NUM_WAYS ),
201
- .M (`CS_WORDS_PER_LINE )
202
- ) transpose (
203
- .data_in (line_rdata),
204
- .data_out (transposed_rdata)
205
- );
206
- assign read_data = transposed_rdata[word_idx][hit_way_idx];
207
- end else begin : g_read_data_1w
208
- `UNUSED_VAR (word_idx)
209
- assign read_data = line_rdata[hit_way_idx];
210
- end
197
+ `BUFFER_EX (way_idx, (read ? hit_idx : evict_way), ~ stall, 1 );
198
+
199
+ assign read_data = line_rdata[way_idx];
211
200
212
201
endmodule
0 commit comments