/* m32r simulator support code
- Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
Contributed by Cygnus Support.
This file is part of GDB, the GNU debugger.
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-#define WANT_CPU
-#define WANT_CPU_M32R
+#define WANT_CPU m32rbf
+#define WANT_CPU_M32RBF
#include "sim-main.h"
-#include <signal.h>
-#include "libiberty.h"
-#include "bfd.h"
-/* FIXME: need to provide general mechanism for accessing target files
- these. For now this is a hack to avoid getting the host version. */
-#include "../../libgloss/m32r/sys/syscall.h"
-#include "targ-vals.h"
-\f
-/* The contents of BUF are in target byte order. */
+#include "cgen-mem.h"
+#include "cgen-ops.h"
-void
-m32r_fetch_register (sd, rn, buf)
- SIM_DESC sd;
- int rn;
- unsigned char *buf;
-{
- SIM_CPU *current_cpu = STATE_CPU (sd, 0);
+/* Decode gdb ctrl register number. */
- if (rn < 16)
- SETTWI (buf, GET_H_GR (rn));
- else if (rn < 21)
- SETTWI (buf, GET_H_CR (rn - 16));
- else switch (rn) {
- case PC_REGNUM:
- SETTWI (buf, GET_H_PC ());
- break;
- case ACCL_REGNUM:
- SETTWI (buf, GETLODI (GET_H_ACCUM ()));
- break;
- case ACCH_REGNUM:
- SETTWI (buf, GETHIDI (GET_H_ACCUM ()));
- break;
-#if 0
- case 23: *reg = STATE_CPU_CPU (sd, 0)->h_cond; break;
- case 24: *reg = STATE_CPU_CPU (sd, 0)->h_sm; break;
- case 25: *reg = STATE_CPU_CPU (sd, 0)->h_bsm; break;
- case 26: *reg = STATE_CPU_CPU (sd, 0)->h_ie; break;
- case 27: *reg = STATE_CPU_CPU (sd, 0)->h_bie; break;
- case 28: *reg = STATE_CPU_CPU (sd, 0)->h_bcarry; break; /* rename: bc */
- case 29: memcpy (buf, &STATE_CPU_CPU (sd, 0)->h_bpc, sizeof(WI)); break; /* duplicate */
-#endif
- default: abort ();
- }
+int
+m32r_decode_gdb_ctrl_regnum (int gdb_regnum)
+{
+ switch (gdb_regnum)
+ {
+ case PSW_REGNUM : return H_CR_PSW;
+ case CBR_REGNUM : return H_CR_CBR;
+ case SPI_REGNUM : return H_CR_SPI;
+ case SPU_REGNUM : return H_CR_SPU;
+ case BPC_REGNUM : return H_CR_BPC;
+ case BBPSW_REGNUM : return H_CR_BBPSW;
+ case BBPC_REGNUM : return H_CR_BBPC;
+ }
+ abort ();
}
-
+
/* The contents of BUF are in target byte order. */
-void
-m32r_store_register (sd, rn, buf)
- SIM_DESC sd;
- int rn;
- unsigned char *buf;
+int
+m32rbf_fetch_register (SIM_CPU *current_cpu, int rn, unsigned char *buf, int len)
{
- SIM_CPU *current_cpu = STATE_CPU (sd, 0);
+ int mach = MACH_NUM (CPU_MACH (current_cpu));
if (rn < 16)
- SET_H_GR (rn, GETTWI (buf));
- else if (rn < 21)
- SET_H_CR (rn - 16, GETTWI (buf));
- else switch (rn) {
- case PC_REGNUM:
- SET_H_PC (GETTWI (buf));
- break;
- case ACCL_REGNUM:
- SETLODI (CPU (h_accum), GETTWI (buf));
- break;
- case ACCH_REGNUM:
- SETHIDI (CPU (h_accum), GETTWI (buf));
- break;
-#if 0
- case 23: STATE_CPU_CPU (sd, 0)->h_cond = *reg; break;
- case 24: STATE_CPU_CPU (sd, 0)->h_sm = *reg; break;
- case 25: STATE_CPU_CPU (sd, 0)->h_bsm = *reg; break;
- case 26: STATE_CPU_CPU (sd, 0)->h_ie = *reg; break;
- case 27: STATE_CPU_CPU (sd, 0)->h_bie = *reg; break;
- case 28: STATE_CPU_CPU (sd, 0)->h_bcarry = *reg; break; /* rename: bc */
- case 29: memcpy (&STATE_CPU_CPU (sd, 0)->h_bpc, buf, sizeof(DI)); break; /* duplicate */
-#endif
- }
+ SETTWI (buf, a_m32r_h_gr_get (current_cpu, rn));
+ else
+ switch (rn)
+ {
+ case PSW_REGNUM :
+ case CBR_REGNUM :
+ case SPI_REGNUM :
+ case SPU_REGNUM :
+ case BPC_REGNUM :
+ case BBPSW_REGNUM :
+ case BBPC_REGNUM :
+ SETTWI (buf, a_m32r_h_cr_get (current_cpu,
+ m32r_decode_gdb_ctrl_regnum (rn)));
+ break;
+ case PC_REGNUM :
+ if (mach == MACH_M32R)
+ SETTWI (buf, m32rbf_h_pc_get (current_cpu));
+ else
+ SETTWI (buf, m32rxf_h_pc_get (current_cpu));
+ break;
+ case ACCL_REGNUM :
+ if (mach == MACH_M32R)
+ SETTWI (buf, GETLODI (m32rbf_h_accum_get (current_cpu)));
+ else
+ SETTWI (buf, GETLODI (m32rxf_h_accum_get (current_cpu)));
+ break;
+ case ACCH_REGNUM :
+ if (mach == MACH_M32R)
+ SETTWI (buf, GETHIDI (m32rbf_h_accum_get (current_cpu)));
+ else
+ SETTWI (buf, GETHIDI (m32rxf_h_accum_get (current_cpu)));
+ break;
+ default :
+ return 0;
+ }
+
+ return -1; /*FIXME*/
}
-\f
-/* Handling the MSPR register is done by creating a device in the core
- mapping that winds up here. */
-device m32r_mspr_device;
+/* The contents of BUF are in target byte order. */
int
-device_io_read_buffer (device *me, const void *source, int space,
- address_word addr, unsigned nr_bytes,
- SIM_CPU *cpu, sim_cia cia)
+m32rbf_store_register (SIM_CPU *current_cpu, int rn, unsigned char *buf, int len)
{
- abort ();
-}
+ int mach = MACH_NUM (CPU_MACH (current_cpu));
-int
-device_io_write_buffer (device *me, const void *source, int space,
- address_word addr, unsigned nr_bytes,
- SIM_CPU *cpu, sim_cia cia)
-{
-#if WITH_SCACHE
- if (addr == MSPR_ADDR
- && (*(char *) source & 1) != 0)
- scache_flush (CPU_STATE (cpu));
-#endif
- return nr_bytes;
-}
+ if (rn < 16)
+ a_m32r_h_gr_set (current_cpu, rn, GETTWI (buf));
+ else
+ switch (rn)
+ {
+ case PSW_REGNUM :
+ case CBR_REGNUM :
+ case SPI_REGNUM :
+ case SPU_REGNUM :
+ case BPC_REGNUM :
+ case BBPSW_REGNUM :
+ case BBPC_REGNUM :
+ a_m32r_h_cr_set (current_cpu,
+ m32r_decode_gdb_ctrl_regnum (rn),
+ GETTWI (buf));
+ break;
+ case PC_REGNUM :
+ if (mach == MACH_M32R)
+ m32rbf_h_pc_set (current_cpu, GETTWI (buf));
+ else
+ m32rxf_h_pc_set (current_cpu, GETTWI (buf));
+ break;
+ case ACCL_REGNUM :
+ {
+ DI val;
+ if (mach == MACH_M32R)
+ val = m32rbf_h_accum_get (current_cpu);
+ else
+ val = m32rxf_h_accum_get (current_cpu);
+ SETLODI (val, GETTWI (buf));
+ if (mach == MACH_M32R)
+ m32rbf_h_accum_set (current_cpu, val);
+ else
+ m32rxf_h_accum_set (current_cpu, val);
+ break;
+ }
+ case ACCH_REGNUM :
+ {
+ DI val;
+ if (mach == MACH_M32R)
+ val = m32rbf_h_accum_get (current_cpu);
+ else
+ val = m32rxf_h_accum_get (current_cpu);
+ SETHIDI (val, GETTWI (buf));
+ if (mach == MACH_M32R)
+ m32rbf_h_accum_set (current_cpu, val);
+ else
+ m32rxf_h_accum_set (current_cpu, val);
+ break;
+ }
+ default :
+ return 0;
+ }
-void device_error () {}
+ return -1; /*FIXME*/
+}
\f
-#if WITH_PROFILE_MODEL_P
+/* Cover fns for mach independent register accesses. */
-void
-m32r_model_mark_get_h_gr (SIM_CPU *cpu, ARGBUF *abuf)
+SI
+a_m32r_h_gr_get (SIM_CPU *current_cpu, UINT regno)
{
- if ((CPU_CGEN_PROFILE (cpu)->h_gr & abuf->h_gr_get) != 0)
+ switch (MACH_NUM (CPU_MACH (current_cpu)))
{
- PROFILE_MODEL_LOAD_STALL_COUNT (CPU_PROFILE_DATA (cpu)) += 2;
- if (TRACE_INSN_P (cpu))
- cgen_trace_printf (cpu, " ; Load stall of 2 cycles.");
+#ifdef HAVE_CPU_M32RBF
+ case MACH_M32R :
+ return m32rbf_h_gr_get (current_cpu, regno);
+#endif
+#ifdef HAVE_CPU_M32RXF
+ case MACH_M32RX :
+ return m32rxf_h_gr_get (current_cpu, regno);
+#endif
+ default :
+ abort ();
}
}
void
-m32r_model_mark_set_h_gr (SIM_CPU *cpu, ARGBUF *abuf)
+a_m32r_h_gr_set (SIM_CPU *current_cpu, UINT regno, SI newval)
{
+ switch (MACH_NUM (CPU_MACH (current_cpu)))
+ {
+#ifdef HAVE_CPU_M32RBF
+ case MACH_M32R :
+ m32rbf_h_gr_set (current_cpu, regno, newval);
+ break;
+#endif
+#ifdef HAVE_CPU_M32RXF
+ case MACH_M32RX :
+ m32rxf_h_gr_set (current_cpu, regno, newval);
+ break;
+#endif
+ default :
+ abort ();
+ }
}
-void
-m32r_model_mark_busy_reg (SIM_CPU *cpu, ARGBUF *abuf)
+USI
+a_m32r_h_cr_get (SIM_CPU *current_cpu, UINT regno)
{
- CPU_CGEN_PROFILE (cpu)->h_gr = abuf->h_gr_set;
+ switch (MACH_NUM (CPU_MACH (current_cpu)))
+ {
+#ifdef HAVE_CPU_M32RBF
+ case MACH_M32R :
+ return m32rbf_h_cr_get (current_cpu, regno);
+#endif
+#ifdef HAVE_CPU_M32RXF
+ case MACH_M32RX :
+ return m32rxf_h_cr_get (current_cpu, regno);
+#endif
+ default :
+ abort ();
+ }
}
void
-m32r_model_mark_unbusy_reg (SIM_CPU *cpu, ARGBUF *abuf)
+a_m32r_h_cr_set (SIM_CPU *current_cpu, UINT regno, USI newval)
{
- CPU_CGEN_PROFILE (cpu)->h_gr = 0;
+ switch (MACH_NUM (CPU_MACH (current_cpu)))
+ {
+#ifdef HAVE_CPU_M32RBF
+ case MACH_M32R :
+ m32rbf_h_cr_set (current_cpu, regno, newval);
+ break;
+#endif
+#ifdef HAVE_CPU_M32RXF
+ case MACH_M32RX :
+ m32rxf_h_cr_set (current_cpu, regno, newval);
+ break;
+#endif
+ default :
+ abort ();
+ }
}
-
-#endif /* WITH_PROFILE_MODEL_P */
-
+\f
USI
-m32r_h_cr_get (SIM_CPU *current_cpu, UINT cr)
+m32rbf_h_cr_get_handler (SIM_CPU *current_cpu, UINT cr)
{
- /* FIXME: Create enums H_CR_FOO, etc. */
switch (cr)
{
- case 0 : /* psw */
- return ((CPU (h_bsm) << 15)
- | (CPU (h_bie) << 14)
- | (CPU (h_bcond) << 8)
- | (CPU (h_sm) << 7)
- | (CPU (h_ie) << 6)
- | (CPU (h_cond) << 0));
- case 1 : /* condition bit */
- return CPU (h_cond);
- case 2 : /* interrupt stack pointer */
- if (! CPU (h_sm))
- return CPU (h_gr[15]);
+ case H_CR_PSW : /* psw */
+ return (((CPU (h_bpsw) & 0xc1) << 8)
+ | ((CPU (h_psw) & 0xc0) << 0)
+ | GET_H_COND ());
+ case H_CR_BBPSW : /* backup backup psw */
+ return CPU (h_bbpsw) & 0xc1;
+ case H_CR_CBR : /* condition bit */
+ return GET_H_COND ();
+ case H_CR_SPI : /* interrupt stack pointer */
+ if (! GET_H_SM ())
+ return CPU (h_gr[H_GR_SP]);
else
- return CPU (h_cr[2]);
- case 3 : /* user stack pointer */
- if (CPU (h_sm))
- return CPU (h_gr[15]);
+ return CPU (h_cr[H_CR_SPI]);
+ case H_CR_SPU : /* user stack pointer */
+ if (GET_H_SM ())
+ return CPU (h_gr[H_GR_SP]);
else
- return CPU (h_cr[3]);
- case 6 : /* backup pc */
- /* ??? We don't really support this yet. */
- case 4 : /* unused */
- case 5 : /* unused */
+ return CPU (h_cr[H_CR_SPU]);
+ case H_CR_BPC : /* backup pc */
+ return CPU (h_cr[H_CR_BPC]) & 0xfffffffe;
+ case H_CR_BBPC : /* backup backup pc */
+ return CPU (h_cr[H_CR_BBPC]) & 0xfffffffe;
+ case 4 : /* ??? unspecified, but apparently available */
+ case 5 : /* ??? unspecified, but apparently available */
return CPU (h_cr[cr]);
default :
return 0;
}
void
-m32r_h_cr_set (SIM_CPU *current_cpu, UINT cr, USI newval)
+m32rbf_h_cr_set_handler (SIM_CPU *current_cpu, UINT cr, USI newval)
{
- /* FIXME: Create enums H_CR_FOO, etc. */
switch (cr)
{
- case 0 : /* psw */
+ case H_CR_PSW : /* psw */
{
- int old_sm = CPU (h_sm);
- CPU (h_bsm) = (newval & (1 << 15)) != 0;
- CPU (h_bie) = (newval & (1 << 14)) != 0;
- CPU (h_bcond) = (newval & (1 << 8)) != 0;
- CPU (h_sm) = (newval & (1 << 7)) != 0;
- CPU (h_ie) = (newval & (1 << 6)) != 0;
- CPU (h_cond) = (newval & (1 << 0)) != 0;
+ int old_sm = (CPU (h_psw) & 0x80) != 0;
+ int new_sm = (newval & 0x80) != 0;
+ CPU (h_bpsw) = (newval >> 8) & 0xff;
+ CPU (h_psw) = newval & 0xff;
+ SET_H_COND (newval & 1);
/* When switching stack modes, update the registers. */
- if (old_sm != CPU (h_sm))
+ if (old_sm != new_sm)
{
if (old_sm)
{
/* Switching user -> system. */
- CPU (h_cr[3]) = CPU (h_gr[15]);
- CPU (h_gr[15]) = CPU (h_cr[2]);
+ CPU (h_cr[H_CR_SPU]) = CPU (h_gr[H_GR_SP]);
+ CPU (h_gr[H_GR_SP]) = CPU (h_cr[H_CR_SPI]);
}
else
{
/* Switching system -> user. */
- CPU (h_cr[2]) = CPU (h_gr[15]);
- CPU (h_gr[15]) = CPU (h_cr[3]);
+ CPU (h_cr[H_CR_SPI]) = CPU (h_gr[H_GR_SP]);
+ CPU (h_gr[H_GR_SP]) = CPU (h_cr[H_CR_SPU]);
}
}
break;
}
- case 1 : /* condition bit */
- CPU (h_cond) = (newval & 1) != 0;
+ case H_CR_BBPSW : /* backup backup psw */
+ CPU (h_bbpsw) = newval & 0xff;
+ break;
+ case H_CR_CBR : /* condition bit */
+ SET_H_COND (newval & 1);
break;
- case 2 : /* interrupt stack pointer */
- if (! CPU (h_sm))
- CPU (h_gr[15]) = newval;
+ case H_CR_SPI : /* interrupt stack pointer */
+ if (! GET_H_SM ())
+ CPU (h_gr[H_GR_SP]) = newval;
else
- CPU (h_cr[2]) = newval;
+ CPU (h_cr[H_CR_SPI]) = newval;
break;
- case 3 : /* user stack pointer */
- if (CPU (h_sm))
- CPU (h_gr[15]) = newval;
+ case H_CR_SPU : /* user stack pointer */
+ if (GET_H_SM ())
+ CPU (h_gr[H_GR_SP]) = newval;
else
- CPU (h_cr[3]) = newval;
+ CPU (h_cr[H_CR_SPU]) = newval;
break;
- case 4 : /* unused */
- case 5 : /* unused */
- case 6 : /* backup pc */
+ case H_CR_BPC : /* backup pc */
+ CPU (h_cr[H_CR_BPC]) = newval;
+ break;
+ case H_CR_BBPC : /* backup backup pc */
+ CPU (h_cr[H_CR_BBPC]) = newval;
+ break;
+ case 4 : /* ??? unspecified, but apparently available */
+ case 5 : /* ??? unspecified, but apparently available */
CPU (h_cr[cr]) = newval;
break;
default :
break;
}
}
+
+/* Cover fns to access h-psw. */
+
+UQI
+m32rbf_h_psw_get_handler (SIM_CPU *current_cpu)
+{
+ return (CPU (h_psw) & 0xfe) | (CPU (h_cond) & 1);
+}
+
+void
+m32rbf_h_psw_set_handler (SIM_CPU *current_cpu, UQI newval)
+{
+ CPU (h_psw) = newval;
+ CPU (h_cond) = newval & 1;
+}
+
+/* Cover fns to access h-accum. */
+
+DI
+m32rbf_h_accum_get_handler (SIM_CPU *current_cpu)
+{
+ /* Sign extend the top 8 bits. */
+ DI r;
+#if 1
+ r = ANDDI (CPU (h_accum), MAKEDI (0xffffff, 0xffffffff));
+ r = XORDI (r, MAKEDI (0x800000, 0));
+ r = SUBDI (r, MAKEDI (0x800000, 0));
+#else
+ SI hi,lo;
+ r = CPU (h_accum);
+ hi = GETHIDI (r);
+ lo = GETLODI (r);
+ hi = ((hi & 0xffffff) ^ 0x800000) - 0x800000;
+ r = MAKEDI (hi, lo);
+#endif
+ return r;
+}
+
+void
+m32rbf_h_accum_set_handler (SIM_CPU *current_cpu, DI newval)
+{
+ CPU (h_accum) = newval;
+}
+\f
+#if WITH_PROFILE_MODEL_P
+
+/* FIXME: Some of these should be inline or macros. Later. */
+
+/* Initialize cycle counting for an insn.
+ FIRST_P is non-zero if this is the first insn in a set of parallel
+ insns. */
+
+void
+m32rbf_model_insn_before (SIM_CPU *cpu, int first_p)
+{
+ M32R_MISC_PROFILE *mp = CPU_M32R_MISC_PROFILE (cpu);
+ mp->cti_stall = 0;
+ mp->load_stall = 0;
+ if (first_p)
+ {
+ mp->load_regs_pending = 0;
+ mp->biggest_cycles = 0;
+ }
+}
+
+/* Record the cycles computed for an insn.
+ LAST_P is non-zero if this is the last insn in a set of parallel insns,
+ and we update the total cycle count.
+ CYCLES is the cycle count of the insn. */
+
+void
+m32rbf_model_insn_after (SIM_CPU *cpu, int last_p, int cycles)
+{
+ PROFILE_DATA *p = CPU_PROFILE_DATA (cpu);
+ M32R_MISC_PROFILE *mp = CPU_M32R_MISC_PROFILE (cpu);
+ unsigned long total = cycles + mp->cti_stall + mp->load_stall;
+
+ if (last_p)
+ {
+ unsigned long biggest = total > mp->biggest_cycles ? total : mp->biggest_cycles;
+ PROFILE_MODEL_TOTAL_CYCLES (p) += biggest;
+ PROFILE_MODEL_CUR_INSN_CYCLES (p) = total;
+ }
+ else
+ {
+ /* Here we take advantage of the fact that !last_p -> first_p. */
+ mp->biggest_cycles = total;
+ PROFILE_MODEL_CUR_INSN_CYCLES (p) = total;
+ }
+
+ /* Branch and load stall counts are recorded independently of the
+ total cycle count. */
+ PROFILE_MODEL_CTI_STALL_CYCLES (p) += mp->cti_stall;
+ PROFILE_MODEL_LOAD_STALL_CYCLES (p) += mp->load_stall;
+
+ mp->load_regs = mp->load_regs_pending;
+}
+
+static INLINE void
+check_load_stall (SIM_CPU *cpu, int regno)
+{
+ UINT h_gr = CPU_M32R_MISC_PROFILE (cpu)->load_regs;
+
+ if (regno != -1
+ && (h_gr & (1 << regno)) != 0)
+ {
+ CPU_M32R_MISC_PROFILE (cpu)->load_stall += 2;
+ if (TRACE_INSN_P (cpu))
+ cgen_trace_printf (cpu, " ; Load stall of 2 cycles.");
+ }
+}
+
+int
+m32rbf_model_m32r_d_u_exec (SIM_CPU *cpu, const IDESC *idesc,
+ int unit_num, int referenced,
+ INT sr, INT sr2, INT dr)
+{
+ check_load_stall (cpu, sr);
+ check_load_stall (cpu, sr2);
+ return idesc->timing->units[unit_num].done;
+}
+
+int
+m32rbf_model_m32r_d_u_cmp (SIM_CPU *cpu, const IDESC *idesc,
+ int unit_num, int referenced,
+ INT src1, INT src2)
+{
+ check_load_stall (cpu, src1);
+ check_load_stall (cpu, src2);
+ return idesc->timing->units[unit_num].done;
+}
+
+int
+m32rbf_model_m32r_d_u_mac (SIM_CPU *cpu, const IDESC *idesc,
+ int unit_num, int referenced,
+ INT src1, INT src2)
+{
+ check_load_stall (cpu, src1);
+ check_load_stall (cpu, src2);
+ return idesc->timing->units[unit_num].done;
+}
+
+int
+m32rbf_model_m32r_d_u_cti (SIM_CPU *cpu, const IDESC *idesc,
+ int unit_num, int referenced,
+ INT sr)
+{
+ PROFILE_DATA *profile = CPU_PROFILE_DATA (cpu);
+ int taken_p = (referenced & (1 << 1)) != 0;
+
+ check_load_stall (cpu, sr);
+ if (taken_p)
+ {
+ CPU_M32R_MISC_PROFILE (cpu)->cti_stall += 2;
+ PROFILE_MODEL_TAKEN_COUNT (profile) += 1;
+ }
+ else
+ PROFILE_MODEL_UNTAKEN_COUNT (profile) += 1;
+ return idesc->timing->units[unit_num].done;
+}
+
+int
+m32rbf_model_m32r_d_u_load (SIM_CPU *cpu, const IDESC *idesc,
+ int unit_num, int referenced,
+ INT sr, INT dr)
+{
+ CPU_M32R_MISC_PROFILE (cpu)->load_regs_pending |= (1 << dr);
+ check_load_stall (cpu, sr);
+ return idesc->timing->units[unit_num].done;
+}
+
+int
+m32rbf_model_m32r_d_u_store (SIM_CPU *cpu, const IDESC *idesc,
+ int unit_num, int referenced,
+ INT src1, INT src2)
+{
+ check_load_stall (cpu, src1);
+ check_load_stall (cpu, src2);
+ return idesc->timing->units[unit_num].done;
+}
+
+int
+m32rbf_model_test_u_exec (SIM_CPU *cpu, const IDESC *idesc,
+ int unit_num, int referenced)
+{
+ return idesc->timing->units[unit_num].done;
+}
+
+#endif /* WITH_PROFILE_MODEL_P */