Use all_non_exited_inferiors in infrun.c
[deliverable/binutils-gdb.git] / sim / frv / frv.c
index 7f48256aa757692fe21d3085fa628ccbd1efa5e4..fb683852d0338fa85adef4a0f453c3e557232ba4 100644 (file)
@@ -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 <http://www.gnu.org/licenses/>.  */
 
 #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 <math.h>
 
 /* 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;
 }
 \f
 /* Cover fns to access the general registers.  */
@@ -112,7 +171,15 @@ 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;
@@ -140,7 +207,9 @@ 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;
@@ -172,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:
@@ -232,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);
@@ -258,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]);
@@ -929,10 +1000,11 @@ 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_fr550) ? 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);
 
@@ -942,15 +1014,16 @@ frvbf_clear_accumulators (SIM_CPU *current_cpu, SI acc_ix, int A)
     {
       /* 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);
     }
 }
 \f
@@ -981,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;
@@ -1040,25 +1114,53 @@ frvbf_media_cut_ss (SIM_CPU *current_cpu, DI acc, SI cut_point)
 SI
 frvbf_iacc_cut (SIM_CPU *current_cpu, DI acc, SI cut_point)
 {
-  /* The cut point is the lower 6 bits (signed) of what we are passed.  */
+  DI lower, upper;
+
+  /* The cut point is the lower 7 bits (signed) of what we are passed.  */
   cut_point = cut_point << 25 >> 25;
 
-  if (cut_point <= -32)
-    cut_point = -31;   /* Special case for full shiftout.  */
+  /* 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.
 
-  /* Negative cuts (cannot saturate).  */
+     Since we can't deal with 128-bit values very easily, convert the
+     operation into an equivalent 64-bit one.  */
   if (cut_point < 0)
-    return acc >> (32 + -cut_point);
+    {
+      /* Avoid an undefined shift operation.  */
+      if (cut_point == -64)
+       acc >>= 63;
+      else
+       acc >>= -cut_point;
+      cut_point = 0;
+    }
 
-  /* Positive cuts will saturate if significant bits are shifted out.  */
-  if (acc != ((acc << cut_point) >> cut_point))
-    if (acc >= 0)
-      return 0x7fffffff;
-    else
-      return 0x80000000;
+  /* 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);
+    }
 
-  /* No saturate, just cut.  */
-  return ((acc << cut_point) >> 32);
+  /* 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).  */
@@ -1119,12 +1221,14 @@ do_media_average (SIM_CPU *current_cpu, HI arg1, HI arg2)
   HI result = sum >> 1;
   int rounding_value;
 
-  /* On fr400 and fr550, 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.  */
This page took 0.027629 seconds and 4 git commands to generate.