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_dcache.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: Data 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_dcache
18
  #(
19
    parameter OPTION_OPERAND_WIDTH = 32,
20
    parameter OPTION_DCACHE_BLOCK_WIDTH = 5,
21
    parameter OPTION_DCACHE_SET_WIDTH = 9,
22
    parameter OPTION_DCACHE_WAYS = 2,
23
    parameter OPTION_DCACHE_LIMIT_WIDTH = 32,
24
    parameter OPTION_DCACHE_SNOOP = "NONE"
25
    )
26
   (
27
    input                             clk,
28
    input                             rst,
29
 
30
    input                             dc_enable_i,
31
    input                             dc_access_i,
32
    output                            refill_o,
33
    output                            refill_req_o,
34
    output                            refill_done_o,
35
 
36
    // CPU Interface
37
    output                            cpu_err_o,
38
    output                            cpu_ack_o,
39
    output reg [OPTION_OPERAND_WIDTH-1:0] cpu_dat_o,
40
    input [OPTION_OPERAND_WIDTH-1:0]  cpu_dat_i,
41
    input [OPTION_OPERAND_WIDTH-1:0]  cpu_adr_i,
42
    input [OPTION_OPERAND_WIDTH-1:0]  cpu_adr_match_i,
43
    input                             cpu_req_i,
44
    input                             cpu_we_i,
45
    input [3:0]                cpu_bsel_i,
46
 
47
    input                             refill_allowed,
48
 
49
    input [OPTION_OPERAND_WIDTH-1:0]  wradr_i,
50
    input [OPTION_OPERAND_WIDTH-1:0]  wrdat_i,
51
    input                             we_i,
52
 
53
    // Snoop address
54
    input [31:0]                       snoop_adr_i,
55
    // Snoop event in this cycle
56
    input                             snoop_valid_i,
57
    // Whether the snoop hit. If so, there will be no tag memory write
58
    // this cycle. The LSU may need to stall the pipeline.
59
    output                            snoop_hit_o,
60
 
61
 
62
    // SPR interface
63
    input [15:0]                       spr_bus_addr_i,
64
    input                             spr_bus_we_i,
65
    input                             spr_bus_stb_i,
66
    input [OPTION_OPERAND_WIDTH-1:0]  spr_bus_dat_i,
67
 
68
    output [OPTION_OPERAND_WIDTH-1:0] spr_bus_dat_o,
69
    output                            spr_bus_ack_o
70
    );
71
 
72
   // States
73
   localparam IDLE              = 5'b00001;
74
   localparam READ              = 5'b00010;
75
   localparam WRITE             = 5'b00100;
76
   localparam REFILL            = 5'b01000;
77
   localparam INVALIDATE        = 5'b10000;
78
 
79
   // Address space in bytes for a way
80
   localparam WAY_WIDTH = OPTION_DCACHE_BLOCK_WIDTH + OPTION_DCACHE_SET_WIDTH;
81
   /*
82
    * Tag memory layout
83
    *            +---------------------------------------------------------+
84
    * (index) -> | LRU | wayN valid | wayN tag |...| way0 valid | way0 tag |
85
    *            +---------------------------------------------------------+
86
    */
87
 
88
   // The tag is the part left of the index
89
   localparam TAG_WIDTH = (OPTION_DCACHE_LIMIT_WIDTH - WAY_WIDTH);
90
 
91
   // The tag memory contains entries with OPTION_DCACHE_WAYS parts of
92
   // each TAGMEM_WAY_WIDTH. Each of those is tag and a valid flag.
93
   localparam TAGMEM_WAY_WIDTH = TAG_WIDTH + 1;
94
   localparam TAGMEM_WAY_VALID = TAGMEM_WAY_WIDTH - 1;
95
 
96
   // Additionally, the tag memory entry contains an LRU value. The
97
   // width of this is 0 for OPTION_DCACHE_LIMIT_WIDTH==1
98
   localparam TAG_LRU_WIDTH = OPTION_DCACHE_WAYS*(OPTION_DCACHE_WAYS-1) >> 1;
99
 
100
   // We have signals for the LRU which are not used for one way
101
   // caches. To avoid signal width [-1:0] this generates [0:0]
102
   // vectors for them, which are removed automatically then.
103
   localparam TAG_LRU_WIDTH_BITS = (OPTION_DCACHE_WAYS >= 2) ? TAG_LRU_WIDTH : 1;
