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