| /* SH5 simulator support code |
| Copyright (C) 2000, 2001, 2006, 2008, 2009, 2010 |
| 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/>. */ |
| |
| #define WANT_CPU |
| #define WANT_CPU_SH64 |
| |
| #include "sim-main.h" |
| #include "sim-fpu.h" |
| #include "cgen-mem.h" |
| #include "cgen-ops.h" |
| |
| #include "gdb/callback.h" |
| #include "defs-compact.h" |
| |
| #include "bfd.h" |
| /* From include/gdb/. */ |
| #include "gdb/sim-sh.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); |
| } |
| } |
| |
| VOID |
| sh64_fipr (SIM_CPU *cpu, unsigned m, unsigned n) |
| { |
| SF result = sh64_fmuls (cpu, sh64_h_fvc_get (cpu, m), sh64_h_fvc_get (cpu, n)); |
| result = sh64_fadds (cpu, result, sh64_fmuls (cpu, sh64_h_frc_get (cpu, m + 1), sh64_h_frc_get (cpu, n + 1))); |
| result = sh64_fadds (cpu, result, sh64_fmuls (cpu, sh64_h_frc_get (cpu, m + 2), sh64_h_frc_get (cpu, n + 2))); |
| result = sh64_fadds (cpu, result, sh64_fmuls (cpu, sh64_h_frc_get (cpu, m + 3), sh64_h_frc_get (cpu, n + 3))); |
| sh64_h_frc_set (cpu, n + 3, result); |
| } |
| |
| SF |
| sh64_fiprs (SIM_CPU *cpu, unsigned g, unsigned h) |
| { |
| SF temp = sh64_fmuls (cpu, sh64_h_fr_get (cpu, g), sh64_h_fr_get (cpu, h)); |
| temp = sh64_fadds (cpu, temp, sh64_fmuls (cpu, sh64_h_fr_get (cpu, g + 1), sh64_h_fr_get (cpu, h + 1))); |
| temp = sh64_fadds (cpu, temp, sh64_fmuls (cpu, sh64_h_fr_get (cpu, g + 2), sh64_h_fr_get (cpu, h + 2))); |
| temp = sh64_fadds (cpu, temp, sh64_fmuls (cpu, sh64_h_fr_get (cpu, g + 3), sh64_h_fr_get (cpu, h + 3))); |
| return temp; |
| } |
| |
| VOID |
| sh64_fldp (SIM_CPU *cpu, PCADDR pc, DI rm, DI rn, unsigned f) |
| { |
| sh64_h_fr_set (cpu, f, GETMEMSF (cpu, pc, rm + rn)); |
| sh64_h_fr_set (cpu, f + 1, GETMEMSF (cpu, pc, rm + rn + 4)); |
| } |
| |
| VOID |
| sh64_fstp (SIM_CPU *cpu, PCADDR pc, DI rm, DI rn, unsigned f) |
| { |
| SETMEMSF (cpu, pc, rm + rn, sh64_h_fr_get (cpu, f)); |
| SETMEMSF (cpu, pc, rm + rn + 4, sh64_h_fr_get (cpu, f + 1)); |
| } |
| |
| VOID |
| sh64_ftrv (SIM_CPU *cpu, UINT ignored) |
| { |
| /* TODO: Unimplemented. */ |
| } |
| |
| VOID |
| sh64_pref (SIM_CPU *cpu, SI addr) |
| { |
| /* TODO: Unimplemented. */ |
| } |
| |
| /* 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); |
| } |
| |
| SI |
| sh64_movua (SIM_CPU *current_cpu, PCADDR pc, SI rn) |
| { |
| SI v; |
| int i; |
| |
| /* Move the data one byte at a time to avoid alignment problems. |
| Be aware of endianness. */ |
| v = 0; |
| for (i = 0; i < 4; ++i) |
| v = (v << 8) | (GETMEMQI (current_cpu, pc, rn + i) & 0xff); |
| |
| v = T2H_4 (v); |
| return v; |
| } |
| |
| 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 }, |
| { "sh2e", & sh2e_mach, MODEL_SH5, NULL, sh64_model_init }, |
| { "sh2a", & sh2a_fpu_mach, MODEL_SH5, NULL, sh64_model_init }, |
| { "sh2a_nofpu", & sh2a_nofpu_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 }, |
| { "sh4_nofpu", & sh4_nofpu_mach, MODEL_SH5, NULL, sh64_model_init }, |
| { "sh4a", & sh4a_mach, MODEL_SH5, NULL, sh64_model_init }, |
| { "sh4a_nofpu", & sh4a_nofpu_mach, MODEL_SH5, NULL, sh64_model_init }, |
| { "sh4al", & sh4al_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 sh2e_mach = |
| { |
| "sh2e", "sh2e", MACH_SH5, |
| 16, 16, &sh_models[1], &sh5_imp_properties, |
| shcompact_init_cpu, |
| sh64_prepare_run |
| }; |
| |
| const MACH sh2a_fpu_mach = |
| { |
| "sh2a", "sh2a", MACH_SH5, |
| 16, 16, &sh_models[2], &sh5_imp_properties, |
| shcompact_init_cpu, |
| sh64_prepare_run |
| }; |
| |
| const MACH sh2a_nofpu_mach = |
| { |
| "sh2a_nofpu", "sh2a_nofpu", MACH_SH5, |
| 16, 16, &sh_models[3], &sh5_imp_properties, |
| shcompact_init_cpu, |
| sh64_prepare_run |
| }; |
| |
| const MACH sh3_mach = |
| { |
| "sh3", "sh3", MACH_SH5, |
| 16, 16, &sh_models[4], &sh5_imp_properties, |
| shcompact_init_cpu, |
| sh64_prepare_run |
| }; |
| |
| const MACH sh3e_mach = |
| { |
| "sh3e", "sh3e", MACH_SH5, |
| 16, 16, &sh_models[5], &sh5_imp_properties, |
| shcompact_init_cpu, |
| sh64_prepare_run |
| }; |
| |
| const MACH sh4_mach = |
| { |
| "sh4", "sh4", MACH_SH5, |
| 16, 16, &sh_models[6], &sh5_imp_properties, |
| shcompact_init_cpu, |
| sh64_prepare_run |
| }; |
| |
| const MACH sh4_nofpu_mach = |
| { |
| "sh4_nofpu", "sh4_nofpu", MACH_SH5, |
| 16, 16, &sh_models[7], &sh5_imp_properties, |
| shcompact_init_cpu, |
| sh64_prepare_run |
| }; |
| |
| const MACH sh4a_mach = |
| { |
| "sh4a", "sh4a", MACH_SH5, |
| 16, 16, &sh_models[8], &sh5_imp_properties, |
| shcompact_init_cpu, |
| sh64_prepare_run |
| }; |
| |
| const MACH sh4a_nofpu_mach = |
| { |
| "sh4a_nofpu", "sh4a_nofpu", MACH_SH5, |
| 16, 16, &sh_models[9], &sh5_imp_properties, |
| shcompact_init_cpu, |
| sh64_prepare_run |
| }; |
| |
| const MACH sh4al_mach = |
| { |
| "sh4al", "sh4al", MACH_SH5, |
| 16, 16, &sh_models[10], &sh5_imp_properties, |
| shcompact_init_cpu, |
| sh64_prepare_run |
| }; |
| |
| const MACH sh5_mach = |
| { |
| "sh5", "sh5", MACH_SH5, |
| 32, 32, &sh_models[11], &sh5_imp_properties, |
| shmedia_init_cpu, |
| sh64_prepare_run |
| }; |