104
 
105
   // Compute the total sum of the entry elements
106
   localparam TAGMEM_WIDTH = TAGMEM_WAY_WIDTH * OPTION_DCACHE_WAYS + TAG_LRU_WIDTH;
107
 
108
   // For convenience we define the position of the LRU in the tag
109
   // memory entries
110
   localparam TAG_LRU_MSB = TAGMEM_WIDTH - 1;
111
   localparam TAG_LRU_LSB = TAG_LRU_MSB - TAG_LRU_WIDTH + 1;
112
 
113
   // FSM state signals
114
   reg [4:0]                           state;
115
   wire                               idle;
116
   wire                               read;
117
   wire                               write;
118
   wire                               refill;
119
 
120
   reg [WAY_WIDTH-1:OPTION_DCACHE_BLOCK_WIDTH] invalidate_adr;
121
   wire [31:0]                         next_refill_adr;
122
   reg [31:0]                          way_wr_dat;
123
   wire                               refill_done;
124
   wire                               refill_hit;
125
   reg [(1<<(OPTION_DCACHE_BLOCK_WIDTH-2))-1:0] refill_valid;
126
   reg [(1<<(OPTION_DCACHE_BLOCK_WIDTH-2))-1:0] refill_valid_r;
127
   wire                               invalidate;
128
 
129
   // The index we read and write from tag memory
130
   wire [OPTION_DCACHE_SET_WIDTH-1:0] tag_rindex;
131
   reg [OPTION_DCACHE_SET_WIDTH-1:0]  tag_windex;
132
 
133
   // The data from the tag memory
134
   wire [TAGMEM_WIDTH-1:0]             tag_dout;
135
   wire [TAG_LRU_WIDTH_BITS-1:0]      tag_lru_out;
136
   wire [TAGMEM_WAY_WIDTH-1:0]         tag_way_out [OPTION_DCACHE_WAYS-1:0];
137
 
138
   // The data to the tag memory
139
   wire [TAGMEM_WIDTH-1:0]             tag_din;
140
   reg [TAG_LRU_WIDTH_BITS-1:0]       tag_lru_in;
141
   reg [TAGMEM_WAY_WIDTH-1:0]          tag_way_in [OPTION_DCACHE_WAYS-1:0];
142
 
143
   reg [TAGMEM_WAY_WIDTH-1:0]          tag_way_save[OPTION_DCACHE_WAYS-1:0];
144
 
145
   // Whether to write to the tag memory in this cycle
146
   reg                                tag_we;
147
 
148
   // This is the tag we need to write to the tag memory during refill
149
   wire [TAG_WIDTH-1:0]        tag_wtag;
150
 
151
   // This is the tag we check against
152
   wire [TAG_WIDTH-1:0]        tag_tag;
153
 
154
   // Access to the way memories
155
   wire [WAY_WIDTH-3:0]        way_raddr[OPTION_DCACHE_WAYS-1:0];
156
   wire [WAY_WIDTH-3:0]        way_waddr[OPTION_DCACHE_WAYS-1:0];
157
   wire [OPTION_OPERAND_WIDTH-1:0]    way_din[OPTION_DCACHE_WAYS-1:0];
158
   wire [OPTION_OPERAND_WIDTH-1:0]    way_dout[OPTION_DCACHE_WAYS-1:0];
159
   reg [OPTION_DCACHE_WAYS-1:0]       way_we;
160
 
161
   // Does any way hit?
162
   wire                               hit;
163
   wire [OPTION_DCACHE_WAYS-1:0]      way_hit;
164
 
165
   // This is the least recently used value before access the memory.
166
   // Those are one hot encoded.
167
   wire [OPTION_DCACHE_WAYS-1:0]      lru;
168
 
169
   // Register that stores the LRU value from lru
170
   reg [OPTION_DCACHE_WAYS-1:0]       tag_save_lru;
171
 
172
   // The access vector to update the LRU history is the way that has
173
   // a hit or is refilled. It is also one-hot encoded.
174
   reg [OPTION_DCACHE_WAYS-1:0]       access;
175
 
176
   // The current LRU history as read from tag memory and the update
177
   // value after we accessed it to write back to tag memory.
178
   wire [TAG_LRU_WIDTH_BITS-1:0]      current_lru_history;
179
   wire [TAG_LRU_WIDTH_BITS-1:0]      next_lru_history;
180
 
181
   // Intermediate signals to ease debugging
