198b9484cSchristos /* Main simulator loop for CGEN-based simulators. 2*88241920Schristos Copyright (C) 1998-2024 Free Software Foundation, Inc. 398b9484cSchristos Contributed by Cygnus Solutions. 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 2098b9484cSchristos /* ??? These are old notes, kept around for now. 2198b9484cSchristos Collecting profile data and tracing slow us down so we don't do them in 2298b9484cSchristos "fast mode". 2398b9484cSchristos There are 6 possibilities on 2 axes: 2498b9484cSchristos - no-scaching, insn-scaching, basic-block-scaching 2598b9484cSchristos - run with full features or run fast 2698b9484cSchristos Supporting all six possibilities in one executable is a bit much but 2798b9484cSchristos supporting full/fast seems reasonable. 2898b9484cSchristos If the scache is configured in it is always used. 2998b9484cSchristos If pbb-scaching is configured in it is always used. 3098b9484cSchristos ??? Sometimes supporting more than one set of semantic functions will make 3198b9484cSchristos the simulator too large - this should be configurable. Blah blah blah. 3298b9484cSchristos ??? Supporting full/fast can be more modular, blah blah blah. 3398b9484cSchristos When the framework is more modular, this can be. 3498b9484cSchristos */ 3598b9484cSchristos 364b169a6bSchristos /* This must come before any other includes. */ 374b169a6bSchristos #include "defs.h" 384b169a6bSchristos 3998b9484cSchristos #include "sim-main.h" 4098b9484cSchristos #include "sim-assert.h" 414b169a6bSchristos #include "sim-signal.h" 4298b9484cSchristos 4398b9484cSchristos #ifndef SIM_ENGINE_PREFIX_HOOK 4498b9484cSchristos #define SIM_ENGINE_PREFIX_HOOK(sd) 4598b9484cSchristos #endif 4698b9484cSchristos #ifndef SIM_ENGINE_POSTFIX_HOOK 4798b9484cSchristos #define SIM_ENGINE_POSTFIX_HOOK(sd) 4898b9484cSchristos #endif 4998b9484cSchristos 5098b9484cSchristos static sim_event_handler has_stepped; 5198b9484cSchristos static void prime_cpu (SIM_CPU *, int); 5298b9484cSchristos static void engine_run_1 (SIM_DESC, int, int); 5398b9484cSchristos static void engine_run_n (SIM_DESC, int, int, int, int); 5498b9484cSchristos 554b169a6bSchristos /* If no profiling or tracing has been enabled, run in fast mode. */ 564b169a6bSchristos static int 574b169a6bSchristos cgen_get_fast_p (SIM_DESC sd) 584b169a6bSchristos { 59*88241920Schristos int c; 604b169a6bSchristos 614b169a6bSchristos for (c = 0; c < MAX_NR_PROCESSORS; ++c) 624b169a6bSchristos { 634b169a6bSchristos SIM_CPU *cpu = STATE_CPU (sd, c); 644b169a6bSchristos 654b169a6bSchristos if (PROFILE_ANY_P (cpu) || TRACE_ANY_P (cpu)) 664b169a6bSchristos return 0; 674b169a6bSchristos } 684b169a6bSchristos 694b169a6bSchristos return 1; 704b169a6bSchristos } 714b169a6bSchristos 7298b9484cSchristos /* sim_resume for cgen */ 7398b9484cSchristos 7498b9484cSchristos void 7598b9484cSchristos sim_resume (SIM_DESC sd, int step, int siggnal) 7698b9484cSchristos { 7798b9484cSchristos sim_engine *engine = STATE_ENGINE (sd); 7898b9484cSchristos jmp_buf buf; 7998b9484cSchristos int jmpval; 804b169a6bSchristos static int fast_p = -1; 8198b9484cSchristos 8298b9484cSchristos ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); 8398b9484cSchristos 844b169a6bSchristos if (fast_p == -1) 854b169a6bSchristos fast_p = cgen_get_fast_p (sd); 864b169a6bSchristos 8798b9484cSchristos /* we only want to be single stepping the simulator once */ 8898b9484cSchristos if (engine->stepper != NULL) 8998b9484cSchristos { 9098b9484cSchristos sim_events_deschedule (sd, engine->stepper); 9198b9484cSchristos engine->stepper = NULL; 9298b9484cSchristos } 9398b9484cSchristos if (step) 9498b9484cSchristos engine->stepper = sim_events_schedule (sd, 1, has_stepped, sd); 9598b9484cSchristos 9698b9484cSchristos sim_module_resume (sd); 9798b9484cSchristos 9898b9484cSchristos #if WITH_SCACHE 9998b9484cSchristos if (USING_SCACHE_P (sd)) 10098b9484cSchristos scache_flush (sd); 10198b9484cSchristos #endif 10298b9484cSchristos 10398b9484cSchristos /* run/resume the simulator */ 10498b9484cSchristos 10598b9484cSchristos sim_engine_set_run_state (sd, sim_running, 0); 10698b9484cSchristos 10798b9484cSchristos engine->jmpbuf = &buf; 10898b9484cSchristos jmpval = setjmp (buf); 10998b9484cSchristos if (jmpval == sim_engine_start_jmpval 11098b9484cSchristos || jmpval == sim_engine_restart_jmpval) 11198b9484cSchristos { 11298b9484cSchristos int last_cpu_nr = sim_engine_last_cpu_nr (sd); 11398b9484cSchristos int next_cpu_nr = sim_engine_next_cpu_nr (sd); 11498b9484cSchristos int nr_cpus = sim_engine_nr_cpus (sd); 11598b9484cSchristos /* ??? Setting max_insns to 0 allows pbb/jit code to run wild and is 11698b9484cSchristos useful if all one wants to do is run a benchmark. Need some better 11798b9484cSchristos way to identify this case. */ 11898b9484cSchristos int max_insns = (step 11998b9484cSchristos ? 1 12098b9484cSchristos : (nr_cpus == 1 12198b9484cSchristos /*&& wip:no-events*/ 12298b9484cSchristos /* Don't do this if running under gdb, need to 12398b9484cSchristos poll ui for events. */ 12498b9484cSchristos && STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) 12598b9484cSchristos ? 0 12698b9484cSchristos : 8); /*FIXME: magic number*/ 12798b9484cSchristos 12898b9484cSchristos sim_events_preprocess (sd, last_cpu_nr >= nr_cpus, next_cpu_nr >= nr_cpus); 12998b9484cSchristos if (next_cpu_nr >= nr_cpus) 13098b9484cSchristos next_cpu_nr = 0; 13198b9484cSchristos if (nr_cpus == 1) 13298b9484cSchristos engine_run_1 (sd, max_insns, fast_p); 13398b9484cSchristos else 13498b9484cSchristos engine_run_n (sd, next_cpu_nr, nr_cpus, max_insns, fast_p); 13598b9484cSchristos } 13698b9484cSchristos #if 1 /*wip*/ 13798b9484cSchristos else 13898b9484cSchristos { 13998b9484cSchristos /* Account for the last insn executed. */ 14098b9484cSchristos SIM_CPU *cpu = STATE_CPU (sd, sim_engine_last_cpu_nr (sd)); 14198b9484cSchristos ++ CPU_INSN_COUNT (cpu); 142212397c6Schristos CGEN_TRACE_INSN_FINI (cpu, NULL, 1); 14398b9484cSchristos } 14498b9484cSchristos #endif 14598b9484cSchristos 14698b9484cSchristos engine->jmpbuf = NULL; 14798b9484cSchristos 14898b9484cSchristos { 14998b9484cSchristos int i; 15098b9484cSchristos int nr_cpus = sim_engine_nr_cpus (sd); 15198b9484cSchristos 15298b9484cSchristos #if 0 /*wip,ignore*/ 15398b9484cSchristos /* If the loop exits, either we single-stepped or @cpu@_engine_stop 15498b9484cSchristos was called. */ 15598b9484cSchristos if (step) 15698b9484cSchristos sim_engine_set_run_state (sd, sim_stopped, SIM_SIGTRAP); 15798b9484cSchristos else 15898b9484cSchristos sim_engine_set_run_state (sd, pending_reason, pending_sigrc); 15998b9484cSchristos #endif 16098b9484cSchristos 16198b9484cSchristos for (i = 0; i < nr_cpus; ++i) 16298b9484cSchristos { 16398b9484cSchristos SIM_CPU *cpu = STATE_CPU (sd, i); 16498b9484cSchristos 16598b9484cSchristos PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu)) += CPU_INSN_COUNT (cpu); 16698b9484cSchristos } 16798b9484cSchristos } 16898b9484cSchristos 16998b9484cSchristos sim_module_suspend (sd); 17098b9484cSchristos } 17198b9484cSchristos 17298b9484cSchristos /* Halt the simulator after just one instruction. */ 17398b9484cSchristos 17498b9484cSchristos static void 17598b9484cSchristos has_stepped (SIM_DESC sd, void *data) 17698b9484cSchristos { 17798b9484cSchristos ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); 17898b9484cSchristos sim_engine_halt (sd, NULL, NULL, NULL_CIA, sim_stopped, SIM_SIGTRAP); 17998b9484cSchristos } 18098b9484cSchristos 18198b9484cSchristos /* Prepare a cpu for running. 18298b9484cSchristos MAX_INSNS is the number of insns to execute per time slice. 18398b9484cSchristos If 0 it means the cpu can run as long as it wants (e.g. until the 18498b9484cSchristos program completes). 18598b9484cSchristos ??? Perhaps this should be an argument to the engine_fn. */ 18698b9484cSchristos 18798b9484cSchristos static void 18898b9484cSchristos prime_cpu (SIM_CPU *cpu, int max_insns) 18998b9484cSchristos { 19098b9484cSchristos CPU_MAX_SLICE_INSNS (cpu) = max_insns; 19198b9484cSchristos CPU_INSN_COUNT (cpu) = 0; 19298b9484cSchristos 19398b9484cSchristos /* Initialize the insn descriptor table. 19498b9484cSchristos This has to be done after all initialization so we just defer it to 19598b9484cSchristos here. */ 19698b9484cSchristos 19798b9484cSchristos if (MACH_PREPARE_RUN (CPU_MACH (cpu))) 19898b9484cSchristos (* MACH_PREPARE_RUN (CPU_MACH (cpu))) (cpu); 19998b9484cSchristos } 20098b9484cSchristos 20198b9484cSchristos /* Main loop, for 1 cpu. */ 20298b9484cSchristos 20398b9484cSchristos static void 20498b9484cSchristos engine_run_1 (SIM_DESC sd, int max_insns, int fast_p) 20598b9484cSchristos { 20698b9484cSchristos sim_cpu *cpu = STATE_CPU (sd, 0); 20798b9484cSchristos ENGINE_FN *fn = fast_p ? CPU_FAST_ENGINE_FN (cpu) : CPU_FULL_ENGINE_FN (cpu); 20898b9484cSchristos 20998b9484cSchristos prime_cpu (cpu, max_insns); 21098b9484cSchristos 21198b9484cSchristos while (1) 21298b9484cSchristos { 21398b9484cSchristos SIM_ENGINE_PREFIX_HOOK (sd); 21498b9484cSchristos 21598b9484cSchristos (*fn) (cpu); 21698b9484cSchristos 21798b9484cSchristos SIM_ENGINE_POSTFIX_HOOK (sd); 21898b9484cSchristos 21998b9484cSchristos /* process any events */ 22098b9484cSchristos if (sim_events_tick (sd)) 22198b9484cSchristos sim_events_process (sd); 22298b9484cSchristos } 22398b9484cSchristos } 22498b9484cSchristos 22598b9484cSchristos /* Main loop, for multiple cpus. */ 22698b9484cSchristos 22798b9484cSchristos static void 22898b9484cSchristos engine_run_n (SIM_DESC sd, int next_cpu_nr, int nr_cpus, int max_insns, int fast_p) 22998b9484cSchristos { 23098b9484cSchristos int i; 2314b169a6bSchristos /* Ensure that engine_fns is fully initialized, this silences a compiler 2324b169a6bSchristos warning when engine_fns is used below. */ 2334b169a6bSchristos ENGINE_FN *engine_fns[MAX_NR_PROCESSORS] = {}; 2344b169a6bSchristos 2354b169a6bSchristos SIM_ASSERT (nr_cpus <= MAX_NR_PROCESSORS); 2364b169a6bSchristos SIM_ASSERT (next_cpu_nr >= 0 && next_cpu_nr < nr_cpus); 23798b9484cSchristos 23898b9484cSchristos for (i = 0; i < nr_cpus; ++i) 23998b9484cSchristos { 24098b9484cSchristos SIM_CPU *cpu = STATE_CPU (sd, i); 24198b9484cSchristos 24298b9484cSchristos engine_fns[i] = fast_p ? CPU_FAST_ENGINE_FN (cpu) : CPU_FULL_ENGINE_FN (cpu); 24398b9484cSchristos prime_cpu (cpu, max_insns); 24498b9484cSchristos } 24598b9484cSchristos 24698b9484cSchristos while (1) 24798b9484cSchristos { 24898b9484cSchristos SIM_ENGINE_PREFIX_HOOK (sd); 24998b9484cSchristos 25098b9484cSchristos /* FIXME: proper cycling of all of them, blah blah blah. */ 2514b169a6bSchristos while (next_cpu_nr < nr_cpus) 25298b9484cSchristos { 25398b9484cSchristos SIM_CPU *cpu = STATE_CPU (sd, next_cpu_nr); 25498b9484cSchristos 25598b9484cSchristos (* engine_fns[next_cpu_nr]) (cpu); 25698b9484cSchristos ++next_cpu_nr; 25798b9484cSchristos } 25898b9484cSchristos 25998b9484cSchristos SIM_ENGINE_POSTFIX_HOOK (sd); 26098b9484cSchristos 26198b9484cSchristos /* process any events */ 26298b9484cSchristos if (sim_events_tick (sd)) 26398b9484cSchristos sim_events_process (sd); 26498b9484cSchristos } 26598b9484cSchristos } 266