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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gdb-6.8/] [sim/] [frv/] [cache.c] - Blame information for rev 298

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

Line No. Rev Author Line
1 24 jeremybenn
/* frv cache model.
2
   Copyright (C) 1999, 2000, 2001, 2003, 2007, 2008
3
   Free Software Foundation, Inc.
4
   Contributed by Red Hat.
5
 
6
This file is part of the GNU simulators.
7
 
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 3 of the License, or
11
(at your option) any later version.
12
 
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
GNU General Public License for more details.
17
 
18
You should have received a copy of the GNU General Public License
19
along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
 
21
#define WANT_CPU frvbf
22
#define WANT_CPU_FRVBF
23
 
24
#include "libiberty.h"
25
#include "sim-main.h"
26
#include "cache.h"
27
#include "bfd.h"
28
 
29
void
30
frv_cache_init (SIM_CPU *cpu, FRV_CACHE *cache)
31
{
32
  int elements;
33
  int i, j;
34
  SIM_DESC sd;
35
 
36
  /* Set defaults for fields which are not initialized.  */
37
  sd = CPU_STATE (cpu);
38
  switch (STATE_ARCHITECTURE (sd)->mach)
39
    {
40
    case bfd_mach_fr400:
41
    case bfd_mach_fr450:
42
      if (cache->configured_sets == 0)
43
        cache->configured_sets = 512;
44
      if (cache->configured_ways == 0)
45
        cache->configured_ways = 2;
46
      if (cache->line_size == 0)
47
        cache->line_size = 32;
48
      if (cache->memory_latency == 0)
49
        cache->memory_latency = 20;
50
      break;
51
    case bfd_mach_fr550:
52
      if (cache->configured_sets == 0)
53
        cache->configured_sets = 128;
54
      if (cache->configured_ways == 0)
55
        cache->configured_ways = 4;
56
      if (cache->line_size == 0)
57
        cache->line_size = 64;
58
      if (cache->memory_latency == 0)
59
        cache->memory_latency = 20;
60
      break;
61
    default:
62
      if (cache->configured_sets == 0)
63
        cache->configured_sets = 64;
64
      if (cache->configured_ways == 0)
65
        cache->configured_ways = 4;
66
      if (cache->line_size == 0)
67
        cache->line_size = 64;
68
      if (cache->memory_latency == 0)
69
        cache->memory_latency = 20;
70
      break;
71
    }
72
 
73
  frv_cache_reconfigure (cpu, cache);
74
 
75
  /* First allocate the cache storage based on the given dimensions.  */
76
  elements = cache->sets * cache->ways;
77
  cache->tag_storage = (FRV_CACHE_TAG *)
78
    zalloc (elements * sizeof (*cache->tag_storage));
79
  cache->data_storage = (char *) xmalloc (elements * cache->line_size);
80
 
81
  /* Initialize the pipelines and status buffers.  */
82
  for (i = LS; i < FRV_CACHE_PIPELINES; ++i)
83
    {
84
      cache->pipeline[i].requests = NULL;
85
      cache->pipeline[i].status.flush.valid = 0;
86
      cache->pipeline[i].status.return_buffer.valid = 0;
87
      cache->pipeline[i].status.return_buffer.data
88
        = (char *) xmalloc (cache->line_size);
89
      for (j = FIRST_STAGE; j < FRV_CACHE_STAGES; ++j)
90
        cache->pipeline[i].stages[j].request = NULL;
91
    }
92
  cache->BARS.valid = 0;
93
  cache->NARS.valid = 0;
94
 
95
  /* Now set the cache state.  */
96
  cache->cpu = cpu;
97
  cache->statistics.accesses = 0;
98
  cache->statistics.hits = 0;
99
}
100
 
101
void
102
frv_cache_term (FRV_CACHE *cache)
103
{
104
  /* Free the cache storage.  */
105
  free (cache->tag_storage);
106
  free (cache->data_storage);
107
  free (cache->pipeline[LS].status.return_buffer.data);
108
  free (cache->pipeline[LD].status.return_buffer.data);
109
}
110
 
111
/* Reset the cache configuration based on registers in the cpu.  */
112
void
113
frv_cache_reconfigure (SIM_CPU *current_cpu, FRV_CACHE *cache)
114
{
115
  int ihsr8;
116
  int icdm;
117
  SIM_DESC sd;
118
 
119
  /* Set defaults for fields which are not initialized.  */
120
  sd = CPU_STATE (current_cpu);
121
  switch (STATE_ARCHITECTURE (sd)->mach)
122
    {
123
    case bfd_mach_fr550:
124
      if (cache == CPU_INSN_CACHE (current_cpu))
125
        {
126
          ihsr8 = GET_IHSR8 ();
127
          icdm = GET_IHSR8_ICDM (ihsr8);
128
          /* If IHSR8.ICDM is set, then the cache becomes a one way cache.  */
129
          if (icdm)
130
            {
131
              cache->sets = cache->sets * cache->ways;
132
              cache->ways = 1;
133
              break;
134
            }
135
        }
136
      /* fall through */
137
    default:
138
      /* Set the cache to its original settings.  */
139
      cache->sets = cache->configured_sets;
140
      cache->ways = cache->configured_ways;
141
      break;
142
    }
143
}
144
 
145
/* Determine whether the given cache is enabled.  */
146
int
147
frv_cache_enabled (FRV_CACHE *cache)
148
{
149
  SIM_CPU *current_cpu = cache->cpu;
150
  int hsr0 = GET_HSR0 ();
151
  if (GET_HSR0_ICE (hsr0) && cache == CPU_INSN_CACHE (current_cpu))
152
    return 1;
153
  if (GET_HSR0_DCE (hsr0) && cache == CPU_DATA_CACHE (current_cpu))
154
    return 1;
155
  return 0;
156
}
157
 
158
/* Determine whether the given address is RAM access, assuming that HSR0.RME
159
   is set.  */
160
static int
161
ram_access (FRV_CACHE *cache, USI address)
162
{
163
  int ihsr8;
164
  int cwe;
165
  USI start, end, way_size;
166
  SIM_CPU *current_cpu = cache->cpu;
167
  SIM_DESC sd = CPU_STATE (current_cpu);
168
 
169
  switch (STATE_ARCHITECTURE (sd)->mach)
170
    {
171
    case bfd_mach_fr550:
172
      /* IHSR8.DCWE or IHSR8.ICWE deternines which ways get RAM access.  */
173
      ihsr8 = GET_IHSR8 ();
174
      if (cache == CPU_INSN_CACHE (current_cpu))
175
        {
176
          start = 0xfe000000;
177
          end = 0xfe008000;
178
          cwe = GET_IHSR8_ICWE (ihsr8);
179
        }
180
      else
181
        {
182
          start = 0xfe400000;
183
          end = 0xfe408000;
184
          cwe = GET_IHSR8_DCWE (ihsr8);
185
        }
186
      way_size = (end - start) / 4;
187
      end -= way_size * cwe;
188
      return address >= start && address < end;
189
    default:
190
      break;
191
    }
192
 
193
  return 1; /* RAM access */
194
}
195
 
196
/* Determine whether the given address should be accessed without using
197
   the cache.  */
