aboutsummaryrefslogtreecommitdiff
path: root/sim/rx/reg.c
diff options
context:
space:
mode:
authorDJ Delorie <dj@redhat.com>2009-11-24 19:22:45 +0000
committerDJ Delorie <dj@redhat.com>2009-11-24 19:22:45 +0000
commit4f8d4a386168d6152f3006187c5ecf722eb27d67 (patch)
treee86bf5972e5f09f8c37230b21c220a65a116e734 /sim/rx/reg.c
parente4d2e6658e104829003a91249ffe27ae1afb0b34 (diff)
downloadgdb-4f8d4a386168d6152f3006187c5ecf722eb27d67.zip
gdb-4f8d4a386168d6152f3006187c5ecf722eb27d67.tar.gz
gdb-4f8d4a386168d6152f3006187c5ecf722eb27d67.tar.bz2
[sim]
* rx: New directory. * configure.ac: Add entry for Renesas RX. * configure: Regenerate. [include/gdb] * sim-rx.h: New.
Diffstat (limited to 'sim/rx/reg.c')
-rw-r--r--sim/rx/reg.c552
1 files changed, 552 insertions, 0 deletions
diff --git a/sim/rx/reg.c b/sim/rx/reg.c
new file mode 100644
index 0000000..27b9d83
--- /dev/null
+++ b/sim/rx/reg.c
@@ -0,0 +1,552 @@
+/* reg.c --- register set model for RX simulator.
+
+ Copyright (C) 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
+ Contributed by Red Hat, 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/>. */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cpu.h"
+#include "bfd.h"
+#include "trace.h"
+
+int verbose = 0;
+int trace = 0;
+int enable_counting = 0;
+
+int rx_in_gdb = 1;
+
+int rx_flagmask;
+int rx_flagand;
+int rx_flagor;
+
+int rx_big_endian;
+regs_type regs;
+int step_result;
+unsigned int heapbottom = 0;
+unsigned int heaptop = 0;
+
+char *reg_names[] = {
+ /* general registers */
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ /* control register */
+ "psw", "pc", "usp", "fpsw", "RES", "RES", "RES", "RES",
+ "bpsw", "bpc", "isp", "fintv", "intb", "RES", "RES", "RES",
+ "RES", "RES", "RES", "RES", "RES", "RES", "RES", "RES",
+ "RES", "RES", "RES", "RES", "RES", "RES", "RES", "RES",
+ "temp", "acc", "acchi", "accmi", "acclo"
+};
+
+unsigned int b2mask[] = { 0, 0xff, 0xffff, 0xffffff, 0xffffffff };
+unsigned int b2signbit[] = { 0, (1 << 7), (1 << 15), (1 << 24), (1 << 31) };
+int b2maxsigned[] = { 0, 0x7f, 0x7fff, 0x7fffff, 0x7fffffff };
+int b2minsigned[] = { 0, -128, -32768, -8388608, -2147483647 - 1 };
+
+static regs_type oldregs;
+
+void
+init_regs (void)
+{
+ memset (&regs, 0, sizeof (regs));
+ memset (&oldregs, 0, sizeof (oldregs));
+}
+
+static unsigned int
+get_reg_i (int id)
+{
+ if (id == 0)
+ return regs.r_psw & FLAGBIT_U ? regs.r_usp : regs.r_isp;
+
+ if (id >= 1 && id <= 15)
+ return regs.r[id];
+
+ switch (id)
+ {
+ case psw:
+ return regs.r_psw;
+ case fpsw:
+ return regs.r_fpsw;
+ case isp:
+ return regs.r_isp;
+ case usp:
+ return regs.r_usp;
+ case bpc:
+ return regs.r_bpc;
+ case bpsw:
+ return regs.r_bpsw;
+ case fintv:
+ return regs.r_fintv;
+ case intb:
+ return regs.r_intb;
+ case pc:
+ return regs.r_pc;
+ case r_temp_idx:
+ return regs.r_temp;
+ case acchi:
+ return (SI)(regs.r_acc >> 32);
+ case accmi:
+ return (SI)(regs.r_acc >> 16);
+ case acclo:
+ return (SI)regs.r_acc;
+ }
+ abort();
+}
+
+unsigned int
+get_reg (int id)
+{
+ unsigned int rv = get_reg_i (id);
+ if (trace > ((id != pc && id != sp) ? 0 : 1))
+ printf ("get_reg (%s) = %08x\n", reg_names[id], rv);
+ return rv;
+}
+
+static unsigned long long
+get_reg64_i (int id)
+{
+ switch (id)
+ {
+ case acc64:
+ return regs.r_acc;
+ default:
+ abort ();
+ }
+}
+
+unsigned long long
+get_reg64 (int id)
+{
+ unsigned long long rv = get_reg64_i (id);
+ if (trace > ((id != pc && id != sp) ? 0 : 1))
+ printf ("get_reg (%s) = %016llx\n", reg_names[id], rv);
+ return rv;
+}
+
+static int highest_sp = 0, lowest_sp = 0xffffff;
+
+void
+stack_heap_stats ()
+{
+ if (heapbottom < heaptop)
+ printf ("heap: %08x - %08x (%d bytes)\n", heapbottom, heaptop,
+ heaptop - heapbottom);
+ if (lowest_sp < highest_sp)
+ printf ("stack: %08x - %08x (%d bytes)\n", lowest_sp, highest_sp,
+ highest_sp - lowest_sp);
+}
+
+void
+put_reg (int id, unsigned int v)
+{
+ if (trace > ((id != pc) ? 0 : 1))
+ printf ("put_reg (%s) = %08x\n", reg_names[id], v);
+
+
+ switch (id)
+ {
+ case psw:
+ regs.r_psw = v;
+ break;
+ case fpsw:
+ {
+ SI anded;
+ /* This is an odd one - The Cx flags are AND'd, and the FS flag
+ is synthetic. */
+ anded = regs.r_fpsw & v;
+ anded |= ~ FPSWBITS_CMASK;
+ regs.r_fpsw = v & anded;
+ if (regs.r_fpsw & FPSWBITS_FMASK)
+ regs.r_fpsw |= FPSWBITS_FSUM;
+ else
+ regs.r_fpsw &= ~FPSWBITS_FSUM;
+ }
+ break;
+ case isp:
+ regs.r_isp = v;
+ break;
+ case usp:
+ regs.r_usp = v;
+ break;
+ case bpc:
+ regs.r_bpc = v;
+ break;
+ case bpsw:
+ regs.r_bpsw = v;
+ break;
+ case fintv:
+ regs.r_fintv = v;
+ break;
+ case intb:
+ regs.r_intb = v;
+ break;
+ case pc:
+ regs.r_pc = v;
+ break;
+
+ case acchi:
+ regs.r_acc = (regs.r_acc & 0xffffffffULL) | ((DI)v << 32);
+ break;
+ case accmi:
+ regs.r_acc = (regs.r_acc & ~0xffffffff0000ULL) | ((DI)v << 16);
+ break;
+ case acclo:
+ regs.r_acc = (regs.r_acc & ~0xffffffffULL) | ((DI)v);
+ break;
+
+ case 0: /* Stack pointer is "in" R0. */
+ {
+ if (v < heaptop)
+ {
+ unsigned int line;
+ const char * dummy;
+ const char * fname = NULL;
+
+ sim_get_current_source_location (& dummy, & fname, &line);
+
+ /* The setjmp and longjmp functions play tricks with the stack pointer. */
+ if (fname == NULL
+ || (strcmp (fname, "_setjmp") != 0
+ && strcmp (fname, "_longjmp") != 0))
+ {
+ printf ("collision in %s: pc %08x heap %08x stack %08x\n",
+ fname, (unsigned int) regs.r_pc, heaptop, v);
+ exit (1);
+ }
+ }
+ else
+ {
+ if (v < lowest_sp)
+ lowest_sp = v;
+ if (v > highest_sp)
+ highest_sp = v;
+ }
+
+ if (regs.r_psw & FLAGBIT_U)
+ regs.r_usp = v;
+ else
+ regs.r_isp = v;
+ break;
+ }
+
+ default:
+ if (id >= 1 || id <= 15)
+ regs.r[id] = v;
+ else
+ abort ();
+ }
+}
+
+void
+put_reg64 (int id, unsigned long long v)
+{
+ if (trace > ((id != pc) ? 0 : 1))
+ printf ("put_reg (%s) = %016llx\n", reg_names[id], v);
+
+ switch (id)
+ {
+ case acc64:
+ regs.r_acc = v;
+ break;
+ default:
+ abort ();
+ }
+}
+
+int
+condition_true (int cond_id)
+{
+ int f;
+
+ static const char *cond_name[] = {
+ "Z",
+ "!Z",
+ "C",
+ "!C",
+ "C&!Z",
+ "!(C&!Z)",
+ "!S",
+ "S",
+ "!(S^O)",
+ "S^O",
+ "!((S^O)|Z)",
+ "(S^O)|Z",
+ "O",
+ "!O",
+ "always",
+ "never"
+ };
+ switch (cond_id & 15)
+ {
+ case 0:
+ f = FLAG_Z;
+ break; /* EQ/Z */
+ case 1:
+ f = !FLAG_Z;
+ break; /* NE/NZ */
+ case 2:
+ f = FLAG_C;
+ break; /* GEU/C */
+ case 3:
+ f = !FLAG_C;
+ break; /* LTU/NC */
+ case 4:
+ f = FLAG_C & !FLAG_Z;
+ break; /* GTU */
+ case 5:
+ f = !(FLAG_C & !FLAG_Z);
+ break; /* LEU */
+ case 6:
+ f = !FLAG_S;
+ break; /* PZ */
+ case 7:
+ f = FLAG_S;
+ break; /* N */
+
+ case 8:
+ f = !(FLAG_S ^ FLAG_O);
+ break; /* GE */
+ case 9:
+ f = FLAG_S ^ FLAG_O;
+ break; /* LT */
+ case 10:
+ f = !((FLAG_S ^ FLAG_O) | FLAG_Z);
+ break; /* GT */
+ case 11:
+ f = (FLAG_S ^ FLAG_O) | FLAG_Z;
+ break; /* LE */
+ case 12:
+ f = FLAG_O;
+ break; /* O */
+ case 13:
+ f = !FLAG_O;
+ break; /* NO */
+ case 14:
+ f = 1; /* always */
+ break;
+ default:
+ f = 0; /* never */
+ break;
+ }
+ if (trace && ((cond_id & 15) != 14))
+ printf ("cond[%d] %s = %s\n", cond_id, cond_name[cond_id & 15],
+ f ? "true" : "false");
+ return f;
+}
+
+void
+set_flags (int mask, int newbits)
+{
+ regs.r_psw &= rx_flagand;
+ regs.r_psw |= rx_flagor;
+ regs.r_psw |= (newbits & mask & rx_flagmask);
+
+ if (trace)
+ {
+ int i;
+ printf ("flags now \033[32m %d", (int)((regs.r_psw >> 24) & 7));
+ for (i = 17; i >= 0; i--)
+ if (0x3000f & (1 << i))
+ {
+ if (regs.r_psw & (1 << i))
+ putchar ("CZSO------------IU"[i]);
+ else
+ putchar ('-');
+ }
+ printf ("\033[0m\n");
+ }
+}
+
+void
+set_oszc (long long value, int b, int c)
+{
+ int mask = b2mask[b];
+ int f = 0;
+
+ if (c)
+ f |= FLAGBIT_C;
+ if ((value & mask) == 0)
+ f |= FLAGBIT_Z;
+ if (value & b2signbit[b])
+ f |= FLAGBIT_S;
+ if ((value > b2maxsigned[b]) || (value < b2minsigned[b]))
+ f |= FLAGBIT_O;
+ set_flags (FLAGBIT_Z | FLAGBIT_S | FLAGBIT_O | FLAGBIT_C, f);
+}
+
+void
+set_szc (long long value, int b, int c)
+{
+ int mask = b2mask[b];
+ int f = 0;
+
+ if (c)
+ f |= FLAGBIT_C;
+ if ((value & mask) == 0)
+ f |= FLAGBIT_Z;
+ if (value & b2signbit[b])
+ f |= FLAGBIT_S;
+ set_flags (FLAGBIT_Z | FLAGBIT_S | FLAGBIT_C, f);
+}
+
+void
+set_osz (long long value, int b)
+{
+ int mask = b2mask[b];
+ int f = 0;
+
+ if ((value & mask) == 0)
+ f |= FLAGBIT_Z;
+ if (value & b2signbit[b])
+ f |= FLAGBIT_S;
+ if ((value > b2maxsigned[b]) || (value < b2minsigned[b]))
+ f |= FLAGBIT_O;
+ set_flags (FLAGBIT_Z | FLAGBIT_S | FLAGBIT_O, f);
+}
+
+void
+set_sz (long long value, int b)
+{
+ int mask = b2mask[b];
+ int f = 0;
+
+ if ((value & mask) == 0)
+ f |= FLAGBIT_Z;
+ if (value & b2signbit[b])
+ f |= FLAGBIT_S;
+ set_flags (FLAGBIT_Z | FLAGBIT_S, f);
+}
+
+void
+set_zc (int z, int c)
+{
+ set_flags (FLAGBIT_C | FLAGBIT_Z,
+ (c ? FLAGBIT_C : 0) | (z ? FLAGBIT_Z : 0));
+}
+
+void
+set_c (int c)
+{
+ set_flags (FLAGBIT_C, c ? FLAGBIT_C : 0);
+}
+
+static char *
+psw2str(int rpsw)
+{
+ static char buf[10];
+ char *bp = buf;
+ int i, ipl;
+
+ ipl = (rpsw & FLAGBITS_IPL) >> FLAGSHIFT_IPL;
+ if (ipl > 9)
+ {
+ *bp++ = (ipl / 10) + '0';
+ ipl %= 10;
+ }
+ *bp++ = ipl + '0';
+ for (i = 20; i >= 0; i--)
+ if (0x13000f & (1 << i))
+ {
+ if (rpsw & (1 << i))
+ *bp++ = "CZSO------------IU--P"[i];
+ else
+ *bp++ = '-';
+ }
+ *bp = 0;
+ return buf;
+}
+
+static char *
+fpsw2str(int rpsw)
+{
+ static char buf[100];
+ char *bp = buf;
+ int i; /* ---+---+---+---+---+---+---+---+ */
+ const char s1[] = "FFFFFF-----------EEEEE-DCCCCCCRR";
+ const char s2[] = "SXUZOV-----------XUZOV-NEXUZOV01";
+ const char rm[4][3] = { "RC", "RZ", "RP", "RN" };
+
+ for (i = 31; i >= 0; i--)
+ if (0xfc007dfc & (1 << i))
+ {
+ if (rpsw & (1 << i))
+ {
+ if (bp > buf)
+ *bp++ = '.';
+ *bp++ = s1[31-i];
+ *bp++ = s2[31-i];
+ }
+ }
+ if (bp > buf)
+ *bp++ = '.';
+ strcpy (bp, rm[rpsw&3]);
+ return buf;
+}
+
+#define TRC(f,n) \
+ if (oldregs.f != regs.f) \
+ { \
+ if (tag) { printf (tag); tag = 0; } \
+ printf(" %s %08x:%08x", n, \
+ (unsigned int)oldregs.f, \
+ (unsigned int)regs.f); \
+ oldregs.f = regs.f; \
+ }
+
+void
+trace_register_changes (void)
+{
+ char *tag = "\033[36mREGS:";
+ int i;
+
+ if (!trace)
+ return;
+ for (i=1; i<16; i++)
+ TRC (r[i], reg_names[i]);
+ TRC (r_intb, "intb");
+ TRC (r_usp, "usp");
+ TRC (r_isp, "isp");
+ if (oldregs.r_psw != regs.r_psw)
+ {
+ if (tag) { printf (tag); tag = 0; }
+ printf(" psw %s:", psw2str(oldregs.r_psw));
+ printf("%s", psw2str(regs.r_psw));
+ oldregs.r_psw = regs.r_psw;
+ }
+
+ if (oldregs.r_fpsw != regs.r_fpsw)
+ {
+ if (tag) { printf (tag); tag = 0; }
+ printf(" fpsw %s:", fpsw2str(oldregs.r_fpsw));
+ printf("%s", fpsw2str(regs.r_fpsw));
+ oldregs.r_fpsw = regs.r_fpsw;
+ }
+
+ if (oldregs.r_acc != regs.r_acc)
+ {
+ if (tag) { printf (tag); tag = 0; }
+ printf(" acc %016llx:", oldregs.r_acc);
+ printf("%016llx", regs.r_acc);
+ oldregs.r_acc = regs.r_acc;
+ }
+
+ if (tag == 0)
+ printf ("\033[0m\n");
+}