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 }
int cgen_cpu_max_extra_bytes (void) { int i; int extra = 0; for (i = 0; sim_machs[i] != 0; ++i) { int size = IMP_PROPS_SIM_CPU_SIZE (MACH_IMP_PROPS (sim_machs[i])); if (size > extra) extra = size; } return extra; }
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; }
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; }