1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669 |
- /* frv cache model.
- Copyright (C) 1999-2015 Free Software Foundation, Inc.
- Contributed by Red Hat.
- This file is part of the GNU simulators.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #define WANT_CPU frvbf
- #define WANT_CPU_FRVBF
- #include "libiberty.h"
- #include "sim-main.h"
- #include "cache.h"
- #include "bfd.h"
- void
- frv_cache_init (SIM_CPU *cpu, FRV_CACHE *cache)
- {
- int elements;
- int i, j;
- SIM_DESC sd;
- /* Set defaults for fields which are not initialized. */
- sd = CPU_STATE (cpu);
- switch (STATE_ARCHITECTURE (sd)->mach)
- {
- case bfd_mach_fr400:
- case bfd_mach_fr450:
- if (cache->configured_sets == 0)
- cache->configured_sets = 512;
- if (cache->configured_ways == 0)
- cache->configured_ways = 2;
- if (cache->line_size == 0)
- cache->line_size = 32;
- if (cache->memory_latency == 0)
- cache->memory_latency = 20;
- break;
- case bfd_mach_fr550:
- if (cache->configured_sets == 0)
- cache->configured_sets = 128;
- if (cache->configured_ways == 0)
- cache->configured_ways = 4;
- if (cache->line_size == 0)
- cache->line_size = 64;
- if (cache->memory_latency == 0)
- cache->memory_latency = 20;
- break;
- default:
- if (cache->configured_sets == 0)
- cache->configured_sets = 64;
- if (cache->configured_ways == 0)
- cache->configured_ways = 4;
- if (cache->line_size == 0)
- cache->line_size = 64;
- if (cache->memory_latency == 0)
- cache->memory_latency = 20;
- break;
- }
- frv_cache_reconfigure (cpu, cache);
- /* First allocate the cache storage based on the given dimensions. */
- elements = cache->sets * cache->ways;
- cache->tag_storage = (FRV_CACHE_TAG *)
- zalloc (elements * sizeof (*cache->tag_storage));
- cache->data_storage = (char *) xmalloc (elements * cache->line_size);
- /* Initialize the pipelines and status buffers. */
- for (i = LS; i < FRV_CACHE_PIPELINES; ++i)
- {
- cache->pipeline[i].requests = NULL;
- cache->pipeline[i].status.flush.valid = 0;
- cache->pipeline[i].status.return_buffer.valid = 0;
- cache->pipeline[i].status.return_buffer.data
- = (char *) xmalloc (cache->line_size);
- for (j = FIRST_STAGE; j < FRV_CACHE_STAGES; ++j)
- cache->pipeline[i].stages[j].request = NULL;
- }
- cache->BARS.valid = 0;
- cache->NARS.valid = 0;
- /* Now set the cache state. */
- cache->cpu = cpu;
- cache->statistics.accesses = 0;
- cache->statistics.hits = 0;
- }
- void
- frv_cache_term (FRV_CACHE *cache)
- {
- /* Free the cache storage. */
- free (cache->tag_storage);
- free (cache->data_storage);
- free (cache->pipeline[LS].status.return_buffer.data);
- free (cache->pipeline[LD].status.return_buffer.data);
- }
- /* Reset the cache configuration based on registers in the cpu. */
- void
- frv_cache_reconfigure (SIM_CPU *current_cpu, FRV_CACHE *cache)
- {
- int ihsr8;
- int icdm;
- SIM_DESC sd;
- /* Set defaults for fields which are not initialized. */
- sd = CPU_STATE (current_cpu);
- switch (STATE_ARCHITECTURE (sd)->mach)
- {
- case bfd_mach_fr550:
- if (cache == CPU_INSN_CACHE (current_cpu))
- {
- ihsr8 = GET_IHSR8 ();
- icdm = GET_IHSR8_ICDM (ihsr8);
- /* If IHSR8.ICDM is set, then the cache becomes a one way cache. */
- if (icdm)
- {
- cache->sets = cache->sets * cache->ways;
- cache->ways = 1;
- break;
- }
- }
- /* fall through */
- default:
- /* Set the cache to its original settings. */
- cache->sets = cache->configured_sets;
- cache->ways = cache->configured_ways;
- break;
- }
- }
- /* Determine whether the given cache is enabled. */
- int
- frv_cache_enabled (FRV_CACHE *cache)
- {
- SIM_CPU *current_cpu = cache->cpu;
- int hsr0 = GET_HSR0 ();
- if (GET_HSR0_ICE (hsr0) && cache == CPU_INSN_CACHE (current_cpu))
- return 1;
- if (GET_HSR0_DCE (hsr0) && cache == CPU_DATA_CACHE (current_cpu))
- return 1;
- return 0;
- }
- /* Determine whether the given address is RAM access, assuming that HSR0.RME
- is set. */
- static int
- ram_access (FRV_CACHE *cache, USI address)
- {
- int ihsr8;
- int cwe;
- USI start, end, way_size;
- SIM_CPU *current_cpu = cache->cpu;
- SIM_DESC sd = CPU_STATE (current_cpu);
- switch (STATE_ARCHITECTURE (sd)->mach)
- {
- case bfd_mach_fr550:
- /* IHSR8.DCWE or IHSR8.ICWE deternines which ways get RAM access. */
- ihsr8 = GET_IHSR8 ();
- if (cache == CPU_INSN_CACHE (current_cpu))
- {
- start = 0xfe000000;
- end = 0xfe008000;
- cwe = GET_IHSR8_ICWE (ihsr8);
- }
- else
- {
- start = 0xfe400000;
- end = 0xfe408000;
- cwe = GET_IHSR8_DCWE (ihsr8);
- }
- way_size = (end - start) / 4;
- end -= way_size * cwe;
- return address >= start && address < end;
- default:
- break;
- }
- return 1; /* RAM access */
- }
- /* Determine whether the given address should be accessed without using
- the cache. */
- static int
- non_cache_access (FRV_CACHE *cache, USI address)
- {
- int hsr0;
- SIM_DESC sd;
- SIM_CPU *current_cpu = cache->cpu;
- sd = CPU_STATE (current_cpu);
- switch (STATE_ARCHITECTURE (sd)->mach)
- {
- case bfd_mach_fr400:
- case bfd_mach_fr450:
- if (address >= 0xff000000
- || address >= 0xfe000000 && address <= 0xfeffffff)
- return 1; /* non-cache access */
- break;
- case bfd_mach_fr550:
- if (address >= 0xff000000
- || address >= 0xfeff0000 && address <= 0xfeffffff)
- return 1; /* non-cache access */
- if (cache == CPU_INSN_CACHE (current_cpu))
- {
- if (address >= 0xfe000000 && address <= 0xfe007fff)
- return 1; /* non-cache access */
- }
- else if (address >= 0xfe400000 && address <= 0xfe407fff)
- return 1; /* non-cache access */
- break;
- default:
- if (address >= 0xff000000
- || address >= 0xfeff0000 && address <= 0xfeffffff)
- return 1; /* non-cache access */
- if (cache == CPU_INSN_CACHE (current_cpu))
- {
- if (address >= 0xfe000000 && address <= 0xfe003fff)
- return 1; /* non-cache access */
- }
- else if (address >= 0xfe400000 && address <= 0xfe403fff)
- return 1; /* non-cache access */
- break;
- }
- hsr0 = GET_HSR0 ();
- if (GET_HSR0_RME (hsr0))
- return ram_access (cache, address);
- return 0; /* cache-access */
- }
- /* Find the cache line corresponding to the given address.
- If it is found then 'return_tag' is set to point to the tag for that line
- and 1 is returned.
- If it is not found, 'return_tag' is set to point to the tag for the least
- recently used line and 0 is returned.
- */
- static int
- get_tag (FRV_CACHE *cache, SI address, FRV_CACHE_TAG **return_tag)
- {
- int set;
- int way;
- int bits;
- USI tag;
- FRV_CACHE_TAG *found;
- FRV_CACHE_TAG *available;
- ++cache->statistics.accesses;
- /* First calculate which set this address will fall into. Do this by
- shifting out the bits representing the offset within the line and
- then keeping enough bits to index the set. */
- set = address & ~(cache->line_size - 1);
- for (bits = cache->line_size - 1; bits != 0; bits >>= 1)
- set >>= 1;
- set &= (cache->sets - 1);
-
- /* Now search the set for a valid tag which matches this address. At the
- same time make note of the least recently used tag, which we will return
- if no match is found. */
- available = NULL;
- tag = CACHE_ADDRESS_TAG (cache, address);
- for (way = 0; way < cache->ways; ++way)
- {
- found = CACHE_TAG (cache, set, way);
- /* This tag is available as the least recently used if it is the
- least recently used seen so far and it is not locked. */
- if (! found->locked && (available == NULL || available->lru > found->lru))
- available = found;
- if (found->valid && found->tag == tag)
- {
- *return_tag = found;
- ++cache->statistics.hits;
- return 1; /* found it */
- }
- }
- *return_tag = available;
- return 0; /* not found */
- }
- /* Write the given data out to memory. */
- static void
- write_data_to_memory (FRV_CACHE *cache, SI address, char *data, int length)
- {
- SIM_CPU *cpu = cache->cpu;
- IADDR pc = CPU_PC_GET (cpu);
- int write_index = 0;
- switch (length)
- {
- case 1:
- default:
- PROFILE_COUNT_WRITE (cpu, address, MODE_QI);
- break;
- case 2:
- PROFILE_COUNT_WRITE (cpu, address, MODE_HI);
- break;
- case 4:
- PROFILE_COUNT_WRITE (cpu, address, MODE_SI);
- break;
- case 8:
- PROFILE_COUNT_WRITE (cpu, address, MODE_DI);
- break;
- }
- for (write_index = 0; write_index < length; ++write_index)
- {
- /* TODO: Better way to copy memory than a byte at a time? */
- sim_core_write_unaligned_1 (cpu, pc, write_map, address + write_index,
- data[write_index]);
- }
- }
- /* Write a cache line out to memory. */
- static void
- write_line_to_memory (FRV_CACHE *cache, FRV_CACHE_TAG *tag)
- {
- SI address = tag->tag;
- int set = CACHE_TAG_SET_NUMBER (cache, tag);
- int bits;
- for (bits = cache->line_size - 1; bits != 0; bits >>= 1)
- set <<= 1;
- address |= set;
- write_data_to_memory (cache, address, tag->line, cache->line_size);
- }
- static void
- read_data_from_memory (SIM_CPU *current_cpu, SI address, char *buffer,
- int length)
- {
- PCADDR pc = CPU_PC_GET (current_cpu);
- int i;
- PROFILE_COUNT_READ (current_cpu, address, MODE_QI);
- for (i = 0; i < length; ++i)
- {
- /* TODO: Better way to copy memory than a byte at a time? */
- buffer[i] = sim_core_read_unaligned_1 (current_cpu, pc, read_map,
- address + i);
- }
- }
- /* Fill the given cache line from memory. */
- static void
- fill_line_from_memory (FRV_CACHE *cache, FRV_CACHE_TAG *tag, SI address)
- {
- PCADDR pc;
- int line_alignment;
- SI read_address;
- SIM_CPU *current_cpu = cache->cpu;
- /* If this line is already valid and the cache is in copy-back mode, then
- write this line to memory before refilling it.
- Check the dirty bit first, since it is less likely to be set. */
- if (tag->dirty && tag->valid)
- {
- int hsr0 = GET_HSR0 ();
- if (GET_HSR0_CBM (hsr0))
- write_line_to_memory (cache, tag);
- }
- else if (tag->line == NULL)
- {
- int line_index = tag - cache->tag_storage;
- tag->line = cache->data_storage + (line_index * cache->line_size);
- }
- pc = CPU_PC_GET (current_cpu);
- line_alignment = cache->line_size - 1;
- read_address = address & ~line_alignment;
- read_data_from_memory (current_cpu, read_address, tag->line,
- cache->line_size);
- tag->tag = CACHE_ADDRESS_TAG (cache, address);
- tag->valid = 1;
- }
- /* Update the LRU information for the tags in the same set as the given tag. */
- static void
- set_most_recently_used (FRV_CACHE *cache, FRV_CACHE_TAG *tag)
- {
- /* All tags in the same set are contiguous, so find the beginning of the
- set by aligning to the size of a set. */
- FRV_CACHE_TAG *item = cache->tag_storage + CACHE_TAG_SET_START (cache, tag);
- FRV_CACHE_TAG *limit = item + cache->ways;
- while (item < limit)
- {
- if (item->lru > tag->lru)
- --item->lru;
- ++item;
- }
- tag->lru = cache->ways; /* Mark as most recently used. */
- }
- /* Update the LRU information for the tags in the same set as the given tag. */
- static void
- set_least_recently_used (FRV_CACHE *cache, FRV_CACHE_TAG *tag)
- {
- /* All tags in the same set are contiguous, so find the beginning of the
- set by aligning to the size of a set. */
- FRV_CACHE_TAG *item = cache->tag_storage + CACHE_TAG_SET_START (cache, tag);
- FRV_CACHE_TAG *limit = item + cache->ways;
- while (item < limit)
- {
- if (item->lru != 0 && item->lru < tag->lru)
- ++item->lru;
- ++item;
- }
- tag->lru = 0; /* Mark as least recently used. */
- }
- /* Find the line containing the given address and load it if it is not
- already loaded.
- Returns the tag of the requested line. */
- static FRV_CACHE_TAG *
- find_or_retrieve_cache_line (FRV_CACHE *cache, SI address)
- {
- /* See if this data is already in the cache. */
- FRV_CACHE_TAG *tag;
- int found = get_tag (cache, address, &tag);
- /* Fill the line from memory, if it is not valid. */
- if (! found)
- {
- /* The tag could be NULL is all ways in the set were used and locked. */
- if (tag == NULL)
- return tag;
- fill_line_from_memory (cache, tag, address);
- tag->dirty = 0;
- }
- /* Update the LRU information for the tags in this set. */
- set_most_recently_used (cache, tag);
- return tag;
- }
- static void
- copy_line_to_return_buffer (FRV_CACHE *cache, int pipe, FRV_CACHE_TAG *tag,
- SI address)
- {
- /* A cache line was available for the data.
- Copy the data from the cache line to the output buffer. */
- memcpy (cache->pipeline[pipe].status.return_buffer.data,
- tag->line, cache->line_size);
- cache->pipeline[pipe].status.return_buffer.address
- = address & ~(cache->line_size - 1);
- cache->pipeline[pipe].status.return_buffer.valid = 1;
- }
- static void
- copy_memory_to_return_buffer (FRV_CACHE *cache, int pipe, SI address)
- {
- address &= ~(cache->line_size - 1);
- read_data_from_memory (cache->cpu, address,
- cache->pipeline[pipe].status.return_buffer.data,
- cache->line_size);
- cache->pipeline[pipe].status.return_buffer.address = address;
- cache->pipeline[pipe].status.return_buffer.valid = 1;
- }
- static void
- set_return_buffer_reqno (FRV_CACHE *cache, int pipe, unsigned reqno)
- {
- cache->pipeline[pipe].status.return_buffer.reqno = reqno;
- }
- /* Read data from the given cache.
- Returns the number of cycles required to obtain the data. */
- int
- frv_cache_read (FRV_CACHE *cache, int pipe, SI address)
- {
- FRV_CACHE_TAG *tag;
- if (non_cache_access (cache, address))
- {
- copy_memory_to_return_buffer (cache, pipe, address);
- return 1;
- }
-
- tag = find_or_retrieve_cache_line (cache, address);
- if (tag == NULL)
- return 0; /* Indicate non-cache-access. */
- /* A cache line was available for the data.
- Copy the data from the cache line to the output buffer. */
- copy_line_to_return_buffer (cache, pipe, tag, address);
- return 1; /* TODO - number of cycles unknown */
- }
- /* Writes data through the given cache.
- The data is assumed to be in target endian order.
- Returns the number of cycles required to write the data. */
- int
- frv_cache_write (FRV_CACHE *cache, SI address, char *data, unsigned length)
- {
- int copy_back;
- /* See if this data is already in the cache. */
- SIM_CPU *current_cpu = cache->cpu;
- USI hsr0 = GET_HSR0 ();
- FRV_CACHE_TAG *tag;
- int found;
- if (non_cache_access (cache, address))
- {
- write_data_to_memory (cache, address, data, length);
- return 1;
- }
- found = get_tag (cache, address, &tag);
- /* Write the data to the cache line if one was available and if it is
- either a hit or a miss in copy-back mode.
- The tag may be NULL if all ways were in use and locked on a miss.
- */
- copy_back = GET_HSR0_CBM (GET_HSR0 ());
- if (tag != NULL && (found || copy_back))
- {
- int line_offset;
- /* Load the line from memory first, if it was a miss. */
- if (! found)
- fill_line_from_memory (cache, tag, address);
- line_offset = address & (cache->line_size - 1);
- memcpy (tag->line + line_offset, data, length);
- tag->dirty = 1;
- /* Update the LRU information for the tags in this set. */
- set_most_recently_used (cache, tag);
- }
- /* Write the data to memory if there was no line available or we are in
- write-through (not copy-back mode). */
- if (tag == NULL || ! copy_back)
- {
- write_data_to_memory (cache, address, data, length);
- if (tag != NULL)
- tag->dirty = 0;
- }
- return 1; /* TODO - number of cycles unknown */
- }
- /* Preload the cache line containing the given address. Lock the
- data if requested.
- Returns the number of cycles required to write the data. */
- int
- frv_cache_preload (FRV_CACHE *cache, SI address, USI length, int lock)
- {
- int offset;
- int lines;
- if (non_cache_access (cache, address))
- return 1;
- /* preload at least 1 line. */
- if (length == 0)
- length = 1;
- offset = address & (cache->line_size - 1);
- lines = 1 + (offset + length - 1) / cache->line_size;
- /* Careful with this loop -- length is unsigned. */
- for (/**/; lines > 0; --lines)
- {
- FRV_CACHE_TAG *tag = find_or_retrieve_cache_line (cache, address);
- if (lock && tag != NULL)
- tag->locked = 1;
- address += cache->line_size;
- }
- return 1; /* TODO - number of cycles unknown */
- }
- /* Unlock the cache line containing the given address.
- Returns the number of cycles required to unlock the line. */
- int
- frv_cache_unlock (FRV_CACHE *cache, SI address)
- {
- FRV_CACHE_TAG *tag;
- int found;
- if (non_cache_access (cache, address))
- return 1;
- found = get_tag (cache, address, &tag);
- if (found)
- tag->locked = 0;
- return 1; /* TODO - number of cycles unknown */
- }
- static void
- invalidate_return_buffer (FRV_CACHE *cache, SI address)
- {
- /* If this address is in one of the return buffers, then invalidate that
- return buffer. */
- address &= ~(cache->line_size - 1);
- if (address == cache->pipeline[LS].status.return_buffer.address)
- cache->pipeline[LS].status.return_buffer.valid = 0;
- if (address == cache->pipeline[LD].status.return_buffer.address)
- cache->pipeline[LD].status.return_buffer.valid = 0;
- }
- /* Invalidate the cache line containing the given address. Flush the
- data if requested.
- Returns the number of cycles required to write the data. */
- int
- frv_cache_invalidate (FRV_CACHE *cache, SI address, int flush)
- {
- /* See if this data is already in the cache. */
- FRV_CACHE_TAG *tag;
- int found;
- /* Check for non-cache access. This operation is still perfromed even if
- the cache is not currently enabled. */
- if (non_cache_access (cache, address))
- return 1;
- /* If the line is found, invalidate it. If a flush is requested, then flush
- it if it is dirty. */
- found = get_tag (cache, address, &tag);
- if (found)
- {
- SIM_CPU *cpu;
- /* If a flush is requested, then flush it if it is dirty. */
- if (tag->dirty && flush)
- write_line_to_memory (cache, tag);
- set_least_recently_used (cache, tag);
- tag->valid = 0;
- tag->locked = 0;
- /* If this is the insn cache, then flush the cpu's scache as well. */
- cpu = cache->cpu;
- if (cache == CPU_INSN_CACHE (cpu))
- scache_flush_cpu (cpu);
- }
- invalidate_return_buffer (cache, address);
- return 1; /* TODO - number of cycles unknown */
- }
- /* Invalidate the entire cache. Flush the data if requested. */
- int
- frv_cache_invalidate_all (FRV_CACHE *cache, int flush)
- {
- /* See if this data is already in the cache. */
- int elements = cache->sets * cache->ways;
- FRV_CACHE_TAG *tag = cache->tag_storage;
- SIM_CPU *cpu;
- int i;
- for(i = 0; i < elements; ++i, ++tag)
- {
- /* If a flush is requested, then flush it if it is dirty. */
- if (tag->valid && tag->dirty && flush)
- write_line_to_memory (cache, tag);
- tag->valid = 0;
- tag->locked = 0;
- }
- /* If this is the insn cache, then flush the cpu's scache as well. */
- cpu = cache->cpu;
- if (cache == CPU_INSN_CACHE (cpu))
- scache_flush_cpu (cpu);
- /* Invalidate both return buffers. */
- cache->pipeline[LS].status.return_buffer.valid = 0;
- cache->pipeline[LD].status.return_buffer.valid = 0;
- return 1; /* TODO - number of cycles unknown */
- }
- /* ---------------------------------------------------------------------------
- Functions for operating the cache in cycle accurate mode.
- ------------------------------------------------------------------------- */
- /* Convert a VLIW slot to a cache pipeline index. */
- static int
- convert_slot_to_index (int slot)
- {
- switch (slot)
- {
- case UNIT_I0:
- case UNIT_C:
- return LS;
- case UNIT_I1:
- return LD;
- default:
- abort ();
- }
- return 0;
- }
- /* Allocate free chains of cache requests. */
- #define FREE_CHAIN_SIZE 16
- static FRV_CACHE_REQUEST *frv_cache_request_free_chain = NULL;
- static FRV_CACHE_REQUEST *frv_store_request_free_chain = NULL;
- static void
- allocate_new_cache_requests (void)
- {
- int i;
- frv_cache_request_free_chain = xmalloc (FREE_CHAIN_SIZE
- * sizeof (FRV_CACHE_REQUEST));
- for (i = 0; i < FREE_CHAIN_SIZE - 1; ++i)
- {
- frv_cache_request_free_chain[i].next
- = & frv_cache_request_free_chain[i + 1];
- }
- frv_cache_request_free_chain[FREE_CHAIN_SIZE - 1].next = NULL;
- }
- /* Return the next free request in the queue for the given cache pipeline. */
- static FRV_CACHE_REQUEST *
- new_cache_request (void)
- {
- FRV_CACHE_REQUEST *req;
- /* Allocate new elements for the free chain if necessary. */
- if (frv_cache_request_free_chain == NULL)
- allocate_new_cache_requests ();
- req = frv_cache_request_free_chain;
- frv_cache_request_free_chain = req->next;
- return req;
- }
- /* Return the given cache request to the free chain. */
- static void
- free_cache_request (FRV_CACHE_REQUEST *req)
- {
- if (req->kind == req_store)
- {
- req->next = frv_store_request_free_chain;
- frv_store_request_free_chain = req;
- }
- else
- {
- req->next = frv_cache_request_free_chain;
- frv_cache_request_free_chain = req;
- }
- }
- /* Search the free chain for an existing store request with a buffer that's
- large enough. */
- static FRV_CACHE_REQUEST *
- new_store_request (int length)
- {
- FRV_CACHE_REQUEST *prev = NULL;
- FRV_CACHE_REQUEST *req;
- for (req = frv_store_request_free_chain; req != NULL; req = req->next)
- {
- if (req->u.store.length == length)
- break;
- prev = req;
- }
- if (req != NULL)
- {
- if (prev == NULL)
- frv_store_request_free_chain = req->next;
- else
- prev->next = req->next;
- return req;
- }
- /* No existing request buffer was found, so make a new one. */
- req = new_cache_request ();
- req->kind = req_store;
- req->u.store.data = xmalloc (length);
- req->u.store.length = length;
- return req;
- }
- /* Remove the given request from the given pipeline. */
- static void
- pipeline_remove_request (FRV_CACHE_PIPELINE *p, FRV_CACHE_REQUEST *request)
- {
- FRV_CACHE_REQUEST *next = request->next;
- FRV_CACHE_REQUEST *prev = request->prev;
- if (prev == NULL)
- p->requests = next;
- else
- prev->next = next;
- if (next != NULL)
- next->prev = prev;
- }
- /* Add the given request to the given pipeline. */
- static void
- pipeline_add_request (FRV_CACHE_PIPELINE *p, FRV_CACHE_REQUEST *request)
- {
- FRV_CACHE_REQUEST *prev = NULL;
- FRV_CACHE_REQUEST *item;
- /* Add the request in priority order. 0 is the highest priority. */
- for (item = p->requests; item != NULL; item = item->next)
- {
- if (item->priority > request->priority)
- break;
- prev = item;
- }
- request->next = item;
- request->prev = prev;
- if (prev == NULL)
- p->requests = request;
- else
- prev->next = request;
- if (item != NULL)
- item->prev = request;
- }
- /* Requeu the given request from the last of the given pipeline. */
- static void
- pipeline_requeue_request (FRV_CACHE_PIPELINE *p)
- {
- FRV_CACHE_STAGE *stage = & p->stages[LAST_STAGE];
- FRV_CACHE_REQUEST *req = stage->request;
- stage->request = NULL;
- pipeline_add_request (p, req);
- }
- /* Return the priority lower than the lowest one in this cache pipeline.
- 0 is the highest priority. */
- static int
- next_priority (FRV_CACHE *cache, FRV_CACHE_PIPELINE *pipeline)
- {
- int i, j;
- int pipe;
- int lowest = 0;
- FRV_CACHE_REQUEST *req;
- /* Check the priorities of any queued items. */
- for (req = pipeline->requests; req != NULL; req = req->next)
- if (req->priority > lowest)
- lowest = req->priority;
- /* Check the priorities of items in the pipeline stages. */
- for (i = FIRST_STAGE; i < FRV_CACHE_STAGES; ++i)
- {
- FRV_CACHE_STAGE *stage = & pipeline->stages[i];
- if (stage->request != NULL && stage->request->priority > lowest)
- lowest = stage->request->priority;
- }
- /* Check the priorities of load requests waiting in WAR. These are one
- higher than the request that spawned them. */
- for (i = 0; i < NUM_WARS; ++i)
- {
- FRV_CACHE_WAR *war = & pipeline->WAR[i];
- if (war->valid && war->priority > lowest)
- lowest = war->priority + 1;
- }
- /* Check the priorities of any BARS or NARS associated with this pipeline.
- These are one higher than the request that spawned them. */
- pipe = pipeline - cache->pipeline;
- if (cache->BARS.valid && cache->BARS.pipe == pipe
- && cache->BARS.priority > lowest)
- lowest = cache->BARS.priority + 1;
- if (cache->NARS.valid && cache->NARS.pipe == pipe
- && cache->NARS.priority > lowest)
- lowest = cache->NARS.priority + 1;
- /* Return a priority 2 lower than the lowest found. This allows a WAR
- request to be generated with a priority greater than this but less than
- the next higher priority request. */
- return lowest + 2;
- }
- static void
- add_WAR_request (FRV_CACHE_PIPELINE* pipeline, FRV_CACHE_WAR *war)
- {
- /* Add the load request to the indexed pipeline. */
- FRV_CACHE_REQUEST *req = new_cache_request ();
- req->kind = req_WAR;
- req->reqno = war->reqno;
- req->priority = war->priority;
- req->address = war->address;
- req->u.WAR.preload = war->preload;
- req->u.WAR.lock = war->lock;
- pipeline_add_request (pipeline, req);
- }
- /* Remove the next request from the given pipeline and return it. */
- static FRV_CACHE_REQUEST *
- pipeline_next_request (FRV_CACHE_PIPELINE *p)
- {
- FRV_CACHE_REQUEST *first = p->requests;
- if (first != NULL)
- pipeline_remove_request (p, first);
- return first;
- }
- /* Return the request which is at the given stage of the given pipeline. */
- static FRV_CACHE_REQUEST *
- pipeline_stage_request (FRV_CACHE_PIPELINE *p, int stage)
- {
- return p->stages[stage].request;
- }
- static void
- advance_pipelines (FRV_CACHE *cache)
- {
- int stage;
- int pipe;
- FRV_CACHE_PIPELINE *pipelines = cache->pipeline;
- /* Free the final stage requests. */
- for (pipe = 0; pipe < FRV_CACHE_PIPELINES; ++pipe)
- {
- FRV_CACHE_REQUEST *req = pipelines[pipe].stages[LAST_STAGE].request;
- if (req != NULL)
- free_cache_request (req);
- }
- /* Shuffle the requests along the pipeline. */
- for (stage = LAST_STAGE; stage > FIRST_STAGE; --stage)
- {
- for (pipe = 0; pipe < FRV_CACHE_PIPELINES; ++pipe)
- pipelines[pipe].stages[stage] = pipelines[pipe].stages[stage - 1];
- }
- /* Add a new request to the pipeline. */
- for (pipe = 0; pipe < FRV_CACHE_PIPELINES; ++pipe)
- pipelines[pipe].stages[FIRST_STAGE].request
- = pipeline_next_request (& pipelines[pipe]);
- }
- /* Handle a request for a load from the given address. */
- void
- frv_cache_request_load (FRV_CACHE *cache, unsigned reqno, SI address, int slot)
- {
- FRV_CACHE_REQUEST *req;
- /* slot is a UNIT_*. Convert it to a cache pipeline index. */
- int pipe = convert_slot_to_index (slot);
- FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
- /* Add the load request to the indexed pipeline. */
- req = new_cache_request ();
- req->kind = req_load;
- req->reqno = reqno;
- req->priority = next_priority (cache, pipeline);
- req->address = address;
- pipeline_add_request (pipeline, req);
- }
- void
- frv_cache_request_store (FRV_CACHE *cache, SI address,
- int slot, char *data, unsigned length)
- {
- FRV_CACHE_REQUEST *req;
- /* slot is a UNIT_*. Convert it to a cache pipeline index. */
- int pipe = convert_slot_to_index (slot);
- FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
- /* Add the load request to the indexed pipeline. */
- req = new_store_request (length);
- req->kind = req_store;
- req->reqno = NO_REQNO;
- req->priority = next_priority (cache, pipeline);
- req->address = address;
- req->u.store.length = length;
- memcpy (req->u.store.data, data, length);
- pipeline_add_request (pipeline, req);
- invalidate_return_buffer (cache, address);
- }
- /* Handle a request to invalidate the cache line containing the given address.
- Flush the data if requested. */
- void
- frv_cache_request_invalidate (FRV_CACHE *cache, unsigned reqno, SI address,
- int slot, int all, int flush)
- {
- FRV_CACHE_REQUEST *req;
- /* slot is a UNIT_*. Convert it to a cache pipeline index. */
- int pipe = convert_slot_to_index (slot);
- FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
- /* Add the load request to the indexed pipeline. */
- req = new_cache_request ();
- req->kind = req_invalidate;
- req->reqno = reqno;
- req->priority = next_priority (cache, pipeline);
- req->address = address;
- req->u.invalidate.all = all;
- req->u.invalidate.flush = flush;
- pipeline_add_request (pipeline, req);
- }
- /* Handle a request to preload the cache line containing the given address. */
- void
- frv_cache_request_preload (FRV_CACHE *cache, SI address,
- int slot, int length, int lock)
- {
- FRV_CACHE_REQUEST *req;
- /* slot is a UNIT_*. Convert it to a cache pipeline index. */
- int pipe = convert_slot_to_index (slot);
- FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
- /* Add the load request to the indexed pipeline. */
- req = new_cache_request ();
- req->kind = req_preload;
- req->reqno = NO_REQNO;
- req->priority = next_priority (cache, pipeline);
- req->address = address;
- req->u.preload.length = length;
- req->u.preload.lock = lock;
- pipeline_add_request (pipeline, req);
- invalidate_return_buffer (cache, address);
- }
- /* Handle a request to unlock the cache line containing the given address. */
- void
- frv_cache_request_unlock (FRV_CACHE *cache, SI address, int slot)
- {
- FRV_CACHE_REQUEST *req;
- /* slot is a UNIT_*. Convert it to a cache pipeline index. */
- int pipe = convert_slot_to_index (slot);
- FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
- /* Add the load request to the indexed pipeline. */
- req = new_cache_request ();
- req->kind = req_unlock;
- req->reqno = NO_REQNO;
- req->priority = next_priority (cache, pipeline);
- req->address = address;
- pipeline_add_request (pipeline, req);
- }
- /* Check whether this address interferes with a pending request of
- higher priority. */
- static int
- address_interference (FRV_CACHE *cache, SI address, FRV_CACHE_REQUEST *req,
- int pipe)
- {
- int i, j;
- int line_mask = ~(cache->line_size - 1);
- int other_pipe;
- int priority = req->priority;
- FRV_CACHE_REQUEST *other_req;
- SI other_address;
- SI all_address;
- address &= line_mask;
- all_address = -1 & line_mask;
- /* Check for collisions in the queue for this pipeline. */
- for (other_req = cache->pipeline[pipe].requests;
- other_req != NULL;
- other_req = other_req->next)
- {
- other_address = other_req->address & line_mask;
- if ((address == other_address || address == all_address)
- && priority > other_req->priority)
- return 1;
- }
- /* Check for a collision in the the other pipeline. */
- other_pipe = pipe ^ 1;
- other_req = cache->pipeline[other_pipe].stages[LAST_STAGE].request;
- if (other_req != NULL)
- {
- other_address = other_req->address & line_mask;
- if (address == other_address || address == all_address)
- return 1;
- }
- /* Check for a collision with load requests waiting in WAR. */
- for (i = LS; i < FRV_CACHE_PIPELINES; ++i)
- {
- for (j = 0; j < NUM_WARS; ++j)
- {
- FRV_CACHE_WAR *war = & cache->pipeline[i].WAR[j];
- if (war->valid
- && (address == (war->address & line_mask)
- || address == all_address)
- && priority > war->priority)
- return 1;
- }
- /* If this is not a WAR request, then yield to any WAR requests in
- either pipeline or to a higher priority request in the same pipeline.
- */
- if (req->kind != req_WAR)
- {
- for (j = FIRST_STAGE; j < FRV_CACHE_STAGES; ++j)
- {
- other_req = cache->pipeline[i].stages[j].request;
- if (other_req != NULL)
- {
- if (other_req->kind == req_WAR)
- return 1;
- if (i == pipe
- && (address == (other_req->address & line_mask)
- || address == all_address)
- && priority > other_req->priority)
- return 1;
- }
- }
- }
- }
- /* Check for a collision with load requests waiting in ARS. */
- if (cache->BARS.valid
- && (address == (cache->BARS.address & line_mask)
- || address == all_address)
- && priority > cache->BARS.priority)
- return 1;
- if (cache->NARS.valid
- && (address == (cache->NARS.address & line_mask)
- || address == all_address)
- && priority > cache->NARS.priority)
- return 1;
- return 0;
- }
- /* Wait for a free WAR register in BARS or NARS. */
- static void
- wait_for_WAR (FRV_CACHE* cache, int pipe, FRV_CACHE_REQUEST *req)
- {
- FRV_CACHE_WAR war;
- FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
- if (! cache->BARS.valid)
- {
- cache->BARS.pipe = pipe;
- cache->BARS.reqno = req->reqno;
- cache->BARS.address = req->address;
- cache->BARS.priority = req->priority - 1;
- switch (req->kind)
- {
- case req_load:
- cache->BARS.preload = 0;
- cache->BARS.lock = 0;
- break;
- case req_store:
- cache->BARS.preload = 1;
- cache->BARS.lock = 0;
- break;
- case req_preload:
- cache->BARS.preload = 1;
- cache->BARS.lock = req->u.preload.lock;
- break;
- }
- cache->BARS.valid = 1;
- return;
- }
- if (! cache->NARS.valid)
- {
- cache->NARS.pipe = pipe;
- cache->NARS.reqno = req->reqno;
- cache->NARS.address = req->address;
- cache->NARS.priority = req->priority - 1;
- switch (req->kind)
- {
- case req_load:
- cache->NARS.preload = 0;
- cache->NARS.lock = 0;
- break;
- case req_store:
- cache->NARS.preload = 1;
- cache->NARS.lock = 0;
- break;
- case req_preload:
- cache->NARS.preload = 1;
- cache->NARS.lock = req->u.preload.lock;
- break;
- }
- cache->NARS.valid = 1;
- return;
- }
- /* All wait registers are busy, so resubmit this request. */
- pipeline_requeue_request (pipeline);
- }
- /* Find a free WAR register and wait for memory to fetch the data. */
- static void
- wait_in_WAR (FRV_CACHE* cache, int pipe, FRV_CACHE_REQUEST *req)
- {
- int war;
- FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
- /* Find a valid WAR to hold this request. */
- for (war = 0; war < NUM_WARS; ++war)
- if (! pipeline->WAR[war].valid)
- break;
- if (war >= NUM_WARS)
- {
- wait_for_WAR (cache, pipe, req);
- return;
- }
- pipeline->WAR[war].address = req->address;
- pipeline->WAR[war].reqno = req->reqno;
- pipeline->WAR[war].priority = req->priority - 1;
- pipeline->WAR[war].latency = cache->memory_latency + 1;
- switch (req->kind)
- {
- case req_load:
- pipeline->WAR[war].preload = 0;
- pipeline->WAR[war].lock = 0;
- break;
- case req_store:
- pipeline->WAR[war].preload = 1;
- pipeline->WAR[war].lock = 0;
- break;
- case req_preload:
- pipeline->WAR[war].preload = 1;
- pipeline->WAR[war].lock = req->u.preload.lock;
- break;
- }
- pipeline->WAR[war].valid = 1;
- }
- static void
- handle_req_load (FRV_CACHE *cache, int pipe, FRV_CACHE_REQUEST *req)
- {
- FRV_CACHE_TAG *tag;
- SI address = req->address;
- /* If this address interferes with an existing request, then requeue it. */
- if (address_interference (cache, address, req, pipe))
- {
- pipeline_requeue_request (& cache->pipeline[pipe]);
- return;
- }
- if (frv_cache_enabled (cache) && ! non_cache_access (cache, address))
- {
- int found = get_tag (cache, address, &tag);
- /* If the data was found, return it to the caller. */
- if (found)
- {
- set_most_recently_used (cache, tag);
- copy_line_to_return_buffer (cache, pipe, tag, address);
- set_return_buffer_reqno (cache, pipe, req->reqno);
- return;
- }
- }
- /* The data is not in the cache or this is a non-cache access. We need to
- wait for the memory unit to fetch it. Store this request in the WAR in
- the meantime. */
- wait_in_WAR (cache, pipe, req);
- }
- static void
- handle_req_preload (FRV_CACHE *cache, int pipe, FRV_CACHE_REQUEST *req)
- {
- int found;
- FRV_CACHE_WAR war;
- FRV_CACHE_TAG *tag;
- int length;
- int lock;
- int offset;
- int lines;
- int line;
- SI address = req->address;
- SI cur_address;
- if (! frv_cache_enabled (cache) || non_cache_access (cache, address))
- return;
- /* preload at least 1 line. */
- length = req->u.preload.length;
- if (length == 0)
- length = 1;
- /* Make sure that this request does not interfere with a pending request. */
- offset = address & (cache->line_size - 1);
- lines = 1 + (offset + length - 1) / cache->line_size;
- cur_address = address & ~(cache->line_size - 1);
- for (line = 0; line < lines; ++line)
- {
- /* If this address interferes with an existing request,
- then requeue it. */
- if (address_interference (cache, cur_address, req, pipe))
- {
- pipeline_requeue_request (& cache->pipeline[pipe]);
- return;
- }
- cur_address += cache->line_size;
- }
- /* Now process each cache line. */
- /* Careful with this loop -- length is unsigned. */
- lock = req->u.preload.lock;
- cur_address = address & ~(cache->line_size - 1);
- for (line = 0; line < lines; ++line)
- {
- /* If the data was found, then lock it if requested. */
- found = get_tag (cache, cur_address, &tag);
- if (found)
- {
- if (lock)
- tag->locked = 1;
- }
- else
- {
- /* The data is not in the cache. We need to wait for the memory
- unit to fetch it. Store this request in the WAR in the meantime.
- */
- wait_in_WAR (cache, pipe, req);
- }
- cur_address += cache->line_size;
- }
- }
- static void
- handle_req_store (FRV_CACHE *cache, int pipe, FRV_CACHE_REQUEST *req)
- {
- SIM_CPU *current_cpu;
- FRV_CACHE_TAG *tag;
- int found;
- int copy_back;
- SI address = req->address;
- char *data = req->u.store.data;
- int length = req->u.store.length;
- /* If this address interferes with an existing request, then requeue it. */
- if (address_interference (cache, address, req, pipe))
- {
- pipeline_requeue_request (& cache->pipeline[pipe]);
- return;
- }
- /* Non-cache access. Write the data directly to memory. */
- if (! frv_cache_enabled (cache) || non_cache_access (cache, address))
- {
- write_data_to_memory (cache, address, data, length);
- return;
- }
- /* See if the data is in the cache. */
- found = get_tag (cache, address, &tag);
- /* Write the data to the cache line if one was available and if it is
- either a hit or a miss in copy-back mode.
- The tag may be NULL if all ways were in use and locked on a miss.
- */
- current_cpu = cache->cpu;
- copy_back = GET_HSR0_CBM (GET_HSR0 ());
- if (tag != NULL && (found || copy_back))
- {
- int line_offset;
- /* Load the line from memory first, if it was a miss. */
- if (! found)
- {
- /* We need to wait for the memory unit to fetch the data.
- Store this request in the WAR and requeue the store request. */
- wait_in_WAR (cache, pipe, req);
- pipeline_requeue_request (& cache->pipeline[pipe]);
- /* Decrement the counts of accesses and hits because when the requeued
- request is processed again, it will appear to be a new access and
- a hit. */
- --cache->statistics.accesses;
- --cache->statistics.hits;
- return;
- }
- line_offset = address & (cache->line_size - 1);
- memcpy (tag->line + line_offset, data, length);
- invalidate_return_buffer (cache, address);
- tag->dirty = 1;
- /* Update the LRU information for the tags in this set. */
- set_most_recently_used (cache, tag);
- }
- /* Write the data to memory if there was no line available or we are in
- write-through (not copy-back mode). */
- if (tag == NULL || ! copy_back)
- {
- write_data_to_memory (cache, address, data, length);
- if (tag != NULL)
- tag->dirty = 0;
- }
- }
- static void
- handle_req_invalidate (FRV_CACHE *cache, int pipe, FRV_CACHE_REQUEST *req)
- {
- FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
- SI address = req->address;
- SI interfere_address = req->u.invalidate.all ? -1 : address;
- /* If this address interferes with an existing request, then requeue it. */
- if (address_interference (cache, interfere_address, req, pipe))
- {
- pipeline_requeue_request (pipeline);
- return;
- }
- /* Invalidate the cache line now. This function already checks for
- non-cache access. */
- if (req->u.invalidate.all)
- frv_cache_invalidate_all (cache, req->u.invalidate.flush);
- else
- frv_cache_invalidate (cache, address, req->u.invalidate.flush);
- if (req->u.invalidate.flush)
- {
- pipeline->status.flush.reqno = req->reqno;
- pipeline->status.flush.address = address;
- pipeline->status.flush.valid = 1;
- }
- }
- static void
- handle_req_unlock (FRV_CACHE *cache, int pipe, FRV_CACHE_REQUEST *req)
- {
- FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
- SI address = req->address;
- /* If this address interferes with an existing request, then requeue it. */
- if (address_interference (cache, address, req, pipe))
- {
- pipeline_requeue_request (pipeline);
- return;
- }
- /* Unlock the cache line. This function checks for non-cache access. */
- frv_cache_unlock (cache, address);
- }
- static void
- handle_req_WAR (FRV_CACHE *cache, int pipe, FRV_CACHE_REQUEST *req)
- {
- char *buffer;
- FRV_CACHE_TAG *tag;
- SI address = req->address;
- if (frv_cache_enabled (cache) && ! non_cache_access (cache, address))
- {
- /* Look for the data in the cache. The statistics of cache hit or
- miss have already been recorded, so save and restore the stats before
- and after obtaining the cache line. */
- FRV_CACHE_STATISTICS save_stats = cache->statistics;
- tag = find_or_retrieve_cache_line (cache, address);
- cache->statistics = save_stats;
- if (tag != NULL)
- {
- if (! req->u.WAR.preload)
- {
- copy_line_to_return_buffer (cache, pipe, tag, address);
- set_return_buffer_reqno (cache, pipe, req->reqno);
- }
- else
- {
- invalidate_return_buffer (cache, address);
- if (req->u.WAR.lock)
- tag->locked = 1;
- }
- return;
- }
- }
- /* All cache lines in the set were locked, so just copy the data to the
- return buffer directly. */
- if (! req->u.WAR.preload)
- {
- copy_memory_to_return_buffer (cache, pipe, address);
- set_return_buffer_reqno (cache, pipe, req->reqno);
- }
- }
- /* Resolve any conflicts and/or execute the given requests. */
- static void
- arbitrate_requests (FRV_CACHE *cache)
- {
- int pipe;
- /* Simply execute the requests in the final pipeline stages. */
- for (pipe = LS; pipe < FRV_CACHE_PIPELINES; ++pipe)
- {
- FRV_CACHE_REQUEST *req
- = pipeline_stage_request (& cache->pipeline[pipe], LAST_STAGE);
- /* Make sure that there is a request to handle. */
- if (req == NULL)
- continue;
- /* Handle the request. */
- switch (req->kind)
- {
- case req_load:
- handle_req_load (cache, pipe, req);
- break;
- case req_store:
- handle_req_store (cache, pipe, req);
- break;
- case req_invalidate:
- handle_req_invalidate (cache, pipe, req);
- break;
- case req_preload:
- handle_req_preload (cache, pipe, req);
- break;
- case req_unlock:
- handle_req_unlock (cache, pipe, req);
- break;
- case req_WAR:
- handle_req_WAR (cache, pipe, req);
- break;
- default:
- abort ();
- }
- }
- }
- /* Move a waiting ARS register to a free WAR register. */
- static void
- move_ARS_to_WAR (FRV_CACHE *cache, int pipe, FRV_CACHE_WAR *war)
- {
- /* If BARS is valid for this pipe, then move it to the given WAR. Move
- NARS to BARS if it is valid. */
- if (cache->BARS.valid && cache->BARS.pipe == pipe)
- {
- war->address = cache->BARS.address;
- war->reqno = cache->BARS.reqno;
- war->priority = cache->BARS.priority;
- war->preload = cache->BARS.preload;
- war->lock = cache->BARS.lock;
- war->latency = cache->memory_latency + 1;
- war->valid = 1;
- if (cache->NARS.valid)
- {
- cache->BARS = cache->NARS;
- cache->NARS.valid = 0;
- }
- else
- cache->BARS.valid = 0;
- return;
- }
- /* If NARS is valid for this pipe, then move it to the given WAR. */
- if (cache->NARS.valid && cache->NARS.pipe == pipe)
- {
- war->address = cache->NARS.address;
- war->reqno = cache->NARS.reqno;
- war->priority = cache->NARS.priority;
- war->preload = cache->NARS.preload;
- war->lock = cache->NARS.lock;
- war->latency = cache->memory_latency + 1;
- war->valid = 1;
- cache->NARS.valid = 0;
- }
- }
- /* Decrease the latencies of the various states in the cache. */
- static void
- decrease_latencies (FRV_CACHE *cache)
- {
- int pipe, j;
- /* Check the WAR registers. */
- for (pipe = LS; pipe < FRV_CACHE_PIPELINES; ++pipe)
- {
- FRV_CACHE_PIPELINE *pipeline = & cache->pipeline[pipe];
- for (j = 0; j < NUM_WARS; ++j)
- {
- FRV_CACHE_WAR *war = & pipeline->WAR[j];
- if (war->valid)
- {
- --war->latency;
- /* If the latency has expired, then submit a WAR request to the
- pipeline. */
- if (war->latency <= 0)
- {
- add_WAR_request (pipeline, war);
- war->valid = 0;
- move_ARS_to_WAR (cache, pipe, war);
- }
- }
- }
- }
- }
- /* Run the cache for the given number of cycles. */
- void
- frv_cache_run (FRV_CACHE *cache, int cycles)
- {
- int i;
- for (i = 0; i < cycles; ++i)
- {
- advance_pipelines (cache);
- arbitrate_requests (cache);
- decrease_latencies (cache);
- }
- }
- int
- frv_cache_read_passive_SI (FRV_CACHE *cache, SI address, SI *value)
- {
- SI offset;
- FRV_CACHE_TAG *tag;
- if (non_cache_access (cache, address))
- return 0;
- {
- FRV_CACHE_STATISTICS save_stats = cache->statistics;
- int found = get_tag (cache, address, &tag);
- cache->statistics = save_stats;
- if (! found)
- return 0; /* Indicate non-cache-access. */
- }
- /* A cache line was available for the data.
- Extract the target data from the line. */
- offset = address & (cache->line_size - 1);
- *value = T2H_4 (*(SI *)(tag->line + offset));
- return 1;
- }
- /* Check the return buffers of the data cache to see if the requested data is
- available. */
- int
- frv_cache_data_in_buffer (FRV_CACHE* cache, int pipe, SI address,
- unsigned reqno)
- {
- return cache->pipeline[pipe].status.return_buffer.valid
- && cache->pipeline[pipe].status.return_buffer.reqno == reqno
- && cache->pipeline[pipe].status.return_buffer.address <= address
- && cache->pipeline[pipe].status.return_buffer.address + cache->line_size
- > address;
- }
- /* Check to see if the requested data has been flushed. */
- int
- frv_cache_data_flushed (FRV_CACHE* cache, int pipe, SI address, unsigned reqno)
- {
- return cache->pipeline[pipe].status.flush.valid
- && cache->pipeline[pipe].status.flush.reqno == reqno
- && cache->pipeline[pipe].status.flush.address <= address
- && cache->pipeline[pipe].status.flush.address + cache->line_size
- > address;
- }
|