198
static int
199
non_cache_access (FRV_CACHE *cache, USI address)
200
{
201
  int hsr0;
202
  SIM_DESC sd;
203
  SIM_CPU *current_cpu = cache->cpu;
204
 
205
  sd = CPU_STATE (current_cpu);
206
  switch (STATE_ARCHITECTURE (sd)->mach)
207
    {
208
    case bfd_mach_fr400:
209
    case bfd_mach_fr450:
210
      if (address >= 0xff000000
211
          || address >= 0xfe000000 && address <= 0xfeffffff)
212
        return 1; /* non-cache access */
213
      break;
214
    case bfd_mach_fr550:
215
      if (address >= 0xff000000
216
          || address >= 0xfeff0000 && address <= 0xfeffffff)
217
        return 1; /* non-cache access */
218
      if (cache == CPU_INSN_CACHE (current_cpu))
219
        {
220
          if (address >= 0xfe000000 && address <= 0xfe007fff)
221
            return 1; /* non-cache access */
222
        }
223
      else if (address >= 0xfe400000 && address <= 0xfe407fff)
224
        return 1; /* non-cache access */
225
      break;
226
    default:
227
      if (address >= 0xff000000
228
          || address >= 0xfeff0000 && address <= 0xfeffffff)
229
        return 1; /* non-cache access */
230
      if (cache == CPU_INSN_CACHE (current_cpu))
231
        {
232
          if (address >= 0xfe000000 && address <= 0xfe003fff)
233
            return 1; /* non-cache access */
234
        }
235
      else if (address >= 0xfe400000 && address <= 0xfe403fff)
236
        return 1; /* non-cache access */
237
      break;
238
    }
239
 
240
  hsr0 = GET_HSR0 ();
241
  if (GET_HSR0_RME (hsr0))
242
    return ram_access (cache, address);
243
 
244
  return 0; /* cache-access */
245
}
246
 
247
/* Find the cache line corresponding to the given address.
248
   If it is found then 'return_tag' is set to point to the tag for that line
249
   and 1 is returned.
250
   If it is not found, 'return_tag' is set to point to the tag for the least
251
   recently used line and 0 is returned.
252
*/
253
static int
254
get_tag (FRV_CACHE *cache, SI address, FRV_CACHE_TAG **return_tag)
255
{
256
  int set;
257
  int way;
258
  int bits;
259
  USI tag;
260
  FRV_CACHE_TAG *found;
261
  FRV_CACHE_TAG *available;
262
 
263
  ++cache->statistics.accesses;
264
 
265
  /* First calculate which set this address will fall into. Do this by
266
     shifting out the bits representing the offset within the line and
267
     then keeping enough bits to index the set.  */
268
  set = address & ~(cache->line_size - 1);
269
  for (bits = cache->line_size - 1; bits != 0; bits >>= 1)
270
    set >>= 1;
271
  set &= (cache->sets - 1);
272
 
273
  /* Now search the set for a valid tag which matches this address.  At the
274
     same time make note of the least recently used tag, which we will return
275
     if no match is found.  */
276
  available = NULL;
277
  tag = CACHE_ADDRESS_TAG (cache, address);
278
  for (way = 0; way < cache->ways; ++way)
279
    {
280
      found = CACHE_TAG (cache, set, way);
281
      /* This tag is available as the least recently used if it is the
282
         least recently used seen so far and it is not locked.  */
283
      if (! found->locked && (available == NULL || available->lru > found->lru))
284
        available = found;
285
      if (found->valid && found->tag == tag)
286
        {
287
          *return_tag = found;
288
          ++cache->statistics.hits;
289
          return 1; /* found it */
290
        }
291
    }
292
 
293
  *return_tag = available;
294
  return 0; /* not found */
295
}
296
 
297
/* Write the given data out to memory.  */
298
static void
299
write_data_to_memory (FRV_CACHE *cache, SI address, char *data, int length)
300
{
301
  SIM_CPU *cpu = cache->cpu;
302
  IADDR pc = CPU_PC_GET (cpu);
303
  int write_index = 0;
304
 
305
  switch (length)
306
    {
307
    case 1:
308
    default:
309
      PROFILE_COUNT_WRITE (cpu, address, MODE_QI);
310
      break;
311
    case 2:
312
      PROFILE_COUNT_WRITE (cpu, address, MODE_HI);
313
      break;
314
    case 4:
315
      PROFILE_COUNT_WRITE (cpu, address, MODE_SI);
316
      break;
317
    case 8:
318
      PROFILE_COUNT_WRITE (cpu, address, MODE_DI);
319
      break;
320
    }
321
 
322
  for (write_index = 0; write_index < length; ++write_index)
323
    {
324
      /* TODO: Better way to copy memory than a byte at a time?  */
325
      sim_core_write_unaligned_1 (cpu, pc, write_map, address + write_index,
326
                                  data[write_index]);
327
    }
328
}
329
 
330
/* Write a cache line out to memory.  */
331
static void
332
write_line_to_memory (FRV_CACHE *cache, FRV_CACHE_TAG *tag)
333
{
334
  SI address = tag->tag;
335
  int set = CACHE_TAG_SET_NUMBER (cache, tag);
336
  int bits;
337
  for (bits = cache->line_size - 1; bits != 0; bits >>= 1)
338
    set <<= 1;
339
  address |= set;
340
  write_data_to_memory (cache, address, tag->line, cache->line_size);
341
}
342
 
343
static void
344
read_data_from_memory (SIM_CPU *current_cpu, SI address, char *buffer,
345
                       int length)
346
{
347
  PCADDR pc = CPU_PC_GET (current_cpu);
348
  int i;
349
  PROFILE_COUNT_READ (current_cpu, address, MODE_QI);
350
  for (i = 0; i < length; ++i)
351
    {
352
      /* TODO: Better way to copy memory than a byte at a time?  */
353
      buffer[i] = sim_core_read_unaligned_1 (current_cpu, pc, read_map,
354
                                             address + i);
355
    }
356
}
357
 
358
/* Fill the given cache line from memory.  */
359
static void
360
fill_line_from_memory (FRV_CACHE *cache, FRV_CACHE_TAG *tag, SI address)
361
{
362
  PCADDR pc;
363
  int line_alignment;
364
  SI read_address;
365
  SIM_CPU *current_cpu = cache->cpu;
366
 
367
  /* If this line is already valid and the cache is in copy-back mode, then
368
     write this line to memory before refilling it.
369
     Check the dirty bit first, since it is less likely to be set.  */
370
  if (tag->dirty && tag->valid)
371
    {
372
      int hsr0 = GET_HSR0 ();
373
      if (GET_HSR0_CBM (hsr0))
374
        write_line_to_memory (cache, tag);
375
    }
376
  else if (tag->line == NULL)
377
    {
378
      int line_index = tag - cache->tag_storage;
379
      tag->line = cache->data_storage + (line_index * cache->line_size);
380
    }
381
 
382
  pc = CPU_PC_GET (current_cpu);
383
  line_alignment = cache->line_size - 1;
384
  read_address = address & ~line_alignment;
385
  read_data_from_memory (current_cpu, read_address, tag->line,
386
                         cache->line_size);
387
  tag->tag = CACHE_ADDRESS_TAG (cache, address);
388
  tag->valid = 1;
389
}
390
 
391
/* Update the LRU information for the tags in the same set as the given tag.  */
392
static void
393
set_most_recently_used (FRV_CACHE *cache, FRV_CACHE_TAG *tag)
394
{
395
  /* All tags in the same set are contiguous, so find the beginning of the
396
     set by aligning to the size of a set.  */
397
  FRV_CACHE_TAG *item = cache->tag_storage + CACHE_TAG_SET_START (cache, tag);
398
  FRV_CACHE_TAG *limit = item + cache->ways;
399
 
400
  while (item < limit)
401
    {
402
      if (item->lru > tag->lru)
403
        --item->lru;
404
      ++item;
405
    }
406
  tag->lru = cache->ways; /* Mark as most recently used.  */
407
}
408
 
409
/* Update the LRU information for the tags in the same set as the given tag.  */
410
static void
411
set_least_recently_used (FRV_CACHE *cache, FRV_CACHE_TAG *tag)
412
{
413
  /* All tags in the same set are contiguous, so find the beginning of the
414
     set by aligning to the size of a set.  */
415
  FRV_CACHE_TAG *item = cache->tag_storage + CACHE_TAG_SET_START (cache, tag);
416
  FRV_CACHE_TAG *limit = item + cache->ways;
417
 
418
  while (item < limit)
419
    {
420
      if (item->lru != 0 && item->lru < tag->lru)
421
        ++item->lru;
422
      ++item;
423
    }
424
  tag->lru = 0; /* Mark as least recently used.  */
425
}
426
 
