OpenCores
URL https://opencores.org/ocsvn/altor32/altor32/trunk

Subversion Repositories altor32

[/] [altor32/] [trunk/] [rtl/] [cpu/] [altor32_icache.v] - Blame information for rev 30

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
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
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.