]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/frv/cache.c
Update the copyright notice of some of the files I missed
[thirdparty/binutils-gdb.git] / sim / frv / cache.c
1 /* frv cache model.
2 Copyright (C) 1999, 2000, 2001, 2003, 2007, 2008, 2009
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 0 is the highest priority. */
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 }