427
/* Find the line containing the given address and load it if it is not
428
   already loaded.
429
   Returns the tag of the requested line.  */
430
static FRV_CACHE_TAG *
431
find_or_retrieve_cache_line (FRV_CACHE *cache, SI address)
432
{
433
  /* See if this data is already in the cache.  */
434
  FRV_CACHE_TAG *tag;
435
  int found = get_tag (cache, address, &tag);
436
 
437
  /* Fill the line from memory, if it is not valid.  */
438
  if (! found)
439
    {
440
      /* The tag could be NULL is all ways in the set were used and locked.  */
441
      if (tag == NULL)
442
        return tag;
443
 
444
      fill_line_from_memory (cache, tag, address);
445
      tag->dirty = 0;
446
    }
447
 
448
  /* Update the LRU information for the tags in this set.  */
449
  set_most_recently_used (cache, tag);
450
 
451
  return tag;
452
}
453
 
454
static void
455
copy_line_to_return_buffer (FRV_CACHE *cache, int pipe, FRV_CACHE_TAG *tag,
456
                            SI address)
457
{
458
  /* A cache line was available for the data.
459
     Copy the data from the cache line to the output buffer.  */
460
  memcpy (cache->pipeline[pipe].status.return_buffer.data,
461
          tag->line, cache->line_size);
462
  cache->pipeline[pipe].status.return_buffer.address
463
    = address & ~(cache->line_size - 1);
464
  cache->pipeline[pipe].status.return_buffer.valid = 1;
465
}
466
 
467
static void
468
copy_memory_to_return_buffer (FRV_CACHE *cache, int pipe, SI address)
469
{
470
  address &= ~(cache->line_size - 1);
471
  read_data_from_memory (cache->cpu, address,
472
                         cache->pipeline[pipe].status.return_buffer.data,
473
                         cache->line_size);
474
  cache->pipeline[pipe].status.return_buffer.address = address;
475
  cache->pipeline[pipe].status.return_buffer.valid = 1;
476
}
477
 
478
static void
479
set_return_buffer_reqno (FRV_CACHE *cache, int pipe, unsigned reqno)
480
{
481
  cache->pipeline[pipe].status.return_buffer.reqno = reqno;
482
}
483
 
484
/* Read data from the given cache.
485
   Returns the number of cycles required to obtain the data.  */
486
int
487
frv_cache_read (FRV_CACHE *cache, int pipe, SI address)
488
{
489
  FRV_CACHE_TAG *tag;
490
 
491
  if (non_cache_access (cache, address))
492
    {
493
      copy_memory_to_return_buffer (cache, pipe, address);
494
      return 1;
495
    }
496
 
497
  tag = find_or_retrieve_cache_line (cache, address);
498
 
499
  if (tag == NULL)
500
    return 0; /* Indicate non-cache-access.  */
501
 
502
  /* A cache line was available for the data.
503
     Copy the data from the cache line to the output buffer.  */
504
  copy_line_to_return_buffer (cache, pipe, tag, address);
505
 
506
  return 1; /* TODO - number of cycles unknown */
507
}
508
 
509
/* Writes data through the given cache.
510
   The data is assumed to be in target endian order.
511
   Returns the number of cycles required to write the data.  */
512
int
513
frv_cache_write (FRV_CACHE *cache, SI address, char *data, unsigned length)
514
{
515
  int copy_back;
516
 
517
  /* See if this data is already in the cache.  */
518
  SIM_CPU *current_cpu = cache->cpu;
519
  USI hsr0 = GET_HSR0 ();
520
  FRV_CACHE_TAG *tag;
521
  int found;
522
 
523
  if (non_cache_access (cache, address))
524
    {
525
      write_data_to_memory (cache, address, data, length);
526
      return 1;
527
    }
528
 
529
  found = get_tag (cache, address, &tag);
530
 
531
  /* Write the data to the cache line if one was available and if it is
532
     either a hit or a miss in copy-back mode.
533
     The tag may be NULL if all ways were in use and locked on a miss.
534
  */
535
  copy_back = GET_HSR0_CBM (GET_HSR0 ());
536
  if (tag != NULL && (found || copy_back))
537
    {
538
      int line_offset;
539
      /* Load the line from memory first, if it was a miss.  */
540
      if (! found)
541
        fill_line_from_memory (cache, tag, address);
542
      line_offset = address & (cache->line_size - 1);
543
      memcpy (tag->line + line_offset, data, length);
544
      tag->dirty = 1;
545
 
546
      /* Update the LRU information for the tags in this set.  */
547
      set_most_recently_used (cache, tag);
548
    }
549
 
550
  /* Write the data to memory if there was no line available or we are in
551
     write-through (not copy-back mode).  */
552
  if (tag == NULL || ! copy_back)
553
    {
554
      write_data_to_memory (cache, address, data, length);
555
      if (tag != NULL)
556
        tag->dirty = 0;
557
    }
558
 
559
  return 1; /* TODO - number of cycles unknown */
560
}
561
 
562
/* Preload the cache line containing the given address. Lock the
563
   data if requested.
564
   Returns the number of cycles required to write the data.  */
565
int
566
frv_cache_preload (FRV_CACHE *cache, SI address, USI length, int lock)
567
{
568
  int offset;
569
  int lines;
570
 
571
  if (non_cache_access (cache, address))
572
    return 1;
573
 
574
  /* preload at least 1 line.  */
575
  if (length == 0)
576
    length = 1;
577
 
578
  offset = address & (cache->line_size - 1);
579
  lines = 1 + (offset + length - 1) / cache->line_size;
580
 
581
  /* Careful with this loop -- length is unsigned.  */
582
  for (/**/; lines > 0; --lines)
583
    {
584
      FRV_CACHE_TAG *tag = find_or_retrieve_cache_line (cache, address);
585
      if (lock && tag != NULL)
586
        tag->locked = 1;
587
      address += cache->line_size;
588
    }
589
 
590
  return 1; /* TODO - number of cycles unknown */
591
}
592
 
593
/* Unlock the cache line containing the given address.
594
   Returns the number of cycles required to unlock the line.  */
595
int
596
frv_cache_unlock (FRV_CACHE *cache, SI address)
597
{
598
  FRV_CACHE_TAG *tag;
599
  int found;
600
 
601
  if (non_cache_access (cache, address))
602
    return 1;
603
 
604
  found = get_tag (cache, address, &tag);
605
 
606
  if (found)
607
    tag->locked = 0;
608
 
609
  return 1; /* TODO - number of cycles unknown */
610
}
611
 
612
static void
613
invalidate_return_buffer (FRV_CACHE *cache, SI address)
614
{
615
  /* If this address is in one of the return buffers, then invalidate that
616
     return buffer.  */
617
  address &= ~(cache->line_size - 1);
618
  if (address == cache->pipeline[LS].status.return_buffer.address)
619
    cache->pipeline[LS].status.return_buffer.valid = 0;
620
  if (address == cache->pipeline[LD].status.return_buffer.address)
621
    cache->pipeline[LD].status.return_buffer.valid = 0;
622
}
623
 
624
/* Invalidate the cache line containing the given address. Flush the
625
   data if requested.
626
   Returns the number of cycles required to write the data.  */
