cpu/
[deliverable/binutils-gdb.git] / sim / frv / frv.c
index bd3220dcacf3ae6d52ced6eda4d4f12956022c48..2640b1c29c692c47daea0aeceb1e5f96349838c4 100644 (file)
@@ -1,5 +1,6 @@
 /* frv simulator support code
-   Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004 Free Software
+   Foundation, Inc.
    Contributed by Red Hat.
 
 This file is part of the GNU simulators.
@@ -27,6 +28,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 +40,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 +89,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.  */
@@ -113,6 +174,7 @@ check_register_alignment (SIM_CPU *current_cpu, UINT reg, int align_mask)
       switch (STATE_ARCHITECTURE (sd)->mach)
        {
        case bfd_mach_fr400:
+       case bfd_mach_fr550:
          frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
          break;
        case bfd_mach_frvtomcat:
@@ -140,6 +202,7 @@ check_fr_register_alignment (SIM_CPU *current_cpu, UINT reg, int align_mask)
       switch (STATE_ARCHITECTURE (sd)->mach)
        {
        case bfd_mach_fr400:
+       case bfd_mach_fr550:
          frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
          break;
        case bfd_mach_frvtomcat:
@@ -431,6 +494,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;
@@ -926,9 +992,13 @@ 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 :
     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
@@ -1027,6 +1097,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 +1208,13 @@ 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
+  /* On fr400 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_fr550:
       /* Check whether rounding will be required.  Rounding will be required
         if the sum is an odd number.  */
       rounding_value = sum & 1;
This page took 0.047383 seconds and 4 git commands to generate.