示例#1
0
void
scache_flush_cpu (SIM_CPU *cpu)
{
  int i,n;

  /* Don't bother if cache not in use.  */
  if (CPU_SCACHE_SIZE (cpu) == 0)
    return;

#if WITH_SCACHE_PBB
  /* It's important that this be reasonably fast as this can be done when
     the simulation is running.  */
  CPU_SCACHE_NEXT_FREE (cpu) = CPU_SCACHE_CACHE (cpu);
  n = CPU_SCACHE_NUM_HASH_CHAINS (cpu) * CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu);
  /* ??? Might be faster to just set the first entry, then update the
     "last entry" marker during allocation.  */
  for (i = 0; i < n; ++i)
    CPU_SCACHE_HASH_TABLE (cpu) [i] . pc = UNUSED_ADDR;
#else
  {
    int elm_size = IMP_PROPS_SCACHE_ELM_SIZE (MACH_IMP_PROPS (CPU_MACH (cpu)));
    SCACHE *sc;

    /* Technically, this may not be necessary, but it helps debugging.  */
    memset (CPU_SCACHE_CACHE (cpu), 0,
	    CPU_SCACHE_SIZE (cpu) * elm_size);

    for (i = 0, sc = CPU_SCACHE_CACHE (cpu); i < CPU_SCACHE_SIZE (cpu);
	 ++i, sc = (SCACHE *) ((char *) sc + elm_size))
      {
	sc->argbuf.addr = UNUSED_ADDR;
      }
  }
#endif
}
示例#2
0
static SIM_RC
scache_init (SIM_DESC sd)
{
  int c;

  for (c = 0; c < MAX_NR_PROCESSORS; ++c)
    {
      SIM_CPU *cpu = STATE_CPU (sd, c);
      int elm_size = IMP_PROPS_SCACHE_ELM_SIZE (MACH_IMP_PROPS (CPU_MACH (cpu)));

      /* elm_size is 0 if the cpu doesn't not have scache support */
      if (elm_size == 0)
	{
	  CPU_SCACHE_SIZE (cpu) = 0;
	  CPU_SCACHE_CACHE (cpu) = NULL;
	}
      else
	{
	  if (CPU_SCACHE_SIZE (cpu) == 0)
	    CPU_SCACHE_SIZE (cpu) = STATE_SCACHE_SIZE (sd);
	  CPU_SCACHE_CACHE (cpu) =
	    (SCACHE *) xmalloc (CPU_SCACHE_SIZE (cpu) * elm_size);
#if WITH_SCACHE_PBB
	  CPU_SCACHE_MAX_CHAIN_LENGTH (cpu) = MAX_CHAIN_LENGTH;
	  CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu) = MAX_HASH_CHAIN_LENGTH;
	  CPU_SCACHE_NUM_HASH_CHAINS (cpu) = max (MIN_HASH_CHAINS,
						  CPU_SCACHE_SIZE (cpu)
						  / SCACHE_HASH_RATIO);
	  CPU_SCACHE_HASH_TABLE (cpu) =
	    (SCACHE_MAP *) xmalloc (CPU_SCACHE_NUM_HASH_CHAINS (cpu)
				    * CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu)
				    * sizeof (SCACHE_MAP));
	  CPU_SCACHE_PBB_BEGIN (cpu) = (SCACHE *) zalloc (elm_size);
	  CPU_SCACHE_CHAIN_LENGTHS (cpu) =
	    (unsigned long *) zalloc ((CPU_SCACHE_MAX_CHAIN_LENGTH (cpu) + 1)
				      * sizeof (long));
#endif
	}
    }

  scache_flush (sd);

  return SIM_RC_OK;
}
示例#3
0
SCACHE *
scache_lookup (SIM_CPU *cpu, IADDR pc)
{
  unsigned int slot = HASH_PC (pc) & (CPU_SCACHE_NUM_HASH_CHAINS (cpu) - 1);
  int i, max_i = CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu);
  SCACHE_MAP *scm;

  /* We don't update hit/miss statistics as this is only used when recording
     branch target addresses.  */

  scm = & CPU_SCACHE_HASH_TABLE (cpu) [slot];
  for (i = 0; i < max_i && scm->pc != UNUSED_ADDR; ++i, ++scm)
    {
      if (scm->pc == pc)
	return scm->sc;
    }
  return 0;
}
示例#4
0
SCACHE *
scache_lookup (SIM_CPU *cpu, IADDR pc)
{
  /* FIXME: hash computation is wrong, doesn't take into account
     NUM_HASH_CHAIN_ENTRIES.  A lot of the hash table will be unused!  */
  unsigned int slot = HASH_PC (pc) & (CPU_SCACHE_NUM_HASH_CHAINS (cpu) - 1);
  int i, max_i = CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu);
  SCACHE_MAP *scm;

  /* We don't update hit/miss statistics as this is only used when recording
     branch target addresses.  */

  scm = & CPU_SCACHE_HASH_TABLE (cpu) [slot];
  for (i = 0; i < max_i && scm->pc != UNUSED_ADDR; ++i, ++scm)
    {
      if (scm->pc == pc)
	return scm->sc;
    }
  return 0;
}
示例#5
0
void
scache_print_profile (SIM_CPU *cpu, int verbose)
{
  SIM_DESC sd = CPU_STATE (cpu);
  unsigned long hits = CPU_SCACHE_HITS (cpu);
  unsigned long misses = CPU_SCACHE_MISSES (cpu);
  char buf[20];
  unsigned long max_val;
  unsigned long *lengths;
  int i;

  if (CPU_SCACHE_SIZE (cpu) == 0)
    return;

  sim_io_printf (sd, "Simulator Cache Statistics\n\n");

  /* One could use PROFILE_LABEL_WIDTH here.  I chose not to.  */
  sim_io_printf (sd, "  Cache size: %s\n",
		 sim_add_commas (buf, sizeof (buf), CPU_SCACHE_SIZE (cpu)));
  sim_io_printf (sd, "  Hits:       %s\n",
		 sim_add_commas (buf, sizeof (buf), hits));
  sim_io_printf (sd, "  Misses:     %s\n",
		 sim_add_commas (buf, sizeof (buf), misses));
  if (hits + misses != 0)
    sim_io_printf (sd, "  Hit rate:   %.2f%%\n",
		   ((double) hits / ((double) hits + (double) misses)) * 100);

#if WITH_SCACHE_PBB
  sim_io_printf (sd, "\n");
  sim_io_printf (sd, "  Hash table size:       %s\n",
		 sim_add_commas (buf, sizeof (buf), CPU_SCACHE_NUM_HASH_CHAINS (cpu)));
  sim_io_printf (sd, "  Max hash list length:  %s\n",
		 sim_add_commas (buf, sizeof (buf), CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu)));
  sim_io_printf (sd, "  Max insn chain length: %s\n",
		 sim_add_commas (buf, sizeof (buf), CPU_SCACHE_MAX_CHAIN_LENGTH (cpu)));
  sim_io_printf (sd, "  Cache full flushes:    %s\n",
		 sim_add_commas (buf, sizeof (buf), CPU_SCACHE_FULL_FLUSHES (cpu)));
  sim_io_printf (sd, "\n");

  if (verbose)
    {
      sim_io_printf (sd, "  Insn chain lengths:\n\n");
      max_val = 0;
      lengths = CPU_SCACHE_CHAIN_LENGTHS (cpu);
      for (i = 1; i < CPU_SCACHE_MAX_CHAIN_LENGTH (cpu); ++i)
	if (lengths[i] > max_val)
	  max_val = lengths[i];
      for (i = 1; i < CPU_SCACHE_MAX_CHAIN_LENGTH (cpu); ++i)
	{
	  sim_io_printf (sd, "  %2d: %*s: ",
			 i,
			 max_val < 10000 ? 5 : 10,
			 sim_add_commas (buf, sizeof (buf), lengths[i]));
	  sim_profile_print_bar (sd, cpu, PROFILE_HISTOGRAM_WIDTH,
				 lengths[i], max_val);
	  sim_io_printf (sd, "\n");
	}
      sim_io_printf (sd, "\n");
    }
