1 |
27 |
ultra_embe |
//-----------------------------------------------------------------
|
2 |
|
|
// AltOR32
|
3 |
|
|
// Alternative Lightweight OpenRisc
|
4 |
|
|
// V2.0
|
5 |
|
|
// Ultra-Embedded.com
|
6 |
|
|
// Copyright 2011 - 2013
|
7 |
|
|
//
|
8 |
|
|
// Email: admin@ultra-embedded.com
|
9 |
|
|
//
|
10 |
|
|
// License: LGPL
|
11 |
|
|
//-----------------------------------------------------------------
|
12 |
|
|
//
|
13 |
|
|
// Copyright (C) 2011 - 2013 Ultra-Embedded.com
|
14 |
|
|
//
|
15 |
|
|
// This source file may be used and distributed without
|
16 |
|
|
// restriction provided that this copyright statement is not
|
17 |
|
|
// removed from the file and that any derivative work contains
|
18 |
|
|
// the original copyright notice and the associated disclaimer.
|
19 |
|
|
//
|
20 |
|
|
// This source file is free software; you can redistribute it
|
21 |
|
|
// and/or modify it under the terms of the GNU Lesser General
|
22 |
|
|
// Public License as published by the Free Software Foundation;
|
23 |
|
|
// either version 2.1 of the License, or (at your option) any
|
24 |
|
|
// later version.
|
25 |
|
|
//
|
26 |
|
|
// This source is distributed in the hope that it will be
|
27 |
|
|
// useful, but WITHOUT ANY WARRANTY; without even the implied
|
28 |
|
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
29 |
|
|
// PURPOSE. See the GNU Lesser General Public License for more
|
30 |
|
|
// details.
|
31 |
|
|
//
|
32 |
|
|
// You should have received a copy of the GNU Lesser General
|
33 |
|
|
// Public License along with this source; if not, write to the
|
34 |
|
|
// Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
35 |
|
|
// Boston, MA 02111-1307 USA
|
36 |
|
|
//-----------------------------------------------------------------
|
37 |
|
|
|
38 |
|
|
//-----------------------------------------------------------------
|
39 |
|
|
// Includes
|
40 |
|
|
//-----------------------------------------------------------------
|
41 |
|
|
`include "altor32_defs.v"
|
42 |
|
|
|
43 |
|
|
//-----------------------------------------------------------------
|
44 |
|
|
// Module - Instruction Cache
|
45 |
|
|
//-----------------------------------------------------------------
|
46 |
|
|
module altor32_icache
|
47 |
|
|
(
|
48 |
|
|
input clk_i /*verilator public*/,
|
49 |
|
|
input rst_i /*verilator public*/,
|
50 |
|
|
|
51 |
|
|
// Processor interface
|
52 |
|
|
input rd_i /*verilator public*/,
|
53 |
|
|
input [31:0] pc_i /*verilator public*/,
|
54 |
|
|
output [31:0] instruction_o /*verilator public*/,
|
55 |
|
|
output valid_o /*verilator public*/,
|
56 |
|
|
input invalidate_i /*verilator public*/,
|
57 |
|
|
|
58 |
|
|
// Status
|
59 |
|
|
output miss_o /*verilator public*/,
|
60 |
|
|
output busy_o /*verilator public*/,
|
61 |
|
|
|
62 |
|
|
// Memory interface (slave)
|
63 |
30 |
ultra_embe |
output reg [31:0] mem_addr_o /*verilator public*/,
|
64 |
27 |
ultra_embe |
input [31:0] mem_data_i /*verilator public*/,
|
65 |
30 |
ultra_embe |
output reg mem_burst_o /*verilator public*/,
|
66 |
|
|
output reg mem_rd_o /*verilator public*/,
|
67 |
27 |
ultra_embe |
input mem_accept_i/*verilator public*/,
|
68 |
|
|
input mem_ack_i/*verilator public*/
|
69 |
|
|
);
|
70 |
|
|
|
71 |
|
|
//-----------------------------------------------------------------
|
72 |
|
|
// Params
|
73 |
|
|
//-----------------------------------------------------------------
|
74 |
|
|
parameter BOOT_VECTOR = 32'h00000000;
|
75 |
|
|
|
76 |
|
|
parameter CACHE_LINE_SIZE_WIDTH = 5; /* 5-bits -> 32 entries */
|
77 |
|
|
parameter CACHE_LINE_SIZE_BYTES = 2 ** CACHE_LINE_SIZE_WIDTH; /* 32 bytes / 4 words per line */
|
78 |
|
|
parameter CACHE_LINE_ADDR_WIDTH = 8; /* 256 lines */
|
79 |
|
|
parameter CACHE_LINE_WORDS_IDX_MAX = CACHE_LINE_SIZE_WIDTH - 2; /* 3-bit = 111 */
|
80 |
|
|
parameter CACHE_TAG_ENTRIES = 2 ** CACHE_LINE_ADDR_WIDTH ; /* 256 tag entries */
|
81 |
|
|
parameter CACHE_DSIZE = CACHE_LINE_ADDR_WIDTH * CACHE_LINE_SIZE_BYTES; /* 8KB data */
|
82 |
|
|
parameter CACHE_DWIDTH = CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 2; /* 10-bits */
|
83 |
|
|
|
84 |
|
|
parameter CACHE_TAG_WIDTH = 16; /* 16-bit tag entry size */
|
85 |
|
|
parameter CACHE_TAG_LINE_ADDR_WIDTH = CACHE_TAG_WIDTH - 1; /* 15 bits of data (tag entry size minus valid bit) */
|
86 |
|
|
|
87 |
|
|
parameter CACHE_TAG_ADDR_LOW = CACHE_LINE_SIZE_WIDTH + CACHE_LINE_ADDR_WIDTH;
|
88 |
|
|
parameter CACHE_TAG_ADDR_HIGH = CACHE_TAG_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH + CACHE_LINE_ADDR_WIDTH - 1;
|
89 |
|
|
|
90 |
|
|
// Tag fields
|
91 |
|
|
parameter CACHE_TAG_VALID_BIT = 15;
|
92 |
|
|
|
93 |
|
|
// 31 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
|
94 |
|
|
// |--------------| | | | | | | | | | | | | | | | |
|
95 |
|
|
// +--------------------+ +-------------------+ +-----------+
|
96 |
|
|
// Tag entry Line address Address
|
97 |
|
|
// (15-bits) (8-bits) within line
|
98 |
|
|
// (5-bits)
|
99 |
|
|
|
100 |
|
|
//-----------------------------------------------------------------
|
101 |
|
|
// Registers / Wires
|
102 |
|
|
//-----------------------------------------------------------------
|
103 |
|
|
wire [CACHE_TAG_WIDTH-1:0] tag_data_out;
|
104 |
|
|
reg [CACHE_TAG_WIDTH-1:0] tag_data_in;
|
105 |
|
|
reg tag_wr;
|
106 |
|
|
|
107 |
|
|
wire [CACHE_LINE_ADDR_WIDTH-1:0] tag_entry;
|
108 |
|
|
wire [CACHE_DWIDTH-1:0] cache_address_rd;
|
109 |
|
|
|
110 |
|
|
reg [CACHE_DWIDTH-1:0] cache_address_wr;
|
111 |
|
|
reg [31:0] cache_data_w;
|
112 |
|
|
reg cache_wr;
|
113 |
|
|
|
114 |
|
|
reg [CACHE_LINE_SIZE_WIDTH-3:0] fetch_word;
|
115 |
|
|
|
116 |
|
|
reg [31:0] last_pc;
|
117 |
|
|
reg [31:0] miss_pc;
|
118 |
|
|
|
119 |
|
|
reg initial_fetch;
|
120 |
|
|
reg flush_req;
|
121 |
|
|
|
122 |
|
|
reg [CACHE_LINE_ADDR_WIDTH-1:0] flush_addr;
|
123 |
|
|
reg flush_wr;
|
124 |
|
|
|
125 |
|
|
reg read_while_busy;
|
126 |
|
|
|
127 |
|
|
// Current state
|
128 |
|
|
parameter STATE_CHECK = 0;
|
129 |
|
|
parameter STATE_FETCH = 1;
|
130 |
|
|
parameter STATE_WAIT = 2;
|
131 |
|
|
parameter STATE_WAIT2 = 3;
|
132 |
|
|
parameter STATE_FLUSH = 4;
|
133 |
|
|
reg [3:0] state;
|
134 |
|
|
|
135 |
|
|
assign tag_entry = (state != STATE_CHECK) ? miss_pc[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH] : pc_i[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH];
|
136 |
|
|
assign cache_address_rd = pc_i[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:2];
|
137 |
|
|
|
138 |
|
|
assign miss_o = (!tag_data_out[CACHE_TAG_VALID_BIT] || (last_pc[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW] != tag_data_out[14:0])) ? 1'b1: 1'b0;
|
139 |
|
|
|
140 |
30 |
ultra_embe |
assign valid_o = !miss_o && !busy_o;
|
141 |
27 |
ultra_embe |
|
142 |
|
|
//-----------------------------------------------------------------
|
143 |
|
|
// Control logic
|
144 |
|
|
//-----------------------------------------------------------------
|
145 |
|
|
reg [CACHE_LINE_SIZE_WIDTH-3:0] v_line_word;
|
146 |
|
|
|
147 |
|
|
always @ (posedge rst_i or posedge clk_i )
|
148 |
|
|
begin
|
149 |
|
|
if (rst_i == 1'b1)
|
150 |
|
|
begin
|
151 |
|
|
fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}};
|
152 |
|
|
mem_addr_o <= 32'h00000000;
|
153 |
|
|
mem_rd_o <= 1'b0;
|
154 |
|
|
mem_burst_o <= 1'b0;
|
155 |
|
|
tag_wr <= 1'b0;
|
156 |
|
|
cache_address_wr<= {CACHE_DWIDTH{1'b0}};
|
157 |
|
|
cache_data_w <= 32'h00000000;
|
158 |
|
|
cache_wr <= 1'b0;
|
159 |
|
|
miss_pc <= BOOT_VECTOR + `VECTOR_RESET;
|
160 |
|
|
last_pc <= 32'h00000000;
|
161 |
|
|
state <= STATE_CHECK;
|
162 |
|
|
initial_fetch <= 1'b1;
|
163 |
|
|
read_while_busy <= 1'b0;
|
164 |
|
|
|
165 |
|
|
flush_addr <= {CACHE_LINE_ADDR_WIDTH{1'b0}};
|
166 |
|
|
flush_wr <= 1'b0;
|
167 |
|
|
flush_req <= 1'b0;
|
168 |
|
|
end
|
169 |
|
|
else
|
170 |
|
|
begin
|
171 |
|
|
|
172 |
|
|
if (mem_accept_i)
|
173 |
|
|
mem_rd_o <= 1'b0;
|
174 |
|
|
tag_wr <= 1'b0;
|
175 |
|
|
cache_wr <= 1'b0;
|
176 |
|
|
initial_fetch <= 1'b0;
|
177 |
|
|
flush_wr <= 1'b0;
|
178 |
|
|
last_pc <= pc_i;
|
179 |
|
|
|
180 |
|
|
// Latch invalidate request even if can't be actioned now...
|
181 |
|
|
if (invalidate_i)
|
182 |
|
|
flush_req <= 1'b1;
|
183 |
|
|
|
184 |
|
|
// New request whilst cache busy?
|
185 |
|
|
if (rd_i)
|
186 |
|
|
read_while_busy <= 1'b1;
|
187 |
|
|
|
188 |
|
|
case (state)
|
189 |
|
|
|
190 |
|
|
//-----------------------------------------
|
191 |
|
|
// CHECK - check cache for hit or miss
|
192 |
|
|
//-----------------------------------------
|
193 |
|
|
STATE_CHECK :
|
194 |
|
|
begin
|
195 |
|
|
// Cache flush request pending?
|
196 |
|
|
if (flush_req || invalidate_i)
|
197 |
|
|
begin
|
198 |
|
|
flush_req <= 1'b0;
|
199 |
|
|
flush_addr <= {CACHE_LINE_ADDR_WIDTH{1'b1}};
|
200 |
|
|
flush_wr <= 1'b1;
|
201 |
|
|
state <= STATE_FLUSH;
|
202 |
|
|
|
203 |
|
|
`ifdef CONF_CORE_DEBUG
|
204 |
|
|
$display("Fetch: Cache flush request");
|
205 |
|
|
`endif
|
206 |
|
|
end
|
207 |
|
|
// Cache miss (& new read request not pending)
|
208 |
|
|
else if ((miss_o && !initial_fetch) && !rd_i && !read_while_busy)
|
209 |
|
|
begin
|
210 |
|
|
read_while_busy <= 1'b0;
|
211 |
|
|
|
212 |
|
|
fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}};
|
213 |
|
|
|
214 |
|
|
`ifdef CONF_CORE_DEBUG
|
215 |
|
|
$display("Fetch: Cache miss at 0x%x (last=%x, current=%x)", miss_pc, last_pc, pc_i);
|
216 |
|
|
`endif
|
217 |
|
|
|
218 |
|
|
// Start fetch from memory
|
219 |
|
|
mem_addr_o <= {miss_pc[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH{1'b0}}};
|
220 |
|
|
mem_rd_o <= 1'b1;
|
221 |
|
|
mem_burst_o <= 1'b1;
|
222 |
|
|
state <= STATE_FETCH;
|
223 |
|
|
|
224 |
|
|
// Update tag memory with this line's details
|
225 |
|
|
tag_data_in <= {1'b1, miss_pc[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]};
|
226 |
|
|
tag_wr <= 1'b1;
|
227 |
|
|
end
|
228 |
|
|
// Cache hit (or new read request)
|
229 |
|
|
else
|
230 |
|
|
begin
|
231 |
|
|
`ifdef CONF_CORE_DEBUG
|
232 |
|
|
$display("Fetch: Cache hit at PC=%x (current=%x)", last_pc, pc_i);
|
233 |
|
|
if (read_while_busy)
|
234 |
|
|
$display("Fetch: Read request whilst busy PC=%x (current=%x)", last_pc, pc_i);
|
235 |
|
|
`endif
|
236 |
|
|
|
237 |
|
|
// Store fetch PC
|
238 |
|
|
miss_pc <= pc_i;
|
239 |
|
|
state <= STATE_CHECK;
|
240 |
|
|
read_while_busy <= 1'b0;
|
241 |
|
|
end
|
242 |
|
|
end
|
243 |
|
|
//-----------------------------------------
|
244 |
|
|
// FETCH - Fetch row from memory
|
245 |
|
|
//-----------------------------------------
|
246 |
|
|
STATE_FETCH :
|
247 |
|
|
begin
|
248 |
|
|
// Data ready from memory?
|
249 |
|
|
if (mem_ack_i)
|
250 |
|
|
begin
|
251 |
|
|
// Write data into cache
|
252 |
|
|
cache_address_wr<= {miss_pc[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH], fetch_word};
|
253 |
|
|
cache_data_w <= mem_data_i;
|
254 |
|
|
cache_wr <= 1'b1;
|
255 |
|
|
|
256 |
|
|
// Line fetch complete?
|
257 |
|
|
if (fetch_word == {CACHE_LINE_WORDS_IDX_MAX{1'b1}})
|
258 |
|
|
begin
|
259 |
|
|
state <= STATE_WAIT;
|
260 |
|
|
end
|
261 |
|
|
// Fetch next word for line
|
262 |
|
|
else
|
263 |
|
|
begin
|
264 |
|
|
v_line_word = fetch_word + 1'b1;
|
265 |
|
|
fetch_word <= v_line_word;
|
266 |
|
|
|
267 |
|
|
mem_addr_o <= {mem_addr_o[31:CACHE_LINE_SIZE_WIDTH], v_line_word, 2'b00};
|
268 |
|
|
mem_rd_o <= 1'b1;
|
269 |
|
|
|
270 |
|
|
if (fetch_word == ({CACHE_LINE_WORDS_IDX_MAX{1'b1}}-1))
|
271 |
|
|
begin
|
272 |
|
|
mem_burst_o <= 1'b0;
|
273 |
|
|
end
|
274 |
|
|
end
|
275 |
|
|
end
|
276 |
|
|
end
|
277 |
|
|
//-----------------------------------------
|
278 |
|
|
// FLUSH - Invalidate tag memory
|
279 |
|
|
//-----------------------------------------
|
280 |
|
|
STATE_FLUSH :
|
281 |
|
|
begin
|
282 |
|
|
if (flush_addr == {CACHE_LINE_ADDR_WIDTH{1'b0}})
|
283 |
|
|
begin
|
284 |
|
|
// Fetch current PC line again
|
285 |
|
|
mem_addr_o <= {pc_i[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH{1'b0}}};
|
286 |
|
|
mem_rd_o <= 1'b1;
|
287 |
|
|
mem_burst_o <= 1'b1;
|
288 |
|
|
state <= STATE_FETCH;
|
289 |
|
|
|
290 |
|
|
// Update tag memory with this line's details
|
291 |
|
|
tag_data_in <= {1'b1, pc_i[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]};
|
292 |
|
|
tag_wr <= 1'b1;
|
293 |
|
|
|
294 |
|
|
// Start of line
|
295 |
|
|
fetch_word <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}};
|
296 |
|
|
|
297 |
|
|
// Clear pending reads whilst busy
|
298 |
|
|
read_while_busy <= 1'b0;
|
299 |
|
|
end
|
300 |
|
|
else
|
301 |
|
|
begin
|
302 |
|
|
flush_addr <= flush_addr - 1;
|
303 |
|
|
flush_wr <= 1'b1;
|
304 |
|
|
state <= STATE_FLUSH;
|
305 |
|
|
end
|
306 |
|
|
end
|
307 |
|
|
//-----------------------------------------
|
308 |
|
|
// WAIT - Wait cycle
|
309 |
|
|
//-----------------------------------------
|
310 |
|
|
STATE_WAIT :
|
311 |
|
|
begin
|
312 |
|
|
// Allow extra wait state to handle write & read collision
|
313 |
|
|
state <= STATE_WAIT2;
|
314 |
|
|
end
|
315 |
|
|
//-----------------------------------------
|
316 |
|
|
// WAIT2 - Wait cycle
|
317 |
|
|
//-----------------------------------------
|
318 |
|
|
STATE_WAIT2 :
|
319 |
|
|
begin
|
320 |
|
|
`ifdef CONF_CORE_DEBUG
|
321 |
|
|
$display("Fetch: Filled line containing PC=%x", miss_pc);
|
322 |
|
|
`endif
|
323 |
|
|
state <= STATE_CHECK;
|
324 |
|
|
end
|
325 |
|
|
|
326 |
|
|
|
327 |
|
|
default:
|
328 |
|
|
;
|
329 |
|
|
endcase
|
330 |
|
|
end
|
331 |
|
|
end
|
332 |
|
|
|
333 |
|
|
// Stall the CPU if cache state machine is not idle!
|
334 |
|
|
assign busy_o = (state == STATE_CHECK & ~read_while_busy) ? 1'b0 : 1'b1;
|
335 |
|
|
|
336 |
|
|
//-----------------------------------------------------------------
|
337 |
|
|
// Instantiation
|
338 |
|
|
//-----------------------------------------------------------------
|
339 |
|
|
|
340 |
|
|
// Tag memory
|
341 |
|
|
altor32_ram_dp
|
342 |
|
|
#(
|
343 |
|
|
.WIDTH(CACHE_TAG_WIDTH),
|
344 |
|
|
.SIZE(CACHE_LINE_ADDR_WIDTH)
|
345 |
|
|
)
|
346 |
|
|
u1_tag_mem
|
347 |
|
|
(
|
348 |
|
|
.aclk_i(clk_i),
|
349 |
|
|
.adat_o(tag_data_out),
|
350 |
|
|
.adat_i(tag_data_in),
|
351 |
|
|
.aadr_i(tag_entry),
|
352 |
|
|
.awr_i(tag_wr),
|
353 |
|
|
|
354 |
|
|
.bclk_i(clk_i),
|
355 |
|
|
.badr_i(flush_addr),
|
356 |
|
|
.bdat_o(/*open*/),
|
357 |
|
|
.bdat_i({CACHE_TAG_WIDTH{1'b0}}),
|
358 |
|
|
.bwr_i(flush_wr)
|
359 |
|
|
);
|
360 |
|
|
|
361 |
|
|
// Data memory
|
362 |
|
|
altor32_ram_dp
|
363 |
|
|
#(
|
364 |
|
|
.WIDTH(32),
|
365 |
|
|
.SIZE(CACHE_DWIDTH)
|
366 |
|
|
)
|
367 |
|
|
u2_data_mem
|
368 |
|
|
(
|
369 |
|
|
.aclk_i(clk_i),
|
370 |
|
|
.aadr_i(cache_address_rd),
|
371 |
|
|
.adat_o(instruction_o),
|
372 |
|
|
.adat_i(32'h00),
|
373 |
|
|
.awr_i(1'b0),
|
374 |
|
|
|
375 |
|
|
.bclk_i(clk_i),
|
376 |
|
|
.badr_i(cache_address_wr),
|
377 |
|
|
.bdat_o(/*open*/),
|
378 |
|
|
.bdat_i(cache_data_w),
|
379 |
|
|
.bwr_i(cache_wr)
|
380 |
|
|
);
|
381 |
|
|
|
382 |
|
|
endmodule
|
383 |
|
|
|