OpenCores
URL https://opencores.org/ocsvn/an-fpga-implementation-of-low-latency-noc-based-mpsoc/an-fpga-implementation-of-low-latency-noc-based-mpsoc/trunk

Subversion Repositories an-fpga-implementation-of-low-latency-noc-based-mpsoc

[/] [an-fpga-implementation-of-low-latency-noc-based-mpsoc/] [trunk/] [mpsoc/] [src_processor/] [mor1kx-5.0/] [rtl/] [verilog/] [mor1kx_icache.v] - Blame information for rev 48

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 48 alirezamon
/******************************************************************************
2
 This Source Code Form is subject to the terms of the
3
 Open Hardware Description License, v. 1.0. If a copy
4
 of the OHDL was not distributed with this file, You
5
 can obtain one at http://juliusbaxter.net/ohdl/ohdl.txt
6
 
7
 Description: Instruction cache implementation
8
 
9
 Copyright (C) 2012-2013
10
    Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
11
    Stefan Wallentowitz <stefan.wallentowitz@tum.de>
12
 
13
 ******************************************************************************/
14
 
15
`include "mor1kx-defines.v"
16
 
17
module mor1kx_icache
18
  #(
19
    parameter OPTION_OPERAND_WIDTH = 32,
20
    parameter OPTION_ICACHE_BLOCK_WIDTH = 5,
21
    parameter OPTION_ICACHE_SET_WIDTH = 9,
22
    parameter OPTION_ICACHE_WAYS = 2,
23
    parameter OPTION_ICACHE_LIMIT_WIDTH = 32
24
    )
25
   (
26
    input                             clk,
27
    input                             rst,
28
 
29
    input                             ic_imem_err_i,
30
    input                             ic_access_i,
31
    output                            refill_o,
32
    output                            refill_req_o,
33
    output                            refill_done_o,
34
    output                            invalidate_o,
35
    output                            cache_hit_o,
36
 
37
    // CPU Interface
38
    output                            cpu_ack_o,
39
    output reg [`OR1K_INSN_WIDTH-1:0] cpu_dat_o,
40
    input [OPTION_OPERAND_WIDTH-1:0]  cpu_adr_i,
41
    input [OPTION_OPERAND_WIDTH-1:0]  cpu_adr_match_i,
42
    input                             cpu_req_i,
43
 
44
    input [OPTION_OPERAND_WIDTH-1:0]  wradr_i,
