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-3.1/] [rtl/] [verilog/] [mor1kx_icache.v] - Blame information for rev 38

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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