627
int
628
frv_cache_invalidate (FRV_CACHE *cache, SI address, int flush)
629
{
630
  /* See if this data is already in the cache.  */
631
  FRV_CACHE_TAG *tag;
632
  int found;
633
 
634
  /* Check for non-cache access.  This operation is still perfromed even if
635
     the cache is not currently enabled.  */
636
  if (non_cache_access (cache, address))
637
    return 1;
638
 
639
  /* If the line is found, invalidate it. If a flush is requested, then flush
640
     it if it is dirty.  */
641
  found = get_tag (cache, address, &tag);
642
  if (found)
643
    {
644
      SIM_CPU *cpu;
645
      /* If a flush is requested, then flush it if it is dirty.  */
646
      if (tag->dirty && flush)
647
        write_line_to_memory (cache, tag);
648
      set_least_recently_used (cache, tag);
649
      tag->valid = 0;
650
      tag->locked = 0;
651
 
652
      /* If this is the insn cache, then flush the cpu's scache as well.  */
653
      cpu = cache->cpu;
654
      if (cache == CPU_INSN_CACHE (cpu))
655
        scache_flush_cpu (cpu);
656
    }
657
 
658
  invalidate_return_buffer (cache, address);
659
 
660
  return 1; /* TODO - number of cycles unknown */
661
}
662
 
663
/* Invalidate the entire cache. Flush the data if requested.  */
664
int
665
frv_cache_invalidate_all (FRV_CACHE *cache, int flush)
666
{
667
  /* See if this data is already in the cache.  */
668
  int elements = cache->sets * cache->ways;
669
  FRV_CACHE_TAG *tag = cache->tag_storage;
670
  SIM_CPU *cpu;
671
  int i;
672
 
673
  for(i = 0; i < elements; ++i, ++tag)
674
    {
675
      /* If a flush is requested, then flush it if it is dirty.  */
676
      if (tag->valid && tag->dirty && flush)
677
        write_line_to_memory (cache, tag);
678
      tag->valid = 0;
679
      tag->locked = 0;
680
    }
681
 
682
 
683
  /* If this is the insn cache, then flush the cpu's scache as well.  */
684
  cpu = cache->cpu;
685
  if (cache == CPU_INSN_CACHE (cpu))
686
    scache_flush_cpu (cpu);
687
 
688
  /* Invalidate both return buffers.  */
689
  cache->pipeline[LS].status.return_buffer.valid = 0;
690
  cache->pipeline[LD].status.return_buffer.valid = 0;
691
 
692
  return 1; /* TODO - number of cycles unknown */
693
}
694
 
695
/* ---------------------------------------------------------------------------
696
   Functions for operating the cache in cycle accurate mode.
697
   -------------------------------------------------------------------------  */
698
/* Convert a VLIW slot to a cache pipeline index.  */
699
static int
700
convert_slot_to_index (int slot)
701
{
702
  switch (slot)
703
    {
704
    case UNIT_I0:
705
    case UNIT_C:
706
      return LS;
707
    case UNIT_I1:
708
      return LD;
709
    default:
710
      abort ();
711
    }
712
  return 0;
713
}
714
 
715
/* Allocate free chains of cache requests.  */
716
#define FREE_CHAIN_SIZE 16
717
static FRV_CACHE_REQUEST *frv_cache_request_free_chain = NULL;
718
static FRV_CACHE_REQUEST *frv_store_request_free_chain = NULL;
719
 
720
static void
721
allocate_new_cache_requests (void)
722
{
723
  int i;
724
  frv_cache_request_free_chain = xmalloc (FREE_CHAIN_SIZE
725
                                          * sizeof (FRV_CACHE_REQUEST));
726
  for (i = 0; i < FREE_CHAIN_SIZE - 1; ++i)
727
    {
728
      frv_cache_request_free_chain[i].next
729
        = & frv_cache_request_free_chain[i + 1];
730
    }
731
 
732
  frv_cache_request_free_chain[FREE_CHAIN_SIZE - 1].next = NULL;
733
}
734
 
735
/* Return the next free request in the queue for the given cache pipeline.  */
736
static FRV_CACHE_REQUEST *
737
new_cache_request (void)
738
{
739
  FRV_CACHE_REQUEST *req;
740
 
741
  /* Allocate new elements for the free chain if necessary.  */
742
  if (frv_cache_request_free_chain == NULL)
743
    allocate_new_cache_requests ();
744
 
745
  req = frv_cache_request_free_chain;
746
  frv_cache_request_free_chain = req->next;
747
 
748
  return req;
749
}
750
 
751
/* Return the given cache request to the free chain.  */
752
static void
753
free_cache_request (FRV_CACHE_REQUEST *req)
754
{
755
  if (req->kind == req_store)
756
    {
757
      req->next = frv_store_request_free_chain;
758
      frv_store_request_free_chain = req;
759
    }
760
  else
761
    {
762
      req->next = frv_cache_request_free_chain;
763
      frv_cache_request_free_chain = req;
764
    }
765
}
766
 
767
/* Search the free chain for an existing store request with a buffer that's
768
   large enough.  */
769
static FRV_CACHE_REQUEST *
770
new_store_request (int length)
771
{
772
  FRV_CACHE_REQUEST *prev = NULL;
773
  FRV_CACHE_REQUEST *req;
774
  for (req = frv_store_request_free_chain; req != NULL; req = req->next)
775
    {
776
      if (req->u.store.length == length)
777
        break;
778
      prev = req;
779
    }
780
  if (req != NULL)
781
    {
782
      if (prev == NULL)
783
        frv_store_request_free_chain = req->next;
784
      else
785
        prev->next = req->next;
786
      return req;
787
    }
788
 
789
  /* No existing request buffer was found, so make a new one.  */
790
  req = new_cache_request ();
791
  req->kind = req_store;
792
  req->u.store.data = xmalloc (length);
793
  req->u.store.length = length;
794
  return req;
795
}
796
 
797
/* Remove the given request from the given pipeline.  */
798
static void
799
pipeline_remove_request (FRV_CACHE_PIPELINE *p, FRV_CACHE_REQUEST *request)
800
{
801
  FRV_CACHE_REQUEST *next = request->next;
802
  FRV_CACHE_REQUEST *prev = request->prev;
803
 
804
  if (prev == NULL)
805
    p->requests = next;
806
  else
807
    prev->next = next;
808
 
809
  if (next != NULL)
810
    next->prev = prev;
811
}
812
 
813
/* Add the given request to the given pipeline.  */
814
static void
815
pipeline_add_request (FRV_CACHE_PIPELINE *p, FRV_CACHE_REQUEST *request)
816
{
817
  FRV_CACHE_REQUEST *prev = NULL;
818
  FRV_CACHE_REQUEST *item;
819
 
820
  /* Add the request in priority order.  0 is the highest priority.  */
821
  for (item = p->requests; item != NULL; item = item->next)
822
    {
823
      if (item->priority > request->priority)
824
        break;
825
      prev = item;
826
    }
827
 
828
  request->next = item;
829
  request->prev = prev;
830
  if (prev == NULL)
831
    p->requests = request;
832
  else
833
    prev->next = request;
834
  if (item != NULL)
835
    item->prev = request;
836
}
837
 
838
/* Requeu the given request from the last of the given pipeline.  */
839
static void
840
pipeline_requeue_request (FRV_CACHE_PIPELINE *p)
841
{
842
  FRV_CACHE_STAGE *stage = & p->stages[LAST_STAGE];
843
  FRV_CACHE_REQUEST *req = stage->request;
844
  stage->request = NULL;
845
  pipeline_add_request (p, req);
846
}
847
 
848
/* Return the priority lower than the lowest one in this cache pipeline.
849
 
850
static int
851
next_priority (FRV_CACHE *cache, FRV_CACHE_PIPELINE *pipeline)
852
{
853
  int i, j;
854
  int pipe;
855
  int lowest = 0;
856
  FRV_CACHE_REQUEST *req;
857
 
858
  /* Check the priorities of any queued items.  */
