1/* Main simulator loop for CGEN-based simulators. 2 Copyright (C) 1998, 2007 Free Software Foundation, Inc. 3 Contributed by Cygnus Solutions. 4 5This file is part of GDB, the GNU debugger. 6 7This program is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 3 of the License, or 10(at your option) any later version. 11 12This program is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along 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#include "sim-main.h" 37#include "sim-assert.h" 38 39#ifndef SIM_ENGINE_PREFIX_HOOK 40#define SIM_ENGINE_PREFIX_HOOK(sd) 41#endif 42#ifndef SIM_ENGINE_POSTFIX_HOOK 43#define SIM_ENGINE_POSTFIX_HOOK(sd) 44#endif 45 46static sim_event_handler has_stepped; 47static void prime_cpu (SIM_CPU *, int); 48static void engine_run_1 (SIM_DESC, int, int); 49static void engine_run_n (SIM_DESC, int, int, int, int); 50 51/* sim_resume for cgen */ 52 53void 54sim_resume (SIM_DESC sd, int step, int siggnal) 55{ 56 sim_engine *engine = STATE_ENGINE (sd); 57 jmp_buf buf; 58 int jmpval; 59 60 ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); 61 62 /* we only want to be single stepping the simulator once */ 63 if (engine->stepper != NULL) 64 { 65 sim_events_deschedule (sd, engine->stepper); 66 engine->stepper = NULL; 67 } 68 if (step) 69 engine->stepper = sim_events_schedule (sd, 1, has_stepped, sd); 70 71 sim_module_resume (sd); 72 73#if WITH_SCACHE 74 if (USING_SCACHE_P (sd)) 75 scache_flush (sd); 76#endif 77 78 /* run/resume the simulator */ 79 80 sim_engine_set_run_state (sd, sim_running, 0); 81 82 engine->jmpbuf = &buf; 83 jmpval = setjmp (buf); 84 if (jmpval == sim_engine_start_jmpval 85 || jmpval == sim_engine_restart_jmpval) 86 { 87 int last_cpu_nr = sim_engine_last_cpu_nr (sd); 88 int next_cpu_nr = sim_engine_next_cpu_nr (sd); 89 int nr_cpus = sim_engine_nr_cpus (sd); 90 /* ??? Setting max_insns to 0 allows pbb/jit code to run wild and is 91 useful if all one wants to do is run a benchmark. Need some better 92 way to identify this case. */ 93 int max_insns = (step 94 ? 1 95 : (nr_cpus == 1 96 /*&& wip:no-events*/ 97 /* Don't do this if running under gdb, need to 98 poll ui for events. */ 99 && STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) 100 ? 0 101 : 8); /*FIXME: magic number*/ 102 int fast_p = STATE_RUN_FAST_P (sd); 103 104 sim_events_preprocess (sd, last_cpu_nr >= nr_cpus, next_cpu_nr >= nr_cpus); 105 if (next_cpu_nr >= nr_cpus) 106 next_cpu_nr = 0; 107 if (nr_cpus == 1) 108 engine_run_1 (sd, max_insns, fast_p); 109 else 110 engine_run_n (sd, next_cpu_nr, nr_cpus, max_insns, fast_p); 111 } 112#if 1 /*wip*/ 113 else 114 { 115 /* Account for the last insn executed. */ 116 SIM_CPU *cpu = STATE_CPU (sd, sim_engine_last_cpu_nr (sd)); 117 ++ CPU_INSN_COUNT (cpu); 118 TRACE_INSN_FINI (cpu, NULL, 1); 119 } 120#endif 121 122 engine->jmpbuf = NULL; 123 124 { 125 int i; 126 int nr_cpus = sim_engine_nr_cpus (sd); 127 128#if 0 /*wip,ignore*/ 129 /* If the loop exits, either we single-stepped or @cpu@_engine_stop 130 was called. */ 131 if (step) 132 sim_engine_set_run_state (sd, sim_stopped, SIM_SIGTRAP); 133 else 134 sim_engine_set_run_state (sd, pending_reason, pending_sigrc); 135#endif 136 137 for (i = 0; i < nr_cpus; ++i) 138 { 139 SIM_CPU *cpu = STATE_CPU (sd, i); 140 141 PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu)) += CPU_INSN_COUNT (cpu); 142 } 143 } 144 145 sim_module_suspend (sd); 146} 147 148/* Halt the simulator after just one instruction. */ 149 150static void 151has_stepped (SIM_DESC sd, void *data) 152{ 153 ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); 154 sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIM_SIGTRAP); 155} 156 157/* Prepare a cpu for running. 158 MAX_INSNS is the number of insns to execute per time slice. 159 If 0 it means the cpu can run as long as it wants (e.g. until the 160 program completes). 161 ??? Perhaps this should be an argument to the engine_fn. */ 162 163static void 164prime_cpu (SIM_CPU *cpu, int max_insns) 165{ 166 CPU_MAX_SLICE_INSNS (cpu) = max_insns; 167 CPU_INSN_COUNT (cpu) = 0; 168 169 /* Initialize the insn descriptor table. 170 This has to be done after all initialization so we just defer it to 171 here. */ 172 173 if (MACH_PREPARE_RUN (CPU_MACH (cpu))) 174 (* MACH_PREPARE_RUN (CPU_MACH (cpu))) (cpu); 175} 176 177/* Main loop, for 1 cpu. */ 178 179static void 180engine_run_1 (SIM_DESC sd, int max_insns, int fast_p) 181{ 182 sim_cpu *cpu = STATE_CPU (sd, 0); 183 ENGINE_FN *fn = fast_p ? CPU_FAST_ENGINE_FN (cpu) : CPU_FULL_ENGINE_FN (cpu); 184 185 prime_cpu (cpu, max_insns); 186 187 while (1) 188 { 189 SIM_ENGINE_PREFIX_HOOK (sd); 190 191 (*fn) (cpu); 192 193 SIM_ENGINE_POSTFIX_HOOK (sd); 194 195 /* process any events */ 196 if (sim_events_tick (sd)) 197 sim_events_process (sd); 198 } 199} 200 201/* Main loop, for multiple cpus. */ 202 203static void 204engine_run_n (SIM_DESC sd, int next_cpu_nr, int nr_cpus, int max_insns, int fast_p) 205{ 206 int i; 207 ENGINE_FN *engine_fns[MAX_NR_PROCESSORS]; 208 209 for (i = 0; i < nr_cpus; ++i) 210 { 211 SIM_CPU *cpu = STATE_CPU (sd, i); 212 213 engine_fns[i] = fast_p ? CPU_FAST_ENGINE_FN (cpu) : CPU_FULL_ENGINE_FN (cpu); 214 prime_cpu (cpu, max_insns); 215 } 216 217 while (1) 218 { 219 SIM_ENGINE_PREFIX_HOOK (sd); 220 221 /* FIXME: proper cycling of all of them, blah blah blah. */ 222 while (next_cpu_nr != nr_cpus) 223 { 224 SIM_CPU *cpu = STATE_CPU (sd, next_cpu_nr); 225 226 (* engine_fns[next_cpu_nr]) (cpu); 227 ++next_cpu_nr; 228 } 229 230 SIM_ENGINE_POSTFIX_HOOK (sd); 231 232 /* process any events */ 233 if (sim_events_tick (sd)) 234 sim_events_process (sd); 235 } 236} 237