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

Subversion Repositories altor32

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

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
    output [31:0]               mem_addr_o /*verilator public*/,
64
    input [31:0]                mem_data_i /*verilator public*/,
65
    output                      mem_burst_o /*verilator public*/,
66
    output                      mem_rd_o /*verilator public*/,
67
    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
wire                            busy_o;
120
wire                            miss_o;
121
 
122
reg                             initial_fetch;
123
reg                             flush_req;
124
 
125
reg [31:0]                      mem_addr_o;
126
reg                             mem_rd_o;
127
reg                             mem_burst_o;
128
 
129
reg [CACHE_LINE_ADDR_WIDTH-1:0] flush_addr;
130
reg                             flush_wr;
131
 
132
reg                             read_while_busy;
133
 
134
// Current state
135
parameter STATE_CHECK       = 0;
136
parameter STATE_FETCH       = 1;
137
parameter STATE_WAIT        = 2;
138
parameter STATE_WAIT2       = 3;
139
parameter STATE_FLUSH       = 4;
140
reg [3:0]                       state;
141
 
142
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];
143
assign cache_address_rd = pc_i[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:2];
144
 
145
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;
146
 
147
wire valid_o            = !miss_o && !busy_o;
148
 
149
//-----------------------------------------------------------------
150
// Control logic
151
//-----------------------------------------------------------------
152
reg [CACHE_LINE_SIZE_WIDTH-3:0] v_line_word;
153
 
154
always @ (posedge rst_i or posedge clk_i )
155
begin
156
   if (rst_i == 1'b1)
157
   begin
158
        fetch_word      <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}};
159
        mem_addr_o      <= 32'h00000000;
160
        mem_rd_o        <= 1'b0;
161
        mem_burst_o     <= 1'b0;
162
        tag_wr          <= 1'b0;