859
  for (req = pipeline->requests; req != NULL; req = req->next)
860
    if (req->priority > lowest)
861
      lowest = req->priority;
862
 
863
  /* Check the priorities of items in the pipeline stages.  */
864
  for (i = FIRST_STAGE; i < FRV_CACHE_STAGES; ++i)
865
    {
866
      FRV_CACHE_STAGE *stage = & pipeline->stages[i];
867
      if (stage->request != NULL && stage->request->priority > lowest)
868
        lowest = stage->request->priority;
869
    }
870
 
871
  /* Check the priorities of load requests waiting in WAR.  These are one
872
     higher than the request that spawned them.  */
873
  for (i = 0; i < NUM_WARS; ++i)
874
    {
875
      FRV_CACHE_WAR *war = & pipeline->WAR[i];
876
      if (war->valid && war->priority > lowest)
877
        lowest = war->priority + 1;
878
    }
879
 
880
  /* Check the priorities of any BARS or NARS associated with this pipeline.
881
     These are one higher than the request that spawned them.  */
882
  pipe = pipeline - cache->pipeline;
883
  if (cache->BARS.valid && cache->BARS.pipe == pipe
884
      && cache->BARS.priority > lowest)
885
    lowest = cache->BARS.priority + 1;
886
  if (cache->NARS.valid && cache->NARS.pipe == pipe
887
      && cache->NARS.priority > lowest)
888
    lowest = cache->NARS.priority + 1;
889
 
890
  /* Return a priority 2 lower than the lowest found.  This allows a WAR
891
     request to be generated with a priority greater than this but less than
892
     the next higher priority request.  */
893
  return lowest + 2;
894
}
895
 
896
static void
897
add_WAR_request (FRV_CACHE_PIPELINE* pipeline, FRV_CACHE_WAR *war)
898
{
899
  /* Add the load request to the indexed pipeline.  */
900
  FRV_CACHE_REQUEST *req = new_cache_request ();
901
  req->kind = req_WAR;
902
  req->reqno = war->reqno;
903
  req->priority = war->priority;
904
  req->address = war->address;
905
  req->u.WAR.preload = war->preload;
906
  req->u.WAR.lock = war->lock;
907
  pipeline_add_request (pipeline, req);
908
}
909
 
910
/* Remove the next request from the given pipeline and return it.  */
911
static FRV_CACHE_REQUEST *
912
pipeline_next_request (FRV_CACHE_PIPELINE *p)
913
{
914
  FRV_CACHE_REQUEST *first = p->requests;
915
  if (first != NULL)
916
    pipeline_remove_request (p, first);
917
  return first;
918
}
919
 
920
/* Return the request which is at the given stage of the given pipeline.  */
921
static FRV_CACHE_REQUEST *
922
pipeline_stage_request (FRV_CACHE_PIPELINE *p, int stage)
923
{
924
  return p->stages[stage].request;
925
}
926
 
927
static void
928
advance_pipelines (FRV_CACHE *cache)
929
{
930
  int stage;
931
  int pipe;
932
  FRV_CACHE_PIPELINE *pipelines = cache->pipeline;
933
 
934
  /* Free the final stage requests.  */
935
  for (pipe = 0; pipe < FRV_CACHE_PIPELINES; ++pipe)
936
    {
937
      FRV_CACHE_REQUEST *req = pipelines[pipe].stages[LAST_STAGE].request;
938
      if (req != NULL)
939
        free_cache_request (req);
940
    }
941
 
942
  /* Shuffle the requests along the pipeline.  */
943
  for (stage = LAST_STAGE; stage > FIRST_STAGE; --stage)
944
    {
945
      for (pipe = 0; pipe < FRV_CACHE_PIPELINES; ++pipe)
946
        pipelines[pipe].stages[stage] = pipelines[pipe].stages[stage - 1];
947
    }
948
 
949
  /* Add a new request to the pipeline.  */
950
  for (pipe = 0; pipe < FRV_CACHE_PIPELINES; ++pipe)
951
    pipelines[pipe].stages[FIRST_STAGE].request
952
      = pipeline_next_request (& pipelines[pipe]);
953
}
954
 
955
/* Handle a request for a load from the given address.  */
956
void
957
frv_cache_request_load (FRV_CACHE *cache, unsigned reqno, SI address, int slot)
958
{
959
  FRV_CACHE_REQUEST *req;
960
 
961
  /* slot is a UNIT_*.  Convert it to a cache pipeline index.  */
962
  int pipe = convert_slot_to_index (slot);
963
  FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
964
 
965
  /* Add the load request to the indexed pipeline.  */
966
  req = new_cache_request ();
967
  req->kind = req_load;
968
  req->reqno = reqno;
969
  req->priority = next_priority (cache, pipeline);
970
  req->address = address;
971
 
972
  pipeline_add_request (pipeline, req);
973
}
974
 
975
void
976
frv_cache_request_store (FRV_CACHE *cache, SI address,
977
                         int slot, char *data, unsigned length)
978
{
979
  FRV_CACHE_REQUEST *req;
980
 
981
  /* slot is a UNIT_*.  Convert it to a cache pipeline index.  */
982
  int pipe = convert_slot_to_index (slot);
983
  FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
984
 
985
  /* Add the load request to the indexed pipeline.  */
986
  req = new_store_request (length);
987
  req->kind = req_store;
988
  req->reqno = NO_REQNO;
989
  req->priority = next_priority (cache, pipeline);
990
  req->address = address;
991
  req->u.store.length = length;
992
  memcpy (req->u.store.data, data, length);
993
 
994
  pipeline_add_request (pipeline, req);
995
  invalidate_return_buffer (cache, address);
996
}
997
 
998
/* Handle a request to invalidate the cache line containing the given address.
999
   Flush the data if requested.  */
1000
void
1001
frv_cache_request_invalidate (FRV_CACHE *cache, unsigned reqno, SI address,
1002
                              int slot, int all, int flush)
1003
{
1004
  FRV_CACHE_REQUEST *req;
1005
 
1006
  /* slot is a UNIT_*.  Convert it to a cache pipeline index.  */
1007
  int pipe = convert_slot_to_index (slot);
1008
  FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
1009
 
1010
  /* Add the load request to the indexed pipeline.  */
1011
  req = new_cache_request ();
1012
  req->kind = req_invalidate;
1013
  req->reqno = reqno;
1014
  req->priority = next_priority (cache, pipeline);
1015
  req->address = address;
1016
  req->u.invalidate.all = all;
1017
  req->u.invalidate.flush = flush;
1018
 
1019
  pipeline_add_request (pipeline, req);
1020
}
1021
 
1022
/* Handle a request to preload the cache line containing the given address.  */
1023
void
1024
frv_cache_request_preload (FRV_CACHE *cache, SI address,
1025
                           int slot, int length, int lock)
1026
{
1027
  FRV_CACHE_REQUEST *req;
1028
 
1029
  /* slot is a UNIT_*.  Convert it to a cache pipeline index.  */
1030
  int pipe = convert_slot_to_index (slot);
1031
  FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
1032
 
1033
  /* Add the load request to the indexed pipeline.  */
1034
  req = new_cache_request ();
1035
  req->kind = req_preload;
1036
  req->reqno = NO_REQNO;
1037
  req->priority = next_priority (cache, pipeline);
1038
  req->address = address;
1039
  req->u.preload.length = length;
1040
  req->u.preload.lock = lock;
1041
 
1042
  pipeline_add_request (pipeline, req);
1043
  invalidate_return_buffer (cache, address);
1044
}
1045
 