45
    input [`OR1K_INSN_WIDTH-1:0]      wrdat_i,
46
    input                             we_i,
47
 
48
    // SPR interface
49
    input [15:0]                       spr_bus_addr_i,
50
    input                             spr_bus_we_i,
51
    input                             spr_bus_stb_i,
52
    input [OPTION_OPERAND_WIDTH-1:0]  spr_bus_dat_i,
53
 
54
    output [OPTION_OPERAND_WIDTH-1:0] spr_bus_dat_o,
55
    output reg                        spr_bus_ack_o
56
    );
57
 
58
   // States
59
   localparam IDLE              = 4'b0001;
60
   localparam READ              = 4'b0010;
61
   localparam REFILL            = 4'b0100;
62
   localparam INVALIDATE        = 4'b1000;
63
 
64
   // Address space in bytes for a way
65
   localparam WAY_WIDTH = OPTION_ICACHE_BLOCK_WIDTH + OPTION_ICACHE_SET_WIDTH;
66
   /*
67
    * Tag memory layout
68
    *            +---------------------------------------------------------+
69
    * (index) -> | LRU | wayN valid | wayN tag |...| way0 valid | way0 tag |
70
    *            +---------------------------------------------------------+
71
    */
72
 
73
   // The tag is the part left of the index
74
   localparam TAG_WIDTH = (OPTION_ICACHE_LIMIT_WIDTH - WAY_WIDTH);
75
 
76
   // The tag memory contains entries with OPTION_ICACHE_WAYS parts of
77
   // each TAGMEM_WAY_WIDTH. Each of those is tag and a valid flag.
78
   localparam TAGMEM_WAY_WIDTH = TAG_WIDTH + 1;
79
   localparam TAGMEM_WAY_VALID = TAGMEM_WAY_WIDTH - 1;
80
 
81
   // Additionally, the tag memory entry contains an LRU value. The
82
   // width of this is actually 0 for OPTION_ICACHE_LIMIT_WIDTH==1
83
   localparam TAG_LRU_WIDTH = OPTION_ICACHE_WAYS*(OPTION_ICACHE_WAYS-1) >> 1;
84
 
85
   // We have signals for the LRU which are not used for one way
86
   // caches. To avoid signal width [-1:0] this generates [0:0]
87
   // vectors for them, which are removed automatically then.
88
   localparam TAG_LRU_WIDTH_BITS = (OPTION_ICACHE_WAYS >= 2) ? TAG_LRU_WIDTH : 1;
89
 
90
   // Compute the total sum of the entry elements
91
   localparam TAGMEM_WIDTH = TAGMEM_WAY_WIDTH * OPTION_ICACHE_WAYS + TAG_LRU_WIDTH;
92
 
93
   // For convenience we define the position of the LRU in the tag
94
   // memory entries
95
   localparam TAG_LRU_MSB = TAGMEM_WIDTH - 1;
96
   localparam TAG_LRU_LSB = TAG_LRU_MSB - TAG_LRU_WIDTH + 1;
97
 
98
   // FSM state signals
99
   reg [3:0]                           state;
100
   wire                               read;
101
   wire                               refill;
102
   wire                               invalidate;
103
 
104
   reg [WAY_WIDTH-1:OPTION_ICACHE_BLOCK_WIDTH] invalidate_adr;
105
   wire [31:0]                         next_refill_adr;
106
   wire                               refill_done;
107
   wire                               refill_hit;
108
   reg [(1<<(OPTION_ICACHE_BLOCK_WIDTH-2))-1:0] refill_valid;
109
   reg [(1<<(OPTION_ICACHE_BLOCK_WIDTH-2))-1:0] refill_valid_r;
110
 
111
   // The index we read and write from tag memory
112
   wire [OPTION_ICACHE_SET_WIDTH-1:0] tag_rindex;
113
   wire [OPTION_ICACHE_SET_WIDTH-1:0] tag_windex;
114
 
115
   // The data from the tag memory
116
   wire [TAGMEM_WIDTH-1:0]             tag_dout;
117
   wire [TAG_LRU_WIDTH_BITS-1:0]      tag_lru_out;
118
   wire [TAGMEM_WAY_WIDTH-1:0]         tag_way_out [OPTION_ICACHE_WAYS-1:0];
119
 
120
   // The data to the tag memory
121
   wire [TAGMEM_WIDTH-1:0]             tag_din;
122
   reg [TAG_LRU_WIDTH_BITS-1:0]       tag_lru_in;
123
   reg [TAGMEM_WAY_WIDTH-1:0]          tag_way_in [OPTION_ICACHE_WAYS-1:0];
124
 
125
   reg [TAGMEM_WAY_WIDTH-1:0]          tag_way_save [OPTION_ICACHE_WAYS-1:0];
126
 
127
   // Whether to write to the tag memory in this cycle
128
   reg                                tag_we;
129
 
130
   // This is the tag we need to write to the tag memory during refill
131
   wire [TAG_WIDTH-1:0]        tag_wtag;
132
 
133
   // This is the tag we check against
134
   wire [TAG_WIDTH-1:0]        tag_tag;
135
 
136
   // Access to the way memories
137
   wire [WAY_WIDTH-3:0]        way_raddr[OPTION_ICACHE_WAYS-1:0];
138
   wire [WAY_WIDTH-3:0]        way_waddr[OPTION_ICACHE_WAYS-1:0];
139
   wire [OPTION_OPERAND_WIDTH-1:0]    way_din[OPTION_ICACHE_WAYS-1:0];
140
   wire [OPTION_OPERAND_WIDTH-1:0]    way_dout[OPTION_ICACHE_WAYS-1:0];
141
   reg [OPTION_ICACHE_WAYS-1:0]       way_we;
142
 
143
   // Does any way hit?
144
   wire                               hit;
145
   wire [OPTION_ICACHE_WAYS-1:0]      way_hit;
146
 
147
   // This is the least recently used value before access the memory.
148
   // Those are one hot encoded.
149
   wire [OPTION_ICACHE_WAYS-1:0]      lru;
150
 
151
   // Register that stores the LRU value from lru
152
   reg [OPTION_ICACHE_WAYS-1:0]       tag_save_lru;
153
 
154
   // The access vector to update the LRU history is the way that has
155
   // a hit or is refilled. It is also one-hot encoded.
156
   reg [OPTION_ICACHE_WAYS-1:0]       access;
157
 
158
   // The current LRU history as read from tag memory and the update
159
   // value after we accessed it to write back to tag memory.
160
   wire [TAG_LRU_WIDTH_BITS-1:0]      current_lru_history;
161
   wire [TAG_LRU_WIDTH_BITS-1:0]      next_lru_history;
162
 
163
   // Intermediate signals to ease debugging
164
   wire [TAG_WIDTH-1:0]               check_way_tag [OPTION_ICACHE_WAYS-1:0];
165
   wire                               check_way_match [OPTION_ICACHE_WAYS-1:0];
166
   wire                               check_way_valid [OPTION_ICACHE_WAYS-1:0];
167
 
168
   genvar                             i;
169
 
170
   // Allowing (out of the cache line being refilled) accesses during refill
171
   // exposes a bug somewhere, causing the Linux kernel to end up with a
172
   // bus error UNHANDLED EXCEPTION.
173
   // Until that is sorted out, disable it.
174
   assign cpu_ack_o = (read /*| refill & ic_access_i*/) & hit |
175
                      refill_hit & ic_access_i;
176
 
177
   assign tag_rindex = cpu_adr_i[WAY_WIDTH-1:OPTION_ICACHE_BLOCK_WIDTH];
178
   /*
179
    * The tag mem is written during reads to write the lru info and during
180
    * refill and invalidate
181
    */
182
   assign tag_windex = read ?
183
                       cpu_adr_match_i[WAY_WIDTH-1:OPTION_ICACHE_BLOCK_WIDTH] :
184
                       invalidate ? invalidate_adr :
185
                       wradr_i[WAY_WIDTH-1:OPTION_ICACHE_BLOCK_WIDTH];
186
   assign tag_tag = cpu_adr_match_i[OPTION_ICACHE_LIMIT_WIDTH-1:WAY_WIDTH];
187
   assign tag_wtag = wradr_i[OPTION_ICACHE_LIMIT_WIDTH-1:WAY_WIDTH];
188
 
189
   generate
190
      if (OPTION_ICACHE_WAYS >= 2) begin
191
         // Multiplex the LRU history from and to tag memory
192
         assign current_lru_history = tag_dout[TAG_LRU_MSB:TAG_LRU_LSB];
193
         assign tag_din[TAG_LRU_MSB:TAG_LRU_LSB] = tag_lru_in;
194
         assign tag_lru_out = tag_dout[TAG_LRU_MSB:TAG_LRU_LSB];
195
      end
196
 
197
      for (i = 0; i < OPTION_ICACHE_WAYS; i=i+1) begin : ways
198
         assign way_raddr[i] = cpu_adr_i[WAY_WIDTH-1:2];
199
         assign way_waddr[i] = wradr_i[WAY_WIDTH-1:2];
200
         assign way_din[i] = wrdat_i;
201
 
202
         // compare stored tag with incoming tag and check valid bit
203
         assign check_way_tag[i] = tag_way_out[i][TAG_WIDTH-1:0];
204
         assign check_way_match[i] = (check_way_tag[i] == tag_tag);
205
         assign check_way_valid[i] = tag_way_out[i][TAGMEM_WAY_VALID];
206
 
207
         assign way_hit[i] = check_way_valid[i] & check_way_match[i];
208
 
209
         // Multiplex the way entries in the tag memory
210
         assign tag_din[(i+1)*TAGMEM_WAY_WIDTH-1:i*TAGMEM_WAY_WIDTH] = tag_way_in[i];
211
         assign tag_way_out[i] = tag_dout[(i+1)*TAGMEM_WAY_WIDTH-1:i*TAGMEM_WAY_WIDTH];
212
      end
213
   endgenerate
214
 
215
   assign hit = |way_hit;
216
   assign cache_hit_o = hit;
217
 
218
   integer w0;
219
   always @(*) begin
220
      cpu_dat_o = {OPTION_OPERAND_WIDTH{1'bx}};
221
 
222
      // Put correct way on the data port
223
      for (w0 = 0; w0 < OPTION_ICACHE_WAYS; w0 = w0 + 1) begin
224
         if (way_hit[w0] | (refill_hit & tag_save_lru[w0])) begin
225
            cpu_dat_o = way_dout[w0];
226
         end
227
      end
228
   end
229
 
230
   assign next_refill_adr = (OPTION_ICACHE_BLOCK_WIDTH == 5) ?
231
                            {wradr_i[31:5], wradr_i[4:0] + 5'd4} : // 32 byte
232
                            {wradr_i[31:4], wradr_i[3:0] + 4'd4};  // 16 byte
233
 
234
   assign refill_done_o = refill_done;
235
   assign refill_done = refill_valid[next_refill_adr[OPTION_ICACHE_BLOCK_WIDTH-1:2]];
236
   assign refill_hit = refill_valid_r[cpu_adr_match_i[OPTION_ICACHE_BLOCK_WIDTH-1:2]] &
237
                       cpu_adr_match_i[OPTION_ICACHE_LIMIT_WIDTH-1:
238
                                       OPTION_ICACHE_BLOCK_WIDTH] ==
239
                       wradr_i[OPTION_ICACHE_LIMIT_WIDTH-1:
240
                               OPTION_ICACHE_BLOCK_WIDTH] &
241
                       refill;
242
 
243
   assign refill = (state == REFILL);
244
   assign read = (state == READ);
245
   assign invalidate = (state == INVALIDATE);
246
 
247
   assign refill_o = refill;
248
 
249
   assign refill_req_o = read & cpu_req_i & !hit | refill;
250
 
251
   /*
252
    * SPR bus interface
253
    */
254
   assign invalidate_o = spr_bus_stb_i & spr_bus_we_i &
255
                         (spr_bus_addr_i == `OR1K_SPR_ICBIR_ADDR);
