OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-6.8/] [sim/] [frv/] [cache.c] - Diff between revs 827 and 840

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.