1046
/* Handle a request to unlock the cache line containing the given address.  */
1047
void
1048
frv_cache_request_unlock (FRV_CACHE *cache, SI address, int slot)
1049
{
1050
  FRV_CACHE_REQUEST *req;
1051
 
1052
  /* slot is a UNIT_*.  Convert it to a cache pipeline index.  */
1053
  int pipe = convert_slot_to_index (slot);
1054
  FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
1055
 
1056
  /* Add the load request to the indexed pipeline.  */
1057
  req = new_cache_request ();
1058
  req->kind = req_unlock;
1059
  req->reqno = NO_REQNO;
1060
  req->priority = next_priority (cache, pipeline);
1061
  req->address = address;
1062
 
1063
  pipeline_add_request (pipeline, req);
1064
}
1065
 
1066
/* Check whether this address interferes with a pending request of
1067
   higher priority.  */
1068
static int
1069
address_interference (FRV_CACHE *cache, SI address, FRV_CACHE_REQUEST *req,
1070
                      int pipe)
1071
{
1072
  int i, j;
1073
  int line_mask = ~(cache->line_size - 1);
1074
  int other_pipe;
1075
  int priority = req->priority;
1076
  FRV_CACHE_REQUEST *other_req;
1077
  SI other_address;
1078
  SI all_address;
1079
 
1080
  address &= line_mask;
1081
  all_address = -1 & line_mask;
1082
 
1083
  /* Check for collisions in the queue for this pipeline.  */
1084
  for (other_req = cache->pipeline[pipe].requests;
1085
       other_req != NULL;
1086
       other_req = other_req->next)
1087
    {
1088
      other_address = other_req->address & line_mask;
1089
      if ((address == other_address || address == all_address)
1090
          && priority > other_req->priority)
1091
        return 1;
1092
    }
1093
 
1094
  /* Check for a collision in the the other pipeline.  */
1095
  other_pipe = pipe ^ 1;
1096
  other_req = cache->pipeline[other_pipe].stages[LAST_STAGE].request;
1097
  if (other_req != NULL)
1098
    {
1099
      other_address = other_req->address & line_mask;
1100
      if (address == other_address || address == all_address)
1101
        return 1;
1102
    }
1103
 
1104
  /* Check for a collision with load requests waiting in WAR.  */
1105
  for (i = LS; i < FRV_CACHE_PIPELINES; ++i)
1106
    {
1107
      for (j = 0; j < NUM_WARS; ++j)
1108
        {
1109
          FRV_CACHE_WAR *war = & cache->pipeline[i].WAR[j];
1110
          if (war->valid
1111
              && (address == (war->address & line_mask)
1112
                  || address == all_address)
1113
              && priority > war->priority)
1114
            return 1;
1115
        }
1116
      /* If this is not a WAR request, then yield to any WAR requests in
1117
         either pipeline or to a higher priority request in the same pipeline.
1118
      */
1119
      if (req->kind != req_WAR)
1120
        {
1121
          for (j = FIRST_STAGE; j < FRV_CACHE_STAGES; ++j)
1122
            {
1123
              other_req = cache->pipeline[i].stages[j].request;
1124
              if (other_req != NULL)
1125
                {
1126
                  if (other_req->kind == req_WAR)
1127
                    return 1;
1128
                  if (i == pipe
1129
                      && (address == (other_req->address & line_mask)
1130
                          || address == all_address)
1131
                      && priority > other_req->priority)
1132
                    return 1;
1133
                }
1134
            }
1135
        }
1136
    }
1137
 
1138
  /* Check for a collision with load requests waiting in ARS.  */
1139
  if (cache->BARS.valid
1140
      && (address == (cache->BARS.address & line_mask)
1141
          || address == all_address)
1142
      && priority > cache->BARS.priority)
1143
    return 1;
1144
  if (cache->NARS.valid
1145
      && (address == (cache->NARS.address & line_mask)
1146
          || address == all_address)
1147
      && priority > cache->NARS.priority)
1148
    return 1;
1149
 
1150
  return 0;
1151
}
1152
 
1153
/* Wait for a free WAR register in BARS or NARS.  */
1154
static void
1155
wait_for_WAR (FRV_CACHE* cache, int pipe, FRV_CACHE_REQUEST *req)
1156
{
1157
  FRV_CACHE_WAR war;
1158
  FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
1159
 
1160
  if (! cache->BARS.valid)
1161
    {
1162
      cache->BARS.pipe = pipe;
1163
      cache->BARS.reqno = req->reqno;
1164
      cache->BARS.address = req->address;
1165
      cache->BARS.priority = req->priority - 1;
1166
      switch (req->kind)
1167
        {
1168
        case req_load:
1169
          cache->BARS.preload = 0;
1170
          cache->BARS.lock = 0;
1171
          break;
1172
        case req_store:
1173
          cache->BARS.preload = 1;
1174
          cache->BARS.lock = 0;
1175
          break;
1176
        case req_preload:
1177
          cache->BARS.preload = 1;
1178
          cache->BARS.lock = req->u.preload.lock;
1179
          break;
1180
        }
1181
      cache->BARS.valid = 1;
1182
      return;
1183
    }
1184
  if (! cache->NARS.valid)
1185
    {
1186
      cache->NARS.pipe = pipe;
1187
      cache->NARS.reqno = req->reqno;
1188
      cache->NARS.address = req->address;
1189
      cache->NARS.priority = req->priority - 1;
1190
      switch (req->kind)
1191
        {
1192
        case req_load:
1193
          cache->NARS.preload = 0;
1194
          cache->NARS.lock = 0;
1195
          break;
1196
        case req_store:
1197
          cache->NARS.preload = 1;
1198
          cache->NARS.lock = 0;
1199
          break;
1200
        case req_preload:
1201
          cache->NARS.preload = 1;
1202
          cache->NARS.lock = req->u.preload.lock;
1203
          break;
1204
        }
1205
      cache->NARS.valid = 1;
1206
      return;
1207
    }
1208
  /* All wait registers are busy, so resubmit this request.  */
1209
  pipeline_requeue_request (pipeline);
1210
}
1211
 
1212
/* Find a free WAR register and wait for memory to fetch the data.  */
1213
static void
1214
wait_in_WAR (FRV_CACHE* cache, int pipe, FRV_CACHE_REQUEST *req)
1215
{
1216
  int war;
1217
  FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
1218
 
1219
  /* Find a valid WAR to  hold this request.  */
1220
  for (war = 0; war < NUM_WARS; ++war)
1221
    if (! pipeline->WAR[war].valid)
1222
      break;
1223
  if (war >= NUM_WARS)
1224
    {
1225
      wait_for_WAR (cache, pipe, req);
1226
      return;
1227
    }
1228
 
1229
  pipeline->WAR[war].address = req->address;
1230
  pipeline->WAR[war].reqno = req->reqno;
1231
  pipeline->WAR[war].priority = req->priority - 1;
1232
  pipeline->WAR[war].latency = cache->memory_latency + 1;
1233
  switch (req->kind)
1234
    {
1235
    case req_load:
1236
      pipeline->WAR[war].preload = 0;
1237
      pipeline->WAR[war].lock = 0;
1238
      break;
1239
    case req_store:
1240
      pipeline->WAR[war].preload = 1;
1241
      pipeline->WAR[war].lock = 0;
1242
      break;
1243
    case req_preload:
1244
      pipeline->WAR[war].preload = 1;
1245
      pipeline->WAR[war].lock = req->u.preload.lock;
1246
      break;
1247
    }
1248
  pipeline->WAR[war].valid = 1;
1249
}
1250
 