256
 
257
   /*
258
    * Cache FSM
259
    */
260
   integer w1;
261
   always @(posedge clk `OR_ASYNC_RST) begin
262
      refill_valid_r <= refill_valid;
263
      spr_bus_ack_o <= 0;
264
      case (state)
265
        IDLE: begin
266
           if (cpu_req_i)
267
             state <= READ;
268
        end
269
 
270
        READ: begin
271
           if (ic_access_i) begin
272
              if (hit) begin
273
                 state <= READ;
274
              end else if (cpu_req_i) begin
275
                 refill_valid <= 0;
276
                 refill_valid_r <= 0;
277
 
278
                 // Store the LRU information for correct replacement
279
                 // on refill. Always one when only one way.
280
                 tag_save_lru <= (OPTION_ICACHE_WAYS==1) | lru;
281
 
282
                 for (w1 = 0; w1 < OPTION_ICACHE_WAYS; w1 = w1 + 1) begin
283
                    tag_way_save[w1] <= tag_way_out[w1];
284
                 end
285
 
286
                 state <= REFILL;
287
              end
288
           end else begin
289
              state <= IDLE;
290
           end
291
        end
292
 
293
        REFILL: begin
294
           if (we_i) begin
295
              refill_valid[wradr_i[OPTION_ICACHE_BLOCK_WIDTH-1:2]] <= 1;
296
 
297
              if (refill_done)
298
                state <= IDLE;
299
           end
300
        end
301
 
302
        INVALIDATE: begin
303
           if (!invalidate_o)
304
             state <= IDLE;
305
           spr_bus_ack_o <= 1;
306
        end
307
 
308
        default:
309
          state <= IDLE;
310
      endcase
311
 
312
      if (invalidate_o & !refill) begin
313
         invalidate_adr <= spr_bus_dat_i[WAY_WIDTH-1:OPTION_ICACHE_BLOCK_WIDTH];
314
         spr_bus_ack_o <= 1;
315
         state <= INVALIDATE;
316
      end
317
 
318
      if (rst)
319
        state <= IDLE;
320
      else if(ic_imem_err_i)
321
        state <= IDLE;
322
   end
323
 
324
   integer w2;
325
   always @(*) begin
326
      // Default is to keep data, don't write and don't access
327
      tag_lru_in = tag_lru_out;
328
      for (w2 = 0; w2 < OPTION_ICACHE_WAYS; w2 = w2 + 1) begin
329
         tag_way_in[w2] = tag_way_out[w2];
330
      end
331
 
332
      tag_we = 1'b0;
333
      way_we = {(OPTION_ICACHE_WAYS){1'b0}};
334
 
335
      access = {(OPTION_ICACHE_WAYS){1'b0}};
336
 
337
      case (state)
338
        READ: begin
339
           if (hit) begin
340
              // We got a hit. The LRU module gets the access
341
              // information. Depending on this we update the LRU
342
              // history in the tag.
343
              access = way_hit;
344
 
345
              // This is the updated LRU history after hit
346
              tag_lru_in = next_lru_history;
347
 
348
              tag_we = 1'b1;
349
           end
350
        end
351
 
352
        REFILL: begin
353
           if (we_i) begin
354
              // Write the data to the way that is replaced (which is
355
              // the LRU)
356
              way_we = tag_save_lru;
357
 
358
              // Access pattern
359
              access = tag_save_lru;
360
 
361
              /* Invalidate the way on the first write */
362
              if (refill_valid == 0) begin
363
                 for (w2 = 0; w2 < OPTION_ICACHE_WAYS; w2 = w2 + 1) begin
364
                    if (tag_save_lru[w2]) begin
365
                       tag_way_in[w2][TAGMEM_WAY_VALID] = 1'b0;
366
                    end
367
                 end
368
 
369
                 tag_we = 1'b1;
370
              end
371
 
372
              // After refill update the tag memory entry of the
373
              // filled way with the LRU history, the tag and set
374
              // valid to 1.
375
              if (refill_done) begin
376
                 for (w2 = 0; w2 < OPTION_ICACHE_WAYS; w2 = w2 + 1) begin
377
                    tag_way_in[w2] = tag_way_save[w2];
378
                    if (tag_save_lru[w2]) begin
379
                       tag_way_in[w2] = { 1'b1, tag_wtag };
380
                    end
381
                 end
382
                 tag_lru_in = next_lru_history;
383
 
384
                 tag_we = 1'b1;
385
              end
386
           end
387
        end
388
 
389
        INVALIDATE: begin
390
           // Lazy invalidation, invalidate everything that matches tag address
391
           tag_lru_in = 0;
392
           for (w2 = 0; w2 < OPTION_ICACHE_WAYS; w2 = w2 + 1) begin
393
              tag_way_in[w2] = 0;
394
           end
395
 
396
           tag_we = 1'b1;
397
        end
398
 
399
        default: begin
400
        end
401
      endcase
402
   end
403
 
404
   /* mor1kx_simple_dpram_sclk AUTO_TEMPLATE (
405
      // Outputs
406
      .dout                     (way_dout[i][OPTION_OPERAND_WIDTH-1:0]),
407
      // Inputs
408
      .raddr                    (way_raddr[i][WAY_WIDTH-3:0]),
409
      .re                       (1'b1),
410
      .waddr                    (way_waddr[i][WAY_WIDTH-3:0]),
411
      .we                       (way_we[i]),
412
      .din                      (way_din[i][31:0]));
413
    */
414
   generate
415
      for (i = 0; i < OPTION_ICACHE_WAYS; i=i+1) begin : way_memories
416
         mor1kx_simple_dpram_sclk
417
               #(
418
                 .ADDR_WIDTH(WAY_WIDTH-2),
419
                 .DATA_WIDTH(OPTION_OPERAND_WIDTH),
420
                 .ENABLE_BYPASS(0)
421
                 )
422
         way_data_ram
423
               (/*AUTOINST*/
424
                // Outputs
425
                .dout                   (way_dout[i][OPTION_OPERAND_WIDTH-1:0]), // Templated
426
                // Inputs
427
                .clk                    (clk),
428
                .raddr                  (way_raddr[i][WAY_WIDTH-3:0]), // Templated
429
                .re                     (1'b1),                  // Templated
430
                .waddr                  (way_waddr[i][WAY_WIDTH-3:0]), // Templated
431
                .we                     (way_we[i]),             // Templated
432
                .din                    (way_din[i][31:0]));      // Templated
433
 
434
      end // block: way_memories
435
 
436
      if (OPTION_ICACHE_WAYS >= 2) begin : gen_u_lru
437
         /* mor1kx_cache_lru AUTO_TEMPLATE(
438
          .current  (current_lru_history),
439
          .update   (next_lru_history),
440
          .lru_pre  (lru),
441
          .lru_post (),
442
          .access   (access),
443
          ); */
444
 
445
         mor1kx_cache_lru
446
           #(.NUMWAYS(OPTION_ICACHE_WAYS))
447
         u_lru(/*AUTOINST*/
448
               // Outputs
449
               .update                  (next_lru_history),      // Templated
450
               .lru_pre                 (lru),                   // Templated
451
               .lru_post                (),                      // Templated
452
               // Inputs
453
               .current                 (current_lru_history),   // Templated
454
               .access                  (access));               // Templated
455
      end // if (OPTION_ICACHE_WAYS >= 2)
456
   endgenerate
457
 
458
   /* mor1kx_simple_dpram_sclk AUTO_TEMPLATE (
459
      // Outputs
460
      .dout                     (tag_dout[TAGMEM_WIDTH-1:0]),
461
      // Inputs
462
      .raddr                    (tag_rindex),
463
      .re                       (1'b1),
464
      .waddr                    (tag_windex),
465
      .we                       (tag_we),
466
      .din                      (tag_din));
467
    */
468
   mor1kx_simple_dpram_sclk
469
     #(
470
       .ADDR_WIDTH(OPTION_ICACHE_SET_WIDTH),
471
       .DATA_WIDTH(TAGMEM_WIDTH),
472
       .ENABLE_BYPASS(0)
473
     )
474
   tag_ram
475
     (/*AUTOINST*/
476
      // Outputs
477
      .dout                             (tag_dout[TAGMEM_WIDTH-1:0]), // Templated
478
      // Inputs
479
      .clk                              (clk),
480
      .raddr                            (tag_rindex),            // Templated
481
      .re                               (1'b1),                  // Templated
482
      .waddr                            (tag_windex),            // Templated
483
      .we                               (tag_we),                // Templated
484
      .din                              (tag_din));              // Templated
485
 
486
endmodule

powered by: WebSVN 2.1.0

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