Fix spelling mistakes in some of the binutils sub-directories.
[deliverable/binutils-gdb.git] / gas / config / tc-riscv.c
index cc77dbf6c00a3c9fe769da654b657e0d276d6736..1d33aeae8c778e400510e487b58629caef91e9af 100644 (file)
@@ -126,8 +126,6 @@ riscv_set_default_priv_spec (const char *s)
   enum riscv_priv_spec_class class;
   unsigned major, minor, revision;
   obj_attribute *attr;
-  size_t buf_size;
-  char *buf;
 
   /* Find the corresponding priv spec class.  */
   if (riscv_get_priv_spec_class (s, &class))
@@ -149,40 +147,24 @@ riscv_set_default_priv_spec (const char *s)
   minor = (unsigned) attr[Tag_RISCV_priv_spec_minor].i;
   revision = (unsigned) attr[Tag_RISCV_priv_spec_revision].i;
 
-  /* The priv attributes setting 0.0.0 is meaningless.  We should have set
-     the default_priv_spec by md_parse_option and riscv_after_parse_args,
-     so just skip the following setting.  */
-  if (major == 0 && minor == 0 && revision == 0)
-    return 1;
-
-  buf_size = riscv_estimate_digit (major)
-            + 1 /* '.' */
-            + riscv_estimate_digit (minor)
-            + 1; /* string terminator */
-  if (revision != 0)
+  if (riscv_get_priv_spec_class_from_numbers (major,
+                                             minor,
+                                             revision,
+                                             &class))
     {
-      buf_size += 1 /* '.' */
-                 + riscv_estimate_digit (revision);
-      buf = xmalloc (buf_size);
-      snprintf (buf, buf_size, "%d.%d.%d", major, minor, revision);
-    }
-  else
-    {
-      buf = xmalloc (buf_size);
-      snprintf (buf, buf_size, "%d.%d", major, minor);
-    }
+      /* The priv attributes setting 0.0.0 is meaningless.  We should have set
+        the default_priv_spec by md_parse_option and riscv_after_parse_args,
+        so just skip the following setting.  */
+      if (class == PRIV_SPEC_CLASS_NONE)
+       return 1;
 
-  if (riscv_get_priv_spec_class (buf, &class))
-    {
       default_priv_spec = class;
-      free (buf);
       return 1;
     }
 
   /* Still can not find the priv spec class.  */
-  as_bad (_("Unknown default privilege spec `%d.%d.%d' set by  "
+  as_bad (_("Unknown default privilege spec `%d.%d.%d' set by "
            "privilege attributes"),  major, minor, revision);
-  free (buf);
   return 0;
 }
 
@@ -374,8 +356,8 @@ static bfd_boolean start_assemble = FALSE;
 /* Indicate ELF attributes are explictly set.  */
 static bfd_boolean explicit_attr = FALSE;
 
-/* Indicate CSR are explictly used.  */
-static bfd_boolean explicit_csr = FALSE;
+/* Indicate CSR or priv instructions are explictly used.  */
+static bfd_boolean explicit_priv_attr = FALSE;
 
 /* Macros for encoding relaxation state for RVC branches and far jumps.  */
 #define RELAX_BRANCH_ENCODE(uncond, rvc, length)       \
@@ -718,53 +700,49 @@ riscv_init_csr_hash (const char *name,
     pre_entry->next = entry;
 }
 
-/* Check wether the CSR is valid according to the ISA.  */
+/* Return the suitable CSR address after checking the ISA dependency and
+   priv spec versions.  */
 
-static void
-riscv_csr_class_check (const char *s,
-                      enum riscv_csr_class csr_class)
+static unsigned int
+riscv_csr_address (const char *csr_name,
+                  struct riscv_csr_extra *entry)
 {
+  struct riscv_csr_extra *saved_entry = entry;
+  enum riscv_csr_class csr_class = entry->csr_class;
+  bfd_boolean need_check_version = TRUE;
   bfd_boolean result = TRUE;
 
-  /* Don't check the ISA dependency when -mcsr-check isn't set.  */
-  if (!riscv_opts.csr_check)
-    return;
-
   switch (csr_class)
     {
     case CSR_CLASS_I:
       result = riscv_subset_supports ("i");
       break;
+    case CSR_CLASS_I_32:
+      result = (xlen == 32 && riscv_subset_supports ("i"));
+      break;
     case CSR_CLASS_F:
       result = riscv_subset_supports ("f");
+      need_check_version = FALSE;
       break;
-    case CSR_CLASS_I_32:
-      result = (xlen == 32 && riscv_subset_supports ("i"));
+    case CSR_CLASS_DEBUG:
+      need_check_version = FALSE;
       break;
     default:
       as_bad (_("internal: bad RISC-V CSR class (0x%x)"), csr_class);
     }
 
-  if (!result)
-    as_warn (_("Invalid CSR `%s' for the current ISA"), s);
-}
-
-/* Check and find the CSR address according to the privilege spec version.  */
-
-static void
-riscv_csr_version_check (const char *csr_name,
-                        struct riscv_csr_extra **entryP)
-{
-  struct riscv_csr_extra *entry = *entryP;
+  /* Don't report the ISA conflict when -mcsr-check isn't set.  */
+  if (riscv_opts.csr_check && !result)
+    as_warn (_("Invalid CSR `%s' for the current ISA"), csr_name);
 
   while (entry != NULL)
     {
-      if (default_priv_spec >= entry->define_version
-         && default_priv_spec < entry->abort_version)
+      if (!need_check_version
+         || (default_priv_spec >= entry->define_version
+             && default_priv_spec < entry->abort_version))
        {
          /* Find the suitable CSR according to the specific version.  */
-         *entryP = entry;
-         return;
+         return entry->address;
        }
       entry = entry->next;
     }
@@ -781,6 +759,8 @@ riscv_csr_version_check (const char *csr_name,
        as_warn (_("Invalid CSR `%s' for the privilege spec `%s'"),
                 csr_name, priv_name);
     }
+
+  return saved_entry->address;
 }
 
 /* Once the CSR is defined, including the old privilege spec, then we call
@@ -803,10 +783,7 @@ reg_csr_lookup_internal (const char *s)
      will regard it as a "Unknown CSR" and report error.  If user use number
      to set the CSR, but over the range (> 0xfff), then assembler will report
      "Improper CSR" error for it.  */
-  riscv_csr_class_check (s, r->csr_class);
-  riscv_csr_version_check (s, &r);
-
-  return r->address;
+  return riscv_csr_address (s, r);
 }
 
 static unsigned int