1251
static void
1252
handle_req_load (FRV_CACHE *cache, int pipe, FRV_CACHE_REQUEST *req)
1253
{
1254
  FRV_CACHE_TAG *tag;
1255
  SI address = req->address;
1256
 
1257
  /* If this address interferes with an existing request, then requeue it.  */
1258
  if (address_interference (cache, address, req, pipe))
1259
    {
1260
      pipeline_requeue_request (& cache->pipeline[pipe]);
1261
      return;
1262
    }
1263
 
1264
  if (frv_cache_enabled (cache) && ! non_cache_access (cache, address))
1265
    {
1266
      int found = get_tag (cache, address, &tag);
1267
 
1268
      /* If the data was found, return it to the caller.  */
1269
      if (found)
1270
        {
1271
          set_most_recently_used (cache, tag);
1272
          copy_line_to_return_buffer (cache, pipe, tag, address);
1273
          set_return_buffer_reqno (cache, pipe, req->reqno);
1274
          return;
1275
        }
1276
    }
1277
 
1278
  /* The data is not in the cache or this is a non-cache access.  We need to
1279
     wait for the memory unit to fetch it.  Store this request in the WAR in
1280
     the meantime.  */
1281
  wait_in_WAR (cache, pipe, req);
1282
}
1283
 
1284
static void
1285
handle_req_preload (FRV_CACHE *cache, int pipe, FRV_CACHE_REQUEST *req)
1286
{
1287
  int found;
1288
  FRV_CACHE_WAR war;
1289
  FRV_CACHE_TAG *tag;
1290
  int length;
1291
  int lock;
1292
  int offset;
1293
  int lines;
1294
  int line;
1295
  SI address = req->address;
1296
  SI cur_address;
1297
 
1298
  if (! frv_cache_enabled (cache) || non_cache_access (cache, address))
1299
    return;
1300
 
1301
  /* preload at least 1 line.  */
1302
  length = req->u.preload.length;
1303
  if (length == 0)
1304
    length = 1;
1305
 
1306
  /* Make sure that this request does not interfere with a pending request.  */
1307
  offset = address & (cache->line_size - 1);
1308
  lines = 1 + (offset + length - 1) / cache->line_size;
1309
  cur_address = address & ~(cache->line_size - 1);
1310
  for (line = 0; line < lines; ++line)
1311
    {
1312
      /* If this address interferes with an existing request,
1313
         then requeue it.  */
1314
      if (address_interference (cache, cur_address, req, pipe))
1315
        {
1316
          pipeline_requeue_request (& cache->pipeline[pipe]);
1317
          return;
1318
        }
1319
      cur_address += cache->line_size;
1320
    }
1321
 
1322
  /* Now process each cache line.  */
1323
  /* Careful with this loop -- length is unsigned.  */
1324
  lock = req->u.preload.lock;
1325
  cur_address = address & ~(cache->line_size - 1);
1326
  for (line = 0; line < lines; ++line)
1327
    {
1328
      /* If the data was found, then lock it if requested.  */
1329
      found = get_tag (cache, cur_address, &tag);
1330
      if (found)
1331
        {
1332
          if (lock)
1333
            tag->locked = 1;
1334
        }
1335
      else
1336
        {
1337
          /* The data is not in the cache.  We need to wait for the memory
1338
             unit to fetch it.  Store this request in the WAR in the meantime.
1339
          */
1340
          wait_in_WAR (cache, pipe, req);
1341
        }
1342
      cur_address += cache->line_size;
1343
    }
1344
}
1345
 
1346
static void
1347
handle_req_store (FRV_CACHE *cache, int pipe, FRV_CACHE_REQUEST *req)
1348
{
1349
  SIM_CPU *current_cpu;
1350
  FRV_CACHE_TAG *tag;
1351
  int found;
1352
  int copy_back;
1353
  SI address = req->address;
1354
  char *data = req->u.store.data;
1355
  int length = req->u.store.length;
1356
 
1357
  /* If this address interferes with an existing request, then requeue it.  */
1358
  if (address_interference (cache, address, req, pipe))
1359
    {
1360
      pipeline_requeue_request (& cache->pipeline[pipe]);
1361
      return;
1362
    }
1363
 
1364
  /* Non-cache access. Write the data directly to memory.  */
1365
  if (! frv_cache_enabled (cache) || non_cache_access (cache, address))
1366
    {
1367
      write_data_to_memory (cache, address, data, length);
1368
      return;
1369
    }
1370
 
1371
  /* See if the data is in the cache.  */
1372
  found = get_tag (cache, address, &tag);
1373
 
1374
  /* Write the data to the cache line if one was available and if it is
1375
     either a hit or a miss in copy-back mode.
1376
     The tag may be NULL if all ways were in use and locked on a miss.
1377
  */
1378
  current_cpu = cache->cpu;
1379
  copy_back = GET_HSR0_CBM (GET_HSR0 ());
1380
  if (tag != NULL && (found || copy_back))
1381
    {
1382
      int line_offset;
1383
      /* Load the line from memory first, if it was a miss.  */
1384
      if (! found)
1385
        {
1386
          /* We need to wait for the memory unit to fetch the data.
1387
             Store this request in the WAR and requeue the store request.  */
1388
          wait_in_WAR (cache, pipe, req);
1389
          pipeline_requeue_request (& cache->pipeline[pipe]);
1390
          /* Decrement the counts of accesses and hits because when the requeued
1391
             request is processed again, it will appear to be a new access and
1392
             a hit.  */
1393
          --cache->statistics.accesses;
1394
          --cache->statistics.hits;
1395
          return;
1396
        }
1397
      line_offset = address & (cache->line_size - 1);
1398
      memcpy (tag->line + line_offset, data, length);
1399
      invalidate_return_buffer (cache, address);
1400
      tag->dirty = 1;
1401
 
1402
      /* Update the LRU information for the tags in this set.  */
1403
      set_most_recently_used (cache, tag);
1404
    }
1405
 
1406
  /* Write the data to memory if there was no line available or we are in
1407
     write-through (not copy-back mode).  */
1408
  if (tag == NULL || ! copy_back)
1409
    {
1410
      write_data_to_memory (cache, address, data, length);
1411
      if (tag != NULL)
1412
        tag->dirty = 0;
1413
    }
1414
}
1415
 
1416
static void
1417
handle_req_invalidate (FRV_CACHE *cache, int pipe, FRV_CACHE_REQUEST *req)
1418
{
1419
  FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
1420
  SI address = req->address;
1421
  SI interfere_address = req->u.invalidate.all ? -1 : address;
1422
 
1423
  /* If this address interferes with an existing request, then requeue it.  */
1424
  if (address_interference (cache, interfere_address, req, pipe))
1425
    {
1426
      pipeline_requeue_request (pipeline);
1427
      return;
1428
    }
1429
 
1430
  /* Invalidate the cache line now.  This function already checks for
1431
     non-cache access.  */
1432
  if (req->u.invalidate.all)
1433
    frv_cache_invalidate_all (cache, req->u.invalidate.flush);
1434
  else
1435
    frv_cache_invalidate (cache, address, req->u.invalidate.flush);
1436
  if (req->u.invalidate.flush)
1437
    {
1438
      pipeline->status.flush.reqno = req->reqno;
1439
      pipeline->status.flush.address = address;
1440
      pipeline->status.flush.valid = 1;
1441
    }
1442
}
1443
 
1444
static void
1445
handle_req_unlock (FRV_CACHE *cache, int pipe, FRV_CACHE_REQUEST *req)
1446
{
1447
  FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
1448
  SI address = req->address;
1449
 
1450
  /* If this address interferes with an existing request, then requeue it.  */
1451
  if (address_interference (cache, address, req, pipe))
1452
    {
1453
      pipeline_requeue_request (pipeline);
1454
      return;
1455
    }
1456
 
1457
  /* Unlock the cache line.  This function checks for non-cache access.  */
1458
  frv_cache_unlock (cache, address);
1459
}
1460
 
