1 /* Main simulator loop for CGEN-based simulators. 2 Copyright (C) 1998-2024 Free Software Foundation, Inc. 3 Contributed by Cygnus Solutions. 4 5 This file is part of GDB, the GNU debugger. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20 /* ??? These are old notes, kept around for now. 21 Collecting profile data and tracing slow us down so we don't do them in 22 "fast mode". 23 There are 6 possibilities on 2 axes: 24 - no-scaching, insn-scaching, basic-block-scaching 25 - run with full features or run fast 26 Supporting all six possibilities in one executable is a bit much but 27 supporting full/fast seems reasonable. 28 If the scache is configured in it is always used. 29 If pbb-scaching is configured in it is always used. 30 ??? Sometimes supporting more than one set of semantic functions will make 31 the simulator too large - this should be configurable. Blah blah blah. 32 ??? Supporting full/fast can be more modular, blah blah blah. 33 When the framework is more modular, this can be. 34 */ 35 36 /* This must come before any other includes. */ 37 #include "defs.h" 38 39 #include "sim-main.h" 40 #include "sim-assert.h" 41 #include "sim-signal.h" 42 43 #ifndef SIM_ENGINE_PREFIX_HOOK 44 #define SIM_ENGINE_PREFIX_HOOK(sd) 45 #endif 46 #ifndef SIM_ENGINE_POSTFIX_HOOK 47 #define SIM_ENGINE_POSTFIX_HOOK(sd) 48 #endif 49 50 static sim_event_handler has_stepped; 51 static void prime_cpu (SIM_CPU *, int); 52 static void engine_run_1 (SIM_DESC, int, int); 53 static void engine_run_n (SIM_DESC, int, int, int, int); 54 55 /* If no profiling or tracing has been enabled, run in fast mode. */ 56 static int 57 cgen_get_fast_p (SIM_DESC sd) 58 { 59 int c; 60 61 for (c = 0; c < MAX_NR_PROCESSORS; ++c) 62 { 63 SIM_CPU *cpu = STATE_CPU (sd, c); 64 65 if (PROFILE_ANY_P (cpu) || TRACE_ANY_P (cpu)) 66 return 0; 67 } 68 69 return 1; 70 } 71 72 /* sim_resume for cgen */ 73 74 void 75 sim_resume (SIM_DESC sd, int step, int siggnal) 76 { 77 sim_engine *engine = STATE_ENGINE (sd); 78 jmp_buf buf; 79 int jmpval; 80 static int fast_p = -1; 81 82 ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); 83 84 if (fast_p == -1) 85 fast_p = cgen_get_fast_p (sd); 86 87 /* we only want to be single stepping the simulator once */ 88 if (engine->stepper != NULL) 89 { 90 sim_events_deschedule (sd, engine->stepper); 91 engine->stepper = NULL; 92 } 93 if (step) 94 engine->stepper = sim_events_schedule (sd, 1, has_stepped, sd); 95 96 sim_module_resume (sd); 97 98 #if WITH_SCACHE 99 if (USING_SCACHE_P (sd)) 100 scache_flush (sd); 101 #endif 102 103 /* run/resume the simulator */ 104 105 sim_engine_set_run_state (sd, sim_running, 0); 106 107 engine->jmpbuf = &buf; 108 jmpval = setjmp (buf); 109 if (jmpval == sim_engine_start_jmpval 110 || jmpval == sim_engine_restart_jmpval) 111 { 112 int last_cpu_nr = sim_engine_last_cpu_nr (sd); 113 int next_cpu_nr = sim_engine_next_cpu_nr (sd); 114 int nr_cpus = sim_engine_nr_cpus (sd); 115 /* ??? Setting max_insns to 0 allows pbb/jit code to run wild and is 116 useful if all one wants to do is run a benchmark. Need some better 117 way to identify this case. */ 118 int max_insns = (step 119 ? 1 120 : (nr_cpus == 1 121 /*&& wip:no-events*/ 122 /* Don't do this if running under gdb, need to 123 poll ui for events. */ 124 && STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) 125 ? 0 126 : 8); /*FIXME: magic number*/ 127 128 sim_events_preprocess (sd, last_cpu_nr >= nr_cpus, next_cpu_nr >= nr_cpus); 129 if (next_cpu_nr >= nr_cpus) 130 next_cpu_nr = 0; 131 if (nr_cpus == 1) 132 engine_run_1 (sd, max_insns, fast_p); 133 else 134 engine_run_n (sd, next_cpu_nr, nr_cpus, max_insns, fast_p); 135 } 136 #if 1 /*wip*/ 137 else 138 { 139 /* Account for the last insn executed. */ 140 SIM_CPU *cpu = STATE_CPU (sd, sim_engine_last_cpu_nr (sd)); 141 ++ CPU_INSN_COUNT (cpu); 142 CGEN_TRACE_INSN_FINI (cpu, NULL, 1); 143 } 144 #endif 145 146 engine->jmpbuf = NULL; 147 148 { 149 int i; 150 int nr_cpus = sim_engine_nr_cpus (sd); 151 152 #if 0 /*wip,ignore*/ 153 /* If the loop exits, either we single-stepped or @cpu@_engine_stop 154 was called. */ 155 if (step) 156 sim_engine_set_run_state (sd, sim_stopped, SIM_SIGTRAP); 157 else 158 sim_engine_set_run_state (sd, pending_reason, pending_sigrc); 159 #endif 160 161 for (i = 0; i < nr_cpus; ++i) 162 { 163 SIM_CPU *cpu = STATE_CPU (sd, i); 164 165 PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu)) += CPU_INSN_COUNT (cpu); 166 } 167 } 168 169 sim_module_suspend (sd); 170 } 171 172 /* Halt the simulator after just one instruction. */ 173 174 static void 175 has_stepped (SIM_DESC sd, void *data) 176 { 177 ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); 178 sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIM_SIGTRAP); 179 } 180 181 /* Prepare a cpu for running. 182 MAX_INSNS is the number of insns to execute per time slice. 183 If 0 it means the cpu can run as long as it wants (e.g. until the 184 program completes). 185 ??? Perhaps this should be an argument to the engine_fn. */ 186 187 static void 188 prime_cpu (SIM_CPU *cpu, int max_insns) 189 { 190 CPU_MAX_SLICE_INSNS (cpu) = max_insns; 191 CPU_INSN_COUNT (cpu) = 0; 192 193 /* Initialize the insn descriptor table. 194 This has to be done after all initialization so we just defer it to 195 here. */ 196 197 if (MACH_PREPARE_RUN (CPU_MACH (cpu))) 198 (* MACH_PREPARE_RUN (CPU_MACH (cpu))) (cpu); 199 } 200 201 /* Main loop, for 1 cpu. */ 202 203 static void 204 engine_run_1 (SIM_DESC sd, int max_insns, int fast_p) 205 { 206 sim_cpu *cpu = STATE_CPU (sd, 0); 207 ENGINE_FN *fn = fast_p ? CPU_FAST_ENGINE_FN (cpu) : CPU_FULL_ENGINE_FN (cpu); 208 209 prime_cpu (cpu, max_insns); 210 211 while (1) 212 { 213 SIM_ENGINE_PREFIX_HOOK (sd); 214 215 (*fn) (cpu); 216 217 SIM_ENGINE_POSTFIX_HOOK (sd); 218 219 /* process any events */ 220 if (sim_events_tick (sd)) 221 sim_events_process (sd); 222 } 223 } 224 225 /* Main loop, for multiple cpus. */ 226 227 static void 228 engine_run_n (SIM_DESC sd, int next_cpu_nr, int nr_cpus, int max_insns, int fast_p) 229 { 230 int i; 231 /* Ensure that engine_fns is fully initialized, this silences a compiler 232 warning when engine_fns is used below. */ 233 ENGINE_FN *engine_fns[MAX_NR_PROCESSORS] = {}; 234 235 SIM_ASSERT (nr_cpus <= MAX_NR_PROCESSORS); 236 SIM_ASSERT (next_cpu_nr >= 0 && next_cpu_nr < nr_cpus); 237 238 for (i = 0; i < nr_cpus; ++i) 239 { 240 SIM_CPU *cpu = STATE_CPU (sd, i); 241 242 engine_fns[i] = fast_p ? CPU_FAST_ENGINE_FN (cpu) : CPU_FULL_ENGINE_FN (cpu); 243 prime_cpu (cpu, max_insns); 244 } 245 246 while (1) 247 { 248 SIM_ENGINE_PREFIX_HOOK (sd); 249 250 /* FIXME: proper cycling of all of them, blah blah blah. */ 251 while (next_cpu_nr < nr_cpus) 252 { 253 SIM_CPU *cpu = STATE_CPU (sd, next_cpu_nr); 254 255 (* engine_fns[next_cpu_nr]) (cpu); 256 ++next_cpu_nr; 257 } 258 259 SIM_ENGINE_POSTFIX_HOOK (sd); 260 261 /* process any events */ 262 if (sim_events_tick (sd)) 263 sim_events_process (sd); 264 } 265 } 266