|  | # Simulator main loop for m32r. -*- C -*- | 
|  | # | 
|  | # Copyright (C) 1996-2018 Free Software Foundation, Inc. | 
|  | # | 
|  | # This file is part of the GNU Simulators. | 
|  | # | 
|  | # This program is free software; you can redistribute it and/or modify | 
|  | # it under the terms of the GNU General Public License as published by | 
|  | # the Free Software Foundation; either version 3 of the License, or | 
|  | # (at your option) any later version. | 
|  | # | 
|  | # This program is distributed in the hope that it will be useful, | 
|  | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | # GNU General Public License for more details. | 
|  | # | 
|  | # You should have received a copy of the GNU General Public License | 
|  | # along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
|  |  | 
|  | # Syntax: | 
|  | # /bin/sh mainloop.in command | 
|  | # | 
|  | # Command is one of: | 
|  | # | 
|  | # init | 
|  | # support | 
|  | # extract-{simple,scache,pbb} | 
|  | # {full,fast}-exec-{simple,scache,pbb} | 
|  | # | 
|  | # A target need only provide a "full" version of one of simple,scache,pbb. | 
|  | # If the target wants it can also provide a fast version of same, or if | 
|  | # the slow (full featured) version is `simple', then the fast version can be | 
|  | # one of scache/pbb. | 
|  | # A target can't provide more than this. | 
|  | # However for illustration's sake this file provides examples of all. | 
|  |  | 
|  | # ??? After a few more ports are done, revisit. | 
|  | # Will eventually need to machine generate a lot of this. | 
|  |  | 
|  | case "x$1" in | 
|  |  | 
|  | xsupport) | 
|  |  | 
|  | cat <<EOF | 
|  |  | 
|  | static INLINE const IDESC * | 
|  | extract16 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn, | 
|  | ARGBUF *abuf, int fast_p) | 
|  | { | 
|  | const IDESC *id = @cpu@_decode (current_cpu, pc, insn, insn, abuf); | 
|  |  | 
|  | @cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p); | 
|  | if (! fast_p) | 
|  | { | 
|  | int trace_p = PC_IN_TRACE_RANGE_P (current_cpu, pc); | 
|  | int profile_p = PC_IN_PROFILE_RANGE_P (current_cpu, pc); | 
|  | @cpu@_fill_argbuf_tp (current_cpu, abuf, trace_p, profile_p); | 
|  | } | 
|  | return id; | 
|  | } | 
|  |  | 
|  | static INLINE const IDESC * | 
|  | extract32 (SIM_CPU *current_cpu, PCADDR pc, CGEN_INSN_INT insn, | 
|  | ARGBUF *abuf, int fast_p) | 
|  | { | 
|  | const IDESC *id = @cpu@_decode (current_cpu, pc, (USI) insn >> 16, insn, abuf); | 
|  |  | 
|  | @cpu@_fill_argbuf (current_cpu, abuf, id, pc, fast_p); | 
|  | if (! fast_p) | 
|  | { | 
|  | int trace_p = PC_IN_TRACE_RANGE_P (current_cpu, pc); | 
|  | int profile_p = PC_IN_PROFILE_RANGE_P (current_cpu, pc); | 
|  | @cpu@_fill_argbuf_tp (current_cpu, abuf, trace_p, profile_p); | 
|  | } | 
|  | return id; | 
|  | } | 
|  |  | 
|  | static INLINE SEM_PC | 
|  | execute (SIM_CPU *current_cpu, SCACHE *sc, int fast_p) | 
|  | { | 
|  | SEM_PC vpc; | 
|  |  | 
|  | if (fast_p) | 
|  | { | 
|  | #if ! WITH_SEM_SWITCH_FAST | 
|  | #if WITH_SCACHE | 
|  | vpc = (*sc->argbuf.semantic.sem_fast) (current_cpu, sc); | 
|  | #else | 
|  | vpc = (*sc->argbuf.semantic.sem_fast) (current_cpu, &sc->argbuf); | 
|  | #endif | 
|  | #else | 
|  | abort (); | 
|  | #endif /* WITH_SEM_SWITCH_FAST */ | 
|  | } | 
|  | else | 
|  | { | 
|  | #if ! WITH_SEM_SWITCH_FULL | 
|  | ARGBUF *abuf = &sc->argbuf; | 
|  | const IDESC *idesc = abuf->idesc; | 
|  | const CGEN_INSN *idata = idesc->idata; | 
|  | #if WITH_SCACHE_PBB | 
|  | int virtual_p = CGEN_INSN_ATTR_VALUE (idata, CGEN_INSN_VIRTUAL); | 
|  | #else | 
|  | int virtual_p = 0; | 
|  | #endif | 
|  |  | 
|  | if (! virtual_p) | 
|  | { | 
|  | /* FIXME: call x-before */ | 
|  | if (ARGBUF_PROFILE_P (abuf)) | 
|  | PROFILE_COUNT_INSN (current_cpu, abuf->addr, idesc->num); | 
|  | /* FIXME: Later make cover macros: PROFILE_INSN_{INIT,FINI}.  */ | 
|  | if (PROFILE_MODEL_P (current_cpu) | 
|  | && ARGBUF_PROFILE_P (abuf)) | 
|  | @cpu@_model_insn_before (current_cpu, 1 /*first_p*/); | 
|  | CGEN_TRACE_INSN_INIT (current_cpu, abuf, 1); | 
|  | CGEN_TRACE_INSN (current_cpu, idata, | 
|  | (const struct argbuf *) abuf, abuf->addr); | 
|  | } | 
|  | #if WITH_SCACHE | 
|  | vpc = (*sc->argbuf.semantic.sem_full) (current_cpu, sc); | 
|  | #else | 
|  | vpc = (*sc->argbuf.semantic.sem_full) (current_cpu, abuf); | 
|  | #endif | 
|  | if (! virtual_p) | 
|  | { | 
|  | /* FIXME: call x-after */ | 
|  | if (PROFILE_MODEL_P (current_cpu) | 
|  | && ARGBUF_PROFILE_P (abuf)) | 
|  | { | 
|  | int cycles; | 
|  |  | 
|  | cycles = (*idesc->timing->model_fn) (current_cpu, sc); | 
|  | @cpu@_model_insn_after (current_cpu, 1 /*last_p*/, cycles); | 
|  | } | 
|  | CGEN_TRACE_INSN_FINI (current_cpu, abuf, 1); | 
|  | } | 
|  | #else | 
|  | abort (); | 
|  | #endif /* WITH_SEM_SWITCH_FULL */ | 
|  | } | 
|  |  | 
|  | return vpc; | 
|  | } | 
|  |  | 
|  | EOF | 
|  |  | 
|  | ;; | 
|  |  | 
|  | xinit) | 
|  |  | 
|  | # Nothing needed. | 
|  |  | 
|  | ;; | 
|  |  | 
|  | xextract-simple | xextract-scache) | 
|  |  | 
|  | cat <<EOF | 
|  | { | 
|  | if ((pc & 3) != 0) | 
|  | { | 
|  | /* This only occurs when single stepping. | 
|  | The test is unnecessary otherwise, but the cost is teensy, | 
|  | compared with decoding/extraction.  */ | 
|  | UHI insn = GETIMEMUHI (current_cpu, pc); | 
|  | extract16 (current_cpu, pc, insn & 0x7fff, sc, FAST_P); | 
|  | } | 
|  | else | 
|  | { | 
|  | USI insn = GETIMEMUSI (current_cpu, pc); | 
|  | if ((SI) insn < 0) | 
|  | { | 
|  | extract32 (current_cpu, pc, insn, sc, FAST_P); | 
|  | } | 
|  | else | 
|  | { | 
|  | extract16 (current_cpu, pc, insn >> 16, sc, FAST_P); | 
|  | extract16 (current_cpu, pc + 2, insn & 0x7fff, sc + 1, FAST_P); | 
|  | /* The m32r doesn't support parallel execution.  */ | 
|  | if ((insn & 0x8000) != 0 | 
|  | && (insn & 0x7fff) != 0x7000) /* parallel nops are ok */ | 
|  | sim_engine_illegal_insn (current_cpu, pc); | 
|  | } | 
|  | } | 
|  | } | 
|  | EOF | 
|  |  | 
|  | ;; | 
|  |  | 
|  | xextract-pbb) | 
|  |  | 
|  | # Inputs:  current_cpu, pc, sc, max_insns, FAST_P | 
|  | # Outputs: sc, pc | 
|  | # sc must be left pointing past the last created entry. | 
|  | # pc must be left pointing past the last created entry. | 
|  | # If the pbb is terminated by a cti insn, SET_CTI_VPC(sc) must be called | 
|  | # to record the vpc of the cti insn. | 
|  | # SET_INSN_COUNT(n) must be called to record number of real insns. | 
|  |  | 
|  | cat <<EOF | 
|  | { | 
|  | const IDESC *idesc; | 
|  | int icount = 0; | 
|  |  | 
|  | if ((pc & 3) != 0) | 
|  | { | 
|  | /* This only occurs when single stepping. | 
|  | The test is unnecessary otherwise, but the cost is teensy, | 
|  | compared with decoding/extraction.  */ | 
|  | UHI insn = GETIMEMUHI (current_cpu, pc); | 
|  | idesc = extract16 (current_cpu, pc, insn & 0x7fff, &sc->argbuf, FAST_P); | 
|  | ++sc; | 
|  | --max_insns; | 
|  | ++icount; | 
|  | pc += 2; | 
|  | if (IDESC_CTI_P (idesc)) | 
|  | { | 
|  | SET_CTI_VPC (sc - 1); | 
|  | goto Finish; | 
|  | } | 
|  | } | 
|  |  | 
|  | while (max_insns > 0) | 
|  | { | 
|  | USI insn = GETIMEMUSI (current_cpu, pc); | 
|  | if ((SI) insn < 0) | 
|  | { | 
|  | idesc = extract32 (current_cpu, pc, insn, &sc->argbuf, FAST_P); | 
|  | ++sc; | 
|  | --max_insns; | 
|  | ++icount; | 
|  | pc += 4; | 
|  | if (IDESC_CTI_P (idesc)) | 
|  | { | 
|  | SET_CTI_VPC (sc - 1); | 
|  | break; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | idesc = extract16 (current_cpu, pc, insn >> 16, &sc->argbuf, FAST_P); | 
|  | ++sc; | 
|  | --max_insns; | 
|  | ++icount; | 
|  | pc += 2; | 
|  | if (IDESC_CTI_P (idesc)) | 
|  | { | 
|  | SET_CTI_VPC (sc - 1); | 
|  | break; | 
|  | } | 
|  | /* The m32r doesn't support parallel execution.  */ | 
|  | if ((insn & 0x8000) != 0) | 
|  | { | 
|  | /* ??? Defer signalling to execution.  */ | 
|  | if ((insn & 0x7fff) != 0x7000) /* parallel nops are ok */ | 
|  | sim_engine_invalid_insn (current_cpu, pc - 2, 0); | 
|  | /* There's no point in processing parallel nops in fast mode. | 
|  | We might as well do this test since we've already tested | 
|  | that we have a parallel nop.  */ | 
|  | if (0 && FAST_P) | 
|  | { | 
|  | pc += 2; | 
|  | continue; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Non-parallel case. | 
|  | While we're guaranteed that there's room to extract the | 
|  | insn, when single stepping we can't; the pbb must stop | 
|  | after the first insn.  */ | 
|  | if (max_insns == 0) | 
|  | break; | 
|  | } | 
|  | /* We're guaranteed that we can always process 16 bit insns in | 
|  | pairs.  */ | 
|  | idesc = extract16 (current_cpu, pc, insn & 0x7fff, &sc->argbuf, FAST_P); | 
|  | ++sc; | 
|  | --max_insns; | 
|  | ++icount; | 
|  | pc += 2; | 
|  | if (IDESC_CTI_P (idesc)) | 
|  | { | 
|  | SET_CTI_VPC (sc - 1); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | Finish: | 
|  | SET_INSN_COUNT (icount); | 
|  | } | 
|  | EOF | 
|  |  | 
|  | ;; | 
|  |  | 
|  | xfull-exec-* | xfast-exec-*) | 
|  |  | 
|  | # Inputs: current_cpu, vpc, FAST_P | 
|  | # Outputs: vpc | 
|  | # vpc is the virtual program counter. | 
|  |  | 
|  | cat <<EOF | 
|  | #if (! FAST_P && WITH_SEM_SWITCH_FULL) || (FAST_P && WITH_SEM_SWITCH_FAST) | 
|  | #define DEFINE_SWITCH | 
|  | #include "sem-switch.c" | 
|  | #else | 
|  | vpc = execute (current_cpu, vpc, FAST_P); | 
|  | #endif | 
|  | EOF | 
|  |  | 
|  | ;; | 
|  |  | 
|  | *) | 
|  | echo "Invalid argument to mainloop.in: $1" >&2 | 
|  | exit 1 | 
|  | ;; | 
|  |  | 
|  | esac |