@@ -1784,6 +1761,35 @@ riscv_csr_read_only_check (insn_t insn)
   return TRUE;
 }
 
+/* Return True if it is a privileged instruction.  Otherwise, return FALSE.
+
+   uret is actually a N-ext instruction.  So it is better to regard it as
+   an user instruction rather than the priv instruction.
+
+   hret is used to return from traps in H-mode.  H-mode is removed since
+   the v1.10 priv spec, but probably be added in the new hypervisor spec.
+   Therefore, hret should be controlled by the hypervisor spec rather than
+   priv spec in the future.
+
+   dret is defined in the debug spec, so it should be checked in the future,
+   too.  */
+
+static bfd_boolean
+riscv_is_priv_insn (insn_t insn)
+{
+  return (((insn ^ MATCH_SRET) & MASK_SRET) == 0
+         || ((insn ^ MATCH_MRET) & MASK_MRET) == 0
+         || ((insn ^ MATCH_SFENCE_VMA) & MASK_SFENCE_VMA) == 0
+         || ((insn ^ MATCH_WFI) & MASK_WFI) == 0
+  /* The sfence.vm is dropped in the v1.10 priv specs, but we still need to
+     check it here to keep the compatible.  Maybe we should issue warning
+     if sfence.vm is used, but the priv spec newer than v1.10 is chosen.
+     We already have a similar check for CSR, but not yet for instructions.
+     It would be good if we could check the spec versions both for CSR and
+     instructions, but not here.  */
+         || ((insn ^ MATCH_SFENCE_VM) & MASK_SFENCE_VM) == 0);
+}
+
 /* This routine assembles an instruction into its binary format.  As a
    side effect, it sets the global variable imm_reloc to the type of
    relocation to do if one of the operands is an address expression.  */
@@ -1851,6 +1857,9 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
                      && !riscv_opts.rvc)
                    break;
 
+                 if (riscv_is_priv_insn (ip->insn_opcode))
+                   explicit_priv_attr = TRUE;
+
                  /* Check if we write a read-only CSR by the CSR
                     instruction.  */
                  if (insn_with_csr
@@ -2215,7 +2224,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
 
            case 'E':           /* Control register.  */
              insn_with_csr = TRUE;
-             explicit_csr = TRUE;
+             explicit_priv_attr = TRUE;
              if (reg_lookup (&s, RCLASS_CSR, &regno))
                INSERT_OPERAND (CSR, *ip, regno);
              else
@@ -3609,9 +3618,13 @@ riscv_write_out_attrs (void)
       && !riscv_set_default_priv_spec (NULL))
     return;
 
-  /* If we already have set elf priv attributes, then generate them.
-     Otherwise, don't generate them when no CSR are used.  */
-  if (!explicit_csr)
+  /* If we already have set elf priv attributes, then no need to do anything,
+     assembler will generate them according to what you set.  Otherwise, don't
+     generate or update them when no CSR and priv instructions are used.
+     Generate the priv attributes according to default_priv_spec, which can be
+     set by -mpriv-spec and --with-priv-spec, and be updated by the original
+     priv attribute sets.  */
+  if (!explicit_priv_attr)
     return;
 
   /* Re-write priv attributes by default_priv_spec.  */
This page took 0.025968 seconds and 4 git commands to generate.