X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=sim%2Ffrv%2Ffrv.c;h=fb683852d0338fa85adef4a0f453c3e557232ba4;hb=05e682e3be7e3d9d63ec358dcf8943fd200545cb;hp=bd3220dcacf3ae6d52ced6eda4d4f12956022c48;hpb=f9e18f5a11abe959220c570da56b09cc0fd6fd62;p=deliverable%2Fbinutils-gdb.git
diff --git a/sim/frv/frv.c b/sim/frv/frv.c
index bd3220dcac..fb683852d0 100644
--- a/sim/frv/frv.c
+++ b/sim/frv/frv.c
@@ -1,22 +1,21 @@
/* frv simulator support code
- Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1998-2020 Free Software Foundation, Inc.
Contributed by Red Hat.
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.
+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, write to the Free Software Foundation, Inc.,
-59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+You should have received a copy of the GNU General Public License
+along with this program. If not, see . */
#define WANT_CPU
#define WANT_CPU_FRVBF
@@ -27,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "cgen-engine.h"
#include "cgen-par.h"
#include "bfd.h"
+#include "gdb/sim-frv.h"
#include
/* Maintain a flag in order to know when to write the address of the next
@@ -38,18 +38,48 @@ int frvbf_write_next_vliw_addr_to_LR;
int
frvbf_fetch_register (SIM_CPU *current_cpu, int rn, unsigned char *buf, int len)
{
- if (rn <= GR_REGNUM_MAX)
- SETTSI (buf, GET_H_GR (rn));
- else if (rn <= FR_REGNUM_MAX)
- SETTSI (buf, GET_H_FR (rn - GR_REGNUM_MAX - 1));
- else if (rn == PC_REGNUM)
+ if (SIM_FRV_GR0_REGNUM <= rn && rn <= SIM_FRV_GR63_REGNUM)
+ {
+ int hi_available, lo_available;
+ int grn = rn - SIM_FRV_GR0_REGNUM;
+
+ frv_gr_registers_available (current_cpu, &hi_available, &lo_available);
+
+ if ((grn < 32 && !lo_available) || (grn >= 32 && !hi_available))
+ return 0;
+ else
+ SETTSI (buf, GET_H_GR (grn));
+ }
+ else if (SIM_FRV_FR0_REGNUM <= rn && rn <= SIM_FRV_FR63_REGNUM)
+ {
+ int hi_available, lo_available;
+ int frn = rn - SIM_FRV_FR0_REGNUM;
+
+ frv_fr_registers_available (current_cpu, &hi_available, &lo_available);
+
+ if ((frn < 32 && !lo_available) || (frn >= 32 && !hi_available))
+ return 0;
+ else
+ SETTSI (buf, GET_H_FR (frn));
+ }
+ else if (rn == SIM_FRV_PC_REGNUM)
SETTSI (buf, GET_H_PC ());
- else if (rn == LR_REGNUM)
- SETTSI (buf, GET_H_SPR (H_SPR_LR));
+ else if (SIM_FRV_SPR0_REGNUM <= rn && rn <= SIM_FRV_SPR4095_REGNUM)
+ {
+ /* Make sure the register is implemented. */
+ FRV_REGISTER_CONTROL *control = CPU_REGISTER_CONTROL (current_cpu);
+ int spr = rn - SIM_FRV_SPR0_REGNUM;
+ if (! control->spr[spr].implemented)
+ return 0;
+ SETTSI (buf, GET_H_SPR (spr));
+ }
else
- SETTSI (buf, 0xdeadbeef);
+ {
+ SETTSI (buf, 0xdeadbeef);
+ return 0;
+ }
- return -1;
+ return len;
}
/* The contents of BUF are in target byte order. */
@@ -57,16 +87,45 @@ frvbf_fetch_register (SIM_CPU *current_cpu, int rn, unsigned char *buf, int len)
int
frvbf_store_register (SIM_CPU *current_cpu, int rn, unsigned char *buf, int len)
{
- if (rn <= GR_REGNUM_MAX)
- SET_H_GR (rn, GETTSI (buf));
- else if (rn <= FR_REGNUM_MAX)
- SET_H_FR (rn - GR_REGNUM_MAX - 1, GETTSI (buf));
- else if (rn == PC_REGNUM)
+ if (SIM_FRV_GR0_REGNUM <= rn && rn <= SIM_FRV_GR63_REGNUM)
+ {
+ int hi_available, lo_available;
+ int grn = rn - SIM_FRV_GR0_REGNUM;
+
+ frv_gr_registers_available (current_cpu, &hi_available, &lo_available);
+
+ if ((grn < 32 && !lo_available) || (grn >= 32 && !hi_available))
+ return 0;
+ else
+ SET_H_GR (grn, GETTSI (buf));
+ }
+ else if (SIM_FRV_FR0_REGNUM <= rn && rn <= SIM_FRV_FR63_REGNUM)
+ {
+ int hi_available, lo_available;
+ int frn = rn - SIM_FRV_FR0_REGNUM;
+
+ frv_fr_registers_available (current_cpu, &hi_available, &lo_available);
+
+ if ((frn < 32 && !lo_available) || (frn >= 32 && !hi_available))
+ return 0;
+ else
+ SET_H_FR (frn, GETTSI (buf));
+ }
+ else if (rn == SIM_FRV_PC_REGNUM)
SET_H_PC (GETTSI (buf));
- else if (rn == LR_REGNUM)
- SET_H_SPR (H_SPR_LR, GETTSI (buf));
+ else if (SIM_FRV_SPR0_REGNUM <= rn && rn <= SIM_FRV_SPR4095_REGNUM)
+ {
+ /* Make sure the register is implemented. */
+ FRV_REGISTER_CONTROL *control = CPU_REGISTER_CONTROL (current_cpu);
+ int spr = rn - SIM_FRV_SPR0_REGNUM;
+ if (! control->spr[spr].implemented)
+ return 0;
+ SET_H_SPR (spr, GETTSI (buf));
+ }
+ else
+ return 0;
- return -1;
+ return len;
}
/* Cover fns to access the general registers. */
@@ -112,7 +171,16 @@ check_register_alignment (SIM_CPU *current_cpu, UINT reg, int align_mask)
SIM_DESC sd = CPU_STATE (current_cpu);
switch (STATE_ARCHITECTURE (sd)->mach)
{
+ /* Note: there is a discrepancy between V2.2 of the FR400
+ instruction manual and the various FR4xx LSI specs.
+ The former claims that unaligned registers cause a
+ register_exception while the latter say it's an
+ illegal_instruction. The LSI specs appear to be
+ correct; in fact, the FR4xx series is not documented
+ as having a register_exception. */
case bfd_mach_fr400:
+ case bfd_mach_fr450:
+ case bfd_mach_fr550:
frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
break;
case bfd_mach_frvtomcat:
@@ -139,7 +207,10 @@ check_fr_register_alignment (SIM_CPU *current_cpu, UINT reg, int align_mask)
SIM_DESC sd = CPU_STATE (current_cpu);
switch (STATE_ARCHITECTURE (sd)->mach)
{
+ /* See comment in check_register_alignment(). */
case bfd_mach_fr400:
+ case bfd_mach_fr450:
+ case bfd_mach_fr550:
frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
break;
case bfd_mach_frvtomcat:
@@ -170,7 +241,9 @@ check_memory_alignment (SIM_CPU *current_cpu, SI address, int align_mask)
SIM_DESC sd = CPU_STATE (current_cpu);
switch (STATE_ARCHITECTURE (sd)->mach)
{
+ /* See comment in check_register_alignment(). */
case bfd_mach_fr400:
+ case bfd_mach_fr450:
frv_queue_data_access_error_interrupt (current_cpu, address);
break;
case bfd_mach_frvtomcat:
@@ -230,7 +303,7 @@ frvbf_h_fr_double_get_handler (SIM_CPU *current_cpu, UINT fr)
/* Check the register alignment. */
fr = check_fr_register_alignment (current_cpu, fr, 1);
- if (CURRENT_HOST_BYTE_ORDER == LITTLE_ENDIAN)
+ if (HOST_BYTE_ORDER == BFD_ENDIAN_LITTLE)
{
value.as_sf[1] = GET_H_FR (fr);
value.as_sf[0] = GET_H_FR (fr + 1);
@@ -256,7 +329,7 @@ frvbf_h_fr_double_set_handler (SIM_CPU *current_cpu, UINT fr, DF newval)
fr = check_fr_register_alignment (current_cpu, fr, 1);
value.as_df = newval;
- if (CURRENT_HOST_BYTE_ORDER == LITTLE_ENDIAN)
+ if (HOST_BYTE_ORDER == BFD_ENDIAN_LITTLE)
{
SET_H_FR (fr , value.as_sf[1]);
SET_H_FR (fr + 1, value.as_sf[0]);
@@ -431,6 +504,9 @@ frvbf_h_spr_set_handler (SIM_CPU *current_cpu, UINT spr, USI newval)
case H_SPR_SR3:
spr_sr_set_handler (current_cpu, spr, newval);
break;
+ case H_SPR_IHSR8:
+ frv_cache_reconfigure (current_cpu, CPU_INSN_CACHE (current_cpu));
+ break;
default:
CPU (h_spr[spr]) = newval;
break;
@@ -924,24 +1000,30 @@ void
frvbf_clear_accumulators (SIM_CPU *current_cpu, SI acc_ix, int A)
{
SIM_DESC sd = CPU_STATE (current_cpu);
- int acc_num =
- (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr500) ? 8 :
- (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400) ? 4 :
+ int acc_mask =
+ (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr500) ? 7 :
+ (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) ? 7 :
+ (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr450) ? 11 :
+ (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400) ? 3 :
63;
+ FRV_PROFILE_STATE *ps = CPU_PROFILE_STATE (current_cpu);
+ ps->mclracc_acc = acc_ix;
+ ps->mclracc_A = A;
if (A == 0 || acc_ix != 0) /* Clear 1 accumuator? */
{
/* This instruction is a nop if the referenced accumulator is not
implemented. */
- if (acc_ix < acc_num)
+ if ((acc_ix & acc_mask) == acc_ix)
sim_queue_fn_di_write (current_cpu, frvbf_h_acc40S_set, acc_ix, 0);
}
else
{
/* Clear all implemented accumulators. */
int i;
- for (i = 0; i < acc_num; ++i)
- sim_queue_fn_di_write (current_cpu, frvbf_h_acc40S_set, i, 0);
+ for (i = 0; i <= acc_mask; ++i)
+ if ((i & acc_mask) == i)
+ sim_queue_fn_di_write (current_cpu, frvbf_h_acc40S_set, i, 0);
}
}
@@ -972,6 +1054,7 @@ SI
frvbf_cut (SIM_CPU *current_cpu, SI reg1, SI reg2, SI cut_point)
{
SI result;
+ cut_point &= 0x3f;
if (cut_point < 32)
{
result = reg1 << cut_point;
@@ -1027,6 +1110,93 @@ frvbf_media_cut_ss (SIM_CPU *current_cpu, DI acc, SI cut_point)
return frvbf_media_cut (current_cpu, acc, cut_point);
}
+/* Compute the result of int accumulator cut (SCUTSS). */
+SI
+frvbf_iacc_cut (SIM_CPU *current_cpu, DI acc, SI cut_point)
+{
+ DI lower, upper;
+
+ /* The cut point is the lower 7 bits (signed) of what we are passed. */
+ cut_point = cut_point << 25 >> 25;
+
+ /* Conceptually, the operation is on a 128-bit sign-extension of ACC.
+ The top bit of the return value corresponds to bit (63 - CUT_POINT)
+ of this 128-bit value.
+
+ Since we can't deal with 128-bit values very easily, convert the
+ operation into an equivalent 64-bit one. */
+ if (cut_point < 0)
+ {
+ /* Avoid an undefined shift operation. */
+ if (cut_point == -64)
+ acc >>= 63;
+ else
+ acc >>= -cut_point;
+ cut_point = 0;
+ }
+
+ /* Get the shifted but unsaturated result. Set LOWER to the lowest
+ 32 bits of the result and UPPER to the result >> 31. */
+ if (cut_point < 32)
+ {
+ /* The cut loses the (32 - CUT_POINT) least significant bits.
+ Round the result up if the most significant of these lost bits
+ is 1. */
+ lower = acc >> (32 - cut_point);
+ if (lower < 0x7fffffff)
+ if (acc & LSBIT64 (32 - cut_point - 1))
+ lower++;
+ upper = lower >> 31;
+ }
+ else
+ {
+ lower = acc << (cut_point - 32);
+ upper = acc >> (63 - cut_point);
+ }
+
+ /* Saturate the result. */
+ if (upper < -1)
+ return ~0x7fffffff;
+ else if (upper > 0)
+ return 0x7fffffff;
+ else
+ return lower;
+}
+
+/* Compute the result of shift-left-arithmetic-with-saturation (SLASS). */
+SI
+frvbf_shift_left_arith_saturate (SIM_CPU *current_cpu, SI arg1, SI arg2)
+{
+ int neg_arg1;
+
+ /* FIXME: what to do with negative shift amt? */
+ if (arg2 <= 0)
+ return arg1;
+
+ if (arg1 == 0)
+ return 0;
+
+ /* Signed shift by 31 or greater saturates by definition. */
+ if (arg2 >= 31)
+ if (arg1 > 0)
+ return (SI) 0x7fffffff;
+ else
+ return (SI) 0x80000000;
+
+ /* OK, arg2 is between 1 and 31. */
+ neg_arg1 = (arg1 < 0);
+ do {
+ arg1 <<= 1;
+ /* Check for sign bit change (saturation). */
+ if (neg_arg1 && (arg1 >= 0))
+ return (SI) 0x80000000;
+ else if (!neg_arg1 && (arg1 < 0))
+ return (SI) 0x7fffffff;
+ } while (--arg2 > 0);
+
+ return arg1;
+}
+
/* Simulate the media custom insns. */
void
frvbf_media_cop (SIM_CPU *current_cpu, int cop_num)
@@ -1051,12 +1221,15 @@ do_media_average (SIM_CPU *current_cpu, HI arg1, HI arg2)
HI result = sum >> 1;
int rounding_value;
- /* On fr400, check the rounding mode. On other machines rounding is always
- toward negative infinity and the result is already correctly rounded. */
+ /* On fr4xx and fr550, check the rounding mode. On other machines
+ rounding is always toward negative infinity and the result is
+ already correctly rounded. */
switch (STATE_ARCHITECTURE (sd)->mach)
{
/* Need to check rounding mode. */
case bfd_mach_fr400:
+ case bfd_mach_fr450:
+ case bfd_mach_fr550:
/* Check whether rounding will be required. Rounding will be required
if the sum is an odd number. */
rounding_value = sum & 1;