182
   wire [TAG_WIDTH-1:0]               check_way_tag [OPTION_DCACHE_WAYS-1:0];
183
   wire                               check_way_match [OPTION_DCACHE_WAYS-1:0];
184
   wire                               check_way_valid [OPTION_DCACHE_WAYS-1:0];
185
 
186
   reg                                write_pending;
187
 
188
   // Extract index to read from snooped address
189
   wire [OPTION_DCACHE_SET_WIDTH-1:0] snoop_index;
190
   assign snoop_index = snoop_adr_i[WAY_WIDTH-1:OPTION_DCACHE_BLOCK_WIDTH];
191
 
192
   // Register that is high one cycle after the actual snoop event to
193
   // drive the comparison
194
   reg                                snoop_check;
195
   // Register that stores the tag for one cycle
196
   reg [TAG_WIDTH-1:0]                 snoop_tag;
197
   // Also store the index for one cycle, for the succeeding write access
198
   reg [OPTION_DCACHE_SET_WIDTH-1:0]  snoop_windex;
199
 
200
   // Snoop tag memory interface
201
   // Data out of tag memory
202
   wire [TAGMEM_WIDTH-1:0]             snoop_dout;
203
   // Each ways information in the tag memory
204
   wire [TAGMEM_WAY_WIDTH-1:0]         snoop_way_out [OPTION_DCACHE_WAYS-1:0];
205
   // Each ways tag in the tag memory
206
   wire [TAG_WIDTH-1:0]        snoop_check_way_tag [OPTION_DCACHE_WAYS-1:0];
207
   // Whether the tag matches the snoop tag
208
   wire                               snoop_check_way_match [OPTION_DCACHE_WAYS-1:0];
209
   // Whether the tag is valid
210
   wire                               snoop_check_way_valid [OPTION_DCACHE_WAYS-1:0];
211
   // Whether the way hits
212
   wire [OPTION_DCACHE_WAYS-1:0]      snoop_way_hit;
213
   // Whether any way hits
214
   wire                               snoop_hit;
215
 
216
   assign snoop_hit_o = (OPTION_DCACHE_SNOOP != "NONE") ? snoop_hit : 0;
217
 
218
   genvar                             i;
219
 
220
   assign cpu_ack_o = ((read | refill) & hit & !write_pending |
221
                       refill_hit) & cpu_req_i & !snoop_hit;
222
 
223
   assign tag_rindex = cpu_adr_i[WAY_WIDTH-1:OPTION_DCACHE_BLOCK_WIDTH];
224
 
225
   assign tag_tag = cpu_adr_match_i[OPTION_DCACHE_LIMIT_WIDTH-1:WAY_WIDTH];
226
   assign tag_wtag = wradr_i[OPTION_DCACHE_LIMIT_WIDTH-1:WAY_WIDTH];
227
 
228
   generate
229
      if (OPTION_DCACHE_WAYS >= 2) begin
230
         // Multiplex the LRU history from and to tag memory
231
         assign current_lru_history = tag_dout[TAG_LRU_MSB:TAG_LRU_LSB];
232
         assign tag_din[TAG_LRU_MSB:TAG_LRU_LSB] = tag_lru_in;
233
         assign tag_lru_out = tag_dout[TAG_LRU_MSB:TAG_LRU_LSB];
234
      end
235
 
236
      for (i = 0; i < OPTION_DCACHE_WAYS; i=i+1) begin : ways
237
         assign way_raddr[i] = cpu_adr_i[WAY_WIDTH-1:2];
238
         assign way_waddr[i] = write ? cpu_adr_match_i[WAY_WIDTH-1:2] :
239
                               wradr_i[WAY_WIDTH-1:2];
240
         assign way_din[i] = way_wr_dat;
241
 
242
         // compare stored tag with incoming tag and check valid bit
243
         assign check_way_tag[i] = tag_way_out[i][TAG_WIDTH-1:0];
244
         assign check_way_match[i] = (check_way_tag[i] == tag_tag);
245
         assign check_way_valid[i] = tag_way_out[i][TAGMEM_WAY_VALID];
246
 
247
         assign way_hit[i] = check_way_valid[i] & check_way_match[i];
248
 
249
         // Multiplex the way entries in the tag memory
250
         assign tag_din[(i+1)*TAGMEM_WAY_WIDTH-1:i*TAGMEM_WAY_WIDTH] = tag_way_in[i];
