diff --git a/gdb/arch/riscv.h b/gdb/arch/riscv.h
index 0aef54638fe..8e814d506ee 100644
--- a/gdb/arch/riscv.h
+++ b/gdb/arch/riscv.h
@@ -55,11 +55,23 @@ struct riscv_gdbarch_features
/* When true this target is RV32E. */
bool embedded = false;
+ /* Track if the target description has an fcsr, fflags, and frm
+ registers. Some targets provide all these in their target
+ descriptions, while some only offer fcsr, while others don't even
+ offer that register. If a target provides fcsr but not fflags and/or
+ frm, then we can emulate these registers as pseudo registers. */
+ bool has_fcsr_reg = false;
+ bool has_fflags_reg = false;
+ bool has_frm_reg = false;
+
/* Equality operator. */
bool operator== (const struct riscv_gdbarch_features &rhs) const
{
return (xlen == rhs.xlen && flen == rhs.flen
- && embedded == rhs.embedded && vlen == rhs.vlen);
+ && embedded == rhs.embedded && vlen == rhs.vlen
+ && has_fflags_reg == rhs.has_fflags_reg
+ && has_frm_reg == rhs.has_frm_reg
+ && has_fcsr_reg == rhs.has_fcsr_reg);
}
/* Inequality operator. */
@@ -72,9 +84,12 @@ struct riscv_gdbarch_features
std::size_t hash () const noexcept
{
std::size_t val = ((embedded ? 1 : 0) << 10
+ | (has_fflags_reg ? 1 : 0) << 11
+ | (has_frm_reg ? 1 : 0) << 12
+ | (has_fcsr_reg ? 1 : 0) << 13
| (xlen & 0x1f) << 5
| (flen & 0x1f) << 0
- | (vlen & 0xfff) << 11);
+ | (vlen & 0xfff) << 14);
return val;
}
};
diff --git a/gdb/features/riscv/32bit-fpu.c b/gdb/features/riscv/32bit-fpu.c
index d92407fb9e0..e763fccfe4c 100644
--- a/gdb/features/riscv/32bit-fpu.c
+++ b/gdb/features/riscv/32bit-fpu.c
@@ -42,9 +42,7 @@ create_feature_riscv_32bit_fpu (struct target_desc *result, long regnum)
tdesc_create_reg (feature, "ft9", regnum++, 1, NULL, 32, "ieee_single");
tdesc_create_reg (feature, "ft10", regnum++, 1, NULL, 32, "ieee_single");
tdesc_create_reg (feature, "ft11", regnum++, 1, NULL, 32, "ieee_single");
- regnum = 66;
- tdesc_create_reg (feature, "fflags", regnum++, 1, NULL, 32, "int");
- tdesc_create_reg (feature, "frm", regnum++, 1, NULL, 32, "int");
+ regnum = 68;
tdesc_create_reg (feature, "fcsr", regnum++, 1, NULL, 32, "int");
return regnum;
}
diff --git a/gdb/features/riscv/32bit-fpu.xml b/gdb/features/riscv/32bit-fpu.xml
index ed8f14c09dc..7d87f9c057b 100644
--- a/gdb/features/riscv/32bit-fpu.xml
+++ b/gdb/features/riscv/32bit-fpu.xml
@@ -44,7 +44,5 @@
-
-
diff --git a/gdb/features/riscv/64bit-fpu.c b/gdb/features/riscv/64bit-fpu.c
index 4fd8ee1e41b..bf9b74b24dc 100644
--- a/gdb/features/riscv/64bit-fpu.c
+++ b/gdb/features/riscv/64bit-fpu.c
@@ -50,9 +50,7 @@ create_feature_riscv_64bit_fpu (struct target_desc *result, long regnum)
tdesc_create_reg (feature, "ft9", regnum++, 1, NULL, 64, "riscv_double");
tdesc_create_reg (feature, "ft10", regnum++, 1, NULL, 64, "riscv_double");
tdesc_create_reg (feature, "ft11", regnum++, 1, NULL, 64, "riscv_double");
- regnum = 66;
- tdesc_create_reg (feature, "fflags", regnum++, 1, NULL, 32, "int");
- tdesc_create_reg (feature, "frm", regnum++, 1, NULL, 32, "int");
+ regnum = 68;
tdesc_create_reg (feature, "fcsr", regnum++, 1, NULL, 32, "int");
return regnum;
}
diff --git a/gdb/features/riscv/64bit-fpu.xml b/gdb/features/riscv/64bit-fpu.xml
index ff42b4a21fb..68f523f0d60 100644
--- a/gdb/features/riscv/64bit-fpu.xml
+++ b/gdb/features/riscv/64bit-fpu.xml
@@ -50,7 +50,5 @@
-
-
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
index 93ee597af58..9df527e13e7 100644
--- a/gdb/riscv-tdep.c
+++ b/gdb/riscv-tdep.c
@@ -933,6 +933,72 @@ riscv_register_name (struct gdbarch *gdbarch, int regnum)
return name;
}
+/* Implement gdbarch_pseudo_register_read. Read pseudo-register REGNUM
+ from REGCACHE and place the register value into BUF. BUF is sized
+ based on the type of register REGNUM, all of BUF should be written too,
+ the result should be sign or zero extended as appropriate. */
+
+static enum register_status
+riscv_pseudo_register_read (struct gdbarch *gdbarch,
+ readable_regcache *regcache,
+ int regnum, gdb_byte *buf)
+{
+ riscv_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (regnum == tdep->fflags_regnum || regnum == tdep->frm_regnum)
+ {
+ /* Clear BUF. */
+ memset (buf, 0, register_size (gdbarch, regnum));
+
+ /* Read the first byte of the fcsr register, this contains both frm
+ and fflags. */
+ enum register_status status
+ = regcache->raw_read_part (RISCV_CSR_FCSR_REGNUM, 0, 1, buf);
+
+ if (status != REG_VALID)
+ return status;
+
+ /* Extract the appropriate parts. */
+ if (regnum == tdep->fflags_regnum)
+ buf[0] &= 0x1f;
+ else if (regnum == tdep->frm_regnum)
+ buf[0] = (buf[0] >> 5) & 0x7;
+
+ return REG_VALID;
+ }
+
+ return REG_UNKNOWN;
+}
+
+/* Implement gdbarch_pseudo_register_write. Write the contents of BUF into
+ pseudo-register REGNUM in REGCACHE. BUF is sized based on the type of
+ register REGNUM. */
+
+static void
+riscv_pseudo_register_write (struct gdbarch *gdbarch,
+ struct regcache *regcache, int regnum,
+ const gdb_byte *buf)
+{
+ riscv_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (regnum == tdep->fflags_regnum || regnum == tdep->frm_regnum)
+ {
+ int fcsr_regnum = RISCV_CSR_FCSR_REGNUM;
+ gdb_byte raw_buf[register_size (gdbarch, fcsr_regnum)];
+
+ regcache->raw_read (fcsr_regnum, raw_buf);
+
+ if (regnum == tdep->fflags_regnum)
+ raw_buf[0] = (raw_buf[0] & ~0x1f) | (buf[0] & 0x1f);
+ else if (regnum == tdep->frm_regnum)
+ raw_buf[0] = (raw_buf[0] & ~(0x7 << 5)) | ((buf[0] & 0x7) << 5);
+
+ regcache->raw_write (fcsr_regnum, raw_buf);
+ }
+ else
+ gdb_assert_not_reached ("unknown pseudo register %d", regnum);
+}
+
/* Implement the cannot_store_register gdbarch method. The zero register
(x0) is read-only on RISC-V. */
@@ -1096,6 +1162,7 @@ riscv_print_one_register_info (struct gdbarch *gdbarch,
else
{
struct value_print_options opts;
+ riscv_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
/* Print the register in hex. */
get_formatted_print_options (&opts, 'x');
@@ -1162,15 +1229,13 @@ riscv_print_one_register_info (struct gdbarch *gdbarch,
}
}
else if (regnum == RISCV_CSR_FCSR_REGNUM
- || regnum == RISCV_CSR_FFLAGS_REGNUM
- || regnum == RISCV_CSR_FRM_REGNUM)
+ || regnum == tdep->fflags_regnum
+ || regnum == tdep->frm_regnum)
{
- LONGEST d;
-
- d = value_as_long (val);
+ LONGEST d = value_as_long (val);
gdb_printf (file, "\t");
- if (regnum != RISCV_CSR_FRM_REGNUM)
+ if (regnum != tdep->frm_regnum)
gdb_printf (file,
"NV:%d DZ:%d OF:%d UF:%d NX:%d",
(int) ((d >> 4) & 0x1),
@@ -1179,7 +1244,7 @@ riscv_print_one_register_info (struct gdbarch *gdbarch,
(int) ((d >> 1) & 0x1),
(int) ((d >> 0) & 0x1));
- if (regnum != RISCV_CSR_FFLAGS_REGNUM)
+ if (regnum != tdep->fflags_regnum)
{
static const char * const sfrm[] =
{
@@ -1284,13 +1349,15 @@ static int
riscv_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
const struct reggroup *reggroup)
{
+ riscv_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
/* Used by 'info registers' and 'info registers '. */
if (gdbarch_register_name (gdbarch, regnum) == NULL
|| gdbarch_register_name (gdbarch, regnum)[0] == '\0')
return 0;
- if (regnum > RISCV_LAST_REGNUM)
+ if (regnum > RISCV_LAST_REGNUM && regnum < gdbarch_num_regs (gdbarch))
{
/* Any extra registers from the CSR tdesc_feature (identified in
riscv_tdesc_unknown_reg) are removed from the save/restore groups
@@ -1331,8 +1398,8 @@ riscv_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
else if (reggroup == float_reggroup)
return (riscv_is_fp_regno_p (regnum)
|| regnum == RISCV_CSR_FCSR_REGNUM
- || regnum == RISCV_CSR_FFLAGS_REGNUM
- || regnum == RISCV_CSR_FRM_REGNUM);
+ || regnum == tdep->fflags_regnum
+ || regnum == tdep->frm_regnum);
else if (reggroup == general_reggroup)
return regnum < RISCV_FIRST_FP_REGNUM;
else if (reggroup == restore_reggroup || reggroup == save_reggroup)
@@ -1340,8 +1407,8 @@ riscv_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
if (riscv_has_fp_regs (gdbarch))
return (regnum <= RISCV_LAST_FP_REGNUM
|| regnum == RISCV_CSR_FCSR_REGNUM
- || regnum == RISCV_CSR_FFLAGS_REGNUM
- || regnum == RISCV_CSR_FRM_REGNUM);
+ || regnum == tdep->fflags_regnum
+ || regnum == tdep->frm_regnum);
else
return regnum < RISCV_FIRST_FP_REGNUM;
}
@@ -1361,6 +1428,45 @@ riscv_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
return 0;
}
+/* Return the name for pseudo-register REGNUM for GDBARCH. */
+
+static const char *
+riscv_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
+{
+ riscv_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (regnum == tdep->fflags_regnum)
+ return "fflags";
+ else if (regnum == tdep->frm_regnum)
+ return "frm";
+ else
+ gdb_assert_not_reached ("unknown pseudo register number %d", regnum);
+}
+
+/* Return the type for pseudo-register REGNUM for GDBARCH. */
+
+static struct type *
+riscv_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ riscv_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (regnum == tdep->fflags_regnum || regnum == tdep->frm_regnum)
+ return builtin_type (gdbarch)->builtin_int32;
+ else
+ gdb_assert_not_reached ("unknown pseudo register number %d", regnum);
+}
+
+/* Return true (non-zero) if pseudo-register REGNUM from GDBARCH is a
+ member of REGGROUP, otherwise return false (zero). */
+
+static int
+riscv_pseudo_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+ const struct reggroup *reggroup)
+{
+ /* The standard function will also work for pseudo-registers. */
+ return riscv_register_reggroup_p (gdbarch, regnum, reggroup);
+}
+
/* Implement the print_registers_info gdbarch method. This is used by
'info registers' and 'info all-registers'. */
@@ -3713,6 +3819,13 @@ riscv_gdbarch_init (struct gdbarch_info info,
return NULL;
}
+ if (tdesc_found_register (tdesc_data.get (), RISCV_CSR_FFLAGS_REGNUM))
+ features.has_fflags_reg = true;
+ if (tdesc_found_register (tdesc_data.get (), RISCV_CSR_FRM_REGNUM))
+ features.has_frm_reg = true;
+ if (tdesc_found_register (tdesc_data.get (), RISCV_CSR_FCSR_REGNUM))
+ features.has_fcsr_reg = true;
+
/* Have a look at what the supplied (if any) bfd object requires of the
target, then check that this matches with what the target is
providing. */
@@ -3811,21 +3924,64 @@ riscv_gdbarch_init (struct gdbarch_info info,
just a little easier. */
set_gdbarch_num_regs (gdbarch, RISCV_LAST_REGNUM + 1);
- /* We don't have to provide the count of 0 here (its the default) but
- include this line to make it explicit that, right now, we don't have
- any pseudo registers on RISC-V. */
- set_gdbarch_num_pseudo_regs (gdbarch, 0);
-
/* Some specific register numbers GDB likes to know about. */
set_gdbarch_sp_regnum (gdbarch, RISCV_SP_REGNUM);
set_gdbarch_pc_regnum (gdbarch, RISCV_PC_REGNUM);
set_gdbarch_print_registers_info (gdbarch, riscv_print_registers_info);
+ set_tdesc_pseudo_register_name (gdbarch, riscv_pseudo_register_name);
+ set_tdesc_pseudo_register_type (gdbarch, riscv_pseudo_register_type);
+ set_tdesc_pseudo_register_reggroup_p (gdbarch,
+ riscv_pseudo_register_reggroup_p);
+ set_gdbarch_pseudo_register_read (gdbarch, riscv_pseudo_register_read);
+ set_gdbarch_pseudo_register_write (gdbarch, riscv_pseudo_register_write);
+
/* Finalise the target description registers. */
tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data),
riscv_tdesc_unknown_reg);
+ /* Calculate the number of pseudo registers we need. The fflags and frm
+ registers are sub-fields of the fcsr CSR register (csr3). However,
+ these registers can also be accessed directly as separate CSR
+ registers (fflags is csr1, and frm is csr2). And so, some targets
+ might choose to offer direct access to all three registers in the
+ target description, while other targets might choose to only offer
+ access to fcsr.
+
+ As we scan the target description we spot which of fcsr, fflags, and
+ frm are available. If fcsr is available but either of fflags and/or
+ frm are not available, then we add pseudo-registers to provide the
+ missing functionality.
+
+ This has to be done after the call to tdesc_use_registers as we don't
+ know the final register number until after that call, and the pseudo
+ register numbers need to be after the physical registers. */
+ int num_pseudo_regs = 0;
+ int next_pseudo_regnum = gdbarch_num_regs (gdbarch);
+
+ if (features.has_fflags_reg)
+ tdep->fflags_regnum = RISCV_CSR_FFLAGS_REGNUM;
+ else if (features.has_fcsr_reg)
+ {
+ tdep->fflags_regnum = next_pseudo_regnum;
+ pending_aliases.emplace_back ("csr1", (void *) &tdep->fflags_regnum);
+ next_pseudo_regnum++;
+ num_pseudo_regs++;
+ }
+
+ if (features.has_frm_reg)
+ tdep->frm_regnum = RISCV_CSR_FRM_REGNUM;
+ else if (features.has_fcsr_reg)
+ {
+ tdep->frm_regnum = next_pseudo_regnum;
+ pending_aliases.emplace_back ("csr2", (void *) &tdep->frm_regnum);
+ next_pseudo_regnum++;
+ num_pseudo_regs++;
+ }
+
+ set_gdbarch_num_pseudo_regs (gdbarch, num_pseudo_regs);
+
/* Override the register type callback setup by the target description
mechanism. This allows us to provide special type for floating point
registers. */
@@ -4033,8 +4189,12 @@ riscv_supply_regset (const struct regset *regset,
if (regnum == -1 || regnum == RISCV_ZERO_REGNUM)
regcache->raw_supply_zeroed (RISCV_ZERO_REGNUM);
- if (regnum == -1 || regnum == RISCV_CSR_FFLAGS_REGNUM
- || regnum == RISCV_CSR_FRM_REGNUM)
+ struct gdbarch *gdbarch = regcache->arch ();
+ riscv_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (regnum == -1
+ || regnum == tdep->fflags_regnum
+ || regnum == tdep->frm_regnum)
{
int fcsr_regnum = RISCV_CSR_FCSR_REGNUM;
@@ -4048,6 +4208,12 @@ riscv_supply_regset (const struct regset *regset,
registers. */
if (regcache->get_register_status (fcsr_regnum) == REG_VALID)
{
+ /* If we have an fcsr register then we should have fflags and frm
+ too, either provided by the target, or provided as a pseudo
+ register by GDB. */
+ gdb_assert (tdep->fflags_regnum >= 0);
+ gdb_assert (tdep->frm_regnum >= 0);
+
ULONGEST fcsr_val;
regcache->raw_read (fcsr_regnum, &fcsr_val);
@@ -4055,15 +4221,19 @@ riscv_supply_regset (const struct regset *regset,
ULONGEST fflags_val = fcsr_val & 0x1f;
ULONGEST frm_val = (fcsr_val >> 5) & 0x7;
- /* And supply these if needed. */
- if (regnum == -1 || regnum == RISCV_CSR_FFLAGS_REGNUM)
- regcache->raw_supply_integer (RISCV_CSR_FFLAGS_REGNUM,
+ /* And supply these if needed. We can only supply real
+ registers, so don't try to supply fflags or frm if they are
+ implemented as pseudo-registers. */
+ if ((regnum == -1 || regnum == tdep->fflags_regnum)
+ && tdep->fflags_regnum < gdbarch_num_regs (gdbarch))
+ regcache->raw_supply_integer (tdep->fflags_regnum,
(gdb_byte *) &fflags_val,
sizeof (fflags_val),
/* is_signed */ false);
- if (regnum == -1 || regnum == RISCV_CSR_FRM_REGNUM)
- regcache->raw_supply_integer (RISCV_CSR_FRM_REGNUM,
+ if ((regnum == -1 || regnum == tdep->frm_regnum)
+ && tdep->frm_regnum < gdbarch_num_regs (gdbarch))
+ regcache->raw_supply_integer (tdep->frm_regnum,
(gdb_byte *)&frm_val,
sizeof (fflags_val),
/* is_signed */ false);
diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
index 826a002ef92..3ae126f4d8a 100644
--- a/gdb/riscv-tdep.h
+++ b/gdb/riscv-tdep.h
@@ -90,6 +90,12 @@ struct riscv_gdbarch_tdep : gdbarch_tdep_base
/* ISA-specific data types. */
struct type *riscv_fpreg_d_type = nullptr;
+ /* The location of these registers, set to -2 by default so we don't
+ match against -1 which is frequently used to mean "all registers",
+ e.g. in the regcache supply/collect code. */
+ int fflags_regnum = -2;
+ int frm_regnum = -2;
+
/* Use for tracking unknown CSRs in the target description.
UNKNOWN_CSRS_FIRST_REGNUM is the number assigned to the first unknown
CSR. All other unknown CSRs will be assigned sequential numbers after
diff --git a/gdb/testsuite/gdb.arch/riscv-info-fcsr.exp b/gdb/testsuite/gdb.arch/riscv-info-fcsr.exp
index 3d6095d7e55..bf319650db3 100644
--- a/gdb/testsuite/gdb.arch/riscv-info-fcsr.exp
+++ b/gdb/testsuite/gdb.arch/riscv-info-fcsr.exp
@@ -73,17 +73,6 @@ proc check_fcsr { fflags_value frm_value frm_string } {
exp_continue
}
- -re "^(fflags\|frm)\\s+\r\n" {
- # Currently, on some targets (e.g. RISC-V native Linux) the
- # fflags and frm registers show as being available, but are
- # unreadable, the result is these registers report
- # themselves as . So long as fcsr is readable
- # (which is checked below), then for now we accept this.
- set reg_name $expect_out(1,string)
- incr reg_counts($reg_name)
- exp_continue
- }
-
-re "^(frm)\\s+${frm_value}\\s+${frm_pattern}\r\n" {
set reg_name $expect_out(1,string)
incr reg_counts($reg_name)
@@ -129,6 +118,19 @@ proc test_fcsr { fflags_value frm_value frm_string } {
with_test_prefix "set through fcsr" {
check_fcsr $fflags_value $frm_value $frm_string
}
+
+ # Reset fcsr register back to zero.
+ gdb_test_no_output "set \$fcsr = 0x0" \
+ "reset fcsr back to 0x0"
+ gdb_test "p/x \$fcsr" " = 0x0"
+
+ # Now set fcsr value through fflags and frm.
+ gdb_test_no_output "set \$fflags = ${fflags_value}"
+ gdb_test_no_output "set \$frm = ${frm_value}"
+
+ with_test_prefix "set through fflags and frm" {
+ check_fcsr $fflags_value $frm_value $frm_string
+ }
}
}
diff --git a/gdb/testsuite/gdb.arch/riscv-tdesc-fcsr-32.xml b/gdb/testsuite/gdb.arch/riscv-tdesc-fcsr-32.xml
new file mode 100644
index 00000000000..844f8e354d9
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-tdesc-fcsr-32.xml
@@ -0,0 +1,75 @@
+
+
+
+ riscv
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gdb/testsuite/gdb.arch/riscv-tdesc-fcsr-64.xml b/gdb/testsuite/gdb.arch/riscv-tdesc-fcsr-64.xml
new file mode 100644
index 00000000000..130e308b903
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-tdesc-fcsr-64.xml
@@ -0,0 +1,79 @@
+
+
+
+ riscv
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gdb/testsuite/gdb.arch/riscv-tdesc-loading-05.xml b/gdb/testsuite/gdb.arch/riscv-tdesc-loading-05.xml
new file mode 100644
index 00000000000..62b472edba6
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-tdesc-loading-05.xml
@@ -0,0 +1,77 @@
+
+
+
+ riscv
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gdb/testsuite/gdb.arch/riscv-tdesc-loading-06.xml b/gdb/testsuite/gdb.arch/riscv-tdesc-loading-06.xml
new file mode 100644
index 00000000000..844f8e354d9
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-tdesc-loading-06.xml
@@ -0,0 +1,75 @@
+
+
+
+ riscv
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gdb/testsuite/gdb.arch/riscv-tdesc-regs.exp b/gdb/testsuite/gdb.arch/riscv-tdesc-regs.exp
index 7f6bc45039f..4bacaaef99c 100644
--- a/gdb/testsuite/gdb.arch/riscv-tdesc-regs.exp
+++ b/gdb/testsuite/gdb.arch/riscv-tdesc-regs.exp
@@ -137,3 +137,39 @@ foreach rgroup {x_all all save restore general system csr} {
}
array unset reg_counts
}
+
+# Next load a target description that contains fcsr, but not fflags or
+# frm. Then check that GDB provides an fflags and frm registers using
+# the pseudo-register mechanism.
+if { $xlen == 4 } {
+ set xml_tdesc "riscv-tdesc-fcsr-32.xml"
+} else {
+ set xml_tdesc "riscv-tdesc-fcsr-64.xml"
+}
+set xml_tdesc "${srcdir}/${subdir}/${xml_tdesc}"
+
+# Maybe copy the target over if we're remote testing.
+if {[is_remote host]} {
+ set remote_file [remote_download host $xml_tdesc]
+} else {
+ set remote_file $xml_tdesc
+}
+
+gdb_test_no_output "set tdesc filename $remote_file" \
+ "load the target description that lacks fflags and frm"
+
+foreach reg {fflags frm} {
+ gdb_test_multiple "info registers $reg" "" {
+ -re "^info registers $reg\r\n" {
+ exp_continue
+ }
+
+ -wrap -re "^Invalid register `$reg`" {
+ fail $gdb_test_name
+ }
+
+ -wrap -re "^$reg\\s+\[^\r\n\]+" {
+ pass $gdb_test_name
+ }
+ }
+}
diff --git a/gdb/testsuite/gdb.base/float.exp b/gdb/testsuite/gdb.base/float.exp
index 62e8346928b..7fff2b90727 100644
--- a/gdb/testsuite/gdb.base/float.exp
+++ b/gdb/testsuite/gdb.base/float.exp
@@ -111,11 +111,18 @@ if { [is_aarch64_target] } then {
} elseif [istarget "sparc*-*-*"] then {
gdb_test "info float" "f0.*f1.*f31.*d0.*d30.*" "info float"
} elseif [istarget "riscv*-*-*"] then {
- # RISC-V may or may not have an FPU
+ # RISC-V may or may not have an FPU. Additionally, the order of
+ # fcsr relative to fflags and frm can change depending on whether
+ # the fflags and frm registers are implemented as real registers
+ # (supplied in the target description) or pseudo-registers
+ # (supplied by GDB as a view into fcsr).
gdb_test_multiple "info float" "info float" {
-re "ft0.*ft1.*ft11.*fflags.*frm.*fcsr.*$gdb_prompt $" {
pass "info float (with FPU)"
}
+ -re "ft0.*ft1.*ft11.*fcsr.*fflags.*frm.*$gdb_prompt $" {
+ pass "info float (with FPU)"
+ }
-re "No floating.point info available for this processor.*$gdb_prompt $" {
pass "info float (without FPU)"
}