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