aboutsummaryrefslogtreecommitdiff
path: root/sim/sh64/sh64.c
diff options
context:
space:
mode:
Diffstat (limited to 'sim/sh64/sh64.c')
-rw-r--r--sim/sh64/sh64.c1030
1 files changed, 1030 insertions, 0 deletions
diff --git a/sim/sh64/sh64.c b/sim/sh64/sh64.c
new file mode 100644
index 0000000..55c90e6
--- /dev/null
+++ b/sim/sh64/sh64.c
@@ -0,0 +1,1030 @@
+/* SH5 simulator support code
+ Copyright (C) 2000, 2001 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 2, 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. */
+
+#define WANT_CPU
+#define WANT_CPU_SH64
+
+#include "sim-main.h"
+#include "sim-fpu.h"
+#include "cgen-mem.h"
+#include "cgen-ops.h"
+
+#include "callback.h"
+#include "defs-compact.h"
+
+#include "bfd.h"
+/* From include/. */
+#include "sim-sh64.h"
+
+#define SYS_exit 1
+#define SYS_read 3
+#define SYS_write 4
+#define SYS_open 5
+#define SYS_close 6
+#define SYS_lseek 19
+#define SYS_time 23
+#define SYS_argc 172
+#define SYS_argnlen 173
+#define SYS_argn 174
+
+IDESC * sh64_idesc_media;
+IDESC * sh64_idesc_compact;
+
+BI
+sh64_endian (SIM_CPU *current_cpu)
+{
+ return (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN);
+}
+
+SF
+sh64_fldi0 (SIM_CPU *current_cpu)
+{
+ SF result;
+ sim_fpu_to32 (&result, &sim_fpu_zero);
+ return result;
+}
+
+SF
+sh64_fldi1 (SIM_CPU *current_cpu)
+{
+ SF result;
+ sim_fpu_to32 (&result, &sim_fpu_one);
+ return result;
+}
+
+DF
+sh64_fabsd(SIM_CPU *current_cpu, DF drgh)
+{
+ DF result;
+ sim_fpu f, fres;
+
+ sim_fpu_64to (&f, drgh);
+ sim_fpu_abs (&fres, &f);
+ sim_fpu_to64 (&result, &fres);
+ return result;
+}
+
+SF
+sh64_fabss(SIM_CPU *current_cpu, SF frgh)
+{
+ SF result;
+ sim_fpu f, fres;
+
+ sim_fpu_32to (&f, frgh);
+ sim_fpu_abs (&fres, &f);
+ sim_fpu_to32 (&result, &fres);
+ return result;
+}
+
+DF
+sh64_faddd(SIM_CPU *current_cpu, DF drg, DF drh)
+{
+ DF result;
+ sim_fpu f1, f2, fres;
+
+ sim_fpu_64to (&f1, drg);
+ sim_fpu_64to (&f2, drh);
+ sim_fpu_add (&fres, &f1, &f2);
+ sim_fpu_to64 (&result, &fres);
+ return result;
+}
+
+SF
+sh64_fadds(SIM_CPU *current_cpu, SF frg, SF frh)
+{
+ SF result;
+ sim_fpu f1, f2, fres;
+
+ sim_fpu_32to (&f1, frg);
+ sim_fpu_32to (&f2, frh);
+ sim_fpu_add (&fres, &f1, &f2);
+ sim_fpu_to32 (&result, &fres);
+ return result;
+}
+
+BI
+sh64_fcmpeqd(SIM_CPU *current_cpu, DF drg, DF drh)
+{
+ sim_fpu f1, f2;
+
+ sim_fpu_64to (&f1, drg);
+ sim_fpu_64to (&f2, drh);
+ return sim_fpu_is_eq (&f1, &f2);
+}
+
+BI
+sh64_fcmpeqs(SIM_CPU *current_cpu, SF frg, SF frh)
+{
+ sim_fpu f1, f2;
+
+ sim_fpu_32to (&f1, frg);
+ sim_fpu_32to (&f2, frh);
+ return sim_fpu_is_eq (&f1, &f2);
+}
+
+BI
+sh64_fcmpged(SIM_CPU *current_cpu, DF drg, DF drh)
+{
+ sim_fpu f1, f2;
+
+ sim_fpu_64to (&f1, drg);
+ sim_fpu_64to (&f2, drh);
+ return sim_fpu_is_ge (&f1, &f2);
+}
+
+BI
+sh64_fcmpges(SIM_CPU *current_cpu, SF frg, SF frh)
+{
+ sim_fpu f1, f2;
+
+ sim_fpu_32to (&f1, frg);
+ sim_fpu_32to (&f2, frh);
+ return sim_fpu_is_ge (&f1, &f2);
+}
+
+BI
+sh64_fcmpgtd(SIM_CPU *current_cpu, DF drg, DF drh)
+{
+ sim_fpu f1, f2;
+
+ sim_fpu_64to (&f1, drg);
+ sim_fpu_64to (&f2, drh);
+ return sim_fpu_is_gt (&f1, &f2);
+}
+
+BI
+sh64_fcmpgts(SIM_CPU *current_cpu, SF frg, SF frh)
+{
+ sim_fpu f1, f2;
+
+ sim_fpu_32to (&f1, frg);
+ sim_fpu_32to (&f2, frh);
+ return sim_fpu_is_gt (&f1, &f2);
+}
+
+BI
+sh64_fcmpund(SIM_CPU *current_cpu, DF drg, DF drh)
+{
+ sim_fpu f1, f2;
+
+ sim_fpu_64to (&f1, drg);
+ sim_fpu_64to (&f2, drh);
+ return (sim_fpu_is_nan (&f1) || sim_fpu_is_nan (&f2));
+}
+
+BI
+sh64_fcmpuns(SIM_CPU *current_cpu, SF frg, SF frh)
+{
+ sim_fpu f1, f2;
+
+ sim_fpu_32to (&f1, frg);
+ sim_fpu_32to (&f2, frh);
+ return (sim_fpu_is_nan (&f1) || sim_fpu_is_nan (&f2));
+}
+
+SF
+sh64_fcnvds(SIM_CPU *current_cpu, DF drgh)
+{
+ union {
+ unsigned long long ll;
+ double d;
+ } f1;
+
+ union {
+ unsigned long l;
+ float f;
+ } f2;
+
+ f1.ll = drgh;
+ f2.f = (float) f1.d;
+
+ return (SF) f2.l;
+}
+
+DF
+sh64_fcnvsd(SIM_CPU *current_cpu, SF frgh)
+{
+ DF result;
+ sim_fpu f;
+
+ sim_fpu_32to (&f, frgh);
+ sim_fpu_to64 (&result, &f);
+ return result;
+}
+
+DF
+sh64_fdivd(SIM_CPU *current_cpu, DF drg, DF drh)
+{
+ DF result;
+ sim_fpu f1, f2, fres;
+
+ sim_fpu_64to (&f1, drg);
+ sim_fpu_64to (&f2, drh);
+ sim_fpu_div (&fres, &f1, &f2);
+ sim_fpu_to64 (&result, &fres);
+ return result;
+}
+
+SF
+sh64_fdivs(SIM_CPU *current_cpu, SF frg, SF frh)
+{
+ SF result;
+ sim_fpu f1, f2, fres;
+
+ sim_fpu_32to (&f1, frg);
+ sim_fpu_32to (&f2, frh);
+ sim_fpu_div (&fres, &f1, &f2);
+ sim_fpu_to32 (&result, &fres);
+ return result;
+}
+
+DF
+sh64_floatld(SIM_CPU *current_cpu, SF frgh)
+{
+ DF result;
+ sim_fpu f;
+
+ sim_fpu_i32to (&f, frgh, sim_fpu_round_default);
+ sim_fpu_to64 (&result, &f);
+ return result;
+}
+
+SF
+sh64_floatls(SIM_CPU *current_cpu, SF frgh)
+{
+ SF result;
+ sim_fpu f;
+
+ sim_fpu_i32to (&f, frgh, sim_fpu_round_default);
+ sim_fpu_to32 (&result, &f);
+ return result;
+}
+
+DF
+sh64_floatqd(SIM_CPU *current_cpu, DF drgh)
+{
+ DF result;
+ sim_fpu f;
+
+ sim_fpu_i64to (&f, drgh, sim_fpu_round_default);
+ sim_fpu_to64 (&result, &f);
+ return result;
+}
+
+SF
+sh64_floatqs(SIM_CPU *current_cpu, DF drgh)
+{
+ SF result;
+ sim_fpu f;
+
+ sim_fpu_i64to (&f, drgh, sim_fpu_round_default);
+ sim_fpu_to32 (&result, &f);
+ return result;
+}
+
+SF
+sh64_fmacs(SIM_CPU *current_cpu, SF fr0, SF frm, SF frn)
+{
+ SF result;
+ sim_fpu m1, m2, a1, fres;
+
+ sim_fpu_32to (&m1, fr0);
+ sim_fpu_32to (&m2, frm);
+ sim_fpu_32to (&a1, frn);
+
+ sim_fpu_mul (&fres, &m1, &m2);
+ sim_fpu_add (&fres, &fres, &a1);
+
+ sim_fpu_to32 (&result, &fres);
+ return result;
+}
+
+DF
+sh64_fmuld(SIM_CPU *current_cpu, DF drg, DF drh)
+{
+ DF result;
+ sim_fpu f1, f2, fres;
+
+ sim_fpu_64to (&f1, drg);
+ sim_fpu_64to (&f2, drh);
+ sim_fpu_mul (&fres, &f1, &f2);
+ sim_fpu_to64 (&result, &fres);
+ return result;
+}
+
+SF
+sh64_fmuls(SIM_CPU *current_cpu, SF frg, SF frh)
+{
+ SF result;
+ sim_fpu f1, f2, fres;
+
+ sim_fpu_32to (&f1, frg);
+ sim_fpu_32to (&f2, frh);
+ sim_fpu_mul (&fres, &f1, &f2);
+ sim_fpu_to32 (&result, &fres);
+ return result;
+}
+
+DF
+sh64_fnegd(SIM_CPU *current_cpu, DF drgh)
+{
+ DF result;
+ sim_fpu f1, f2;
+
+ sim_fpu_64to (&f1, drgh);
+ sim_fpu_neg (&f2, &f1);
+ sim_fpu_to64 (&result, &f2);
+ return result;
+}
+
+SF
+sh64_fnegs(SIM_CPU *current_cpu, SF frgh)
+{
+ SF result;
+ sim_fpu f, fres;
+
+ sim_fpu_32to (&f, frgh);
+ sim_fpu_neg (&fres, &f);
+ sim_fpu_to32 (&result, &fres);
+ return result;
+}
+
+DF
+sh64_fsqrtd(SIM_CPU *current_cpu, DF drgh)
+{
+ DF result;
+ sim_fpu f, fres;
+
+ sim_fpu_64to (&f, drgh);
+ sim_fpu_sqrt (&fres, &f);
+ sim_fpu_to64 (&result, &fres);
+ return result;
+}
+
+SF
+sh64_fsqrts(SIM_CPU *current_cpu, SF frgh)
+{
+ SF result;
+ sim_fpu f, fres;
+
+ sim_fpu_32to (&f, frgh);
+ sim_fpu_sqrt (&fres, &f);
+ sim_fpu_to32 (&result, &fres);
+ return result;
+}
+
+DF
+sh64_fsubd(SIM_CPU *current_cpu, DF drg, DF drh)
+{
+ DF result;
+ sim_fpu f1, f2, fres;
+
+ sim_fpu_64to (&f1, drg);
+ sim_fpu_64to (&f2, drh);
+ sim_fpu_sub (&fres, &f1, &f2);
+ sim_fpu_to64 (&result, &fres);
+ return result;
+}
+
+SF
+sh64_fsubs(SIM_CPU *current_cpu, SF frg, SF frh)
+{
+ SF result;
+ sim_fpu f1, f2, fres;
+
+ sim_fpu_32to (&f1, frg);
+ sim_fpu_32to (&f2, frh);
+ sim_fpu_sub (&fres, &f1, &f2);
+ sim_fpu_to32 (&result, &fres);
+ return result;
+}
+
+SF
+sh64_ftrcdl(SIM_CPU *current_cpu, DF drgh)
+{
+ SI result;
+ sim_fpu f;
+
+ sim_fpu_64to (&f, drgh);
+ sim_fpu_to32i (&result, &f, sim_fpu_round_zero);
+ return (SF) result;
+}
+
+SF
+sh64_ftrcsl(SIM_CPU *current_cpu, SF frgh)
+{
+ SI result;
+ sim_fpu f;
+
+ sim_fpu_32to (&f, frgh);
+ sim_fpu_to32i (&result, &f, sim_fpu_round_zero);
+ return (SF) result;
+}
+
+DF
+sh64_ftrcdq(SIM_CPU *current_cpu, DF drgh)
+{
+ DI result;
+ sim_fpu f;
+
+ sim_fpu_64to (&f, drgh);
+ sim_fpu_to64i (&result, &f, sim_fpu_round_zero);
+ return (DF) result;
+}
+
+DF
+sh64_ftrcsq(SIM_CPU *current_cpu, SF frgh)
+{
+ DI result;
+ sim_fpu f;
+
+ sim_fpu_32to (&f, frgh);
+ sim_fpu_to64i (&result, &f, sim_fpu_round_zero);
+ return (DF) result;
+}
+
+void
+sh64_ftrvs(SIM_CPU *cpu, unsigned g, unsigned h, unsigned f)
+{
+ int i, j;
+
+ for (i = 0; i < 4; i++)
+ {
+ SF result;
+ sim_fpu sum;
+ sim_fpu_32to (&sum, 0);
+
+ for (j = 0; j < 4; j++)
+ {
+ sim_fpu f1, f2, temp;
+ sim_fpu_32to (&f1, sh64_h_fr_get (cpu, (g + i) + (j * 4)));
+ sim_fpu_32to (&f2, sh64_h_fr_get (cpu, h + j));
+ sim_fpu_mul (&temp, &f1, &f2);
+ sim_fpu_add (&sum, &sum, &temp);
+ }
+ sim_fpu_to32 (&result, &sum);
+ sh64_h_fr_set (cpu, f + i, result);
+ }
+}
+
+/* Count the number of arguments. */
+static int
+count_argc (cpu)
+ SIM_CPU *cpu;
+{
+ int i = 0;
+
+ if (! STATE_PROG_ARGV (CPU_STATE (cpu)))
+ return -1;
+
+ while (STATE_PROG_ARGV (CPU_STATE (cpu)) [i] != NULL)
+ ++i;
+
+ return i;
+}
+
+/* Read a null terminated string from memory, return in a buffer */
+static char *
+fetch_str (current_cpu, pc, addr)
+ SIM_CPU *current_cpu;
+ PCADDR pc;
+ DI addr;
+{
+ char *buf;
+ int nr = 0;
+ while (sim_core_read_1 (current_cpu,
+ pc, read_map, addr + nr) != 0)
+ nr++;
+ buf = NZALLOC (char, nr + 1);
+ sim_read (CPU_STATE (current_cpu), addr, buf, nr);
+ return buf;
+}
+
+static void
+trap_handler (SIM_CPU *current_cpu, int shmedia_abi_p, UQI trapnum, PCADDR pc)
+{
+ char ch;
+ switch (trapnum)
+ {
+ case 1:
+ ch = GET_H_GRC (0);
+ sim_io_write_stdout (CPU_STATE (current_cpu), &ch, 1);
+ fflush (stdout);
+ break;
+ case 2:
+ sim_engine_halt (CPU_STATE (current_cpu), current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
+ break;
+ case 34:
+ {
+ int i;
+ int ret_reg = (shmedia_abi_p) ? 2 : 0;
+ char *buf;
+ DI PARM1 = GET_H_GR ((shmedia_abi_p) ? 3 : 5);
+ DI PARM2 = GET_H_GR ((shmedia_abi_p) ? 4 : 6);
+ DI PARM3 = GET_H_GR ((shmedia_abi_p) ? 5 : 7);
+
+ switch (GET_H_GR ((shmedia_abi_p) ? 2 : 4))
+ {
+ case SYS_write:
+ buf = zalloc (PARM3);
+ sim_read (CPU_STATE (current_cpu), PARM2, buf, PARM3);
+ SET_H_GR (ret_reg,
+ sim_io_write (CPU_STATE (current_cpu),
+ PARM1, buf, PARM3));
+ zfree (buf);
+ break;
+
+ case SYS_lseek:
+ SET_H_GR (ret_reg,
+ sim_io_lseek (CPU_STATE (current_cpu),
+ PARM1, PARM2, PARM3));
+ break;
+
+ case SYS_exit:
+ sim_engine_halt (CPU_STATE (current_cpu), current_cpu,
+ NULL, pc, sim_exited, PARM1);
+ break;
+
+ case SYS_read:
+ buf = zalloc (PARM3);
+ SET_H_GR (ret_reg,
+ sim_io_read (CPU_STATE (current_cpu),
+ PARM1, buf, PARM3));
+ sim_write (CPU_STATE (current_cpu), PARM2, buf, PARM3);
+ zfree (buf);
+ break;
+
+ case SYS_open:
+ buf = fetch_str (current_cpu, pc, PARM1);
+ SET_H_GR (ret_reg,
+ sim_io_open (CPU_STATE (current_cpu),
+ buf, PARM2));
+ zfree (buf);
+ break;
+
+ case SYS_close:
+ SET_H_GR (ret_reg,
+ sim_io_close (CPU_STATE (current_cpu), PARM1));
+ break;
+
+ case SYS_time:
+ SET_H_GR (ret_reg, time (0));
+ break;
+
+ case SYS_argc:
+ SET_H_GR (ret_reg, count_argc (current_cpu));
+ break;
+
+ case SYS_argnlen:
+ if (PARM1 < count_argc (current_cpu))
+ SET_H_GR (ret_reg,
+ strlen (STATE_PROG_ARGV (CPU_STATE (current_cpu)) [PARM1]));
+ else
+ SET_H_GR (ret_reg, -1);
+ break;
+
+ case SYS_argn:
+ if (PARM1 < count_argc (current_cpu))
+ {
+ /* Include the NULL byte. */
+ i = strlen (STATE_PROG_ARGV (CPU_STATE (current_cpu)) [PARM1]) + 1;
+ sim_write (CPU_STATE (current_cpu),
+ PARM2,
+ STATE_PROG_ARGV (CPU_STATE (current_cpu)) [PARM1],
+ i);
+
+ /* Just for good measure. */
+ SET_H_GR (ret_reg, i);
+ break;
+ }
+ else
+ SET_H_GR (ret_reg, -1);
+ break;
+
+ default:
+ SET_H_GR (ret_reg, -1);
+ }
+ }
+ break;
+ case 253:
+ puts ("pass");
+ exit (0);
+ case 254:
+ puts ("fail");
+ exit (1);
+ case 0xc3:
+ /* fall through. */
+ case 255:
+ sim_engine_halt (CPU_STATE (current_cpu), current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
+ break;
+ }
+}
+
+void
+sh64_trapa (SIM_CPU *current_cpu, DI rm, PCADDR pc)
+{
+ trap_handler (current_cpu, 1, (UQI) rm & 0xff, pc);
+}
+
+void
+sh64_compact_trapa (SIM_CPU *current_cpu, UQI trapnum, PCADDR pc)
+{
+ int mach_sh5_p;
+
+ /* If this is an SH5 executable, this is SHcompact code running in
+ the SHmedia ABI. */
+
+ mach_sh5_p =
+ (bfd_get_mach (STATE_PROG_BFD (CPU_STATE (current_cpu))) == bfd_mach_sh5);
+
+ trap_handler (current_cpu, mach_sh5_p, trapnum, pc);
+}
+
+DI
+sh64_nsb (SIM_CPU *current_cpu, DI rm)
+{
+ int result = 0, count;
+ UDI source = (UDI) rm;
+
+ if ((source >> 63))
+ source = ~source;
+ source <<= 1;
+
+ for (count = 32; count; count >>= 1)
+ {
+ UDI newval = source << count;
+
+ if ((newval >> count) == source)
+ {
+ result |= count;
+ source = newval;
+ }
+ }
+
+ return result;
+}
+
+void
+sh64_break (SIM_CPU *current_cpu, PCADDR pc)
+{
+ SIM_DESC sd = CPU_STATE (current_cpu);
+ sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
+}
+
+void
+set_isa (SIM_CPU *current_cpu, int mode)
+{
+ /* Do nothing. */
+}
+
+/* The semantic code invokes this for invalid (unrecognized) instructions. */
+
+SEM_PC
+sim_engine_invalid_insn (SIM_CPU *current_cpu, IADDR cia, SEM_PC vpc)
+{
+ SIM_DESC sd = CPU_STATE (current_cpu);
+ sim_engine_halt (sd, current_cpu, NULL, cia, sim_stopped, SIM_SIGILL);
+
+ return vpc;
+}
+
+
+/* Process an address exception. */
+
+void
+sh64_core_signal (SIM_DESC sd, SIM_CPU *current_cpu, sim_cia cia,
+ unsigned int map, int nr_bytes, address_word addr,
+ transfer_type transfer, sim_core_signals sig)
+{
+ sim_core_signal (sd, current_cpu, cia, map, nr_bytes, addr,
+ transfer, sig);
+}
+
+
+/* Initialize cycle counting for an insn.
+ FIRST_P is non-zero if this is the first insn in a set of parallel
+ insns. */
+
+void
+sh64_compact_model_insn_before (SIM_CPU *cpu, int first_p)
+{
+ /* Do nothing. */
+}
+
+void
+sh64_media_model_insn_before (SIM_CPU *cpu, int first_p)
+{
+ /* Do nothing. */
+}
+
+/* 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
+sh64_compact_model_insn_after(SIM_CPU *cpu, int last_p, int cycles)
+{
+ /* Do nothing. */
+}
+
+void
+sh64_media_model_insn_after(SIM_CPU *cpu, int last_p, int cycles)
+{
+ /* Do nothing. */
+}
+
+int
+sh64_fetch_register (SIM_CPU *cpu, int nr, unsigned char *buf, int len)
+{
+ /* Fetch general purpose registers. */
+ if (nr >= SIM_SH64_R0_REGNUM
+ && nr < (SIM_SH64_R0_REGNUM + SIM_SH64_NR_R_REGS)
+ && len == 8)
+ {
+ *((unsigned64*) buf) =
+ H2T_8 (sh64_h_gr_get (cpu, nr - SIM_SH64_R0_REGNUM));
+ return len;
+ }
+
+ /* Fetch PC. */
+ if (nr == SIM_SH64_PC_REGNUM && len == 8)
+ {
+ *((unsigned64*) buf) = H2T_8 (sh64_h_pc_get (cpu) | sh64_h_ism_get (cpu));
+ return len;
+ }
+
+ /* Fetch status register (SR). */
+ if (nr == SIM_SH64_SR_REGNUM && len == 8)
+ {
+ *((unsigned64*) buf) = H2T_8 (sh64_h_sr_get (cpu));
+ return len;
+ }
+
+ /* Fetch saved status register (SSR) and PC (SPC). */
+ if ((nr == SIM_SH64_SSR_REGNUM || nr == SIM_SH64_SPC_REGNUM)
+ && len == 8)
+ {
+ *((unsigned64*) buf) = 0;
+ return len;
+ }
+
+ /* Fetch target registers. */
+ if (nr >= SIM_SH64_TR0_REGNUM
+ && nr < (SIM_SH64_TR0_REGNUM + SIM_SH64_NR_TR_REGS)
+ && len == 8)
+ {
+ *((unsigned64*) buf) =
+ H2T_8 (sh64_h_tr_get (cpu, nr - SIM_SH64_TR0_REGNUM));
+ return len;
+ }
+
+ /* Fetch floating point registers. */
+ if (nr >= SIM_SH64_FR0_REGNUM
+ && nr < (SIM_SH64_FR0_REGNUM + SIM_SH64_NR_FP_REGS)
+ && len == 4)
+ {
+ *((unsigned32*) buf) =
+ H2T_4 (sh64_h_fr_get (cpu, nr - SIM_SH64_FR0_REGNUM));
+ return len;
+ }
+
+ /* We should never get here. */
+ return 0;
+}
+
+int
+sh64_store_register (SIM_CPU *cpu, int nr, unsigned char *buf, int len)
+{
+ /* Store general purpose registers. */
+ if (nr >= SIM_SH64_R0_REGNUM
+ && nr < (SIM_SH64_R0_REGNUM + SIM_SH64_NR_R_REGS)
+ && len == 8)
+ {
+ sh64_h_gr_set (cpu, nr - SIM_SH64_R0_REGNUM, T2H_8 (*((unsigned64*)buf)));
+ return len;
+ }
+
+ /* Store PC. */
+ if (nr == SIM_SH64_PC_REGNUM && len == 8)
+ {
+ unsigned64 new_pc = T2H_8 (*((unsigned64*)buf));
+ sh64_h_pc_set (cpu, new_pc);
+ return len;
+ }
+
+ /* Store status register (SR). */
+ if (nr == SIM_SH64_SR_REGNUM && len == 8)
+ {
+ sh64_h_sr_set (cpu, T2H_8 (*((unsigned64*)buf)));
+ return len;
+ }
+
+ /* Store saved status register (SSR) and PC (SPC). */
+ if (nr == SIM_SH64_SSR_REGNUM || nr == SIM_SH64_SPC_REGNUM)
+ {
+ /* Do nothing. */
+ return len;
+ }
+
+ /* Store target registers. */
+ if (nr >= SIM_SH64_TR0_REGNUM
+ && nr < (SIM_SH64_TR0_REGNUM + SIM_SH64_NR_TR_REGS)
+ && len == 8)
+ {
+ sh64_h_tr_set (cpu, nr - SIM_SH64_TR0_REGNUM, T2H_8 (*((unsigned64*)buf)));
+ return len;
+ }
+
+ /* Store floating point registers. */
+ if (nr >= SIM_SH64_FR0_REGNUM
+ && nr < (SIM_SH64_FR0_REGNUM + SIM_SH64_NR_FP_REGS)
+ && len == 4)
+ {
+ sh64_h_fr_set (cpu, nr - SIM_SH64_FR0_REGNUM, T2H_4 (*((unsigned32*)buf)));
+ return len;
+ }
+
+ /* We should never get here. */
+ return 0;
+}
+
+void
+sh64_engine_run_full(SIM_CPU *cpu)
+{
+ if (sh64_h_ism_get (cpu) == ISM_MEDIA)
+ {
+ if (!sh64_idesc_media)
+ {
+ sh64_media_init_idesc_table (cpu);
+ sh64_idesc_media = CPU_IDESC (cpu);
+ }
+ else
+ CPU_IDESC (cpu) = sh64_idesc_media;
+ sh64_media_engine_run_full (cpu);
+ }
+ else
+ {
+ if (!sh64_idesc_compact)
+ {
+ sh64_compact_init_idesc_table (cpu);
+ sh64_idesc_compact = CPU_IDESC (cpu);
+ }
+ else
+ CPU_IDESC (cpu) = sh64_idesc_compact;
+ sh64_compact_engine_run_full (cpu);
+ }
+}
+
+void
+sh64_engine_run_fast (SIM_CPU *cpu)
+{
+ if (sh64_h_ism_get (cpu) == ISM_MEDIA)
+ {
+ if (!sh64_idesc_media)
+ {
+ sh64_media_init_idesc_table (cpu);
+ sh64_idesc_media = CPU_IDESC (cpu);
+ }
+ else
+ CPU_IDESC (cpu) = sh64_idesc_media;
+ sh64_media_engine_run_fast (cpu);
+ }
+ else
+ {
+ if (!sh64_idesc_compact)
+ {
+ sh64_compact_init_idesc_table (cpu);
+ sh64_idesc_compact = CPU_IDESC (cpu);
+ }
+ else
+ CPU_IDESC (cpu) = sh64_idesc_compact;
+ sh64_compact_engine_run_fast (cpu);
+ }
+}
+
+static void
+sh64_prepare_run (SIM_CPU *cpu)
+{
+ /* Nothing. */
+}
+
+static const CGEN_INSN *
+sh64_get_idata (SIM_CPU *cpu, int inum)
+{
+ return CPU_IDESC (cpu) [inum].idata;
+}
+
+static void
+sh64_init_cpu (SIM_CPU *cpu)
+{
+ CPU_REG_FETCH (cpu) = sh64_fetch_register;
+ CPU_REG_STORE (cpu) = sh64_store_register;
+ CPU_PC_FETCH (cpu) = sh64_h_pc_get;
+ CPU_PC_STORE (cpu) = sh64_h_pc_set;
+ CPU_GET_IDATA (cpu) = sh64_get_idata;
+ /* Only used by profiling. 0 disables it. */
+ CPU_MAX_INSNS (cpu) = 0;
+ CPU_INSN_NAME (cpu) = cgen_insn_name;
+ CPU_FULL_ENGINE_FN (cpu) = sh64_engine_run_full;
+#if WITH_FAST
+ CPU_FAST_ENGINE_FN (cpu) = sh64_engine_run_fast;
+#else
+ CPU_FAST_ENGINE_FN (cpu) = sh64_engine_run_full;
+#endif
+}
+
+static void
+shmedia_init_cpu (SIM_CPU *cpu)
+{
+ sh64_init_cpu (cpu);
+}
+
+static void
+shcompact_init_cpu (SIM_CPU *cpu)
+{
+ sh64_init_cpu (cpu);
+}
+
+static void
+sh64_model_init()
+{
+ /* Do nothing. */
+}
+
+static const MODEL sh_models [] =
+{
+ { "sh2", & sh2_mach, MODEL_SH5, NULL, sh64_model_init },
+ { "sh3", & sh3_mach, MODEL_SH5, NULL, sh64_model_init },
+ { "sh3e", & sh3_mach, MODEL_SH5, NULL, sh64_model_init },
+ { "sh4", & sh4_mach, MODEL_SH5, NULL, sh64_model_init },
+ { "sh5", & sh5_mach, MODEL_SH5, NULL, sh64_model_init },
+ { 0 }
+};
+
+static const MACH_IMP_PROPERTIES sh5_imp_properties =
+{
+ sizeof (SIM_CPU),
+#if WITH_SCACHE
+ sizeof (SCACHE)
+#else
+ 0
+#endif
+};
+
+const MACH sh2_mach =
+{
+ "sh2", "sh2", MACH_SH5,
+ 16, 16, &sh_models[0], &sh5_imp_properties,
+ shcompact_init_cpu,
+ sh64_prepare_run
+};
+
+const MACH sh3_mach =
+{
+ "sh3", "sh3", MACH_SH5,
+ 16, 16, &sh_models[1], &sh5_imp_properties,
+ shcompact_init_cpu,
+ sh64_prepare_run
+};
+
+const MACH sh3e_mach =
+{
+ "sh3e", "sh3e", MACH_SH5,
+ 16, 16, &sh_models[2], &sh5_imp_properties,
+ shcompact_init_cpu,
+ sh64_prepare_run
+};
+
+const MACH sh4_mach =
+{
+ "sh4", "sh4", MACH_SH5,
+ 16, 16, &sh_models[3], &sh5_imp_properties,
+ shcompact_init_cpu,
+ sh64_prepare_run
+};
+
+const MACH sh5_mach =
+{
+ "sh5", "sh5", MACH_SH5,
+ 32, 32, &sh_models[4], &sh5_imp_properties,
+ shmedia_init_cpu,
+ sh64_prepare_run
+};