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