1461
static void
1462
handle_req_WAR (FRV_CACHE *cache, int pipe, FRV_CACHE_REQUEST *req)
1463
{
1464
  char *buffer;
1465
  FRV_CACHE_TAG *tag;
1466
  SI address = req->address;
1467
 
1468
  if (frv_cache_enabled (cache) && ! non_cache_access (cache, address))
1469
    {
1470
      /* Look for the data in the cache.  The statistics of cache hit or
1471
         miss have already been recorded, so save and restore the stats before
1472
         and after obtaining the cache line.  */
1473
      FRV_CACHE_STATISTICS save_stats = cache->statistics;
1474
      tag = find_or_retrieve_cache_line (cache, address);
1475
      cache->statistics = save_stats;
1476
      if (tag != NULL)
1477
        {
1478
          if (! req->u.WAR.preload)
1479
            {
1480
              copy_line_to_return_buffer (cache, pipe, tag, address);
1481
              set_return_buffer_reqno (cache, pipe, req->reqno);
1482
            }
1483
          else
1484
            {
1485
              invalidate_return_buffer (cache, address);
1486
              if (req->u.WAR.lock)
1487
                tag->locked = 1;
1488
            }
1489
          return;
1490
        }
1491
    }
1492
 
1493
  /* All cache lines in the set were locked, so just copy the data to the
1494
     return buffer directly.  */
1495
  if (! req->u.WAR.preload)
1496
    {
1497
      copy_memory_to_return_buffer (cache, pipe, address);
1498
      set_return_buffer_reqno (cache, pipe, req->reqno);
1499
    }
1500
}
1501
 
1502
/* Resolve any conflicts and/or execute the given requests.  */
1503
static void
1504
arbitrate_requests (FRV_CACHE *cache)
1505
{
1506
  int pipe;
1507
  /* Simply execute the requests in the final pipeline stages.  */
1508
  for (pipe = LS; pipe < FRV_CACHE_PIPELINES; ++pipe)
1509
    {
1510
      FRV_CACHE_REQUEST *req
1511
        = pipeline_stage_request (& cache->pipeline[pipe], LAST_STAGE);
1512
      /* Make sure that there is a request to handle.  */
1513
      if (req == NULL)
1514
        continue;
1515
 
1516
      /* Handle the request.  */
1517
      switch (req->kind)
1518
        {
1519
        case req_load:
1520
          handle_req_load (cache, pipe, req);
1521
          break;
1522
        case req_store:
1523
          handle_req_store (cache, pipe, req);
1524
          break;
1525
        case req_invalidate:
1526
          handle_req_invalidate (cache, pipe, req);
1527
          break;
1528
        case req_preload:
1529
          handle_req_preload (cache, pipe, req);
1530
          break;
1531
        case req_unlock:
1532
          handle_req_unlock (cache, pipe, req);
1533
          break;
1534
        case req_WAR:
1535
          handle_req_WAR (cache, pipe, req);
1536
          break;
1537
        default:
1538
          abort ();
1539
        }
1540
    }
1541
}
1542
 
1543
/* Move a waiting ARS register to a free WAR register.  */
1544
static void
1545
move_ARS_to_WAR (FRV_CACHE *cache, int pipe, FRV_CACHE_WAR *war)
1546
{
1547
  /* If BARS is valid for this pipe, then move it to the given WAR. Move
1548
     NARS to BARS if it is valid.  */
1549
  if (cache->BARS.valid && cache->BARS.pipe == pipe)
1550
    {
1551
      war->address = cache->BARS.address;
1552
      war->reqno = cache->BARS.reqno;
1553
      war->priority = cache->BARS.priority;
1554
      war->preload = cache->BARS.preload;
1555
      war->lock = cache->BARS.lock;
1556
      war->latency = cache->memory_latency + 1;
1557
      war->valid = 1;
1558
      if (cache->NARS.valid)
1559
        {
1560
          cache->BARS = cache->NARS;
1561
          cache->NARS.valid = 0;
1562
        }
1563
      else
1564
        cache->BARS.valid = 0;
1565
      return;
1566
    }
1567
  /* If NARS is valid for this pipe, then move it to the given WAR.  */
1568
  if (cache->NARS.valid && cache->NARS.pipe == pipe)
1569
    {
1570
      war->address = cache->NARS.address;
1571
      war->reqno = cache->NARS.reqno;
1572
      war->priority = cache->NARS.priority;
1573
      war->preload = cache->NARS.preload;
1574
      war->lock = cache->NARS.lock;
1575
      war->latency = cache->memory_latency + 1;
1576
      war->valid = 1;
1577
      cache->NARS.valid = 0;
1578
    }
1579
}
1580
 
1581
/* Decrease the latencies of the various states in the cache.  */
1582
static void
1583
decrease_latencies (FRV_CACHE *cache)
1584
{
1585
  int pipe, j;
1586
  /* Check the WAR registers.  */
1587
  for (pipe = LS; pipe < FRV_CACHE_PIPELINES; ++pipe)
1588
    {
1589
      FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
1590
      for (j = 0; j < NUM_WARS; ++j)
1591
        {
1592
          FRV_CACHE_WAR *war = & pipeline->WAR[j];
1593
          if (war->valid)
1594
            {
1595
              --war->latency;
1596
              /* If the latency has expired, then submit a WAR request to the
1597
                 pipeline.  */
1598
              if (war->latency <= 0)
1599
                {
1600
                  add_WAR_request (pipeline, war);
1601
                  war->valid = 0;
1602
                  move_ARS_to_WAR (cache, pipe, war);
1603
                }
1604
            }
1605
        }
1606
    }
1607
}
1608
 
1609
/* Run the cache for the given number of cycles.  */
1610
void
1611
frv_cache_run (FRV_CACHE *cache, int cycles)
1612
{
1613
  int i;
1614
  for (i = 0; i < cycles; ++i)
1615
    {
1616
      advance_pipelines (cache);
1617
      arbitrate_requests (cache);
1618
      decrease_latencies (cache);
1619
    }
1620
}
1621
 
1622
int
1623
frv_cache_read_passive_SI (FRV_CACHE *cache, SI address, SI *value)
1624
{
1625
  SI offset;
1626
  FRV_CACHE_TAG *tag;
1627
 
1628
  if (non_cache_access (cache, address))
1629
    return 0;
1630
 
1631
  {
1632
    FRV_CACHE_STATISTICS save_stats = cache->statistics;
1633
    int found = get_tag (cache, address, &tag);
1634
    cache->statistics = save_stats;
1635
 
1636
    if (! found)
1637
      return 0; /* Indicate non-cache-access.  */
1638
  }
1639
 
1640
  /* A cache line was available for the data.
1641
     Extract the target data from the line.  */
1642
  offset = address & (cache->line_size - 1);
1643
  *value = T2H_4 (*(SI *)(tag->line + offset));
1644
  return 1;
1645
}
1646
 
1647
/* Check the return buffers of the data cache to see if the requested data is
1648
   available.  */
1649
int
1650
frv_cache_data_in_buffer (FRV_CACHE* cache, int pipe, SI address,
1651
                          unsigned reqno)
1652
{
1653
  return cache->pipeline[pipe].status.return_buffer.valid
1654
    && cache->pipeline[pipe].status.return_buffer.reqno == reqno
1655
    && cache->pipeline[pipe].status.return_buffer.address <= address
1656
    && cache->pipeline[pipe].status.return_buffer.address + cache->line_size
1657
       > address;
1658
}
1659
 
1660
/* Check to see if the requested data has been flushed.  */
1661
int
1662
frv_cache_data_flushed (FRV_CACHE* cache, int pipe, SI address, unsigned reqno)
1663
{
1664
  return cache->pipeline[pipe].status.flush.valid
1665
    && cache->pipeline[pipe].status.flush.reqno == reqno
1666
    && cache->pipeline[pipe].status.flush.address <= address
1667
    && cache->pipeline[pipe].status.flush.address + cache->line_size
1668
       > address;
1669
}

powered by: WebSVN 2.1.0

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