/* Support code for various pieces of CGEN simulators.
- Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 1999, 2007, 2008, 2009, 2010
+ 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 2, or (at your option)
-any later version.
+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, write to the Free Software Foundation, Inc.,
-59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#include "bfd.h"
#include "sim-main.h"
#include "dis-asm.h"
-#include "cpu-opc.h"
-#include "decode.h"
#define MEMOPS_DEFINE_INLINE
-#include "mem-ops.h"
+#include "cgen-mem.h"
#define SEMOPS_DEFINE_INLINE
-#include "sem-ops.h"
+#include "cgen-ops.h"
+
+#undef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
const char *mode_names[] = {
- "VM",
+ "VOID",
"BI",
"QI",
"HI",
"SI",
"DI",
- "UBI",
"UQI",
"UHI",
"USI",
"DF",
"XF",
"TF",
+ 0, /* MODE_TARGET_MAX */
+ "INT",
+ "UINT",
+ "PTR"
};
-/* Initialize cgen things.
- This is called after sim_post_argv_init. */
+/* Opcode table for virtual insns used by the simulator. */
-void
-cgen_init (SIM_DESC sd)
-{
- int i, c;
- int run_fast_p = 1;
+#define V CGEN_ATTR_MASK (CGEN_INSN_VIRTUAL)
- /* If no profiling or tracing has been enabled, run in fast mode. */
- for (c = 0; c < MAX_NR_PROCESSORS; ++c)
- {
- sim_cpu *cpu = STATE_CPU (sd, c);
-
- for (i = 0; i < MAX_PROFILE_VALUES; ++i)
- if (CPU_PROFILE_FLAGS (cpu) [i])
- {
- run_fast_p = 0;
- break;
- }
- for (i = 0; i < MAX_TRACE_VALUES; ++i)
- if (CPU_TRACE_FLAGS (cpu) [i])
- {
- run_fast_p = 0;
- break;
- }
- if (! run_fast_p)
- break;
- }
- STATE_RUN_FAST_P (sd) = run_fast_p;
-}
-\f
-void
-engine_halt (cpu, reason, sigrc)
- sim_cpu *cpu;
- enum exec_state reason;
- int sigrc;
+static const CGEN_IBASE virtual_insn_entries[] =
{
- CPU_EXEC_STATE (cpu) = reason;
- CPU_HALT_SIGRC (cpu) = sigrc;
+ {
+ VIRTUAL_INSN_X_INVALID, "--invalid--", NULL, 0, { V, { 0 } }
+ },
+ {
+ VIRTUAL_INSN_X_BEFORE, "--before--", NULL, 0, { V, { 0 } }
+ },
+ {
+ VIRTUAL_INSN_X_AFTER, "--after--", NULL, 0, { V, { 0 } }
+ },
+ {
+ VIRTUAL_INSN_X_BEGIN, "--begin--", NULL, 0, { V, { 0 } }
+ },
+ {
+ VIRTUAL_INSN_X_CHAIN, "--chain--", NULL, 0, { V, { 0 } }
+ },
+ {
+ VIRTUAL_INSN_X_CTI_CHAIN, "--cti-chain--", NULL, 0, { V, { 0 } }
+ }
+};
- longjmp (STATE_HALT_JMP_BUF (CPU_STATE (cpu)), 1);
-}
+#undef V
-void
-engine_signal (cpu, sig)
- sim_cpu *cpu;
- enum sim_signal_type sig;
+const CGEN_INSN cgen_virtual_insn_table[] =
{
- engine_halt (cpu, EXEC_STATE_STOPPED, sig);
-}
-
-/* Convert SIM_SIGFOO to SIGFOO. */
+ { & virtual_insn_entries[0] },
+ { & virtual_insn_entries[1] },
+ { & virtual_insn_entries[2] },
+ { & virtual_insn_entries[3] },
+ { & virtual_insn_entries[4] },
+ { & virtual_insn_entries[5] }
+};
-int
-sim_signal_to_host (sig)
- int sig;
-{
- switch (sig)
- {
- case SIM_SIGILL :
-#ifdef SIGILL
- return SIGILL;
-#endif
- break;
-
- case SIM_SIGTRAP :
-#ifdef SIGTRAP
- return SIGTRAP;
-#else
-#ifdef _MSC_VER
- /* Wingdb uses this value. */
- return 5;
-#endif
-#endif
- break;
-
- case SIM_SIGALIGN :
- case SIM_SIGACCESS :
-#ifdef SIGSEGV
- return SIGSEGV;
-#endif
- break;
-
- case SIM_SIGXCPU :
-#ifdef SIGXCPU
- return SIGXCPU;
-#endif
- break;
- }
- return 1;
-}
-\f
-/* FIXME: Add "no return" attribute to illegal insn handlers.
- They all call longjmp. */
-/* FIXME: May wish to call a target supplied routine which can then call
- sim_halt if it wants: to allow target to gain control for moment. */
+/* Initialize cgen things.
+ This is called after sim_post_argv_init. */
void
-ex_illegal (SIM_CPU *cpu, PCADDR pc, insn_t insn, ARGBUF *abuf)
+cgen_init (SIM_DESC sd)
{
- abuf->length = CGEN_BASE_INSN_SIZE;
- abuf->addr = pc;
- /* Leave signalling to semantic fn. */
-}
+ int i, c;
-void
-exc_illegal (SIM_CPU *cpu, PCADDR pc, insn_t insn, ARGBUF *abuf)
-{
- abuf->length = CGEN_BASE_INSN_SIZE;
- abuf->addr = pc;
- /* Leave signalling to semantic fn. */
+ /* If no profiling or tracing has been enabled, run in fast mode. */
+ {
+ int run_fast_p = 1;
+
+ for (c = 0; c < MAX_NR_PROCESSORS; ++c)
+ {
+ SIM_CPU *cpu = STATE_CPU (sd, c);
+
+ for (i = 0; i < MAX_PROFILE_VALUES; ++i)
+ if (CPU_PROFILE_FLAGS (cpu) [i])
+ {
+ run_fast_p = 0;
+ break;
+ }
+ for (i = 0; i < MAX_TRACE_VALUES; ++i)
+ if (CPU_TRACE_FLAGS (cpu) [i])
+ {
+ run_fast_p = 0;
+ break;
+ }
+ if (! run_fast_p)
+ break;
+ }
+ STATE_RUN_FAST_P (sd) = run_fast_p;
+ }
}
-PCADDR
-sem_illegal (current_cpu, sem_arg)
- SIM_CPU *current_cpu;
- struct argbuf *sem_arg;
-{
- engine_halt (current_cpu, EXEC_STATE_SIGNALLED, SIM_SIGILL);
- return 0;
-}
+/* Return the name of insn number I. */
-PCADDR
-semc_illegal (current_cpu, sem_arg)
- SIM_CPU *current_cpu;
- struct scache *sem_arg;
-{
- engine_halt (current_cpu, EXEC_STATE_SIGNALLED, SIM_SIGILL);
- return 0;
-}
-\f
-/* Disassembly support.
- ??? While executing an instruction, the insn has been decoded and all its
- fields have been extracted. It is certainly possible to do the disassembly
- with that data. This seems simpler, but maybe in the future the already
- extracted fields will be used. */
-
-/* Pseudo FILE object for strings. */
-typedef struct {
- char *buffer;
- char *current;
-} SFILE;
-
-/* sprintf to a "stream" */
-
-static int
-disasm_sprintf VPARAMS ((SFILE *f, const char *format, ...))
+const char *
+cgen_insn_name (SIM_CPU *cpu, int i)
{
-#ifndef __STDC__
- SFILE *f;
- const char *format;
-#endif
- int n;
- va_list args;
-
- VA_START (args, format);
-#ifndef __STDC__
- f = va_arg (args, SFILE *);
- format = va_arg (args, char *);
-#endif
- vsprintf (f->current, format, args);
- f->current += n = strlen (f->current);
- va_end (args);
- return n;
+ return CGEN_INSN_NAME ((* CPU_GET_IDATA (cpu)) ((cpu), (i)));
}
-void
-sim_disassemble_insn (SIM_CPU *cpu, const struct cgen_insn *insn,
- const struct argbuf *abuf, PCADDR pc, char *buf)
-{
- int length;
- unsigned long insn_value;
- struct disassemble_info disasm_info;
- struct cgen_fields fields;
- SFILE sfile;
- char insn_buf[20];
- SIM_DESC sd = CPU_STATE (cpu);
-
- sfile.buffer = sfile.current = buf;
- INIT_DISASSEMBLE_INFO (disasm_info, (FILE *) &sfile,
- (fprintf_ftype) disasm_sprintf);
- disasm_info.endian =
- (bfd_big_endian (STATE_PROG_BFD (sd)) ? BFD_ENDIAN_BIG
- : bfd_little_endian (STATE_PROG_BFD (sd)) ? BFD_ENDIAN_LITTLE
- : BFD_ENDIAN_UNKNOWN);
+/* Return the maximum number of extra bytes required for a SIM_CPU struct. */
- switch (abuf->length)
- {
- case 1 :
- insn_value = sim_core_read_1 (CPU_STATE (cpu), sim_core_read_map, pc);
- break;
- case 2 :
- insn_value = sim_core_read_2 (CPU_STATE (cpu), sim_core_read_map, pc);
- break;
- case 4 :
- insn_value = sim_core_read_4 (CPU_STATE (cpu), sim_core_read_map, pc);
- break;
- default:
- abort ();
- }
+int
+cgen_cpu_max_extra_bytes (void)
+{
+ int i;
+ int extra = 0;
- length = (*CGEN_EXTRACT_FN (insn)) (insn, NULL, insn_value, &fields);
- if (length != abuf->length)
- {
- (*CGEN_PRINT_FN (insn)) (&disasm_info, insn, &fields, pc, length);
- }
- else
+ for (i = 0; sim_machs[i] != 0; ++i)
{
- /* This shouldn't happen, but aborting is too drastic. */
- strcpy (buf, "***unknown***");
+ int size = IMP_PROPS_SIM_CPU_SIZE (MACH_IMP_PROPS (sim_machs[i]));
+ if (size > extra)
+ extra = size;
}
+ return extra;
}
\f
#ifdef DI_FN_SUPPORT
}
#endif /* DI_FN_SUPPORT */
+\f
+QI
+RORQI (val, shift)
+ 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 (val, shift)
+ 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 (val, shift)
+ 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 (val, shift)
+ 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 (val, shift)
+ 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 (val, shift)
+ 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, msg);
+ sim_io_printf (sd, "\n");
+
+ sim_engine_halt (sd, cpu, NULL, CIA_GET (cpu), sim_stopped, SIM_SIGTRAP);
+}