#endif /* WITH_SCACHE_PBB */
}
示例#6
0
SCACHE *
scache_lookup_or_alloc (SIM_CPU *cpu, IADDR pc, int n, SCACHE **bufp)
{
  /* FIXME: hash computation is wrong, doesn't take into account
     NUM_HASH_CHAIN_ENTRIES.  A lot of the hash table will be unused!  */
  unsigned int slot = HASH_PC (pc) & (CPU_SCACHE_NUM_HASH_CHAINS (cpu) - 1);
  int i, max_i = CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu);
  SCACHE_MAP *scm;
  SCACHE *sc;

  scm = & CPU_SCACHE_HASH_TABLE (cpu) [slot];
  for (i = 0; i < max_i && scm->pc != UNUSED_ADDR; ++i, ++scm)
    {
      if (scm->pc == pc)
	{
	  PROFILE_COUNT_SCACHE_HIT (cpu);
	  return scm->sc;
	}
    }
  PROFILE_COUNT_SCACHE_MISS (cpu);

  /* The address we want isn't cached.  Bummer.
     If the hash chain we have for this address is full, throw out an entry
     to make room.  */

  if (i == max_i)
    {
      /* Rather than do something sophisticated like LRU, we just throw out
	 a semi-random entry.  Let someone else have the joy of saying how
	 wrong this is.  NEXT_FREE is the entry to throw out and cycles
	 through all possibilities.  */
      static int next_free = 0;

      scm = & CPU_SCACHE_HASH_TABLE (cpu) [slot];
      /* FIXME: This seems rather clumsy.  */
      for (i = 0; i < next_free; ++i, ++scm)
	continue;
      ++next_free;
      if (next_free == CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu))
	next_free = 0;
    }

  /* At this point SCM points to the hash table entry to use.
     Now make sure there's room in the cache.  */
  /* FIXME: Kinda weird to use a next_free adjusted scm when cache is
     flushed.  */

  {
    int elm_size = IMP_PROPS_SCACHE_ELM_SIZE (MACH_IMP_PROPS (CPU_MACH (cpu)));
    int elms_used = (((char *) CPU_SCACHE_NEXT_FREE (cpu)
		      - (char *) CPU_SCACHE_CACHE (cpu))
		     / elm_size);
    int elms_left = CPU_SCACHE_SIZE (cpu) - elms_used;

    if (elms_left < n)
      {
	PROFILE_COUNT_SCACHE_FULL_FLUSH (cpu);
	scache_flush_cpu (cpu);
      }
  }

  sc = CPU_SCACHE_NEXT_FREE (cpu);
  scm->pc = pc;
  scm->sc = sc;

  *bufp = sc;
  return NULL;
}