251
         assign tag_way_out[i] = tag_dout[(i+1)*TAGMEM_WAY_WIDTH-1:i*TAGMEM_WAY_WIDTH];
252
 
253
         if (OPTION_DCACHE_SNOOP != "NONE") begin
254
            // The same for the snoop tag memory
255
            assign snoop_way_out[i] = snoop_dout[(i+1)*TAGMEM_WAY_WIDTH-1:i*TAGMEM_WAY_WIDTH];
256
 
257
            assign snoop_check_way_tag[i] = snoop_way_out[i][TAG_WIDTH-1:0];
258
            assign snoop_check_way_match[i] = (snoop_check_way_tag[i] == snoop_tag);
259
            assign snoop_check_way_valid[i] = snoop_way_out[i][TAGMEM_WAY_VALID];
260
 
261
            assign snoop_way_hit[i] = snoop_check_way_valid[i] & snoop_check_way_match[i];
262
         end
263
      end
264
   endgenerate
265
 
266
   assign hit = |way_hit;
267
 
268
   assign snoop_hit = (OPTION_DCACHE_SNOOP != "NONE") &
269
                      |snoop_way_hit & snoop_check;
270
 
271
   integer w0;
272
   always @(*) begin
273
      cpu_dat_o = {OPTION_OPERAND_WIDTH{1'bx}};
274
 
275
      // Put correct way on the data port
276
      for (w0 = 0; w0 < OPTION_DCACHE_WAYS; w0 = w0 + 1) begin
277
         if (way_hit[w0] | (refill_hit & tag_save_lru[w0])) begin
278
            cpu_dat_o = way_dout[w0];
279
         end
280
      end
281
   end
282
 
283
   assign next_refill_adr = (OPTION_DCACHE_BLOCK_WIDTH == 5) ?
284
                            {wradr_i[31:5], wradr_i[4:0] + 5'd4} : // 32 byte
285
                            {wradr_i[31:4], wradr_i[3:0] + 4'd4};  // 16 byte
286
 
287
   assign refill_done_o = refill_done;
288
   assign refill_done = refill_valid[next_refill_adr[OPTION_DCACHE_BLOCK_WIDTH-1:2]];
289
   assign refill_hit = refill_valid_r[cpu_adr_match_i[OPTION_DCACHE_BLOCK_WIDTH-1:2]] &
290
                       cpu_adr_match_i[OPTION_DCACHE_LIMIT_WIDTH-1:
291
                                       OPTION_DCACHE_BLOCK_WIDTH] ==
292
                       wradr_i[OPTION_DCACHE_LIMIT_WIDTH-1:
293
                               OPTION_DCACHE_BLOCK_WIDTH] &
294
                       refill & !write_pending;
295
 
296
   assign idle = (state == IDLE);
297
   assign refill = (state == REFILL);
298
   assign read = (state == READ);
299
   assign write = (state == WRITE);
300
 
301
   assign refill_o = refill;
302
 
303
   assign refill_req_o = read & cpu_req_i & !hit & !write_pending & refill_allowed | refill;
304
 
305
   /*
306
    * SPR bus interface
307
    */
308
 
309
   // The SPR interface is used to invalidate the cache blocks. When
310
   // an invalidation is started, the respective entry in the tag
311
   // memory is cleared. When another transfer is in progress, the
312
   // handling is delayed until it is possible to serve it.
313
   //
314
   // The invalidation is acknowledged to the SPR bus, but the cycle
315
   // is terminated by the core. We therefore need to hold the
316
   // invalidate acknowledgement. Meanwhile we continuously write the
317
   // tag memory which is no problem.
318
 
319
   // Net that signals an acknowledgement
320
   reg invalidate_ack;
321
 
322
   // An invalidate request is either a block flush or a block invalidate
323
   assign invalidate = spr_bus_stb_i & spr_bus_we_i &
324
                       (spr_bus_addr_i == `OR1K_SPR_DCBFR_ADDR |
325
                        spr_bus_addr_i == `OR1K_SPR_DCBIR_ADDR);
326
 
327
   // Acknowledge to the SPR bus.
328
   assign spr_bus_ack_o = invalidate_ack;
329
 
330
   /*
331
    * Cache FSM
332
    * Starts in IDLE.
333
    * State changes between READ and WRITE happens cpu_we_i is asserted or not.
334
    * cpu_we_i is in sync with cpu_adr_i, so that means that it's the
335
    * *upcoming* write that it is indicating. It only toggles for one cycle,
336
    * so if we are busy doing something else when this signal comes
337
    * (i.e. refilling) we assert the write_pending signal.
338
    * cpu_req_i is in sync with cpu_adr_match_i, so it can be used to
339
    * determined if a cache hit should cause a refill or if a write should
340
    * really be executed.
341
    */
342
   integer w1;
343
   always @(posedge clk `OR_ASYNC_RST) begin
344
      if (rst) begin
345
         state <= IDLE;
346
         write_pending <= 0;
347
      end else begin
348
         if (cpu_we_i)
349
           write_pending <= 1;
350
         else if (!cpu_req_i)
351
           write_pending <= 0;
352
 
353
         refill_valid_r <= refill_valid;
354
 
355
         if (snoop_valid_i) begin
356
            //
357
            // If there is a snoop event, we need to store this
358
            // information. This happens independent of whether we
359
            // have a snoop tag memory or not.
360
            //
361
            snoop_check <= 1;
362
            snoop_windex <= snoop_index;
363
            snoop_tag <= snoop_adr_i[OPTION_DCACHE_LIMIT_WIDTH-1:WAY_WIDTH];
364
         end else begin
365
            snoop_check <= 0;
366
         end
367
 
368
         case (state)
369
           IDLE: begin
370
              if (invalidate) begin
371
                 // If there is an invalidation request
372
                 //
373
                 // Store address in invalidate_adr that is muxed to the tag
374
                 // memory write address
375
                 invalidate_adr <= spr_bus_dat_i[WAY_WIDTH-1:OPTION_DCACHE_BLOCK_WIDTH];
376
 
377
                 // Change to invalidate state that actually accesses
378
                 // the tag memory
379
                 state <= INVALIDATE;
380
              end else if (cpu_we_i | write_pending)
381
                state <= WRITE;
382
              else if (cpu_req_i)
383
                state <= READ;
384
           end
385
 
386
           READ: begin
387
              if (dc_access_i | cpu_we_i & dc_enable_i) begin
388
                 if (!hit & cpu_req_i & !write_pending & refill_allowed) begin
389
                    refill_valid <= 0;
390
                    refill_valid_r <= 0;
391
 
392
                    // Store the LRU information for correct replacement
393
                    // on refill. Always one when only one way.
394
                    tag_save_lru <= (OPTION_DCACHE_WAYS==1) | lru;
395
 
396
                    for (w1 = 0; w1 < OPTION_DCACHE_WAYS; w1 = w1 + 1) begin
397
                       tag_way_save[w1] <= tag_way_out[w1];
398
                    end
399
 
400
                    state <= REFILL;
401
                 end else if (cpu_we_i | write_pending) begin
402
                    state <= WRITE;
403
                 end else if (invalidate) begin
404
                    state <= IDLE;
405
                 end
406
              end else if (!dc_enable_i | invalidate) begin
407
                 state <= IDLE;
408
              end
409
           end
410
 
411
           REFILL: begin
412
              if (we_i) begin
413
                 refill_valid[wradr_i[OPTION_DCACHE_BLOCK_WIDTH-1:2]] <= 1;
414
 
415
                 if (refill_done)
416
                   state <= IDLE;
417
              end
418
              // Abort refill on snoop-hit
419
              // TODO: only abort on snoop-hits to refill address
420
              if (snoop_hit) begin
421
                 refill_valid <= 0;
422
                 refill_valid_r <= 0;
423
                 state <= IDLE;
424
              end
425
           end
426
 
427
           WRITE: begin
428
              if ((!dc_access_i | !cpu_req_i | !cpu_we_i) & !snoop_hit) begin
429
                 write_pending <= 0;
430
                 state <= READ;
431
              end
432
           end
433
 
434
           INVALIDATE: begin
435
              if (invalidate) begin
436
                 // Store address in invalidate_adr that is muxed to the tag
437
                 // memory write address
438
                 invalidate_adr <= spr_bus_dat_i[WAY_WIDTH-1:OPTION_DCACHE_BLOCK_WIDTH];
439
 
440
                 state <= INVALIDATE;
441
              end else begin
442
                 state <= IDLE;
443
              end
444
           end
445
 
446
           default:
447
             state <= IDLE;
448
         endcase
449
      end
450
   end
451
 
452
   //
453
   // This is the combinational part of the state machine that
454
   // interfaces the tag and way memories.
455
   //
456
   integer w2;
457
   always @(*) begin
458
      // Default is to keep data, don't write and don't access
459
      tag_lru_in = tag_lru_out;
460
      for (w2 = 0; w2 < OPTION_DCACHE_WAYS; w2 = w2 + 1) begin
461
         tag_way_in[w2] = tag_way_out[w2];
462
      end
463
 
464
      tag_we = 1'b0;
465
      way_we = {(OPTION_DCACHE_WAYS){1'b0}};
466
 
467
      access = {(OPTION_DCACHE_WAYS){1'b0}};
468
 
469
      way_wr_dat = wrdat_i;
470
 
471
      // The default is (of course) not to acknowledge the invalidate
472
      invalidate_ack = 1'b0;
473
 
474
      if (snoop_hit) begin
475
         // This is the write access
476
         tag_we = 1'b1;
477
         tag_windex = snoop_windex;
478
         for (w2 = 0; w2 < OPTION_DCACHE_WAYS; w2 = w2 + 1) begin
479
            if (snoop_way_hit[w2]) begin
480
               tag_way_in[w2] = 0;
481
            end else begin
482
               tag_way_in[w2] = snoop_way_out[w2];
483
            end
484
         end
485
      end else begin
486
         //
487
         // The tag mem is written during reads and writes to write
488
         // the lru info and  during refill and invalidate.
489
         //
490
         tag_windex = read | write ?
491
                      cpu_adr_match_i[WAY_WIDTH-1:OPTION_DCACHE_BLOCK_WIDTH] :
492
                      (state == INVALIDATE) ? invalidate_adr :
493
                      wradr_i[WAY_WIDTH-1:OPTION_DCACHE_BLOCK_WIDTH];
494
 
495
         case (state)
496
           IDLE: begin
497
              //
498
              // When idle we can always acknowledge the invalidate as it
499
              // has the highest priority in handling. When something is
500
              // changed on the state machine handling above this needs
501
              // to be changed.
502
              //
503
              invalidate_ack = 1'b1;
504
           end
505
 
506
           READ: begin
507
              if (hit) begin
508
                 //
509
                 // We got a hit. The LRU module gets the access
510
                 // information. Depending on this we update the LRU
511
                 // history in the tag.
512
                 //
513
                 access = way_hit;
514
 
515
                 // This is the updated LRU history after hit
516
                 tag_lru_in = next_lru_history;
517
 
518
                 tag_we = 1'b1;
519
              end
520
           end
521
 
522
           WRITE: begin
523
              way_wr_dat = cpu_dat_i;
524
              if (hit & cpu_req_i) begin
525
                 /* Mux cache output with write data */
526
                 if (!cpu_bsel_i[3])
527
                   way_wr_dat[31:24] = cpu_dat_o[31:24];
528
                 if (!cpu_bsel_i[2])
529
                   way_wr_dat[23:16] = cpu_dat_o[23:16];
530
                 if (!cpu_bsel_i[1])
531
                   way_wr_dat[15:8] = cpu_dat_o[15:8];
532
                 if (!cpu_bsel_i[0])
533
                   way_wr_dat[7:0] = cpu_dat_o[7:0];
534
 
535
              way_we = way_hit;
536
 
537
              tag_lru_in = next_lru_history;
538
 
539
                 tag_we = 1'b1;
540
              end
541
           end
542
 
543
           REFILL: begin
544
              if (we_i) begin
545
                 //
546
                 // Write the data to the way that is replaced (which is
547
                 // the LRU)
548
                 //
549
                 way_we = tag_save_lru;
550
 
551
                 // Access pattern
552
                 access = tag_save_lru;
553
 
554
                 /* Invalidate the way on the first write */
555
                 if (refill_valid == 0) begin
556
                    for (w2 = 0; w2 < OPTION_DCACHE_WAYS; w2 = w2 + 1) begin
557
                       if (tag_save_lru[w2]) begin
558
                          tag_way_in[w2][TAGMEM_WAY_VALID] = 1'b0;
559
                       end
560
                    end
561
 
562
                    tag_we = 1'b1;
563
                 end
564
 
565
                 //
566
                 // After refill update the tag memory entry of the
567
                 // filled way with the LRU history, the tag and set
568
                 // valid to 1.
569
                 //
570
                 if (refill_done) begin
571
                    for (w2 = 0; w2 < OPTION_DCACHE_WAYS; w2 = w2 + 1) begin
572
                       tag_way_in[w2] = tag_way_save[w2];
573
                       if (tag_save_lru[w2]) begin
574
                          tag_way_in[w2] = { 1'b1, tag_wtag };
575
                       end
576
                    end
577
                    tag_lru_in = next_lru_history;
578
 
579
                    tag_we = 1'b1;
580
                 end
581
              end
582
           end
583
 
584
           INVALIDATE: begin
585
              invalidate_ack = 1'b1;
586
 
587
              // Lazy invalidation, invalidate everything that matches tag address
588
              tag_lru_in = 0;
589
              for (w2 = 0; w2 < OPTION_DCACHE_WAYS; w2 = w2 + 1) begin
590
                 tag_way_in[w2] = 0;
591
              end
592
 
593
              tag_we = 1'b1;
594
           end
595
 
596
           default: begin
597
           end
598
         endcase
599
      end
600
   end
601
 
602
   generate
603
      for (i = 0; i < OPTION_DCACHE_WAYS; i=i+1) begin : way_memories
604
         mor1kx_simple_dpram_sclk
605
               #(
606
                 .ADDR_WIDTH(WAY_WIDTH-2),
607
                 .DATA_WIDTH(OPTION_OPERAND_WIDTH),
608
                 .ENABLE_BYPASS(1)
609
                 )
610
         way_data_ram
611
               (
612
                // Outputs
613
                .dout                   (way_dout[i]),
614
                // Inputs
615
                .clk                    (clk),
616
                .raddr                  (way_raddr[i][WAY_WIDTH-3:0]),
617
                .re                     (1'b1),
618
                .waddr                  (way_waddr[i][WAY_WIDTH-3:0]),
619
                .we                     (way_we[i]),
620
                .din                    (way_din[i][31:0]));
621
 
622
      end
623
 
624
      if (OPTION_DCACHE_WAYS >= 2) begin : gen_u_lru
625
         /* mor1kx_cache_lru AUTO_TEMPLATE(
626
          .current  (current_lru_history),
627
          .update   (next_lru_history),
628
          .lru_pre  (lru),
629
          .lru_post (),
630
          .access   (access),
631
          ); */
632
 
633
         mor1kx_cache_lru
634
           #(.NUMWAYS(OPTION_DCACHE_WAYS))
635
         u_lru(/*AUTOINST*/
636
               // Outputs
637
               .update                  (next_lru_history),      // Templated
638
               .lru_pre                 (lru),                   // Templated
639
               .lru_post                (),                      // Templated
640
               // Inputs
641
               .current                 (current_lru_history),   // Templated
642
               .access                  (access));               // Templated
643
      end // if (OPTION_DCACHE_WAYS >= 2)
644
   endgenerate
645
 
646
   mor1kx_simple_dpram_sclk
647
     #(
648
       .ADDR_WIDTH(OPTION_DCACHE_SET_WIDTH),
649
       .DATA_WIDTH(TAGMEM_WIDTH),
650
       .ENABLE_BYPASS(OPTION_DCACHE_SNOOP != "NONE")
651
     )
652
   tag_ram
653
     (
654
      // Outputs
655
      .dout                             (tag_dout[TAGMEM_WIDTH-1:0]),
656
      // Inputs
657
      .clk                              (clk),
658
      .raddr                            (tag_rindex),
659
      .re                               (1'b1),
660
      .waddr                            (tag_windex),
661
      .we                               (tag_we),
662
      .din                              (tag_din));
663
 
664
generate
665
if (OPTION_DCACHE_SNOOP != "NONE") begin
666
   mor1kx_simple_dpram_sclk
667
     #(
668
       .ADDR_WIDTH(OPTION_DCACHE_SET_WIDTH),
669
       .DATA_WIDTH(TAGMEM_WIDTH),
670
       .ENABLE_BYPASS(1)
671
       )
672
   snoop_tag_ram
673
     (
674
      // Outputs
675
      .dout                     (snoop_dout[TAGMEM_WIDTH-1:0]),
676
      // Inputs
677
      .clk                      (clk),
678
      .raddr                    (snoop_index),
679
      .re                       (1'b1),
680
      .waddr                    (tag_windex),
681
      .we                       (tag_we),
682
      .din                      (tag_din));
683
end
684
endgenerate
685
 
686
endmodule

powered by: WebSVN 2.1.0

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