163
        cache_address_wr<= {CACHE_DWIDTH{1'b0}};
164
        cache_data_w    <= 32'h00000000;
165
        cache_wr        <= 1'b0;
166
        miss_pc         <= BOOT_VECTOR + `VECTOR_RESET;
167
        last_pc         <= 32'h00000000;
168
        state           <= STATE_CHECK;
169
        initial_fetch   <= 1'b1;
170
        read_while_busy <= 1'b0;
171
 
172
        flush_addr      <= {CACHE_LINE_ADDR_WIDTH{1'b0}};
173
        flush_wr        <= 1'b0;
174
        flush_req       <= 1'b0;
175
   end
176
   else
177
   begin
178
 
179
        if (mem_accept_i)
180
            mem_rd_o        <= 1'b0;
181
        tag_wr          <= 1'b0;
182
        cache_wr        <= 1'b0;
183
        initial_fetch   <= 1'b0;
184
        flush_wr        <= 1'b0;
185
        last_pc         <= pc_i;
186
 
187
        // Latch invalidate request even if can't be actioned now...
188
        if (invalidate_i)
189
            flush_req <= 1'b1;
190
 
191
        // New request whilst cache busy?
192
        if (rd_i)
193
            read_while_busy <= 1'b1;
194
 
195
        case (state)
196
 
197
            //-----------------------------------------
198
            // CHECK - check cache for hit or miss
199
            //-----------------------------------------
200
            STATE_CHECK :
201
            begin
202
                // Cache flush request pending?
203
                if (flush_req || invalidate_i)
204
                begin
205
                    flush_req       <= 1'b0;
206
                    flush_addr      <= {CACHE_LINE_ADDR_WIDTH{1'b1}};
207
                    flush_wr        <= 1'b1;
208
                    state           <= STATE_FLUSH;
209
 
210
`ifdef CONF_CORE_DEBUG
211
                    $display("Fetch: Cache flush request");
212
`endif
213
                end
214
                // Cache miss (& new read request not pending)
215
                else if ((miss_o && !initial_fetch) && !rd_i && !read_while_busy)
216
                begin
217
                    read_while_busy <= 1'b0;
218
 
219
                    fetch_word    <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}};
220
 
221
`ifdef CONF_CORE_DEBUG
222
                    $display("Fetch: Cache miss at 0x%x (last=%x, current=%x)", miss_pc, last_pc, pc_i);
223
`endif
224
 
225
                    // Start fetch from memory
226
                    mem_addr_o  <= {miss_pc[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH{1'b0}}};
227
                    mem_rd_o    <= 1'b1;
228
                    mem_burst_o <= 1'b1;
229
                    state       <= STATE_FETCH;
230
 
231
                    // Update tag memory with this line's details   
232
                    tag_data_in <= {1'b1, miss_pc[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]};
233
                    tag_wr      <= 1'b1;
234
                end
235
                // Cache hit (or new read request)
236
                else
237
                begin
238
`ifdef CONF_CORE_DEBUG
239
                    $display("Fetch: Cache hit at PC=%x (current=%x)", last_pc, pc_i);
240
                    if (read_while_busy)
241
                        $display("Fetch: Read request whilst busy PC=%x (current=%x)", last_pc, pc_i);
242
`endif
243
 
244
                    // Store fetch PC
245
                    miss_pc     <= pc_i;
246
                    state       <= STATE_CHECK;
247
                    read_while_busy <= 1'b0;
248
                end
249
            end
250
            //-----------------------------------------
251
            // FETCH - Fetch row from memory
252
            //-----------------------------------------
253
            STATE_FETCH :
254
            begin
255
                // Data ready from memory?
256
                if (mem_ack_i)
257
                begin
258
                    // Write data into cache
259
                    cache_address_wr<= {miss_pc[CACHE_LINE_ADDR_WIDTH + CACHE_LINE_SIZE_WIDTH - 1:CACHE_LINE_SIZE_WIDTH], fetch_word};
260
                    cache_data_w    <= mem_data_i;
261
                    cache_wr        <= 1'b1;
262
 
263
                    // Line fetch complete?
264
                    if (fetch_word == {CACHE_LINE_WORDS_IDX_MAX{1'b1}})
265
                    begin
266
                        state       <= STATE_WAIT;
267
                    end
268
                    // Fetch next word for line
269
                    else
270
                    begin
271
                        v_line_word = fetch_word + 1'b1;
272
                        fetch_word <= v_line_word;
273
 
274
                        mem_addr_o <= {mem_addr_o[31:CACHE_LINE_SIZE_WIDTH], v_line_word, 2'b00};
275
                        mem_rd_o   <= 1'b1;
276
 
277
                        if (fetch_word == ({CACHE_LINE_WORDS_IDX_MAX{1'b1}}-1))
278
                        begin
279
                            mem_burst_o <= 1'b0;
280
                        end
281
                    end
282
                end
283
            end
284
            //-----------------------------------------
285
            // FLUSH - Invalidate tag memory
286
            //-----------------------------------------
287
            STATE_FLUSH :
288
            begin
289
                if (flush_addr == {CACHE_LINE_ADDR_WIDTH{1'b0}})
290
                begin
291
                    // Fetch current PC line again
292
                    mem_addr_o  <= {pc_i[31:CACHE_LINE_SIZE_WIDTH], {CACHE_LINE_SIZE_WIDTH{1'b0}}};
293
                    mem_rd_o    <= 1'b1;
294
                    mem_burst_o <= 1'b1;
295
                    state       <= STATE_FETCH;
296
 
297
                    // Update tag memory with this line's details   
298
                    tag_data_in <= {1'b1, pc_i[CACHE_TAG_ADDR_HIGH:CACHE_TAG_ADDR_LOW]};
299
                    tag_wr      <= 1'b1;
300
 
301
                    // Start of line
302
                    fetch_word    <= {CACHE_LINE_SIZE_WIDTH-2{1'b0}};
303
 
304
                    // Clear pending reads whilst busy
305
                    read_while_busy <= 1'b0;
306
                end
307
                else
308
                begin
309
                    flush_addr  <= flush_addr - 1;
310
                    flush_wr    <= 1'b1;
311
                    state       <= STATE_FLUSH;
312
                end
313
            end
314
            //-----------------------------------------
315
            // WAIT - Wait cycle
316
            //-----------------------------------------
317
            STATE_WAIT :
318
            begin
319
                // Allow extra wait state to handle write & read collision               
320
                state   <= STATE_WAIT2;
321
            end
322
            //-----------------------------------------
323
            // WAIT2 - Wait cycle
324
            //-----------------------------------------
325
            STATE_WAIT2 :
326
            begin
327
`ifdef CONF_CORE_DEBUG
328
                $display("Fetch: Filled line containing PC=%x", miss_pc);
329
`endif
330
                state   <= STATE_CHECK;
331
            end
332
 
333
 
334
            default:
335
                ;
336
           endcase
337
   end
338
end
339
 
340
// Stall the CPU if cache state machine is not idle!
341
assign busy_o = (state == STATE_CHECK & ~read_while_busy) ? 1'b0 : 1'b1;
342
 
343
//-----------------------------------------------------------------
344
// Instantiation
345
//-----------------------------------------------------------------
346
 
347
// Tag memory    
348
altor32_ram_dp
349
#(
350
    .WIDTH(CACHE_TAG_WIDTH),
351
    .SIZE(CACHE_LINE_ADDR_WIDTH)
352
)
353
u1_tag_mem
354
(
355
    .aclk_i(clk_i),
356
    .adat_o(tag_data_out),
357
    .adat_i(tag_data_in),
358
    .aadr_i(tag_entry),
359
    .awr_i(tag_wr),
360
 
361
    .bclk_i(clk_i),
362
    .badr_i(flush_addr),
363
    .bdat_o(/*open*/),
364
    .bdat_i({CACHE_TAG_WIDTH{1'b0}}),
365
    .bwr_i(flush_wr)
366
);
367
 
368
// Data memory
369
altor32_ram_dp
370
#(
371
    .WIDTH(32),
372
    .SIZE(CACHE_DWIDTH)
373
)
374
u2_data_mem
375
(
376
    .aclk_i(clk_i),
377
    .aadr_i(cache_address_rd),
378
    .adat_o(instruction_o),
379
    .adat_i(32'h00),
380
    .awr_i(1'b0),
381
 
382
    .bclk_i(clk_i),
383
    .badr_i(cache_address_wr),
384
    .bdat_o(/*open*/),
385
    .bdat_i(cache_data_w),
386
    .bwr_i(cache_wr)
387
);
388
 
389
endmodule
390
 

powered by: WebSVN 2.1.0

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