198b9484cSchristos /* Simulator cache routines for CGEN simulators (and maybe others). 2*88241920Schristos Copyright (C) 1996-2024 Free Software Foundation, Inc. 398b9484cSchristos Contributed by Cygnus Support. 498b9484cSchristos 598b9484cSchristos This file is part of GDB, the GNU debugger. 698b9484cSchristos 798b9484cSchristos This program is free software; you can redistribute it and/or modify 898b9484cSchristos it under the terms of the GNU General Public License as published by 998b9484cSchristos the Free Software Foundation; either version 3 of the License, or 1098b9484cSchristos (at your option) any later version. 1198b9484cSchristos 1298b9484cSchristos This program is distributed in the hope that it will be useful, 1398b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 1498b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1598b9484cSchristos GNU General Public License for more details. 1698b9484cSchristos 1798b9484cSchristos You should have received a copy of the GNU General Public License 1898b9484cSchristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 1998b9484cSchristos 204b169a6bSchristos /* This must come before any other includes. */ 214b169a6bSchristos #include "defs.h" 224b169a6bSchristos 2398b9484cSchristos #define SCACHE_DEFINE_INLINE 2498b9484cSchristos 2598b9484cSchristos #include <stdlib.h> 264b169a6bSchristos 2798b9484cSchristos #include "libiberty.h" 284b169a6bSchristos 294b169a6bSchristos #include "sim-main.h" 3098b9484cSchristos #include "sim-options.h" 3198b9484cSchristos #include "sim-io.h" 3298b9484cSchristos 3398b9484cSchristos /* Unused address. */ 3498b9484cSchristos #define UNUSED_ADDR 0xffffffff 3598b9484cSchristos 3698b9484cSchristos /* Scache configuration parameters. 3798b9484cSchristos ??? Experiments to determine reasonable values is wip. 3898b9484cSchristos These are just guesses. */ 3998b9484cSchristos 4098b9484cSchristos /* Default number of scache elements. 4198b9484cSchristos The size of an element is typically 32-64 bytes, so the size of the 4298b9484cSchristos default scache will be between 512K and 1M bytes. */ 4398b9484cSchristos #ifdef CONFIG_SIM_CACHE_SIZE 4498b9484cSchristos #define SCACHE_DEFAULT_CACHE_SIZE CONFIG_SIM_CACHE_SIZE 4598b9484cSchristos #else 4698b9484cSchristos #define SCACHE_DEFAULT_CACHE_SIZE 16384 4798b9484cSchristos #endif 4898b9484cSchristos 4998b9484cSchristos /* Minimum cache size. 5098b9484cSchristos The m32r port assumes a cache size of at least 2 so it can decode both 16 5198b9484cSchristos bit insns. When compiling we need an extra for the chain entry. And this 5298b9484cSchristos must be a multiple of 2. Hence 4 is the minimum (though, for those with 5398b9484cSchristos featuritis or itchy pedantic bits, we could make this conditional on 5498b9484cSchristos WITH_SCACHE_PBB). */ 5598b9484cSchristos #define MIN_SCACHE_SIZE 4 5698b9484cSchristos 5798b9484cSchristos /* Ratio of size of text section to size of scache. 5898b9484cSchristos When compiling, we don't want to flush the scache more than we have to 5998b9484cSchristos but we also don't want it to be exorbitantly(sp?) large. So we pick a high 6098b9484cSchristos default value, then reduce it by the size of the program being simulated, 6198b9484cSchristos but we don't override any value specified on the command line. 6298b9484cSchristos If not specified on the command line, the size to use is computed as 6398b9484cSchristos max (MIN_SCACHE_SIZE, 6498b9484cSchristos min (DEFAULT_SCACHE_SIZE, 6598b9484cSchristos text_size / (base_insn_size * INSN_SCACHE_RATIO))). */ 6698b9484cSchristos /* ??? Interesting idea but not currently used. */ 6798b9484cSchristos #define INSN_SCACHE_RATIO 4 6898b9484cSchristos 6998b9484cSchristos /* Default maximum insn chain length. 7098b9484cSchristos The only reason for a maximum is so we can place a maximum size on the 7198b9484cSchristos profiling table. Chain lengths are determined by cti's. 7298b9484cSchristos 32 is a more reasonable number, but when profiling, the before/after 7398b9484cSchristos handlers take up that much more space. The scache is filled from front to 7498b9484cSchristos back so all this determines is when the scache needs to be flushed. */ 7598b9484cSchristos #define MAX_CHAIN_LENGTH 64 7698b9484cSchristos 7798b9484cSchristos /* Default maximum hash list length. */ 7898b9484cSchristos #define MAX_HASH_CHAIN_LENGTH 4 7998b9484cSchristos 8098b9484cSchristos /* Minimum hash table size. */ 8198b9484cSchristos #define MIN_HASH_CHAINS 32 8298b9484cSchristos 8398b9484cSchristos /* Ratio of number of scache elements to number of hash lists. 8498b9484cSchristos Since the user can only specify the size of the scache, we compute the 8598b9484cSchristos size of the hash table as 8698b9484cSchristos max (MIN_HASH_CHAINS, scache_size / SCACHE_HASH_RATIO). */ 8798b9484cSchristos #define SCACHE_HASH_RATIO 8 8898b9484cSchristos 8998b9484cSchristos /* Hash a PC value. 9098b9484cSchristos FIXME: May wish to make the hashing architecture specific. 9198b9484cSchristos FIXME: revisit */ 9298b9484cSchristos #define HASH_PC(pc) (((pc) >> 2) + ((pc) >> 5)) 9398b9484cSchristos 9498b9484cSchristos static MODULE_INIT_FN scache_init; 9598b9484cSchristos static MODULE_UNINSTALL_FN scache_uninstall; 9698b9484cSchristos 9798b9484cSchristos static DECLARE_OPTION_HANDLER (scache_option_handler); 9898b9484cSchristos 9998b9484cSchristos #define OPTION_PROFILE_SCACHE (OPTION_START + 0) 10098b9484cSchristos 10198b9484cSchristos static const OPTION scache_options[] = { 10298b9484cSchristos { {"scache-size", optional_argument, NULL, 'c'}, 10398b9484cSchristos 'c', "[SIZE]", "Specify size of simulator execution cache", 10498b9484cSchristos scache_option_handler }, 10598b9484cSchristos #if WITH_SCACHE_PBB 10698b9484cSchristos /* ??? It might be nice to allow the user to specify the size of the hash 10798b9484cSchristos table, the maximum hash list length, and the maximum chain length, but 10898b9484cSchristos for now that might be more akin to featuritis. */ 10998b9484cSchristos #endif 11098b9484cSchristos { {"profile-scache", optional_argument, NULL, OPTION_PROFILE_SCACHE}, 11198b9484cSchristos '\0', "on|off", "Perform simulator execution cache profiling", 11298b9484cSchristos scache_option_handler }, 11398b9484cSchristos { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL } 11498b9484cSchristos }; 11598b9484cSchristos 11698b9484cSchristos static SIM_RC 11798b9484cSchristos scache_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, 11898b9484cSchristos char *arg, int is_command) 11998b9484cSchristos { 12098b9484cSchristos switch (opt) 12198b9484cSchristos { 12298b9484cSchristos case 'c' : 12398b9484cSchristos if (WITH_SCACHE) 12498b9484cSchristos { 12598b9484cSchristos if (arg != NULL) 12698b9484cSchristos { 127ba340e45Schristos unsigned int n = (unsigned int) strtoul (arg, NULL, 0); 12898b9484cSchristos if (n < MIN_SCACHE_SIZE) 12998b9484cSchristos { 130ba340e45Schristos sim_io_eprintf (sd, "invalid scache size `%u', must be at least %u", 131ba340e45Schristos n, MIN_SCACHE_SIZE); 13298b9484cSchristos return SIM_RC_FAIL; 13398b9484cSchristos } 13498b9484cSchristos /* Ensure it's a multiple of 2. */ 13598b9484cSchristos if ((n & (n - 1)) != 0) 13698b9484cSchristos { 137ba340e45Schristos unsigned int i; 138ba340e45Schristos sim_io_eprintf (sd, "scache size `%u' not a multiple of 2\n", n); 139ba340e45Schristos /* Round up to nearest multiple of 2. */ 140ba340e45Schristos for (i = 1; i && i < n; i <<= 1) 14198b9484cSchristos continue; 142ba340e45Schristos if (i) 143ba340e45Schristos { 14498b9484cSchristos n = i; 145ba340e45Schristos sim_io_eprintf (sd, "rounding scache size up to %u\n", n); 14698b9484cSchristos } 14798b9484cSchristos } 14898b9484cSchristos if (cpu == NULL) 14998b9484cSchristos STATE_SCACHE_SIZE (sd) = n; 15098b9484cSchristos else 15198b9484cSchristos CPU_SCACHE_SIZE (cpu) = n; 15298b9484cSchristos } 15398b9484cSchristos else 15498b9484cSchristos { 15598b9484cSchristos if (cpu == NULL) 15698b9484cSchristos STATE_SCACHE_SIZE (sd) = SCACHE_DEFAULT_CACHE_SIZE; 15798b9484cSchristos else 15898b9484cSchristos CPU_SCACHE_SIZE (cpu) = SCACHE_DEFAULT_CACHE_SIZE; 15998b9484cSchristos } 16098b9484cSchristos } 16198b9484cSchristos else 16298b9484cSchristos sim_io_eprintf (sd, "Simulator execution cache not enabled, `--scache-size' ignored\n"); 16398b9484cSchristos break; 16498b9484cSchristos 16598b9484cSchristos case OPTION_PROFILE_SCACHE : 16698b9484cSchristos if (WITH_SCACHE && WITH_PROFILE_SCACHE_P) 16798b9484cSchristos { 16898b9484cSchristos /* FIXME: handle cpu != NULL. */ 16998b9484cSchristos return sim_profile_set_option (sd, "-scache", PROFILE_SCACHE_IDX, 17098b9484cSchristos arg); 17198b9484cSchristos } 17298b9484cSchristos else 17398b9484cSchristos sim_io_eprintf (sd, "Simulator cache profiling not compiled in, `--profile-scache' ignored\n"); 17498b9484cSchristos break; 17598b9484cSchristos } 17698b9484cSchristos 17798b9484cSchristos return SIM_RC_OK; 17898b9484cSchristos } 17998b9484cSchristos 1804b169a6bSchristos /* Provide a prototype to silence -Wmissing-prototypes. */ 1814b169a6bSchristos SIM_RC sim_install_scache (SIM_DESC sd); 1824b169a6bSchristos 1834b169a6bSchristos /* Install the simulator cache into the simulator. */ 18498b9484cSchristos SIM_RC 1854b169a6bSchristos sim_install_scache (SIM_DESC sd) 18698b9484cSchristos { 18798b9484cSchristos sim_add_option_table (sd, NULL, scache_options); 18898b9484cSchristos sim_module_add_init_fn (sd, scache_init); 18998b9484cSchristos sim_module_add_uninstall_fn (sd, scache_uninstall); 19098b9484cSchristos 19198b9484cSchristos /* This is the default, it may be overridden on the command line. */ 19298b9484cSchristos STATE_SCACHE_SIZE (sd) = WITH_SCACHE; 19398b9484cSchristos 19498b9484cSchristos return SIM_RC_OK; 19598b9484cSchristos } 19698b9484cSchristos 19798b9484cSchristos static SIM_RC 19898b9484cSchristos scache_init (SIM_DESC sd) 19998b9484cSchristos { 20098b9484cSchristos int c; 20198b9484cSchristos 20298b9484cSchristos for (c = 0; c < MAX_NR_PROCESSORS; ++c) 20398b9484cSchristos { 20498b9484cSchristos SIM_CPU *cpu = STATE_CPU (sd, c); 20598b9484cSchristos int elm_size = IMP_PROPS_SCACHE_ELM_SIZE (MACH_IMP_PROPS (CPU_MACH (cpu))); 20698b9484cSchristos 20798b9484cSchristos /* elm_size is 0 if the cpu doesn't not have scache support */ 20898b9484cSchristos if (elm_size == 0) 20998b9484cSchristos { 21098b9484cSchristos CPU_SCACHE_SIZE (cpu) = 0; 21198b9484cSchristos CPU_SCACHE_CACHE (cpu) = NULL; 21298b9484cSchristos } 21398b9484cSchristos else 21498b9484cSchristos { 21598b9484cSchristos if (CPU_SCACHE_SIZE (cpu) == 0) 21698b9484cSchristos CPU_SCACHE_SIZE (cpu) = STATE_SCACHE_SIZE (sd); 21798b9484cSchristos CPU_SCACHE_CACHE (cpu) = 21898b9484cSchristos (SCACHE *) xmalloc (CPU_SCACHE_SIZE (cpu) * elm_size); 21998b9484cSchristos #if WITH_SCACHE_PBB 22098b9484cSchristos CPU_SCACHE_MAX_CHAIN_LENGTH (cpu) = MAX_CHAIN_LENGTH; 22198b9484cSchristos CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu) = MAX_HASH_CHAIN_LENGTH; 222ba340e45Schristos CPU_SCACHE_NUM_HASH_CHAINS (cpu) = max (MIN_HASH_CHAINS, 22398b9484cSchristos CPU_SCACHE_SIZE (cpu) 22498b9484cSchristos / SCACHE_HASH_RATIO); 22598b9484cSchristos CPU_SCACHE_HASH_TABLE (cpu) = 22698b9484cSchristos (SCACHE_MAP *) xmalloc (CPU_SCACHE_NUM_HASH_CHAINS (cpu) 22798b9484cSchristos * CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu) 22898b9484cSchristos * sizeof (SCACHE_MAP)); 22998b9484cSchristos CPU_SCACHE_PBB_BEGIN (cpu) = (SCACHE *) zalloc (elm_size); 23098b9484cSchristos CPU_SCACHE_CHAIN_LENGTHS (cpu) = 23198b9484cSchristos (unsigned long *) zalloc ((CPU_SCACHE_MAX_CHAIN_LENGTH (cpu) + 1) 23298b9484cSchristos * sizeof (long)); 23398b9484cSchristos #endif 23498b9484cSchristos } 23598b9484cSchristos } 23698b9484cSchristos 23798b9484cSchristos scache_flush (sd); 23898b9484cSchristos 23998b9484cSchristos return SIM_RC_OK; 24098b9484cSchristos } 24198b9484cSchristos 24298b9484cSchristos static void 24398b9484cSchristos scache_uninstall (SIM_DESC sd) 24498b9484cSchristos { 24598b9484cSchristos int c; 24698b9484cSchristos 24798b9484cSchristos for (c = 0; c < MAX_NR_PROCESSORS; ++c) 24898b9484cSchristos { 24998b9484cSchristos SIM_CPU *cpu = STATE_CPU (sd, c); 25098b9484cSchristos 25198b9484cSchristos if (CPU_SCACHE_CACHE (cpu) != NULL) 25298b9484cSchristos free (CPU_SCACHE_CACHE (cpu)); 25398b9484cSchristos #if WITH_SCACHE_PBB 25498b9484cSchristos if (CPU_SCACHE_HASH_TABLE (cpu) != NULL) 25598b9484cSchristos free (CPU_SCACHE_HASH_TABLE (cpu)); 25698b9484cSchristos if (CPU_SCACHE_PBB_BEGIN (cpu) != NULL) 25798b9484cSchristos free (CPU_SCACHE_PBB_BEGIN (cpu)); 25898b9484cSchristos if (CPU_SCACHE_CHAIN_LENGTHS (cpu) != NULL) 25998b9484cSchristos free (CPU_SCACHE_CHAIN_LENGTHS (cpu)); 26098b9484cSchristos #endif 26198b9484cSchristos } 26298b9484cSchristos } 26398b9484cSchristos 26498b9484cSchristos void 26598b9484cSchristos scache_flush (SIM_DESC sd) 26698b9484cSchristos { 26798b9484cSchristos int c; 26898b9484cSchristos 26998b9484cSchristos for (c = 0; c < MAX_NR_PROCESSORS; ++c) 27098b9484cSchristos { 27198b9484cSchristos SIM_CPU *cpu = STATE_CPU (sd, c); 27298b9484cSchristos scache_flush_cpu (cpu); 27398b9484cSchristos } 27498b9484cSchristos } 27598b9484cSchristos 27698b9484cSchristos void 27798b9484cSchristos scache_flush_cpu (SIM_CPU *cpu) 27898b9484cSchristos { 279*88241920Schristos int i; 280*88241920Schristos #if WITH_SCACHE_PBB 281*88241920Schristos int n; 282*88241920Schristos #endif 28398b9484cSchristos 28498b9484cSchristos /* Don't bother if cache not in use. */ 28598b9484cSchristos if (CPU_SCACHE_SIZE (cpu) == 0) 28698b9484cSchristos return; 28798b9484cSchristos 28898b9484cSchristos #if WITH_SCACHE_PBB 28998b9484cSchristos /* It's important that this be reasonably fast as this can be done when 29098b9484cSchristos the simulation is running. */ 29198b9484cSchristos CPU_SCACHE_NEXT_FREE (cpu) = CPU_SCACHE_CACHE (cpu); 29298b9484cSchristos n = CPU_SCACHE_NUM_HASH_CHAINS (cpu) * CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu); 29398b9484cSchristos /* ??? Might be faster to just set the first entry, then update the 29498b9484cSchristos "last entry" marker during allocation. */ 29598b9484cSchristos for (i = 0; i < n; ++i) 29698b9484cSchristos CPU_SCACHE_HASH_TABLE (cpu) [i] . pc = UNUSED_ADDR; 29798b9484cSchristos #else 29898b9484cSchristos { 29998b9484cSchristos int elm_size = IMP_PROPS_SCACHE_ELM_SIZE (MACH_IMP_PROPS (CPU_MACH (cpu))); 30098b9484cSchristos SCACHE *sc; 30198b9484cSchristos 30298b9484cSchristos /* Technically, this may not be necessary, but it helps debugging. */ 30398b9484cSchristos memset (CPU_SCACHE_CACHE (cpu), 0, 30498b9484cSchristos CPU_SCACHE_SIZE (cpu) * elm_size); 30598b9484cSchristos 30698b9484cSchristos for (i = 0, sc = CPU_SCACHE_CACHE (cpu); i < CPU_SCACHE_SIZE (cpu); 30798b9484cSchristos ++i, sc = (SCACHE *) ((char *) sc + elm_size)) 30898b9484cSchristos { 30998b9484cSchristos sc->argbuf.addr = UNUSED_ADDR; 31098b9484cSchristos } 31198b9484cSchristos } 31298b9484cSchristos #endif 31398b9484cSchristos } 31498b9484cSchristos 31598b9484cSchristos #if WITH_SCACHE_PBB 31698b9484cSchristos 31798b9484cSchristos /* Look up PC in the hash table of scache entry points. 31898b9484cSchristos Returns the entry or NULL if not found. */ 31998b9484cSchristos 32098b9484cSchristos SCACHE * 32198b9484cSchristos scache_lookup (SIM_CPU *cpu, IADDR pc) 32298b9484cSchristos { 32398b9484cSchristos /* FIXME: hash computation is wrong, doesn't take into account 32498b9484cSchristos NUM_HASH_CHAIN_ENTRIES. A lot of the hash table will be unused! */ 32598b9484cSchristos unsigned int slot = HASH_PC (pc) & (CPU_SCACHE_NUM_HASH_CHAINS (cpu) - 1); 32698b9484cSchristos int i, max_i = CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu); 32798b9484cSchristos SCACHE_MAP *scm; 32898b9484cSchristos 32998b9484cSchristos /* We don't update hit/miss statistics as this is only used when recording 33098b9484cSchristos branch target addresses. */ 33198b9484cSchristos 33298b9484cSchristos scm = & CPU_SCACHE_HASH_TABLE (cpu) [slot]; 33398b9484cSchristos for (i = 0; i < max_i && scm->pc != UNUSED_ADDR; ++i, ++scm) 33498b9484cSchristos { 33598b9484cSchristos if (scm->pc == pc) 33698b9484cSchristos return scm->sc; 33798b9484cSchristos } 33898b9484cSchristos return 0; 33998b9484cSchristos } 34098b9484cSchristos 34198b9484cSchristos /* Look up PC and if not found create an entry for it. 34298b9484cSchristos If found the result is a pointer to the SCACHE entry. 34398b9484cSchristos If not found the result is NULL, and the address of a buffer of at least 34498b9484cSchristos N entries is stored in BUFP. 34598b9484cSchristos It's done this way so the caller can still distinguish found/not-found. 34698b9484cSchristos If the table is full, it is emptied to make room. 34798b9484cSchristos If the maximum length of a hash list is reached a random entry is thrown out 34898b9484cSchristos to make room. 34998b9484cSchristos ??? One might want to try to make this smarter, but let's see some 35098b9484cSchristos measurable benefit first. */ 35198b9484cSchristos 35298b9484cSchristos SCACHE * 35398b9484cSchristos scache_lookup_or_alloc (SIM_CPU *cpu, IADDR pc, int n, SCACHE **bufp) 35498b9484cSchristos { 35598b9484cSchristos /* FIXME: hash computation is wrong, doesn't take into account 35698b9484cSchristos NUM_HASH_CHAIN_ENTRIES. A lot of the hash table will be unused! */ 35798b9484cSchristos unsigned int slot = HASH_PC (pc) & (CPU_SCACHE_NUM_HASH_CHAINS (cpu) - 1); 35898b9484cSchristos int i, max_i = CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu); 35998b9484cSchristos SCACHE_MAP *scm; 36098b9484cSchristos SCACHE *sc; 36198b9484cSchristos 36298b9484cSchristos scm = & CPU_SCACHE_HASH_TABLE (cpu) [slot]; 36398b9484cSchristos for (i = 0; i < max_i && scm->pc != UNUSED_ADDR; ++i, ++scm) 36498b9484cSchristos { 36598b9484cSchristos if (scm->pc == pc) 36698b9484cSchristos { 36798b9484cSchristos PROFILE_COUNT_SCACHE_HIT (cpu); 36898b9484cSchristos return scm->sc; 36998b9484cSchristos } 37098b9484cSchristos } 37198b9484cSchristos PROFILE_COUNT_SCACHE_MISS (cpu); 37298b9484cSchristos 37398b9484cSchristos /* The address we want isn't cached. Bummer. 37498b9484cSchristos If the hash chain we have for this address is full, throw out an entry 37598b9484cSchristos to make room. */ 37698b9484cSchristos 37798b9484cSchristos if (i == max_i) 37898b9484cSchristos { 37998b9484cSchristos /* Rather than do something sophisticated like LRU, we just throw out 38098b9484cSchristos a semi-random entry. Let someone else have the joy of saying how 38198b9484cSchristos wrong this is. NEXT_FREE is the entry to throw out and cycles 38298b9484cSchristos through all possibilities. */ 38398b9484cSchristos static int next_free = 0; 38498b9484cSchristos 38598b9484cSchristos scm = & CPU_SCACHE_HASH_TABLE (cpu) [slot]; 38698b9484cSchristos /* FIXME: This seems rather clumsy. */ 38798b9484cSchristos for (i = 0; i < next_free; ++i, ++scm) 38898b9484cSchristos continue; 38998b9484cSchristos ++next_free; 39098b9484cSchristos if (next_free == CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu)) 39198b9484cSchristos next_free = 0; 39298b9484cSchristos } 39398b9484cSchristos 39498b9484cSchristos /* At this point SCM points to the hash table entry to use. 39598b9484cSchristos Now make sure there's room in the cache. */ 39698b9484cSchristos /* FIXME: Kinda weird to use a next_free adjusted scm when cache is 39798b9484cSchristos flushed. */ 39898b9484cSchristos 39998b9484cSchristos { 40098b9484cSchristos int elm_size = IMP_PROPS_SCACHE_ELM_SIZE (MACH_IMP_PROPS (CPU_MACH (cpu))); 40198b9484cSchristos int elms_used = (((char *) CPU_SCACHE_NEXT_FREE (cpu) 40298b9484cSchristos - (char *) CPU_SCACHE_CACHE (cpu)) 40398b9484cSchristos / elm_size); 40498b9484cSchristos int elms_left = CPU_SCACHE_SIZE (cpu) - elms_used; 40598b9484cSchristos 40698b9484cSchristos if (elms_left < n) 40798b9484cSchristos { 40898b9484cSchristos PROFILE_COUNT_SCACHE_FULL_FLUSH (cpu); 40998b9484cSchristos scache_flush_cpu (cpu); 41098b9484cSchristos } 41198b9484cSchristos } 41298b9484cSchristos 41398b9484cSchristos sc = CPU_SCACHE_NEXT_FREE (cpu); 41498b9484cSchristos scm->pc = pc; 41598b9484cSchristos scm->sc = sc; 41698b9484cSchristos 41798b9484cSchristos *bufp = sc; 41898b9484cSchristos return NULL; 41998b9484cSchristos } 42098b9484cSchristos 42198b9484cSchristos #endif /* WITH_SCACHE_PBB */ 42298b9484cSchristos 42398b9484cSchristos /* Print cache access statics for CPU. */ 42498b9484cSchristos 42598b9484cSchristos void 426*88241920Schristos scache_print_profile (SIM_CPU *cpu, bool verbose) 42798b9484cSchristos { 42898b9484cSchristos SIM_DESC sd = CPU_STATE (cpu); 42998b9484cSchristos unsigned long hits = CPU_SCACHE_HITS (cpu); 43098b9484cSchristos unsigned long misses = CPU_SCACHE_MISSES (cpu); 43198b9484cSchristos char buf[20]; 43298b9484cSchristos 43398b9484cSchristos if (CPU_SCACHE_SIZE (cpu) == 0) 43498b9484cSchristos return; 43598b9484cSchristos 43698b9484cSchristos sim_io_printf (sd, "Simulator Cache Statistics\n\n"); 43798b9484cSchristos 43898b9484cSchristos /* One could use PROFILE_LABEL_WIDTH here. I chose not to. */ 43998b9484cSchristos sim_io_printf (sd, " Cache size: %s\n", 44098b9484cSchristos sim_add_commas (buf, sizeof (buf), CPU_SCACHE_SIZE (cpu))); 44198b9484cSchristos sim_io_printf (sd, " Hits: %s\n", 44298b9484cSchristos sim_add_commas (buf, sizeof (buf), hits)); 44398b9484cSchristos sim_io_printf (sd, " Misses: %s\n", 44498b9484cSchristos sim_add_commas (buf, sizeof (buf), misses)); 44598b9484cSchristos if (hits + misses != 0) 44698b9484cSchristos sim_io_printf (sd, " Hit rate: %.2f%%\n", 44798b9484cSchristos ((double) hits / ((double) hits + (double) misses)) * 100); 44898b9484cSchristos 44998b9484cSchristos #if WITH_SCACHE_PBB 45098b9484cSchristos sim_io_printf (sd, "\n"); 45198b9484cSchristos sim_io_printf (sd, " Hash table size: %s\n", 45298b9484cSchristos sim_add_commas (buf, sizeof (buf), CPU_SCACHE_NUM_HASH_CHAINS (cpu))); 45398b9484cSchristos sim_io_printf (sd, " Max hash list length: %s\n", 45498b9484cSchristos sim_add_commas (buf, sizeof (buf), CPU_SCACHE_NUM_HASH_CHAIN_ENTRIES (cpu))); 45598b9484cSchristos sim_io_printf (sd, " Max insn chain length: %s\n", 45698b9484cSchristos sim_add_commas (buf, sizeof (buf), CPU_SCACHE_MAX_CHAIN_LENGTH (cpu))); 45798b9484cSchristos sim_io_printf (sd, " Cache full flushes: %s\n", 45898b9484cSchristos sim_add_commas (buf, sizeof (buf), CPU_SCACHE_FULL_FLUSHES (cpu))); 45998b9484cSchristos sim_io_printf (sd, "\n"); 46098b9484cSchristos 46198b9484cSchristos if (verbose) 46298b9484cSchristos { 463*88241920Schristos unsigned long max_val; 464*88241920Schristos unsigned long *lengths; 465*88241920Schristos int i; 466*88241920Schristos 46798b9484cSchristos sim_io_printf (sd, " Insn chain lengths:\n\n"); 46898b9484cSchristos max_val = 0; 46998b9484cSchristos lengths = CPU_SCACHE_CHAIN_LENGTHS (cpu); 47098b9484cSchristos for (i = 1; i < CPU_SCACHE_MAX_CHAIN_LENGTH (cpu); ++i) 47198b9484cSchristos if (lengths[i] > max_val) 47298b9484cSchristos max_val = lengths[i]; 47398b9484cSchristos for (i = 1; i < CPU_SCACHE_MAX_CHAIN_LENGTH (cpu); ++i) 47498b9484cSchristos { 47598b9484cSchristos sim_io_printf (sd, " %2d: %*s: ", 47698b9484cSchristos i, 47798b9484cSchristos max_val < 10000 ? 5 : 10, 47898b9484cSchristos sim_add_commas (buf, sizeof (buf), lengths[i])); 47998b9484cSchristos sim_profile_print_bar (sd, cpu, PROFILE_HISTOGRAM_WIDTH, 48098b9484cSchristos lengths[i], max_val); 48198b9484cSchristos sim_io_printf (sd, "\n"); 48298b9484cSchristos } 48398b9484cSchristos sim_io_printf (sd, "\n"); 48498b9484cSchristos } 48598b9484cSchristos #endif /* WITH_SCACHE_PBB */ 48698b9484cSchristos } 487