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