| /* Support code for various pieces of CGEN simulators. | |
| Copyright (C) 1996-2021 Free Software Foundation, Inc. | |
| Contributed by Cygnus Support. | |
| This file is part of GDB, the GNU debugger. | |
| 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/>. */ | |
| /* This must come before any other includes. */ | |
| #include "defs.h" | |
| #include "bfd.h" | |
| #include "sim-main.h" | |
| #include "sim-signal.h" | |
| #include "dis-asm.h" | |
| #define MEMOPS_DEFINE_INLINE | |
| #include "cgen-mem.h" | |
| #define SEMOPS_DEFINE_INLINE | |
| #include "cgen-ops.h" | |
| const char * const cgen_mode_names[] = { | |
| "VOID", | |
| "BI", | |
| "QI", | |
| "HI", | |
| "SI", | |
| "DI", | |
| "UQI", | |
| "UHI", | |
| "USI", | |
| "UDI", | |
| "SF", | |
| "DF", | |
| "XF", | |
| "TF", | |
| 0, /* MODE_TARGET_MAX */ | |
| "INT", | |
| "UINT", | |
| "PTR" | |
| }; | |
| /* Opcode table for virtual insns used by the simulator. */ | |
| #define V CGEN_ATTR_MASK (CGEN_INSN_VIRTUAL) | |
| static const CGEN_IBASE virtual_insn_entries[] = | |
| { | |
| { | |
| VIRTUAL_INSN_X_INVALID, "--invalid--", NULL, 0, { V, {} } | |
| }, | |
| { | |
| VIRTUAL_INSN_X_BEFORE, "--before--", NULL, 0, { V, {} } | |
| }, | |
| { | |
| VIRTUAL_INSN_X_AFTER, "--after--", NULL, 0, { V, {} } | |
| }, | |
| { | |
| VIRTUAL_INSN_X_BEGIN, "--begin--", NULL, 0, { V, {} } | |
| }, | |
| { | |
| VIRTUAL_INSN_X_CHAIN, "--chain--", NULL, 0, { V, {} } | |
| }, | |
| { | |
| VIRTUAL_INSN_X_CTI_CHAIN, "--cti-chain--", NULL, 0, { V, {} } | |
| } | |
| }; | |
| #undef V | |
| const CGEN_INSN cgen_virtual_insn_table[] = | |
| { | |
| { & virtual_insn_entries[0] }, | |
| { & virtual_insn_entries[1] }, | |
| { & virtual_insn_entries[2] }, | |
| { & virtual_insn_entries[3] }, | |
| { & virtual_insn_entries[4] }, | |
| { & virtual_insn_entries[5] } | |
| }; | |
| /* Return the name of insn number I. */ | |
| const char * | |
| cgen_insn_name (SIM_CPU *cpu, int i) | |
| { | |
| return CGEN_INSN_NAME ((* CPU_GET_IDATA (cpu)) ((cpu), (i))); | |
| } | |
| /* Return the maximum number of extra bytes required for a SIM_CPU struct. */ | |
| int | |
| cgen_cpu_max_extra_bytes (SIM_DESC sd) | |
| { | |
| const SIM_MACH * const *machp; | |
| int extra = 0; | |
| SIM_ASSERT (STATE_MACHS (sd) != NULL); | |
| for (machp = STATE_MACHS (sd); *machp != NULL; ++machp) | |
| { | |
| int size = IMP_PROPS_SIM_CPU_SIZE (MACH_IMP_PROPS (*machp)); | |
| if (size > extra) | |
| extra = size; | |
| } | |
| return extra; | |
| } | |
| #ifdef DI_FN_SUPPORT | |
| DI | |
| ANDDI (a, b) | |
| DI a, b; | |
| { | |
| SI ahi = GETHIDI (a); | |
| SI alo = GETLODI (a); | |
| SI bhi = GETHIDI (b); | |
| SI blo = GETLODI (b); | |
| return MAKEDI (ahi & bhi, alo & blo); | |
| } | |
| DI | |
| ORDI (a, b) | |
| DI a, b; | |
| { | |
| SI ahi = GETHIDI (a); | |
| SI alo = GETLODI (a); | |
| SI bhi = GETHIDI (b); | |
| SI blo = GETLODI (b); | |
| return MAKEDI (ahi | bhi, alo | blo); | |
| } | |
| DI | |
| ADDDI (a, b) | |
| DI a, b; | |
| { | |
| USI ahi = GETHIDI (a); | |
| USI alo = GETLODI (a); | |
| USI bhi = GETHIDI (b); | |
| USI blo = GETLODI (b); | |
| USI x = alo + blo; | |
| return MAKEDI (ahi + bhi + (x < alo), x); | |
| } | |
| DI | |
| MULDI (a, b) | |
| DI a, b; | |
| { | |
| USI ahi = GETHIDI (a); | |
| USI alo = GETLODI (a); | |
| USI bhi = GETHIDI (b); | |
| USI blo = GETLODI (b); | |
| USI rhi,rlo; | |
| USI x0, x1, x2, x3; | |
| x0 = alo * blo; | |
| x1 = alo * bhi; | |
| x2 = ahi * blo; | |
| x3 = ahi * bhi; | |
| #define SI_TYPE_SIZE 32 | |
| #define BITS4 (SI_TYPE_SIZE / 4) | |
| #define ll_B (1L << (SI_TYPE_SIZE / 2)) | |
| #define ll_lowpart(t) ((USI) (t) % ll_B) | |
| #define ll_highpart(t) ((USI) (t) / ll_B) | |
| x1 += ll_highpart (x0); /* this can't give carry */ | |
| x1 += x2; /* but this indeed can */ | |
| if (x1 < x2) /* did we get it? */ | |
| x3 += ll_B; /* yes, add it in the proper pos. */ | |
| rhi = x3 + ll_highpart (x1); | |
| rlo = ll_lowpart (x1) * ll_B + ll_lowpart (x0); | |
| return MAKEDI (rhi + (alo * bhi) + (ahi * blo), rlo); | |
| } | |
| DI | |
| SHLDI (val, shift) | |
| DI val; | |
| SI shift; | |
| { | |
| USI hi = GETHIDI (val); | |
| USI lo = GETLODI (val); | |
| /* FIXME: Need to worry about shift < 0 || shift >= 32. */ | |
| return MAKEDI ((hi << shift) | (lo >> (32 - shift)), lo << shift); | |
| } | |
| DI | |
| SLADI (val, shift) | |
| DI val; | |
| SI shift; | |
| { | |
| SI hi = GETHIDI (val); | |
| USI lo = GETLODI (val); | |
| /* FIXME: Need to worry about shift < 0 || shift >= 32. */ | |
| return MAKEDI ((hi << shift) | (lo >> (32 - shift)), lo << shift); | |
| } | |
| DI | |
| SRADI (val, shift) | |
| DI val; | |
| SI shift; | |
| { | |
| SI hi = GETHIDI (val); | |
| USI lo = GETLODI (val); | |
| /* We use SRASI because the result is implementation defined if hi < 0. */ | |
| /* FIXME: Need to worry about shift < 0 || shift >= 32. */ | |
| return MAKEDI (SRASI (hi, shift), (hi << (32 - shift)) | (lo >> shift)); | |
| } | |
| int | |
| GEDI (a, b) | |
| DI a, b; | |
| { | |
| SI ahi = GETHIDI (a); | |
| USI alo = GETLODI (a); | |
| SI bhi = GETHIDI (b); | |
| USI blo = GETLODI (b); | |
| if (ahi > bhi) | |
| return 1; | |
| if (ahi == bhi) | |
| return alo >= blo; | |
| return 0; | |
| } | |
| int | |
| LEDI (a, b) | |
| DI a, b; | |
| { | |
| SI ahi = GETHIDI (a); | |
| USI alo = GETLODI (a); | |
| SI bhi = GETHIDI (b); | |
| USI blo = GETLODI (b); | |
| if (ahi < bhi) | |
| return 1; | |
| if (ahi == bhi) | |
| return alo <= blo; | |
| return 0; | |
| } | |
| DI | |
| CONVHIDI (val) | |
| HI val; | |
| { | |
| if (val < 0) | |
| return MAKEDI (-1, val); | |
| else | |
| return MAKEDI (0, val); | |
| } | |
| DI | |
| CONVSIDI (val) | |
| SI val; | |
| { | |
| if (val < 0) | |
| return MAKEDI (-1, val); | |
| else | |
| return MAKEDI (0, val); | |
| } | |
| SI | |
| CONVDISI (val) | |
| DI val; | |
| { | |
| return GETLODI (val); | |
| } | |
| #endif /* DI_FN_SUPPORT */ | |
| QI | |
| RORQI (QI val, int shift) | |
| { | |
| if (shift != 0) | |
| { | |
| int remain = 8 - shift; | |
| int mask = (1 << shift) - 1; | |
| QI result = (val & mask) << remain; | |
| mask = (1 << remain) - 1; | |
| result |= (val >> shift) & mask; | |
| return result; | |
| } | |
| return val; | |
| } | |
| QI | |
| ROLQI (QI val, int shift) | |
| { | |
| if (shift != 0) | |
| { | |
| int remain = 8 - shift; | |
| int mask = (1 << remain) - 1; | |
| QI result = (val & mask) << shift; | |
| mask = (1 << shift) - 1; | |
| result |= (val >> remain) & mask; | |
| return result; | |
| } | |
| return val; | |
| } | |
| HI | |
| RORHI (HI val, int shift) | |
| { | |
| if (shift != 0) | |
| { | |
| int remain = 16 - shift; | |
| int mask = (1 << shift) - 1; | |
| HI result = (val & mask) << remain; | |
| mask = (1 << remain) - 1; | |
| result |= (val >> shift) & mask; | |
| return result; | |
| } | |
| return val; | |
| } | |
| HI | |
| ROLHI (HI val, int shift) | |
| { | |
| if (shift != 0) | |
| { | |
| int remain = 16 - shift; | |
| int mask = (1 << remain) - 1; | |
| HI result = (val & mask) << shift; | |
| mask = (1 << shift) - 1; | |
| result |= (val >> remain) & mask; | |
| return result; | |
| } | |
| return val; | |
| } | |
| SI | |
| RORSI (SI val, int shift) | |
| { | |
| if (shift != 0) | |
| { | |
| int remain = 32 - shift; | |
| int mask = (1 << shift) - 1; | |
| SI result = (val & mask) << remain; | |
| mask = (1 << remain) - 1; | |
| result |= (val >> shift) & mask; | |
| return result; | |
| } | |
| return val; | |
| } | |
| SI | |
| ROLSI (SI val, int shift) | |
| { | |
| if (shift != 0) | |
| { | |
| int remain = 32 - shift; | |
| int mask = (1 << remain) - 1; | |
| SI result = (val & mask) << shift; | |
| mask = (1 << shift) - 1; | |
| result |= (val >> remain) & mask; | |
| return result; | |
| } | |
| return val; | |
| } | |
| /* Emit an error message from CGEN RTL. */ | |
| void | |
| cgen_rtx_error (SIM_CPU *cpu, const char * msg) | |
| { | |
| SIM_DESC sd = CPU_STATE (cpu); | |
| sim_io_printf (sd, "%s", msg); | |
| sim_io_printf (sd, "\n"); | |
| sim_engine_halt (sd, cpu, NULL, CPU_PC_GET (cpu), sim_stopped, SIM_SIGTRAP); | |
| } |