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)" }