Fix TCL error in gdb.python/py-format-string.exp.
[deliverable/binutils-gdb.git] / sim / frv / frv.c
index 7f48256aa757692fe21d3085fa628ccbd1efa5e4..fb683852d0338fa85adef4a0f453c3e557232ba4 100644 (file)
@@ -1,22 +1,21 @@
 /* frv simulator support code
 /* 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
    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.
 
 
 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
 
 #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 "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
 #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)
 {
 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 ());
     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
   else
-    SETTSI (buf, 0xdeadbeef);
+    {
+      SETTSI (buf, 0xdeadbeef);
+      return 0;
+    }
 
 
-  return -1;
+  return len;
 }
 
 /* The contents of BUF are in target byte order.  */
 }
 
 /* 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)
 {
 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));
     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.  */
 }
 \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)
        {
       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_fr400:
+       case bfd_mach_fr450:
        case bfd_mach_fr550:
          frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
          break;
        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)
        {
       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_fr400:
+       case bfd_mach_fr450:
        case bfd_mach_fr550:
          frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
          break;
        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)
        {
       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_fr400:
+       case bfd_mach_fr450:
          frv_queue_data_access_error_interrupt (current_cpu, address);
          break;
        case bfd_mach_frvtomcat:
          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);
 
   /* 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);
     {
       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;
   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]);
     {
       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);
 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);
 
     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. */
     {
       /* 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;
        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
     }
 }
 \f
@@ -981,6 +1054,7 @@ SI
 frvbf_cut (SIM_CPU *current_cpu, SI reg1, SI reg2, SI cut_point)
 {
   SI result;
 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;
   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)
 {
 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;
 
   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)
   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).  */
 }
 
 /* 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;
 
   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:
   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.  */
     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.027185 seconds and 4 git commands to generate.