/* reg.c --- register set model for RX simulator. Copyright (C) 2005-2015 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 "config.h" #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 (®s, 0, sizeof (regs)); memset (&oldregs, 0, sizeof (oldregs)); #ifdef CYCLE_ACCURATE regs.rt = -1; oldregs.rt = -1; #endif } 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) { unsigned 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) { unsigned 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) { unsigned 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) { unsigned 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"); }