[PATCH^3] gdb: mips: Add MIPSR6 support

Message ID AS8PR03MB969878E63A85A786E3461C52967D2@AS8PR03MB9698.eurprd03.prod.outlook.com
State New
Headers
Series [PATCH^3] gdb: mips: Add MIPSR6 support |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gdb_check--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_gdb_check--master-arm success Testing passed

Commit Message

Milos Kalicanin Jan. 30, 2024, 3:17 p.m. UTC
  Introduce new instruction encodings from Release 6 of the MIPS
architecture [1]. Support breakpoints and single stepping with
compact branches, forbidden slots, new branch instruction and
new atomic load-store instruction encodings.

Changes from v2: Added new tests

[1] "MIPS64 Architecture for Programmers Volume II-A: The MIPS64
    Instruction Set Reference Manual", Document Number: MD00087,
    Revision 6.06, December 15, 2016, Section 3 "The MIPS64
    Instruction Set", pp. 42-530
https://s3-eu-west-1.amazonaws.com/downloads-mips/documents/MD00087-2B-MIPS64BIS-AFP-6.06.pdf

2024-01-30  Andrew Bennett  <andrew.bennett@imgtec.com>
	    Matthew Fortune  <matthew.fortune@mips.com>
	    Faraz Shahbazker  <fshahbazker@wavecomp.com>

gdb/ChangeLog:
	* mips-tdep.c (is_mipsr6_isa): New.
	(b0s21_imm): New define.
	(mips32_relative_offset21, mips32_relative_offset26): New.
	(is_add32bit_overflow, is_add64bit_overflow): New.
	(mips32_next_pc): Handle r6 compact and fpu coprocessor branches.
	Move handling of BLEZ, BGTZ opcode into ...
	(mips32_blez_pc): New.
	(mips32_instruction_is_compact_branch): New.
	(mips32_insn_at_pc_has_forbidden_slot):  New.
	(mips32_scan_prologue): Ignore pre-r6 addi encoding on r6.
	Stop at compact branch also.
	(LLSC_R6_OPCODE,LL_R6_FUNCT,LLE_FUNCT,
	LLD_R6_FUNCT,SC_R6_FUNCT,SCE_FUNCT,
	SCD_R6_FUNCT: New defines.
	(is_ll_insn, is_sc_insn): New.
	(mips_deal_with_atomic_sequence): Use is_ll_insn/is_sc_insn.
	Handle compact branches.
	(mips_about_to_return): Handle jrc and macro jr.
	(mips32_stack_frame_destroyed_p): Likewise.
	(mips32_instruction_has_delay_slot): Don't handle JALX on r6.
	Handle compact branches and coprocessor branches.
	(mips_adjust_breakpoint_address): Skip forbidden slot for
	compact branches.
---
 gdb/mips-tdep.c                       |  520 ++++++++-
 gdb/testsuite/gdb.arch/mips-64-r6.c   | 1469 +++++++++++++++++++++++++
 gdb/testsuite/gdb.arch/mips-64-r6.exp |   99 ++
 3 files changed, 2046 insertions(+), 42 deletions(-)
 create mode 100644 gdb/testsuite/gdb.arch/mips-64-r6.c
 create mode 100644 gdb/testsuite/gdb.arch/mips-64-r6.exp
  

Comments

Milos Kalicanin Jan. 30, 2024, 3:43 p.m. UTC | #1
Adding Simon Marchi.
  
Simon Marchi Feb. 2, 2024, 8:57 p.m. UTC | #2
On 1/30/24 10:17, Milos Kalicanin wrote:
> Introduce new instruction encodings from Release 6 of the MIPS
> architecture [1]. Support breakpoints and single stepping with
> compact branches, forbidden slots, new branch instruction and
> new atomic load-store instruction encodings.
> 
> Changes from v2: Added new tests

Thanks for the update.

I noted a few cosmetic comments below.  As I said last time, I can only
do a superficial review.

> [1] "MIPS64 Architecture for Programmers Volume II-A: The MIPS64
>     Instruction Set Reference Manual", Document Number: MD00087,
>     Revision 6.06, December 15, 2016, Section 3 "The MIPS64
>     Instruction Set", pp. 42-530
> https://s3-eu-west-1.amazonaws.com/downloads-mips/documents/MD00087-2B-MIPS64BIS-AFP-6.06.pdf
> 
> 2024-01-30  Andrew Bennett  <andrew.bennett@imgtec.com>
> 	    Matthew Fortune  <matthew.fortune@mips.com>
> 	    Faraz Shahbazker  <fshahbazker@wavecomp.com>
> 
> gdb/ChangeLog:
> 	* mips-tdep.c (is_mipsr6_isa): New.
> 	(b0s21_imm): New define.
> 	(mips32_relative_offset21, mips32_relative_offset26): New.
> 	(is_add32bit_overflow, is_add64bit_overflow): New.
> 	(mips32_next_pc): Handle r6 compact and fpu coprocessor branches.
> 	Move handling of BLEZ, BGTZ opcode into ...
> 	(mips32_blez_pc): New.
> 	(mips32_instruction_is_compact_branch): New.
> 	(mips32_insn_at_pc_has_forbidden_slot):  New.
> 	(mips32_scan_prologue): Ignore pre-r6 addi encoding on r6.
> 	Stop at compact branch also.
> 	(LLSC_R6_OPCODE,LL_R6_FUNCT,LLE_FUNCT,
> 	LLD_R6_FUNCT,SC_R6_FUNCT,SCE_FUNCT,
> 	SCD_R6_FUNCT: New defines.
> 	(is_ll_insn, is_sc_insn): New.
> 	(mips_deal_with_atomic_sequence): Use is_ll_insn/is_sc_insn.
> 	Handle compact branches.
> 	(mips_about_to_return): Handle jrc and macro jr.
> 	(mips32_stack_frame_destroyed_p): Likewise.
> 	(mips32_instruction_has_delay_slot): Don't handle JALX on r6.
> 	Handle compact branches and coprocessor branches.
> 	(mips_adjust_breakpoint_address): Skip forbidden slot for
> 	compact branches.
> ---
>  gdb/mips-tdep.c                       |  520 ++++++++-
>  gdb/testsuite/gdb.arch/mips-64-r6.c   | 1469 +++++++++++++++++++++++++
>  gdb/testsuite/gdb.arch/mips-64-r6.exp |   99 ++
>  3 files changed, 2046 insertions(+), 42 deletions(-)
>  create mode 100644 gdb/testsuite/gdb.arch/mips-64-r6.c
>  create mode 100644 gdb/testsuite/gdb.arch/mips-64-r6.exp
> 
> diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
> index bf0b66c4b00..a60377f25e0 100644
> --- a/gdb/mips-tdep.c
> +++ b/gdb/mips-tdep.c
> @@ -76,6 +76,9 @@ static int mips16_insn_at_pc_has_delay_slot (struct gdbarch *gdbarch,
>  static void mips_print_float_info (struct gdbarch *, struct ui_file *,
>  				   frame_info_ptr, const char *);
>  
> +static void mips_read_fp_register_single (struct frame_info_ptr, int,
> +					  gdb_byte *);
> +
>  /* A useful bit in the CP0 status register (MIPS_PS_REGNUM).  */
>  /* This bit is set if we are emulating 32-bit FPRs on a 64-bit chip.  */
>  #define ST0_FR (1 << 26)
> @@ -1500,6 +1503,16 @@ mips_fetch_instruction (struct gdbarch *gdbarch,
>    return extract_unsigned_integer (buf, instlen, byte_order);
>  }
>  
> +/* Return one if the gdbarch is based on MIPS Release 6.  */
> +static int
> +is_mipsr6_isa (struct gdbarch *gdbarch)

Change to bool and "Return true".

> +{
> +  const struct bfd_arch_info *info = gdbarch_bfd_arch_info (gdbarch);
> +
> +  return (info->mach == bfd_mach_mipsisa32r6
> +	  || info->mach == bfd_mach_mipsisa64r6);
> +}
> +
>  /* These are the fields of 32 bit mips instructions.  */
>  #define mips32_op(x) (x >> 26)
>  #define itype_op(x) (x >> 26)
> @@ -1542,6 +1555,7 @@ mips_fetch_instruction (struct gdbarch *gdbarch,
>  #define b0s11_op(x) ((x) & 0x7ff)
>  #define b0s12_imm(x) ((x) & 0xfff)
>  #define b0s16_imm(x) ((x) & 0xffff)
> +#define b0s21_imm(x) ((x) & 0x1fffff)
>  #define b0s26_imm(x) ((x) & 0x3ffffff)
>  #define b6s10_ext(x) (((x) >> 6) & 0x3ff)
>  #define b11s5_reg(x) (((x) >> 11) & 0x1f)
> @@ -1578,6 +1592,18 @@ mips32_relative_offset (ULONGEST inst)
>    return ((itype_immediate (inst) ^ 0x8000) - 0x8000) << 2;
>  }
>  
> +static LONGEST
> +mips32_relative_offset21 (ULONGEST insn)
> +{
> +  return ((b0s21_imm (insn) ^ 0x100000) - 0x100000) << 2;
> +}
> +
> +static LONGEST
> +mips32_relative_offset26 (ULONGEST insn)
> +{
> +  return ((b0s26_imm (insn) ^ 0x2000000) - 0x2000000) << 2;
> +}
> +
>  /* Determine the address of the next instruction executed after the INST
>     floating condition branch instruction at PC.  COUNT specifies the
>     number of the floating condition bits tested by the branch.  */
> @@ -1636,6 +1662,71 @@ is_octeon_bbit_op (int op, struct gdbarch *gdbarch)
>    return 0;
>  }
>  
> +static int
> +is_add32bit_overflow (int32_t a, int32_t b)

bool

> +{
> +  int32_t r = (uint32_t) a + (uint32_t) b;
> +  return (a < 0 && b < 0 && r >= 0) || (a >= 0 && b >= 0 && r < 0);
> +}
> +
> +static int
> +is_add64bit_overflow (int64_t a, int64_t b)

bool

> +{
> +  if (a != (int32_t)a)
> +    return 1;
> +  if (b != (int32_t)b)
> +    return 1;
> +  return is_add32bit_overflow ((int32_t)a, (int32_t)b);

Spaces after casts (4 times).

> +}
> +
> +/* Calculate address of next instruction after BLEZ.  */
> +
> +static CORE_ADDR
> +mips32_blez_pc (struct gdbarch *gdbarch, struct regcache *regcache,

Omit "struct" where possible.

> +		ULONGEST inst, CORE_ADDR pc, int invert)
> +{
> +  int rs = itype_rs (inst);
> +  int rt = itype_rt (inst);
> +  LONGEST val_rs = regcache_raw_get_signed (regcache, rs);
> +  LONGEST val_rt = regcache_raw_get_signed (regcache, rt);
> +  ULONGEST uval_rs = regcache_raw_get_unsigned (regcache, rs);
> +  ULONGEST uval_rt = regcache_raw_get_unsigned (regcache, rt);

Move declarations to more specific scopes when possible.

> +  int taken = 0;

bool and false

> +  int delay_slot_size = 4;
> +
> +  /* BLEZ, BLEZL, BGTZ, BGTZL */
> +  if (rt == 0)
> +    taken = (val_rs <= 0);
> +  else if (is_mipsr6_isa (gdbarch))
> +    {
> +      /* BLEZALC, BGTZALC */
> +      if (rs == 0 && rt != 0)
> +	taken = (val_rt <= 0);
> +      /* BGEZALC, BLTZALC */
> +      else if (rs == rt && rt != 0)
> +	taken = (val_rt >= 0);
> +      /* BGEUC, BLTUC */
> +      else if (rs != rt && rs != 0 && rt != 0)
> +	taken = (uval_rs >= uval_rt);
> +
> +      /* Step through the forbidden slot to avoid repeated exceptions we do
> +	 not currently have access to the BD bit when hitting a breakpoint
> +	 and therefore cannot tell if the breakpoint hit on the branch or the
> +	 forbidden slot.  */
> +      /* delay_slot_size = 0; */
> +    }
> +
> +  if (invert)
> +    taken = !taken;
> +
> +  /* Calculate branch target.  */
> +  if (taken)
> +    pc += mips32_relative_offset (inst);
> +  else
> +    pc += delay_slot_size;
> +
> +  return pc;
> +}
>  
>  /* Determine where to set a single step breakpoint while considering
>     branch prediction.  */
> @@ -1646,12 +1737,17 @@ mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
>    struct gdbarch *gdbarch = regcache->arch ();
>    unsigned long inst;
>    int op;
> +  int mips64bitreg = 0;
> +
> +  if (mips_isa_regsize (gdbarch) == 8)
> +    mips64bitreg = 1;

More simply:

  bool mips64bitreg = mips_isa_regsize (gdbarch) == 8);

> +
>    inst = mips_fetch_instruction (gdbarch, ISA_MIPS, pc, NULL);
>    op = itype_op (inst);
>    if ((inst & 0xe0000000) != 0)		/* Not a special, jump or branch
>  					   instruction.  */
>      {
> -      if (op >> 2 == 5)
> +      if (op >> 2 == 5 && ((op & 0x02) == 0 || itype_rt (inst) == 0))
>  	/* BEQL, BNEL, BLEZL, BGTZL: bits 0101xx */
>  	{
>  	  switch (op & 0x03)
> @@ -1661,7 +1757,7 @@ mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
>  	    case 1:		/* BNEL */
>  	      goto neq_branch;
>  	    case 2:		/* BLEZL */
> -	      goto less_branch;
> +	      goto lez_branch;
>  	    case 3:		/* BGTZL */
>  	      goto greater_branch;
>  	    default:
> @@ -1671,15 +1767,19 @@ mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
>        else if (op == 17 && itype_rs (inst) == 8)
>  	/* BC1F, BC1FL, BC1T, BC1TL: 010001 01000 */
>  	pc = mips32_bc1_pc (gdbarch, regcache, inst, pc + 4, 1);
> -      else if (op == 17 && itype_rs (inst) == 9
> +      else if (!is_mipsr6_isa (gdbarch)
> +	       && op == 17
> +	       && itype_rs (inst) == 9
>  	       && (itype_rt (inst) & 2) == 0)
>  	/* BC1ANY2F, BC1ANY2T: 010001 01001 xxx0x */
>  	pc = mips32_bc1_pc (gdbarch, regcache, inst, pc + 4, 2);
> -      else if (op == 17 && itype_rs (inst) == 10
> -	       && (itype_rt (inst) & 2) == 0)
> +      else if (!is_mipsr6_isa (gdbarch)
> +		&& op == 17
> +		&& itype_rs (inst) == 10
> +		&& (itype_rt (inst) & 2) == 0)
>  	/* BC1ANY4F, BC1ANY4T: 010001 01010 xxx0x */
>  	pc = mips32_bc1_pc (gdbarch, regcache, inst, pc + 4, 4);
> -      else if (op == 29)
> +      else if (!is_mipsr6_isa (gdbarch) && op == 29)
>  	/* JALX: 011101 */
>  	/* The new PC will be alternate mode.  */
>  	{
> @@ -1707,7 +1807,128 @@ mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
>  	  else
>  	    pc += 8;        /* After the delay slot.  */
>  	}
> +      else if (is_mipsr6_isa (gdbarch))
> +	{
> +	  /* BOVC, BEQZALC, BEQC and BNVC, BNEZALC, BNEC */
> +	  if (op == 8 || op == 24)
> +	    {
> +	      int rs = rtype_rs (inst);
> +	      int rt = rtype_rt (inst);
> +	      LONGEST val_rs = regcache_raw_get_signed (regcache, rs);
> +	      LONGEST val_rt = regcache_raw_get_signed (regcache, rt);
> +	      int taken = 0;

Add new line after this.  Also, use bool and false.

> +	      /* BOVC (BNVC) */
> +	      if (rs >= rt)
> +		{
> +		  if (mips64bitreg == 1)
> +		    taken = is_add64bit_overflow (val_rs, val_rt);
> +		  else
> +		    taken = is_add32bit_overflow (val_rs, val_rt);
> +		}
> +	      /* BEQZALC (BNEZALC) */
> +	      else if (rs < rt && rs == 0)
> +		taken = (val_rt == 0);
> +	      /* BEQC (BNEC) */
> +	      else
> +		taken = (val_rs == val_rt);
> +
> +	      /* BNVC, BNEZALC, BNEC */
> +	      if (op == 24)
> +		taken = !taken;
>  
> +	      if (taken)
> +		pc += mips32_relative_offset (inst) + 4;
> +	      else
> +		/* Step through the forbidden slot to avoid repeated exceptions
> +		   we do not currently have access to the BD bit when hitting a
> +		   breakpoint and therefore cannot tell if the breakpoint
> +		   hit on the branch or the forbidden slot.  */
> +		pc += 8;

Add { } braces to the previous else (because of the presence of the
comment).

> +	    }
> +	  /* BC1EQZ, BC1NEZ */
> +	  else if (op == 17 && (itype_rs (inst) == 9 || itype_rs (inst) == 13))
> +	    {
> +	      gdb_byte status;
> +	      gdb_byte true_val = 0;
> +	      unsigned int fp = (gdbarch_num_regs (gdbarch)
> +				 + mips_regnum (gdbarch)->fp0
> +				 + itype_rt (inst));
> +	      struct frame_info_ptr frame = get_current_frame ();
> +	      gdb_byte *raw_buffer = (gdb_byte *) alloca (sizeof (gdb_byte) * 4);
> +	      mips_read_fp_register_single (frame, fp, raw_buffer);
> +
> +	      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
> +		status = *(raw_buffer + 3);
> +	      else
> +		status = *(raw_buffer);
> +
> +	      if (itype_rs (inst) == 13)
> +		true_val = 1;
> +
> +	      if ((status & 0x1) == true_val)
> +		pc += mips32_relative_offset (inst) + 4;
> +	      else
> +		pc += 8;
> +	    }
> +	  else if (op == 22 || op == 23)
> +	  /* BLEZC, BGEZC, BGEC, BGTZC, BLTZC, BLTC */
> +	    {
> +	      int rs = rtype_rs (inst);
> +	      int rt = rtype_rt (inst);
> +	      LONGEST val_rs = regcache_raw_get_signed (regcache, rs);
> +	      LONGEST val_rt = regcache_raw_get_signed (regcache, rt);
> +	      int taken = 0;
> +	      /* The R5 rt == 0 case is handled above so we treat it as
> +		 an unknown instruction here for future ISA usage.  */
> +	      if (rs == 0 && rt != 0)
> +		taken = (val_rt <= 0);
> +	      else if (rs == rt && rt != 0)
> +		taken = (val_rt >= 0);
> +	      else if (rs != rt && rs != 0 && rt != 0)
> +		taken = (val_rs >= val_rt);
> +
> +	      if (op == 23)
> +		taken = !taken;
> +
> +	      if (taken)
> +		pc += mips32_relative_offset (inst) + 4;
> +	      else
> +		/* Step through the forbidden slot to avoid repeated exceptions
> +		   we do not currently have access to the BD bit when hitting a
> +		   breakpoint and therefore cannot tell if the breakpoint
> +		   hit on the branch or the forbidden slot.  */
> +		pc += 8;

Add curly braces.

> +	    }
> +	  else if (op == 50 || op == 58)
> +	  /* BC, BALC */
> +	    pc += mips32_relative_offset26 (inst) + 4;
> +	  else if ((op == 54 || op == 62)
> +		   && rtype_rs (inst) == 0)
> +	  /* JIC, JIALC */
> +	    {
> +	      pc = regcache_raw_get_signed (regcache, itype_rt (inst));
> +	      pc += (itype_immediate (inst) ^ 0x8000) - 0x8000;
> +	    }
> +	  else if (op == 54 || op == 62)
> +	  /* BEQZC, BNEZC */
> +	    {
> +	      int rs = itype_rs (inst);
> +	      LONGEST rs_val = regcache_raw_get_signed (regcache, rs);
> +	      int taken = (rs_val == 0);
> +	      if (op == 62)
> +		taken = !taken;
> +	      if (taken)
> +		pc += mips32_relative_offset21 (inst) + 4;
> +	      else
> +		/* Step through the forbidden slot to avoid repeated exceptions
> +		   we do not currently have access to the BD bit when hitting a
> +		   breakpoint and therefore cannot tell if the breakpoint
> +		   hit on the branch or the forbidden slot.  */
> +		pc += 8;

Add curly braces.

> +	    }
> +	  else
> +	    pc += 4;		/* Not a branch, next instruction is easy.  */
> +	}
>        else
>  	pc += 4;		/* Not a branch, next instruction is easy.  */
>      }
> @@ -1751,7 +1972,6 @@ mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
>  	      case 2:		/* BLTZL */
>  	      case 16:		/* BLTZAL */
>  	      case 18:		/* BLTZALL */
> -	      less_branch:
>  		if (regcache_raw_get_signed (regcache, itype_rs (inst)) < 0)
>  		  pc += mips32_relative_offset (inst) + 4;
>  		else
> @@ -1767,22 +1987,38 @@ mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
>  		  pc += 8;	/* after the delay slot */
>  		break;
>  	      case 0x1c:	/* BPOSGE32 */
> +	      case 0x1d:	/* BPOSGE32C */
>  	      case 0x1e:	/* BPOSGE64 */
>  		pc += 4;
>  		if (itype_rs (inst) == 0)
>  		  {
>  		    unsigned int pos = (op & 2) ? 64 : 32;
>  		    int dspctl = mips_regnum (gdbarch)->dspctl;
> +		    int delay_slot_size = 4;
>  
>  		    if (dspctl == -1)
>  		      /* No way to handle; it'll most likely trap anyway.  */
>  		      break;
>  
> +		    /* BPOSGE32C */
> +		    if (op == 0x1d)
> +		      {
> +			if (!is_mipsr6_isa (gdbarch))
> +			  break;
> +
> +			/* Step through the forbidden slot to avoid repeated
> +			   exceptions we do not currently have access to the BD
> +			   bit when hitting a breakpoint and therefore cannot
> +			   tell if the breakpoint hit on the branch or the
> +			   forbidden slot.  */
> +			/* delay_slot_size = 0; */
> +		      }
> +
>  		    if ((regcache_raw_get_unsigned (regcache,
>  						    dspctl) & 0x7f) >= pos)
>  		      pc += mips32_relative_offset (inst);
>  		    else
> -		      pc += 4;
> +		      pc += delay_slot_size;
>  		  }
>  		break;
>  		/* All of the other instructions in the REGIMM category */
> @@ -1816,19 +2052,14 @@ mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
>  	  else
>  	    pc += 8;
>  	  break;
> -	case 6:		/* BLEZ, BLEZL */
> -	  if (regcache_raw_get_signed (regcache, itype_rs (inst)) <= 0)
> -	    pc += mips32_relative_offset (inst) + 4;
> -	  else
> -	    pc += 8;
> +	case 6:		/* BLEZ, BLEZL, BLEZALC, BGEZALC, BGEUC */
> +	lez_branch:
> +	  pc = mips32_blez_pc (gdbarch, regcache, inst, pc + 4, 0);
>  	  break;
>  	case 7:
>  	default:
> -	greater_branch:	/* BGTZ, BGTZL */
> -	  if (regcache_raw_get_signed (regcache, itype_rs (inst)) > 0)
> -	    pc += mips32_relative_offset (inst) + 4;
> -	  else
> -	    pc += 8;
> +	greater_branch:	/* BGTZ, BGTZL, BGTZALC, BLTZALC, BLTUC */
> +	  pc = mips32_blez_pc (gdbarch, regcache, inst, pc + 4, 1);
>  	  break;
>  	}			/* switch */
>      }				/* else */
> @@ -2451,6 +2682,72 @@ micromips_instruction_is_compact_branch (unsigned short insn)
>      }
>  }
>  
> +/* Return non-zero if the MIPS instruction INSN is a compact branch
> +   or jump.  A value of 1 indicates an unconditional compact branch
> +   and a value of 2 indicates a conditional compact branch.  */
> +
> +static int
> +mips32_instruction_is_compact_branch (struct gdbarch *gdbarch, ULONGEST insn)

Can you please add an enum type for the result?

Also, the "is" in the function makes it sound like the function
determines if INSN is a compact branch or not, and that it would return
a boolean.  But the comment makes it sound like it classifies the
instruction in some categories.  Can you find a better name for the
function?

> +{
> +  switch (itype_op (insn))
> +    {
> +    /* BC */
> +    case 50:
> +    /* BALC */
> +    case 58:
> +      if (is_mipsr6_isa (gdbarch))
> +	return 1;
> +      break;
> +    /* BOVC, BEQZALC, BEQC */
> +    case 8:
> +    /* BNVC, BNEZALC, BNEC */
> +    case 24:
> +      if (is_mipsr6_isa (gdbarch))
> +	return 2;
> +      break;
> +    /* BEQZC, JIC */
> +    case 54:
> +    /* BNEZC, JIALC */
> +    case 62:
> +      if (is_mipsr6_isa (gdbarch))
> +	/* JIC, JIALC are unconditional */
> +	return (itype_rs (insn) == 0) ? 1 : 2;
> +      break;
> +    /* BLEZC, BGEZC, BGEC */
> +    case 22:
> +    /* BGTZC, BLTZC, BLTC */
> +    case 23:
> +    /* BLEZALC, BGEZALC, BGEUC */
> +    case 6:
> +    /* BGTZALC, BLTZALC, BLTUC */
> +    case 7:
> +      if (is_mipsr6_isa (gdbarch)
> +	  && itype_rt (insn) != 0)
> +	return 2;
> +      break;
> +    /* BPOSGE32C */
> +    case 1:
> +      if (is_mipsr6_isa (gdbarch)
> +	  && itype_rt (insn) == 0x1d && itype_rs (insn) == 0)
> +	return 2;
> +    }
> +  return 0;
> +}
> +
> +/* Return non-zero if a standard MIPS instruction at ADDR has a branch
> +   forbidden slot (i.e. it is a conditional compact branch instruction).  */
> +
> +static int
> +mips32_insn_at_pc_has_forbidden_slot (struct gdbarch *gdbarch, CORE_ADDR addr)

"Return true" and bool.

> +{
> +  int status;
> +  ULONGEST insn = mips_fetch_instruction (gdbarch, ISA_MIPS, addr, &status);
> +  if (status)
> +    return 0;
> +
> +  return mips32_instruction_is_compact_branch (gdbarch, insn) == 2;
> +}
> +
>  struct mips_frame_cache
>  {
>    CORE_ADDR base;
> @@ -3494,7 +3791,8 @@ mips32_scan_prologue (struct gdbarch *gdbarch,
>        reg = high_word & 0x1f;
>  
>        if (high_word == 0x27bd		/* addiu $sp,$sp,-i */
> -	  || high_word == 0x23bd	/* addi $sp,$sp,-i */
> +	  || (high_word == 0x23bd	/* addi $sp,$sp,-i */
> +	      && !is_mipsr6_isa (gdbarch))
>  	  || high_word == 0x67bd)	/* daddiu $sp,$sp,-i */
>  	{
>  	  if (offset < 0)		/* Negative stack adjustment?  */
> @@ -3632,7 +3930,9 @@ mips32_scan_prologue (struct gdbarch *gdbarch,
>  
>        /* A jump or branch, or enough non-prologue insns seen?  If so,
>  	 then we must have reached the end of the prologue by now.  */
> -      if (prev_delay_slot || non_prologue_insns > 1)
> +      if (prev_delay_slot
> +	  || non_prologue_insns > 1
> +	  || mips32_instruction_is_compact_branch (gdbarch, inst))
>  	break;
>  
>        prev_non_prologue_insn = this_non_prologue_insn;
> @@ -3938,6 +4238,59 @@ mips_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR addr)
>  #define LLD_OPCODE 0x34
>  #define SC_OPCODE 0x38
>  #define SCD_OPCODE 0x3c
> +#define LLSC_R6_OPCODE 0x1f
> +#define LL_R6_FUNCT 0x36
> +#define LLE_FUNCT 0x2e
> +#define LLD_R6_FUNCT 0x37
> +#define SC_R6_FUNCT 0x26
> +#define SCE_FUNCT 0x1e
> +#define SCD_R6_FUNCT 0x27
> +
> +static int
> +is_ll_insn (struct gdbarch *gdbarch, ULONGEST insn)

bool, and true/false below.

> +{
> +  if (itype_op (insn) == LL_OPCODE
> +      || itype_op (insn) == LLD_OPCODE)
> +    return 1;
> +
> +  if (rtype_op (insn) == LLSC_R6_OPCODE
> +      && rtype_funct (insn) == LLE_FUNCT
> +      && (insn & 0x40) == 0)
> +    return 1;
> +
> +  /* Handle LL and LLP varieties.  */
> +  if (is_mipsr6_isa (gdbarch)
> +      && rtype_op (insn) == LLSC_R6_OPCODE
> +      && (rtype_funct (insn) == LL_R6_FUNCT
> +	  || rtype_funct (insn) == LLD_R6_FUNCT
> +	  || rtype_funct (insn) == LLE_FUNCT))
> +    return 1;
> +
> +  return 0;
> +}
> +
> +static int
> +is_sc_insn (struct gdbarch *gdbarch, ULONGEST insn)

Same.

> +}
> +
> +
> +
> +/*
> + * Any test_r6_* function returns non-zero => failure
> + */
> +#define EXPECT(X) if ((X)) abort ();
> +
> +
> +main ()
> +{
> +  EXPECT(test_r6_branch());
> +
> +  EXPECT(test_r6_forbidden());
> +
> +  EXPECT(test_r6_64());
> +
> +  EXPECT(test_r6());
> +
> +  EXPECT(test_r6_fpu());
> +
> +
> +  EXPECT(test_r6_llsc_dp());
> +
> +
> +  EXPECT(test_r6_llsc_wp());
> +}
> diff --git a/gdb/testsuite/gdb.arch/mips-64-r6.exp b/gdb/testsuite/gdb.arch/mips-64-r6.exp
> new file mode 100644
> index 00000000000..1ab04daddd5
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/mips-64-r6.exp
> @@ -0,0 +1,99 @@
> +# Copyright (C) 2012-2023 Free Software Foundation, Inc.
> +
> +# 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 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.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program; if not, see <http://www.gnu.org/licenses/>.
> +
> +# Test mips release 6 patch.
> +
> +require {istarget "*mips*"}
> +
> +proc single_step {} {
> +    global gdb_prompt
> +
> +    send_gdb "si\n"
> +    gdb_expect {
> +	-re "$gdb_prompt \$" {
> +	    return 1
> +	}
> +	-re ".*Breakpoint.*test_.*" {
> +	    return 2
> +	}
> +	-re ".*exited normally.*" {
> +	    return 3
> +	}
> +	-re ".*The program is not being run.*" {
> +	    return 4
> +	}
> +    }
> +    return 0
> +}
> +
> +set testfile "mips-64-r6"
> +set srcfile ${testfile}.c
> +set binfile ${objdir}/${subdir}/${testfile}

You should be able to use "standard_testfile" at the top to set those.

> +
> +verbose -log "\[DEBUG\] testfile=${testfile}\n"
> +verbose -log "\[DEBUG\] srcfile=${srcfile}\n"
> +verbose -log "\[DEBUG\] binfile=${binfile}\n"
> +verbose -log "\[DEBUG\] srcdir/subdir/srcfile=${srcdir}/${subdir}/${srcfile}\n\n"

That shouldn't be necessary, they are all standard variables used in all
tests.

> +
> +if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug nowarnings}] != "" } {

Why the nowarnings?

> +     fail "compilation"

Use:

  untested "failed to compile"

> +     return
> +}
> +
> +pass "compilation"

Remove this "pass".

> +
> +clean_restart $binfile
> +# Native needs run.
> +runto_main

Use:

    if { ![runto_main } {
        return
    }

> +
> +set tests ""
> +foreach n [list "r6_branch" "r6_forbidden" "r6_64" "r6" "r6_fpu" "r6_llsc_dp" "r6_llsc_wp"] {
> +    lappend tests "test_$n"
> +}
> +
> +# put breakpoint on each test-function
> +foreach func $tests {
> +    gdb_test "break $func" "Breakpoint.*at.*" "set breakpoint on $func"
> +}

I don't really understand why you have a loop to fill the `tests` list,
then another loop.  Can't you just have:

set tests {r6_branch r6_forbidden ...}

foreach test $tests {
    gdb_test "break test_$test" ...
}

?

> +
> +
> +set rt [single_step]
> +if { $rt == 0 } {
> +    fail "single_step returned $rt"
> +}
> +
> +set start [timestamp]
> +global timeout
> +while { $rt != 0 && [timestamp] - $start < 3*$timeout } {
> +
> +     if { $rt == 3 } {
> +	pass "all tests are fine"
> +	return
> +    } elseif { $rt == 4 } {
> +	fail "Program exited abnormally"
> +	return
> +    }
> +#    elseif { $rt == 1 || $rt == 2 } { # 1->got gdb_prompt ; 2->hit breakpoint
> +#   	verbose -log "\[DEBUG_\] 'single_step' returned rt=$rt ; timeout = $timeout"
> +#    }
> +
> +    set rt [single_step]
> +}
> +
> +if {$rt == 0 } {
> +    fail "stepi"
> +}

I don't really understand the test mechanic.  Can you describe what you
are trying to achieve?

Simon
  
Milos Kalicanin Feb. 8, 2024, 2:23 p.m. UTC | #3
Thanks for reply, Simon. Your suggestions will be applied soon.

Speaking of test mechanic:
It's quite simple. Pseudocode follows:
-put breakpoint on each test function (test_r6_r6, test_r6, test_r6_llsc_dp...)
-single step using gdb command 'stepi', checking response:
        if (response == gdb_prompt) or (response == 'breakpoint hit'):
                proceed further
        elseif (response == exited abnormally)
                test failure
        elseif (response == exited normally)
                tests passed successfully
        else
                tests failure
-previous loop is constrained with timeout

Reason for 'abnormal exit' would be 'test function returned nonzero status':
> /*
> * Any test_r6_* function returns non-zero => failure
> */
> #define EXPECT(X) if ((X)) abort ();

In inline asm, register $11 or [err] identifies instruction currently being tested.
If any instruction's output is wrong, program jumps to epilog saving non-zero exit status and signaling failure. If all instructions are tested and returned expected result, output register [err] is set to 0, signaling success.

Let me know if you have any more suggestions/questions.

Kind Regards,
Milos
  
Simon Marchi Feb. 12, 2024, 5:38 p.m. UTC | #4
On 2024-02-08 09:23, Milos Kalicanin wrote:
> Thanks for reply, Simon. Your suggestions will be applied soon.
> 
> Speaking of test mechanic:
> It's quite simple. Pseudocode follows:
> -put breakpoint on each test function (test_r6_r6, test_r6, test_r6_llsc_dp...)
> -single step using gdb command 'stepi', checking response:
>         if (response == gdb_prompt) or (response == 'breakpoint hit'):
>                 proceed further
>         elseif (response == exited abnormally)
>                 test failure
>         elseif (response == exited normally)
>                 tests passed successfully
>         else
>                 tests failure
> -previous loop is constrained with timeout

Ok, so the idea is basically to single step the whole binary until the
program exits?  When you send a new version, I'll see if I can make the
expect code a bit nicer.  This is a bit arcane if you're not used to
tcl/expect/dejagnu.

Some more nits I found while reading the .c file from the test:

 - Indentation should be two spaces.
 - Return type of functions on its own line.
 - `(void)` instead of `()` for functions without parameters, in C.
 - main function is missing the return type.
 - stdio.h include appears to be unused (haven't really checked, but my
   editor says so)
 - use /* */ for comments, not //, wrapped at 80 columns ideally.
 - I think that comments at the right of the line are fine for very
   short comments like `/* BOVC */`, but longer comments should go on
   the previous line.
 - space before parenthesis in function calls (including asm() calls,
   they are not functions, but they kinda look like functions).  In
   theory, `xstr (...)` too.

Here's how you can format things so it fits the style:

int
test_r6_64 (void)
{
  volatile int err = 0;

  asm (".set push                                   \n\t"
       ".set noreorder                              \n\t"
       ".data                                       \n\t"
       "d0:   .dword 0                              \n\t"
       "dval: .dword 0xaa55bb66cc77dd88             \n\t"
       ...
       "move %[err], $11                            \n\t"
       ".set pop                                    \n\t"
       : [err] "+r" (err) /* outputs */
       :                  /* inputs */
       : "$3", "$4", "$5", "$6", "$7", "$8",
         "$9", "$10", "$11" /* clobbers */
  );

  return err;
}

Here, the "clobbers" line didn't really need to be wrapped, it would fit
on one line, but I broke it just to show how I would format it, if it
needed to be broken (other instances in the file have longer lines).

It's not the end of the world if the formatting isn't perfect, but those
guidelines should get you pretty close.

Finally, I built myself a mip64r6el buildroot image
(qemu_mips64r6el_malta_defconfig).  I'd really like to try to test it,
if only to learn and document how to run the testsuite against an
buildroot qemu image.  When I try to build the test file using the
cross-compiler, I get:

  $ mips64el-buildroot-linux-gnu-gcc -march=mips64r6 mips-64-r6.c
  mips-64-r6.c: In function ‘test_r6_fpu’:
  mips-64-r6.c:900:3: error: the register ‘$f6’ cannot be clobbered in ‘asm’ for the current target
    900 |   asm(
        |   ^~~

Is this expected?


>> /* * Any test_r6_* function returns non-zero => failure */ #define
>> EXPECT(X) if ((X)) abort ();
> 
> In inline asm, register $11 or [err] identifies instruction currently
> being tested.  If any instruction's output is wrong, program jumps to
> epilog saving non-zero exit status and signaling failure. If all
> instructions are tested and returned expected result, output register
> [err] is set to 0, signaling success.

Ack, thanks.

Simon
  
Milos Kalicanin Feb. 14, 2024, 2:49 p.m. UTC | #5
> Ok, so the idea is basically to single step the whole binary until the
program exits?
Essentialy.

> Some more nits I found while reading the .c file from the test: ...
I've sent a new update. Hope it's close enough now.

> Finally, I built myself a mip64r6el buildroot image
> (qemu_mips64r6el_malta_defconfig).  I'd really like to try to test it,
> if only to learn and document how to run the testsuite against an
> buildroot qemu image.  When I try to build the test file using the
> cross-compiler, I get:
>
> $ mips64el-buildroot-linux-gnu-gcc -march=mips64r6 mips-64-r6.c
> mips-64-r6.c: In function ‘test_r6_fpu’:
> mips-64-r6.c:900:3: error: the register ‘$f6’ cannot be clobbered in ‘asm’ for
> the current target
>    900 |   asm(
>        |   ^~~
>
> Is this expected?
This is the line I've been using to run tests:
$ DEJAGNU=$BUILD_DIR/binutils-gdb-build/gdb/testsuite/site.exp make check-gdb RUNTESTFLAGS=" CFLAGS_FOR_TARGET='-march=mips64r6 -mabi=64' --target_board=mips-sim-mti64_64" TESTS="gdb.arch/mips-64-r6.exp"

with target-triple == mips-img-elf and
target-alias == mips-img-elf

i.e. codescape's "mips-img-elf-gcc" baremetal compiler.

Did you verify that built test binary is release 6 ?
Some linker scripts have hardcoded release 2 so you may need to change it.

And is target built as -mhard-float ?

Eventually, I'll test with mips64el-buildroot-linux-gnu-gcc also and inform you in a few days.

Best Regards,
Milos
  

Patch

diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
index bf0b66c4b00..a60377f25e0 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -76,6 +76,9 @@  static int mips16_insn_at_pc_has_delay_slot (struct gdbarch *gdbarch,
 static void mips_print_float_info (struct gdbarch *, struct ui_file *,
 				   frame_info_ptr, const char *);
 
+static void mips_read_fp_register_single (struct frame_info_ptr, int,
+					  gdb_byte *);
+
 /* A useful bit in the CP0 status register (MIPS_PS_REGNUM).  */
 /* This bit is set if we are emulating 32-bit FPRs on a 64-bit chip.  */
 #define ST0_FR (1 << 26)
@@ -1500,6 +1503,16 @@  mips_fetch_instruction (struct gdbarch *gdbarch,
   return extract_unsigned_integer (buf, instlen, byte_order);
 }
 
+/* Return one if the gdbarch is based on MIPS Release 6.  */
+static int
+is_mipsr6_isa (struct gdbarch *gdbarch)
+{
+  const struct bfd_arch_info *info = gdbarch_bfd_arch_info (gdbarch);
+
+  return (info->mach == bfd_mach_mipsisa32r6
+	  || info->mach == bfd_mach_mipsisa64r6);
+}
+
 /* These are the fields of 32 bit mips instructions.  */
 #define mips32_op(x) (x >> 26)
 #define itype_op(x) (x >> 26)
@@ -1542,6 +1555,7 @@  mips_fetch_instruction (struct gdbarch *gdbarch,
 #define b0s11_op(x) ((x) & 0x7ff)
 #define b0s12_imm(x) ((x) & 0xfff)
 #define b0s16_imm(x) ((x) & 0xffff)
+#define b0s21_imm(x) ((x) & 0x1fffff)
 #define b0s26_imm(x) ((x) & 0x3ffffff)
 #define b6s10_ext(x) (((x) >> 6) & 0x3ff)
 #define b11s5_reg(x) (((x) >> 11) & 0x1f)
@@ -1578,6 +1592,18 @@  mips32_relative_offset (ULONGEST inst)
   return ((itype_immediate (inst) ^ 0x8000) - 0x8000) << 2;
 }
 
+static LONGEST
+mips32_relative_offset21 (ULONGEST insn)
+{
+  return ((b0s21_imm (insn) ^ 0x100000) - 0x100000) << 2;
+}
+
+static LONGEST
+mips32_relative_offset26 (ULONGEST insn)
+{
+  return ((b0s26_imm (insn) ^ 0x2000000) - 0x2000000) << 2;
+}
+
 /* Determine the address of the next instruction executed after the INST
    floating condition branch instruction at PC.  COUNT specifies the
    number of the floating condition bits tested by the branch.  */
@@ -1636,6 +1662,71 @@  is_octeon_bbit_op (int op, struct gdbarch *gdbarch)
   return 0;
 }
 
+static int
+is_add32bit_overflow (int32_t a, int32_t b)
+{
+  int32_t r = (uint32_t) a + (uint32_t) b;
+  return (a < 0 && b < 0 && r >= 0) || (a >= 0 && b >= 0 && r < 0);
+}
+
+static int
+is_add64bit_overflow (int64_t a, int64_t b)
+{
+  if (a != (int32_t)a)
+    return 1;
+  if (b != (int32_t)b)
+    return 1;
+  return is_add32bit_overflow ((int32_t)a, (int32_t)b);
+}
+
+/* Calculate address of next instruction after BLEZ.  */
+
+static CORE_ADDR
+mips32_blez_pc (struct gdbarch *gdbarch, struct regcache *regcache,
+		ULONGEST inst, CORE_ADDR pc, int invert)
+{
+  int rs = itype_rs (inst);
+  int rt = itype_rt (inst);
+  LONGEST val_rs = regcache_raw_get_signed (regcache, rs);
+  LONGEST val_rt = regcache_raw_get_signed (regcache, rt);
+  ULONGEST uval_rs = regcache_raw_get_unsigned (regcache, rs);
+  ULONGEST uval_rt = regcache_raw_get_unsigned (regcache, rt);
+  int taken = 0;
+  int delay_slot_size = 4;
+
+  /* BLEZ, BLEZL, BGTZ, BGTZL */
+  if (rt == 0)
+    taken = (val_rs <= 0);
+  else if (is_mipsr6_isa (gdbarch))
+    {
+      /* BLEZALC, BGTZALC */
+      if (rs == 0 && rt != 0)
+	taken = (val_rt <= 0);
+      /* BGEZALC, BLTZALC */
+      else if (rs == rt && rt != 0)
+	taken = (val_rt >= 0);
+      /* BGEUC, BLTUC */
+      else if (rs != rt && rs != 0 && rt != 0)
+	taken = (uval_rs >= uval_rt);
+
+      /* Step through the forbidden slot to avoid repeated exceptions we do
+	 not currently have access to the BD bit when hitting a breakpoint
+	 and therefore cannot tell if the breakpoint hit on the branch or the
+	 forbidden slot.  */
+      /* delay_slot_size = 0; */
+    }
+
+  if (invert)
+    taken = !taken;
+
+  /* Calculate branch target.  */
+  if (taken)
+    pc += mips32_relative_offset (inst);
+  else
+    pc += delay_slot_size;
+
+  return pc;
+}
 
 /* Determine where to set a single step breakpoint while considering
    branch prediction.  */
@@ -1646,12 +1737,17 @@  mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
   struct gdbarch *gdbarch = regcache->arch ();
   unsigned long inst;
   int op;
+  int mips64bitreg = 0;
+
+  if (mips_isa_regsize (gdbarch) == 8)
+    mips64bitreg = 1;
+
   inst = mips_fetch_instruction (gdbarch, ISA_MIPS, pc, NULL);
   op = itype_op (inst);
   if ((inst & 0xe0000000) != 0)		/* Not a special, jump or branch
 					   instruction.  */
     {
-      if (op >> 2 == 5)
+      if (op >> 2 == 5 && ((op & 0x02) == 0 || itype_rt (inst) == 0))
 	/* BEQL, BNEL, BLEZL, BGTZL: bits 0101xx */
 	{
 	  switch (op & 0x03)
@@ -1661,7 +1757,7 @@  mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
 	    case 1:		/* BNEL */
 	      goto neq_branch;
 	    case 2:		/* BLEZL */
-	      goto less_branch;
+	      goto lez_branch;
 	    case 3:		/* BGTZL */
 	      goto greater_branch;
 	    default:
@@ -1671,15 +1767,19 @@  mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
       else if (op == 17 && itype_rs (inst) == 8)
 	/* BC1F, BC1FL, BC1T, BC1TL: 010001 01000 */
 	pc = mips32_bc1_pc (gdbarch, regcache, inst, pc + 4, 1);
-      else if (op == 17 && itype_rs (inst) == 9
+      else if (!is_mipsr6_isa (gdbarch)
+	       && op == 17
+	       && itype_rs (inst) == 9
 	       && (itype_rt (inst) & 2) == 0)
 	/* BC1ANY2F, BC1ANY2T: 010001 01001 xxx0x */
 	pc = mips32_bc1_pc (gdbarch, regcache, inst, pc + 4, 2);
-      else if (op == 17 && itype_rs (inst) == 10
-	       && (itype_rt (inst) & 2) == 0)
+      else if (!is_mipsr6_isa (gdbarch)
+		&& op == 17
+		&& itype_rs (inst) == 10
+		&& (itype_rt (inst) & 2) == 0)
 	/* BC1ANY4F, BC1ANY4T: 010001 01010 xxx0x */
 	pc = mips32_bc1_pc (gdbarch, regcache, inst, pc + 4, 4);
-      else if (op == 29)
+      else if (!is_mipsr6_isa (gdbarch) && op == 29)
 	/* JALX: 011101 */
 	/* The new PC will be alternate mode.  */
 	{
@@ -1707,7 +1807,128 @@  mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
 	  else
 	    pc += 8;        /* After the delay slot.  */
 	}
+      else if (is_mipsr6_isa (gdbarch))
+	{
+	  /* BOVC, BEQZALC, BEQC and BNVC, BNEZALC, BNEC */
+	  if (op == 8 || op == 24)
+	    {
+	      int rs = rtype_rs (inst);
+	      int rt = rtype_rt (inst);
+	      LONGEST val_rs = regcache_raw_get_signed (regcache, rs);
+	      LONGEST val_rt = regcache_raw_get_signed (regcache, rt);
+	      int taken = 0;
+	      /* BOVC (BNVC) */
+	      if (rs >= rt)
+		{
+		  if (mips64bitreg == 1)
+		    taken = is_add64bit_overflow (val_rs, val_rt);
+		  else
+		    taken = is_add32bit_overflow (val_rs, val_rt);
+		}
+	      /* BEQZALC (BNEZALC) */
+	      else if (rs < rt && rs == 0)
+		taken = (val_rt == 0);
+	      /* BEQC (BNEC) */
+	      else
+		taken = (val_rs == val_rt);
+
+	      /* BNVC, BNEZALC, BNEC */
+	      if (op == 24)
+		taken = !taken;
 
+	      if (taken)
+		pc += mips32_relative_offset (inst) + 4;
+	      else
+		/* Step through the forbidden slot to avoid repeated exceptions
+		   we do not currently have access to the BD bit when hitting a
+		   breakpoint and therefore cannot tell if the breakpoint
+		   hit on the branch or the forbidden slot.  */
+		pc += 8;
+	    }
+	  /* BC1EQZ, BC1NEZ */
+	  else if (op == 17 && (itype_rs (inst) == 9 || itype_rs (inst) == 13))
+	    {
+	      gdb_byte status;
+	      gdb_byte true_val = 0;
+	      unsigned int fp = (gdbarch_num_regs (gdbarch)
+				 + mips_regnum (gdbarch)->fp0
+				 + itype_rt (inst));
+	      struct frame_info_ptr frame = get_current_frame ();
+	      gdb_byte *raw_buffer = (gdb_byte *) alloca (sizeof (gdb_byte) * 4);
+	      mips_read_fp_register_single (frame, fp, raw_buffer);
+
+	      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+		status = *(raw_buffer + 3);
+	      else
+		status = *(raw_buffer);
+
+	      if (itype_rs (inst) == 13)
+		true_val = 1;
+
+	      if ((status & 0x1) == true_val)
+		pc += mips32_relative_offset (inst) + 4;
+	      else
+		pc += 8;
+	    }
+	  else if (op == 22 || op == 23)
+	  /* BLEZC, BGEZC, BGEC, BGTZC, BLTZC, BLTC */
+	    {
+	      int rs = rtype_rs (inst);
+	      int rt = rtype_rt (inst);
+	      LONGEST val_rs = regcache_raw_get_signed (regcache, rs);
+	      LONGEST val_rt = regcache_raw_get_signed (regcache, rt);
+	      int taken = 0;
+	      /* The R5 rt == 0 case is handled above so we treat it as
+		 an unknown instruction here for future ISA usage.  */
+	      if (rs == 0 && rt != 0)
+		taken = (val_rt <= 0);
+	      else if (rs == rt && rt != 0)
+		taken = (val_rt >= 0);
+	      else if (rs != rt && rs != 0 && rt != 0)
+		taken = (val_rs >= val_rt);
+
+	      if (op == 23)
+		taken = !taken;
+
+	      if (taken)
+		pc += mips32_relative_offset (inst) + 4;
+	      else
+		/* Step through the forbidden slot to avoid repeated exceptions
+		   we do not currently have access to the BD bit when hitting a
+		   breakpoint and therefore cannot tell if the breakpoint
+		   hit on the branch or the forbidden slot.  */
+		pc += 8;
+	    }
+	  else if (op == 50 || op == 58)
+	  /* BC, BALC */
+	    pc += mips32_relative_offset26 (inst) + 4;
+	  else if ((op == 54 || op == 62)
+		   && rtype_rs (inst) == 0)
+	  /* JIC, JIALC */
+	    {
+	      pc = regcache_raw_get_signed (regcache, itype_rt (inst));
+	      pc += (itype_immediate (inst) ^ 0x8000) - 0x8000;
+	    }
+	  else if (op == 54 || op == 62)
+	  /* BEQZC, BNEZC */
+	    {
+	      int rs = itype_rs (inst);
+	      LONGEST rs_val = regcache_raw_get_signed (regcache, rs);
+	      int taken = (rs_val == 0);
+	      if (op == 62)
+		taken = !taken;
+	      if (taken)
+		pc += mips32_relative_offset21 (inst) + 4;
+	      else
+		/* Step through the forbidden slot to avoid repeated exceptions
+		   we do not currently have access to the BD bit when hitting a
+		   breakpoint and therefore cannot tell if the breakpoint
+		   hit on the branch or the forbidden slot.  */
+		pc += 8;
+	    }
+	  else
+	    pc += 4;		/* Not a branch, next instruction is easy.  */
+	}
       else
 	pc += 4;		/* Not a branch, next instruction is easy.  */
     }
@@ -1751,7 +1972,6 @@  mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
 	      case 2:		/* BLTZL */
 	      case 16:		/* BLTZAL */
 	      case 18:		/* BLTZALL */
-	      less_branch:
 		if (regcache_raw_get_signed (regcache, itype_rs (inst)) < 0)
 		  pc += mips32_relative_offset (inst) + 4;
 		else
@@ -1767,22 +1987,38 @@  mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
 		  pc += 8;	/* after the delay slot */
 		break;
 	      case 0x1c:	/* BPOSGE32 */
+	      case 0x1d:	/* BPOSGE32C */
 	      case 0x1e:	/* BPOSGE64 */
 		pc += 4;
 		if (itype_rs (inst) == 0)
 		  {
 		    unsigned int pos = (op & 2) ? 64 : 32;
 		    int dspctl = mips_regnum (gdbarch)->dspctl;
+		    int delay_slot_size = 4;
 
 		    if (dspctl == -1)
 		      /* No way to handle; it'll most likely trap anyway.  */
 		      break;
 
+		    /* BPOSGE32C */
+		    if (op == 0x1d)
+		      {
+			if (!is_mipsr6_isa (gdbarch))
+			  break;
+
+			/* Step through the forbidden slot to avoid repeated
+			   exceptions we do not currently have access to the BD
+			   bit when hitting a breakpoint and therefore cannot
+			   tell if the breakpoint hit on the branch or the
+			   forbidden slot.  */
+			/* delay_slot_size = 0; */
+		      }
+
 		    if ((regcache_raw_get_unsigned (regcache,
 						    dspctl) & 0x7f) >= pos)
 		      pc += mips32_relative_offset (inst);
 		    else
-		      pc += 4;
+		      pc += delay_slot_size;
 		  }
 		break;
 		/* All of the other instructions in the REGIMM category */
@@ -1816,19 +2052,14 @@  mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
 	  else
 	    pc += 8;
 	  break;
-	case 6:		/* BLEZ, BLEZL */
-	  if (regcache_raw_get_signed (regcache, itype_rs (inst)) <= 0)
-	    pc += mips32_relative_offset (inst) + 4;
-	  else
-	    pc += 8;
+	case 6:		/* BLEZ, BLEZL, BLEZALC, BGEZALC, BGEUC */
+	lez_branch:
+	  pc = mips32_blez_pc (gdbarch, regcache, inst, pc + 4, 0);
 	  break;
 	case 7:
 	default:
-	greater_branch:	/* BGTZ, BGTZL */
-	  if (regcache_raw_get_signed (regcache, itype_rs (inst)) > 0)
-	    pc += mips32_relative_offset (inst) + 4;
-	  else
-	    pc += 8;
+	greater_branch:	/* BGTZ, BGTZL, BGTZALC, BLTZALC, BLTUC */
+	  pc = mips32_blez_pc (gdbarch, regcache, inst, pc + 4, 1);
 	  break;
 	}			/* switch */
     }				/* else */
@@ -2451,6 +2682,72 @@  micromips_instruction_is_compact_branch (unsigned short insn)
     }
 }
 
+/* Return non-zero if the MIPS instruction INSN is a compact branch
+   or jump.  A value of 1 indicates an unconditional compact branch
+   and a value of 2 indicates a conditional compact branch.  */
+
+static int
+mips32_instruction_is_compact_branch (struct gdbarch *gdbarch, ULONGEST insn)
+{
+  switch (itype_op (insn))
+    {
+    /* BC */
+    case 50:
+    /* BALC */
+    case 58:
+      if (is_mipsr6_isa (gdbarch))
+	return 1;
+      break;
+    /* BOVC, BEQZALC, BEQC */
+    case 8:
+    /* BNVC, BNEZALC, BNEC */
+    case 24:
+      if (is_mipsr6_isa (gdbarch))
+	return 2;
+      break;
+    /* BEQZC, JIC */
+    case 54:
+    /* BNEZC, JIALC */
+    case 62:
+      if (is_mipsr6_isa (gdbarch))
+	/* JIC, JIALC are unconditional */
+	return (itype_rs (insn) == 0) ? 1 : 2;
+      break;
+    /* BLEZC, BGEZC, BGEC */
+    case 22:
+    /* BGTZC, BLTZC, BLTC */
+    case 23:
+    /* BLEZALC, BGEZALC, BGEUC */
+    case 6:
+    /* BGTZALC, BLTZALC, BLTUC */
+    case 7:
+      if (is_mipsr6_isa (gdbarch)
+	  && itype_rt (insn) != 0)
+	return 2;
+      break;
+    /* BPOSGE32C */
+    case 1:
+      if (is_mipsr6_isa (gdbarch)
+	  && itype_rt (insn) == 0x1d && itype_rs (insn) == 0)
+	return 2;
+    }
+  return 0;
+}
+
+/* Return non-zero if a standard MIPS instruction at ADDR has a branch
+   forbidden slot (i.e. it is a conditional compact branch instruction).  */
+
+static int
+mips32_insn_at_pc_has_forbidden_slot (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  int status;
+  ULONGEST insn = mips_fetch_instruction (gdbarch, ISA_MIPS, addr, &status);
+  if (status)
+    return 0;
+
+  return mips32_instruction_is_compact_branch (gdbarch, insn) == 2;
+}
+
 struct mips_frame_cache
 {
   CORE_ADDR base;
@@ -3494,7 +3791,8 @@  mips32_scan_prologue (struct gdbarch *gdbarch,
       reg = high_word & 0x1f;
 
       if (high_word == 0x27bd		/* addiu $sp,$sp,-i */
-	  || high_word == 0x23bd	/* addi $sp,$sp,-i */
+	  || (high_word == 0x23bd	/* addi $sp,$sp,-i */
+	      && !is_mipsr6_isa (gdbarch))
 	  || high_word == 0x67bd)	/* daddiu $sp,$sp,-i */
 	{
 	  if (offset < 0)		/* Negative stack adjustment?  */
@@ -3632,7 +3930,9 @@  mips32_scan_prologue (struct gdbarch *gdbarch,
 
       /* A jump or branch, or enough non-prologue insns seen?  If so,
 	 then we must have reached the end of the prologue by now.  */
-      if (prev_delay_slot || non_prologue_insns > 1)
+      if (prev_delay_slot
+	  || non_prologue_insns > 1
+	  || mips32_instruction_is_compact_branch (gdbarch, inst))
 	break;
 
       prev_non_prologue_insn = this_non_prologue_insn;
@@ -3938,6 +4238,59 @@  mips_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR addr)
 #define LLD_OPCODE 0x34
 #define SC_OPCODE 0x38
 #define SCD_OPCODE 0x3c
+#define LLSC_R6_OPCODE 0x1f
+#define LL_R6_FUNCT 0x36
+#define LLE_FUNCT 0x2e
+#define LLD_R6_FUNCT 0x37
+#define SC_R6_FUNCT 0x26
+#define SCE_FUNCT 0x1e
+#define SCD_R6_FUNCT 0x27
+
+static int
+is_ll_insn (struct gdbarch *gdbarch, ULONGEST insn)
+{
+  if (itype_op (insn) == LL_OPCODE
+      || itype_op (insn) == LLD_OPCODE)
+    return 1;
+
+  if (rtype_op (insn) == LLSC_R6_OPCODE
+      && rtype_funct (insn) == LLE_FUNCT
+      && (insn & 0x40) == 0)
+    return 1;
+
+  /* Handle LL and LLP varieties.  */
+  if (is_mipsr6_isa (gdbarch)
+      && rtype_op (insn) == LLSC_R6_OPCODE
+      && (rtype_funct (insn) == LL_R6_FUNCT
+	  || rtype_funct (insn) == LLD_R6_FUNCT
+	  || rtype_funct (insn) == LLE_FUNCT))
+    return 1;
+
+  return 0;
+}
+
+static int
+is_sc_insn (struct gdbarch *gdbarch, ULONGEST insn)
+{
+  if (itype_op (insn) == SC_OPCODE
+      || itype_op (insn) == SCD_OPCODE)
+    return 1;
+
+  if (rtype_op (insn) == LLSC_R6_OPCODE
+      && rtype_funct (insn) == SCE_FUNCT
+      && (insn & 0x40) == 0)
+    return 1;
+
+  /* Handle SC and SCP varieties.  */
+  if (is_mipsr6_isa (gdbarch)
+      && rtype_op (insn) == LLSC_R6_OPCODE
+      && (rtype_funct (insn) == SC_R6_FUNCT
+	  || rtype_funct (insn) == SCD_R6_FUNCT
+	  || rtype_funct (insn) == SCE_FUNCT))
+    return 1;
+
+  return 0;
+}
 
 static std::vector<CORE_ADDR>
 mips_deal_with_atomic_sequence (struct gdbarch *gdbarch, CORE_ADDR pc)
@@ -3950,10 +4303,11 @@  mips_deal_with_atomic_sequence (struct gdbarch *gdbarch, CORE_ADDR pc)
   int index;
   int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed).  */  
   const int atomic_sequence_length = 16; /* Instruction sequence length.  */
+  int is_mipsr6 = is_mipsr6_isa (gdbarch);
 
   insn = mips_fetch_instruction (gdbarch, ISA_MIPS, loc, NULL);
   /* Assume all atomic sequences start with a ll/lld instruction.  */
-  if (itype_op (insn) != LL_OPCODE && itype_op (insn) != LLD_OPCODE)
+  if (!is_ll_insn (gdbarch, insn))
     return {};
 
   /* Assume that no atomic sequence is longer than "atomic_sequence_length" 
@@ -3983,28 +4337,72 @@  mips_deal_with_atomic_sequence (struct gdbarch *gdbarch, CORE_ADDR pc)
 	  return {}; /* fallback to the standard single-step code.  */
 	case 4: /* BEQ */
 	case 5: /* BNE */
-	case 6: /* BLEZ */
-	case 7: /* BGTZ */
 	case 20: /* BEQL */
 	case 21: /* BNEL */
-	case 22: /* BLEZL */
-	case 23: /* BGTTL */
+	case 22: /* BLEZL (BLEZC, BGEZC, BGEC) */
+	case 23: /* BGTZL (BGTZC, BLTZC, BLTC) */
+	  is_branch = 1;
+	  break;
+	case 6: /* BLEZ (BLEZALC, BGEZALC, BGEUC) */
+	case 7: /* BGTZ (BGTZALC, BLTZALC, BLTUC) */
+	  if (is_mipsr6)
+	    {
+	      /* BLEZALC, BGTZALC */
+	      if (itype_rs (insn) == 0 && itype_rt (insn) != 0)
+		return {}; /* fallback to the standard single-step code.  */
+	      /* BGEZALC, BLTZALC */
+	      else if (itype_rs (insn) == itype_rt (insn)
+		       && itype_rt (insn) != 0)
+		return {}; /* fallback to the standard single-step code.  */
+	    }
 	  is_branch = 1;
 	  break;
+	case 8: /* BOVC, BEQZALC, BEQC */
+	case 24: /* BNVC, BNEZALC, BNEC */
+	  if (is_mipsr6)
+	    is_branch = 1;
+	  break;
+	case 50: /* BC */
+	case 58: /* BALC */
+	  if (is_mipsr6)
+	    return {}; /* fallback to the standard single-step code.  */
+	  break;
+	case 54: /* BEQZC, JIC */
+	case 62: /* BNEZC, JIALC */
+	  if (is_mipsr6)
+	    {
+	      if (itype_rs (insn) == 0) /* JIC, JIALC */
+		return {}; /* fallback to the standard single-step code.  */
+	      else
+		is_branch = 2; /* Marker for branches with a 21-bit offset.  */
+	    }
+	  break;
 	case 17: /* COP1 */
-	  is_branch = ((itype_rs (insn) == 9 || itype_rs (insn) == 10)
-		       && (itype_rt (insn) & 0x2) == 0);
-	  if (is_branch) /* BC1ANY2F, BC1ANY2T, BC1ANY4F, BC1ANY4T */
+	  is_branch = ((!is_mipsr6
+			/* BC1ANY2F, BC1ANY2T, BC1ANY4F, BC1ANY4T */
+			&& (itype_rs (insn) == 9 || itype_rs (insn) == 10)
+			&& (itype_rt (insn) & 0x2) == 0)
+		       /* BZ.df:  010001 110xx */
+		       || (itype_rs (insn) & 0x18) == 0x18);
+	  if (is_branch)
 	    break;
 	  [[fallthrough]];
 	case 18: /* COP2 */
 	case 19: /* COP3 */
-	  is_branch = (itype_rs (insn) == 8); /* BCzF, BCzFL, BCzT, BCzTL */
+	  /* BCzF, BCzFL, BCzT, BCzTL, BC*EQZ, BC*NEZ */
+	  is_branch = ((itype_rs (insn) == 8)
+		       || (is_mipsr6
+			   && (itype_rs (insn) == 9
+			       || itype_rs (insn) == 13)));
 	  break;
 	}
       if (is_branch)
 	{
-	  branch_bp = loc + mips32_relative_offset (insn) + 4;
+	  /* Is this a special PC21_S2 branch? */
+	  if (is_branch == 2)
+	    branch_bp = loc + mips32_relative_offset21 (insn) + 4;
+	  else
+	    branch_bp = loc + mips32_relative_offset (insn) + 4;
 	  if (last_breakpoint >= 1)
 	    return {}; /* More than one branch found, fallback to the
 			  standard single-step code.  */
@@ -4012,12 +4410,12 @@  mips_deal_with_atomic_sequence (struct gdbarch *gdbarch, CORE_ADDR pc)
 	  last_breakpoint++;
 	}
 
-      if (itype_op (insn) == SC_OPCODE || itype_op (insn) == SCD_OPCODE)
+      if (is_sc_insn (gdbarch, insn))
 	break;
     }
 
   /* Assume that the atomic sequence ends with a sc/scd instruction.  */
-  if (itype_op (insn) != SC_OPCODE && itype_op (insn) != SCD_OPCODE)
+  if (!is_sc_insn (gdbarch, insn))
     return {};
 
   loc += MIPS_INSN32_SIZE;
@@ -4242,8 +4640,14 @@  mips_about_to_return (struct gdbarch *gdbarch, CORE_ADDR pc)
   gdb_assert (mips_pc_is_mips (pc));
 
   insn = mips_fetch_instruction (gdbarch, ISA_MIPS, pc, NULL);
-  hint = 0x7c0;
-  return (insn & ~hint) == 0x3e00008;			/* jr(.hb) $ra */
+  /* Mask the hint and the jalr/jr bit.  */
+  hint = 0x7c1;
+
+  if (is_mipsr6_isa (gdbarch) && insn == 0xd81f0000) /* jrc $31 */
+    return 1;
+
+  /* jr(.hb) $ra and "jalr(.hb) $ra" */
+  return ((insn & ~hint) == 0x3e00008);
 }
 
 
@@ -6760,7 +7164,9 @@  mips32_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
 
 	  if (high_word != 0x27bd	/* addiu $sp,$sp,offset */
 	      && high_word != 0x67bd	/* daddiu $sp,$sp,offset */
-	      && inst != 0x03e00008	/* jr $ra */
+	      && (inst & ~0x1) != 0x03e00008 /* jr $31 or jalr $0, $31 */
+	      && (!is_mipsr6_isa (gdbarch)
+		  || inst != 0xd81f0000) /* jrc $31 */
 	      && inst != 0x00000000)	/* nop */
 	    return 0;
 	}
@@ -7139,22 +7545,31 @@  mips32_instruction_has_delay_slot (struct gdbarch *gdbarch, ULONGEST inst)
   int op;
   int rs;
   int rt;
+  int is_mipsr6 = is_mipsr6_isa (gdbarch);
 
   op = itype_op (inst);
   if ((inst & 0xe0000000) != 0)
     {
       rs = itype_rs (inst);
       rt = itype_rt (inst);
-      return (is_octeon_bbit_op (op, gdbarch) 
-	      || op >> 2 == 5	/* BEQL, BNEL, BLEZL, BGTZL: bits 0101xx  */
-	      || op == 29	/* JALX: bits 011101  */
+      return (is_octeon_bbit_op (op, gdbarch)
+	      || (op >> 1 == 10) /* BEQL, BNEL: bits 01010x  */
+	      || (op >> 1 == 11 && rt == 0) /* BLEZL, BGTZL: bits 01011x  */
+	      || (!is_mipsr6 && op == 29)	/* JALX: bits 011101  */
 	      || (op == 17
 		  && (rs == 8
 				/* BC1F, BC1FL, BC1T, BC1TL: 010001 01000  */
-		      || (rs == 9 && (rt & 0x2) == 0)
+		      || (!is_mipsr6 && rs == 9 && (rt & 0x2) == 0)
 				/* BC1ANY2F, BC1ANY2T: bits 010001 01001  */
-		      || (rs == 10 && (rt & 0x2) == 0))));
+		      || (!is_mipsr6 && rs == 10 && (rt & 0x2) == 0)))
 				/* BC1ANY4F, BC1ANY4T: bits 010001 01010  */
+	      || (is_mipsr6
+		  && ((op == 17
+		       && (rs == 9  /* BC1EQZ: 010001 01001  */
+			   || rs == 13))  /* BC1NEZ: 010001 01101  */
+		      || (op == 18
+			  && (rs == 9  /* BC2EQZ: 010010 01001  */
+			      || rs == 13)))));  /* BC2NEZ: 010010 01101  */
     }
   else
     switch (op & 0x07)		/* extract bits 28,27,26  */
@@ -7173,7 +7588,11 @@  mips32_instruction_has_delay_slot (struct gdbarch *gdbarch, ULONGEST inst)
 		|| ((rt & 0x1e) == 0x1c && rs == 0));
 				/* BPOSGE32, BPOSGE64: bits 1110x  */
 	break;			/* end REGIMM  */
-      default:			/* J, JAL, BEQ, BNE, BLEZ, BGTZ  */
+	case 6:			/* BLEZ  */
+	case 7:			/* BGTZ  */
+	 return (itype_rt (inst) == 0);
+	 break;
+      default:			/* J, JAL, BEQ, BNE  */
 	return 1;
 	break;
       }
@@ -7385,7 +7804,18 @@  mips_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
 
      So, we'll use the second solution.  To do this we need to know if
      the instruction we're trying to set the breakpoint on is in the
-     branch delay slot.  */
+     branch delay slot.
+
+     A similar problem occurs for breakpoints on forbidden slots where
+     the trap will be reported for the branch with the BD bit set.
+     In this case it would be ideal to recover using solution 1 from
+     above as there is no problem with the branch being skipped
+     (since the forbidden slot only exists on not-taken branches).
+     However, the BD bit is not available in all scenarios currently
+     so instead we move the breakpoint on to the next instruction.
+     This means that it is not possible to stop on an instruction
+     that can be in a forbidden slot even if that instruction is
+     jumped to directly.  */
 
   boundary = mips_segment_boundary (bpaddr);
 
@@ -7407,6 +7837,12 @@  mips_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
       prev_addr = bpaddr - 4;
       if (mips32_insn_at_pc_has_delay_slot (gdbarch, prev_addr))
 	bpaddr = prev_addr;
+      /* If the previous instruction has a forbidden slot, we have to
+	 move the breakpoint to the following instruction to prevent
+	 breakpoints in forbidden slots being reported as unknown
+	 traps.  */
+      else if (mips32_insn_at_pc_has_forbidden_slot (gdbarch, prev_addr))
+	bpaddr += 4;
     }
   else
     {
diff --git a/gdb/testsuite/gdb.arch/mips-64-r6.c b/gdb/testsuite/gdb.arch/mips-64-r6.c
new file mode 100644
index 00000000000..833274cef36
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/mips-64-r6.c
@@ -0,0 +1,1469 @@ 
+/*
+   Copyright 2006-2024 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 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.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+
+#define xstr(s) str(s)
+#define str(s) #s
+
+/* ============ macros from sim/testutils/mips/utils-r6.inc ============= */
+
+// 58 is local label to exit with errcode != 0
+#define fp_assert(a, b) "beq " xstr(a) ", " xstr(b) ", 1f \n\t" \
+			"nop \n\t" \
+			"b 58f \n\t" \
+			"nop \n\t" \
+			"1: \n\t"
+
+// Clobbers: $4,$6,$7
+#define r6ck_1r(inst, a, ret) \
+  "li $4, " xstr(a) "    \n\t" \
+  "li $6, " xstr(ret) "  \n\t" \
+  xstr(inst) " $7, $4    \n\t" \
+  fp_assert($6, $7)
+
+// Clobbers: $4,$6,$7
+#define r6ck_1dr(inst, a, ret) \
+  "ld $4, " xstr(a) "   \n\t" \
+  "ld $6, " xstr(ret) " \n\t" \
+  xstr(inst) " $7, $4   \n\t" \
+  fp_assert($6, $7)
+
+// Clobbers: $4,$5,$6,$7
+#define r6ck_2r(inst, a, b, ret) \
+  "li $4, " xstr(a) "   \n\t" \
+  "li $5, " xstr(b) "   \n\t" \
+  "li $6, " xstr(ret) " \n\t" \
+  xstr(inst) " $7, $4, $5   \n\t" \
+  fp_assert($6, $7)
+
+// Clobbers: $4,$5,$6,$7
+#define r6ck_2dr(inst, a, b, ret) \
+  "ld $4, " xstr(a) "    \n\t" \
+  "ld $5, " xstr(b) "    \n\t" \
+  "ld $6, " xstr(ret) "  \n\t" \
+  xstr(inst) " $7, $4, $5  \n\t" \
+  fp_assert($6, $7)
+
+// Clobbers: $4,$5,$6,$7
+#define r6ck_2dr1i(inst, a, b, imm, ret) \
+  "ld $4, " xstr(a) "      \n\t" \
+  "ld $5, " xstr(b) "      \n\t" \
+  "ld $6, " xstr(ret) "    \n\t" \
+  xstr(inst) " $7, $4, $5, " xstr(imm) "  \n\t" \
+  fp_assert($6, $7)
+
+// Clobbers: $4,$6,$7
+#define r6ck_1r1i(inst, a, imm, ret) \
+  "li $4, " xstr(a) "      \n\t" \
+  "li $6, " xstr(ret) "    \n\t" \
+  xstr(inst) " $7, $4, " xstr(imm) "  \n\t" \
+  fp_assert($6, $7)
+
+// Clobbers: $4,$6,$7
+#define r6ck_1dr1i(inst, a, imm, ret) \
+  "ld $4, " xstr(a) "     \n\t" \
+  "ld $6, " xstr(ret) "   \n\t" \
+  xstr(inst) " $7, $4, " xstr(imm) "  \n\t" \
+  fp_assert($6, $7)
+
+// Clobbers: $4,$6
+#define r6ck_0dr1i(inst, a, imm, ret) \
+  "ld $4, " xstr(a) "     \n\t" \
+  "ld $6, " xstr(ret) "   \n\t" \
+  xstr(inst) " $4, $4, " xstr(imm) "   \n\t" \
+  fp_assert($6, $4)
+
+// Clobbers: $4,$5,$6,$7
+#define r6ck_2r1i(inst, a, b, imm, ret) \
+  "li $4, " xstr(a) "     \n\t" \
+  "li $5, " xstr(b) "     \n\t" \
+  "li $6, " xstr(ret) "   \n\t" \
+  xstr(inst) " $7, $4, $5, " xstr(imm) "   \n\t" \
+  fp_assert($6, $7)
+
+// Clobbers: $4,$5,$6,$7,$8,$f2,$f4,$f6
+#define r6ck_3s(inst, a, b, c, ret) \
+  "li $4, " xstr(a) "     \n\t" \
+  "li $5, " xstr(b) "     \n\t" \
+  "li $6, " xstr(c) "     \n\t" \
+  "li $7, " xstr(ret) "   \n\t" \
+  "mtc1 $4, $f2           \n\t" \
+  "mtc1 $5, $f4           \n\t" \
+  "mtc1 $6, $f6           \n\t" \
+  xstr(inst) " $f2, $f4, $f6       \n\t" \
+  "mfc1 $8, $f2           \n\t" \
+  fp_assert($7, $8)
+
+// Clobbers: $4,$5,$6,$7,$f2,$f4
+#define r6ck_2s(inst, a, b, ret) \
+  "li $4, " xstr(a) "       \n\t" \
+  "li $5, " xstr(b) "       \n\t" \
+  "li $6, " xstr(ret) "     \n\t" \
+  "mtc1 $4, $f2             \n\t" \
+  "mtc1 $5, $f4             \n\t" \
+  xstr(inst) " $f2, $f4     \n\t" \
+  "mfc1 $7, $f2             \n\t" \
+  fp_assert($6, $7)
+
+// Clobbers: $4,$5,$6,$7,$8,$9,$10,$f2,$f4
+#define r6ck_2d(inst, a, b, ret) \
+  ".data                  \n\t" \
+"1: .dword " xstr(a) "    \n\t" \
+"2: .dword " xstr(b) "    \n\t" \
+"3: .dword " xstr(ret) "  \n\t" \
+" .text                   \n\t" \
+  "la $4, 1b              \n\t" \
+  "la $5, 2b              \n\t" \
+  "la $6, 3b              \n\t" \
+  "ldc1 $f2, 0($4)        \n\t" \
+  "ldc1 $f4, 0($5)        \n\t" \
+  "lw $7, 0($6)           \n\t" \
+  "lw $8, 4($6)           \n\t" \
+  xstr(inst) " $f2, $f4   \n\t" \
+  "mfhc1 $9, $f2          \n\t" \
+  "mfc1 $10, $f2          \n\t" \
+  fp_assert($7, $9) \
+  fp_assert($8, $10)
+
+// Clobbers: $2,$4,$5,$6,$7,$8,$9,$10,$f2,$f4,$f6
+#define r6ck_3d(inst, a, b, c, ret) \
+  ".data                                \n\t" \
+"1: .dword " xstr(a) "                  \n\t" \
+"2: .dword " xstr(b) "                  \n\t" \
+"3: .dword " xstr(c) "                  \n\t" \
+"4: .dword " xstr(ret) "                \n\t" \
+  ".text                                \n\t" \
+  "la $4, 1b                            \n\t" \
+  "la $5, 2b                            \n\t" \
+  "la $6, 3b                            \n\t" \
+  "la $2, 4b                            \n\t" \
+  "ldc1 $f2, 0($4)                      \n\t" \
+  "ldc1 $f4, 0($5)                      \n\t" \
+  "ldc1 $f6, 0($6)                      \n\t" \
+  "lw $7, 0($2)                         \n\t" \
+  "lw $8, 4($2)                         \n\t" \
+  xstr(inst) " $f2, $f4, $f6            \n\t" \
+  "mfhc1 $9, $f2                        \n\t" \
+  "mfc1 $10, $f2                        \n\t" \
+  fp_assert($7, $9) \
+  fp_assert($8, $10)
+
+
+/* ============ macros from sim/testutils/mips/testutils.inc ============= */
+
+/* Put value 'val' into register 'reg'
+ * Clobbers: None                              */
+#define load32(reg, val) \
+	"li	" xstr(reg) ", " xstr(val) "     \n\t"
+
+/* Check whether two registers contain the same value
+ *  Clobbers: None                                     */
+#define checkreg(reg, expreg) \
+	".set push         \n\t" \
+	".set noat         \n\t" \
+	".set noreorder    \n\t" \
+	"beq "	xstr(expreg) ", " xstr(reg) ", 901f    \n\t" \
+	"nop               \n\t" \
+	"b 58f              \n\t" \
+	"nop                \n\t" \
+"901:                   \n\t" \
+	".set pop           \n\t"
+
+/* Check if register 'reg' contains value 'val'.
+ * Clobbers: $1                                  */
+#define check32(reg, val) \
+	".set push         \n\t" \
+	".set noat         \n\t" \
+	load32($1, val) \
+	checkreg(reg, $1) \
+	".set pop          \n\t"
+
+/* Checkpair based on endianess
+ * Clobbers: $1                 */
+#define checkpair_xendian(lo, hi, base, ec, w) \
+	".set noat               \n\t" \
+	"lw   $1, " xstr(ec) "   \n\t" \
+	"andi $1, $1, 0x1        \n\t" \
+	"beqz  $1, 2f            \n\t" \
+	".set at                 \n\t" \
+"1:                          \n\t" \
+	checkpair_be_##w(lo, hi, base) \
+	"b 3f                    \n\t" \
+	"nop                     \n\t" \
+"2:                          \n\t" \
+	checkpair_le_##w(lo, hi, base) \
+"3:                          \n\t"
+
+/*
+    checkpair_xendian($2, $3, test_data_2, end_check_2, d)
+=
+"lw $1, end_check_2  \n\t"
+"andi $1, $1, 0x1    \n\t"
+"beqz $1, 2f         \n\t"
+"1:                  \n\t"
+checkpair_be_d($2, $3, test_data_2) = checkpair($2, $3, test_data_2, w, 4, 0)
+"b 3f                \n\t"
+"nop                 \n\t"
+"2:                  \n\t"
+checkpair_le_d($2, $3, test_data_2) = checkpair($2, $3, test_data_2, w, 0, 4)
+"3:                  \n\t"
+*/
+
+/* Check hi-lo register pair against data stored at base+o1 and base+o2
+ * Clobbers: $1 - $5                              */
+#define	checkpair(lo, hi, base, w, o1, o2) \
+	"move  $2, " xstr(lo) "   \n\t" \
+	"move  $3, " xstr(hi) "   \n\t" \
+	".set noat                \n\t" \
+	"la   $1, " xstr(base) "  \n\t" \
+	"l" xstr(w) " $4, " xstr(o1) "($1)  \n\t" \
+	"l" xstr(w)	" $5, " xstr(o2) "($1)  \n\t" \
+	".set at                  \n\t" \
+	checkreg($2, $4) \
+	checkreg($3, $5)
+
+#define checkpair_le_d(lo, hi, base) \
+	checkpair(lo, hi, base, w, 0, 4)
+
+#define checkpair_be_d(lo, hi, base) \
+  checkpair(lo, hi, base, w, 4, 0)
+
+
+#define checkpair_le_q(lo, hi, base) \
+  checkpair(lo, hi, base, d, 0, 8)
+
+#define checkpair_be_q(lo, hi, base) \
+  checkpair(lo, hi, base, d, 8, 0)
+
+#define checkpair_qword(lo, hi, base, oe) \
+	checkpair_xendian(lo, hi, base, oe, q)
+
+#define checkpair_dword(lo, hi, base, oe) \
+	checkpair_xendian(lo, hi, base, oe, d)
+
+void abort (void);
+
+
+int test_r6_branch()
+{
+    // using volatile to prevent certain optimizations which could cause instruction deletion
+    volatile int err = -1; // identifies instruction which caused error. (err == 0) ==> all instructions executed successfully
+
+    volatile int a14 = 0xffffffff; // the other variables are bound to registers
+    volatile int a13 = 0x123;
+    volatile int a12 = 0x45;
+    volatile int a7 = 0x45;
+    volatile int a8 = 0xfffffffe;
+    volatile int a9 = 2147483647;
+    volatile int a11 = 0;
+    volatile int a10 = 0;
+    asm (
+    ".set push                     \n\t" // create new scope for asm configuration
+    ".set noreorder                \n\t" // don't allow reordering of instructions
+    "li %[err], 1                  \n\t"
+    "bovc %[a12], %[a13], Lfail    \n\t" // BOVC
+    "nop                           \n\t"
+    "bovc %[a9], %[a13], L2        \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L2:                           \n\t"
+    "li %[err], 2                  \n\t"
+    "bnvc %[a9], %[a13], Lfail     \n\t" // BNVC
+    "nop                           \n\t"
+    "bnvc %[a12], %[a13], L3       \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L3:                           \n\t"
+    "li %[err], 3                  \n\t"
+    "beqc %[a12], %[a13], Lfail    \n\t" // BEQC
+    "nop                           \n\t"
+    "beqc %[a12], %[a7], L4        \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L4:                           \n\t"
+    "li %[err], 4                  \n\t"
+    "bnec %[a12], %[a7], Lfail     \n\t" // BNEC
+    "nop                           \n\t"
+    "bnec %[a12], %[a13], L5       \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L5:                           \n\t"
+    "li %[err], 5                  \n\t"
+    "bltc %[a13], %[a12], Lfail    \n\t" // BLTC
+    "nop                           \n\t"
+    "bltc %[a12], %[a13], L6       \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L6:                           \n\t"
+    "L7:                           \n\t"
+    "li %[err], 7                  \n\t"
+    "bgec %[a12], %[a13], Lfail    \n\t" // BGEC
+    "nop                           \n\t"
+    "bgec %[a13], %[a12], L8       \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L8:                           \n\t"
+    "L9:                           \n\t"
+    "li %[err], 9                  \n\t"
+    "bltuc %[a14], %[a13], Lfail   \n\t" // BLTUC
+    "nop                           \n\t"
+    "bltuc %[a8], %[a14], L10      \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L10:                          \n\t"
+    "L11:                          \n\t"
+    "li %[err], 11                 \n\t"
+    "bgeuc %[a13], %[a14], Lfail   \n\t" // BGEUC
+    "nop                           \n\t"
+    "bgeuc %[a14], %[a8], L12      \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L12:                          \n\t"
+    "L13:                          \n\t"
+    "li %[err], 13                 \n\t"
+    "bltzc %[a13], Lfail           \n\t" // BLTZC
+    "nop                           \n\t"
+    "bltzc %[a11], Lfail           \n\t"
+    "nop                           \n\t"
+    "bltzc %[a14], L14             \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L14:                          \n\t"
+    "li %[err], 14                 \n\t"
+    "blezc %[a13], Lfail           \n\t" // BLEZC
+    "nop                           \n\t"
+    "blezc %[a11], L145            \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L145:                         \n\t"
+    "blezc %[a14], L15             \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L15:                          \n\t"
+    "li %[err], 15                 \n\t"
+    "bgezc %[a8], Lfail            \n\t" // BGEZC
+    "nop                           \n\t"
+    "bgezc %[a11], L155            \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L155:                         \n\t"
+    "bgezc %[a13], L16             \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L16:                          \n\t"
+    "li %[err], 16                 \n\t"
+    "bgtzc %[a8], Lfail            \n\t" // BGTZC
+    "nop                           \n\t"
+    "bgtzc %[a11], Lfail           \n\t"
+    "nop                           \n\t"
+    "bgtzc %[a13], L17             \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "li %[a10], 0                  \n\t"
+    "L17:                          \n\t"
+    "li %[err], 17                 \n\t"
+    "blezalc %[a12], Lfail         \n\t" // BLEZALC
+    "nop                           \n\t"
+    "blezalc %[a11], Lret          \n\t"
+    "li %[a10], 1                  \n\t"
+    "beqzc %[a10], L175            \n\t" // BEQZC
+    "nop                           \n\t"
+    "li %[err], 8531               \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L175:                         \n\t"
+    "li %[err], 23531              \n\t"
+    "blezalc %[a14], Lret          \n\t"
+    "li %[a10], 1                  \n\t"
+    "beqzc %[a10], L18             \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L18:                          \n\t"
+    "li %[err], 18                 \n\t"
+    "bgezalc %[a14], Lfail         \n\t" // BGEZALC
+    "nop                           \n\t"
+    "bgezalc %[a11], Lret          \n\t"
+    "li %[a10], 1                  \n\t"
+    "beqzc %[a10], L185            \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L185:                         \n\t"
+    "bgezalc %[a12], Lret          \n\t"
+    "li %[a10], 1                  \n\t"
+    "beqzc %[a10], L19             \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L19:                          \n\t"
+    "li %[err], 19                 \n\t"
+    "bgtzalc %[a14], Lfail         \n\t" // BGTZALC
+    "nop                           \n\t"
+    "bgtzalc %[a11], Lfail         \n\t"
+    "nop                           \n\t"
+    "bgtzalc %[a12], Lret          \n\t"
+    "li %[a10], 1                  \n\t"
+    "beqzc %[a10], L20             \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L20:                          \n\t"
+    "li %[err], 20                 \n\t"
+    "bltzalc %[a12], Lfail         \n\t" // BLTZALC
+    "nop                           \n\t"
+    "bltzalc %[a11], Lfail         \n\t"
+    "nop                           \n\t"
+    "bltzalc %[a14], Lret          \n\t"
+    "li %[a10], 1                  \n\t"
+    "beqzc %[a10], L21             \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L21:                          \n\t"
+    "li %[err], 21                 \n\t"
+    "bc L22                        \n\t" // BC
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L22:                          \n\t"
+    "li %[err], 22                 \n\t"
+    "balc Lret                     \n\t" // BALC
+    "li %[a10], 1                  \n\t"
+    "beqzc %[a10], L23             \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L23:                          \n\t"
+    "li %[err], 23                 \n\t"
+    "jal GetPC                     \n\t" // JAL
+    "nop                           \n\t"
+    "jic $6, 4                     \n\t" // JIC
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L24:                          \n\t"
+    "li %[err], 24                 \n\t"
+    "li %[a10], 1                  \n\t"
+    "jal GetPC                     \n\t"
+    "nop                           \n\t"
+    "jialc $6, 20                  \n\t" // JIALC
+    "nop                           \n\t"
+    "beqzc %[a10], L25             \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "LJIALCRET:                    \n\t"
+    "li %[a10], 0                  \n\t"
+    "jr $31                        \n\t" // JR
+    "nop                           \n\t"
+    "L25:                          \n\t"
+    "li %[err], 25                 \n\t"
+    "jal GetPC                     \n\t"
+    "nop                           \n\t"
+    "move %[a11], $6               \n\t"
+    "nal                           \n\t"
+    "nop                           \n\t"
+    "addiu %[a11], 12              \n\t" // ADDIU
+    "beqc %[a11], $31, L26         \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "L26:                          \n\t"
+    "li %[err], 26                 \n\t"
+    "balc Lret                     \n\t"
+    "li %[a10], 1                  \n\t"
+    "beqzc %[a10], Lend            \n\t"
+    "nop                           \n\t"
+    "b Lfail                       \n\t"
+    "nop                           \n\t"
+    "Lret:                         \n\t"
+    "li %[a10], 0                  \n\t"
+    "daddiu $31, 4                 \n\t" // DADDIU
+    "jrc $31                       \n\t" // JRC
+    "nop                           \n\t"
+    "GetPC:                        \n\t"
+    "move $6, $31                  \n\t"
+    "jr $31                        \n\t"
+    "Lend:                         \n\t"
+    "li %[err], 0                  \n\t"
+    "Lfail:                        \n\t"
+    ".set pop                      \n\t" // restore previous config
+    : [err] "+r"(err), [a14] "+r"(a14), [a13] "+r"(a13), [a12] "+r"(a12),
+    [a7] "+r"(a7), [a8] "+r"(a8), [a9] "+r"(a9), [a10] "+r"(a10), [a11] "+r"(a11)
+    : // inputs
+    : "$31", "$6" // clobbers
+
+    );
+
+    return err;
+
+}
+
+int test_r6_forbidden()
+{
+    volatile int err = -1;
+    volatile int a4 = 0;
+    volatile int a2 = 0;
+    volatile int a1 = 0;
+
+    asm(
+    ".set push                         \n\t"
+    ".set noreorder                    \n\t"
+    "li %[err], 1                      \n\t" // Test if FS is ignored when branch is taken
+    "li %[a4], 0                       \n\t"
+    "beqzalc %[a4], L41                \n\t"
+    "li %[err], -85                    \n\t"
+    "L42:                              \n\t"
+    "b Lfail2                          \n\t"
+    "nop                               \n\t"
+    "L41:                              \n\t"
+    "blez %[err], Lfail2               \n\t"
+    "li %[err], 2                      \n\t" // Test if FS is used when branch is not taken
+    "li %[a4], 1                       \n\t"
+    "blezc %[a4], L43                  \n\t"
+    "addiu %[a4], %[a4], 1             \n\t"
+    "li %[a2], 2                       \n\t"
+    "beq %[a4], %[a2], L44             \n\t"
+    "nop                               \n\t"
+    "L43:                              \n\t"
+    "nop                               \n\t"
+    "b Lfail2                          \n\t"
+    "nop                               \n\t"
+    "L44:                              \n\t"
+    "li %[err], 3                      \n\t" // Test if FS causes an error when it contains a branch
+    "li %[a4], 3                       \n\t"
+    "beqzalc %[a4], Lfail2             \n\t"
+    "nop                               \n\t" // Note: bc L45 here causes Segmentation Fault: Illegal instruction which is OK.
+    "b Lend2                           \n\t"
+    "nop                               \n\t"
+    "L45:                              \n\t"
+    "nop                               \n\t"
+    "b Lfail2                          \n\t"
+    "nop                               \n\t"
+    "Lend2:                            \n\t"
+    "li %[err], 0                      \n\t"
+    "Lfail2:                           \n\t"
+    "nop                               \n\t"
+    ".set pop                          \n\t"
+
+      : [err] "+r" (err), [a4] "+r"(a4), [a2] "+r"(a2), [a1] "+r"(a1) // outputs
+      : // inputs
+      : "$31" // clobbers
+    );
+
+    return err;
+}
+
+int test_r6_64()
+{
+  volatile int err = 0;
+
+  asm(
+    ".set push                                   \n\t"
+    ".set noreorder                              \n\t"
+    ".data                                       \n\t"
+    "d0:   .dword 0                              \n\t"
+    "dval: .dword 0xaa55bb66cc77dd88             \n\t"
+    "d1:   .dword 0xaaaabbbbccccdddd             \n\t"
+    "d2:   .dword 256                            \n\t"
+    "dlo:  .dword 0xaabbbbccccdddd00             \n\t"
+    "dhi:  .dword 0xffffffffffffffaa             \n\t"
+    "dhiu: .dword 0x00000000000000aa             \n\t"
+    "d3:   .dword 0xffaaaabbbbccccde             \n\t"
+    "d4:   .dword 0xffffffffffffffdd             \n\t"
+    "d5:   .dword 0x00000000000000dd             \n\t"
+    "d6:   .dword 0x00aaaabbbbccccdd             \n\t"
+    "d7:   .dword 0xeeeeffff00001111             \n\t"
+    "d8:   .dword 0xbbccccddddeeeeff             \n\t"
+    "d9:   .dword 0x000000ddaaaabbbb             \n\t"
+    "d10:  .dword 0x5555dddd3333bbbb             \n\t"
+    "d11:  .dword 0x9999999999999999             \n\t"
+    "d12:  .dword 56                             \n\t"
+    "d13:  .dword 8                              \n\t"
+    "d14:  .dword 57                             \n\t"
+    "d15:  .dword 0x000000ddaaaac98b             \n\t"
+    "d16:  .dword 0xffffffffdead00dd             \n\t"
+    "d17:  .dword 0xffffffffc0de0000             \n\t"
+    "d18:  .dword 0x0000123400000000             \n\t"
+    "d19:  .dword 0xffffabcddead00dd             \n\t"
+    "d20:  .dword 0xc0de000000000000             \n\t"
+    "d21:  .dword 0x8000abcddead00dd             \n\t"
+    "dmask:.dword 0xffffffffffff0000             \n\t"
+    "dval1: .word 0x1234abcd                     \n\t"
+    "dval2: .word 0xffee0000                     \n\t"
+    "dval3: .dword 0xffffffffffffffff            \n\t"
+    "  .fill 240,1,0                             \n\t"
+    "dval4: .dword 0x5555555555555555            \n\t"
+    "  .fill  264,1,0                            \n\t"
+    "dval5: .dword 0xaaaaaaaaaaaaaaaa            \n\t"
+
+    // Register $11 stores instruction currently being tested and hence identifies error if it occurs
+    ".text                                       \n\t"
+    "li $11, 1                                   \n\t" // Test DMUL
+    r6ck_2r(dmul, 6, 5, 30)
+    r6ck_2r(dmul, -7, 9, -63)
+    r6ck_2r(dmul, -1, 1, -1)
+    r6ck_2dr(dmul, d1, d2, dlo)
+
+    "li $11, 2                                   \n\t" // Test DMUH
+    r6ck_2r(dmuh, 6, 5, 0)
+    r6ck_2r(dmuh, -7, 9, 0xffffffffffffffff)
+    r6ck_2r(dmuh, -1, 1, -1)
+    r6ck_2dr(dmuh, d1, d2, dhi)
+
+    "li $11, 3                                   \n\t" // Test DMULU
+    r6ck_2r(dmulu, 12, 10, 120)
+    r6ck_2r(dmulu, -1, 1, -1)
+    r6ck_2dr(dmulu, d1, d2, dlo)
+
+    "li $11, 4                                   \n\t" // Test DMUHU
+    r6ck_2r(dmuhu, 12, 10, 0)
+    r6ck_2r(dmuhu, -1, 1, 0)
+    r6ck_2dr(dmuhu, d1, d2, dhiu)
+
+    "li $11, 5                                   \n\t" // Test DDIV
+    r6ck_2r(ddiv, 10001, 10, 1000)
+    r6ck_2r(ddiv, -123456, 560, -220)
+    r6ck_2dr(ddiv, d1, d2, d3)
+
+    "li $11, 6                                   \n\t" // Test DMOD
+    r6ck_2r(dmod, 10001, 10, 1)
+    r6ck_2r(dmod, -123456, 560, 0xffffffffffffff00)
+    r6ck_2dr(dmod, d1, d2, d4)
+
+    "li $11, 7                                   \n\t" // Test DDIVU
+    r6ck_2r(ddivu, 9, 100, 0)
+    r6ck_2dr(ddivu, d1, d2, d6)
+
+    "li $11, 8                                   \n\t" // Test DMODU
+    r6ck_2r(dmodu, 9, 100, 9)
+    r6ck_2dr(dmodu, d1, d2, d5)
+
+    "li $11, 9                                   \n\t" // Test DALIGN
+    r6ck_2dr1i(dalign, d7, d1, 3, d8)
+    r6ck_2dr1i(dalign, d1, d5, 4, d9)
+
+    "li $11, 10                                  \n\t" // Test DBITSWAP
+    r6ck_1dr(dbitswap, d1, d10)
+    r6ck_1dr(dbitswap, d11, d11)
+
+    "li $11, 11                                  \n\t" // Test DCLZ
+    r6ck_1dr(dclz, d5, d12)
+    r6ck_1dr(dclz, d6, d13)
+
+    "li $11, 12                                  \n\t" // Test DCLO
+    r6ck_1dr(dclo, d5, d0)
+    r6ck_1dr(dclo, dhi, d14)
+
+    "li $11, 13                                  \n\t" // Test DLSA
+    r6ck_2r1i(dlsa, 0x82, 0x2000068, 4, 0x2000888)
+    r6ck_2dr1i(dlsa, d5, d9, 4, d15)
+
+    "li $11, 14                                  \n\t" // Test DAUI
+    r6ck_1dr1i(daui, d5, 0xdead, d16)
+    r6ck_1dr1i(daui, d0, 0xc0de, d17)
+
+    "li $11, 15                                  \n\t" // Test DAHI
+    r6ck_0dr1i(dahi, d0, 0x1234, d18)
+    r6ck_0dr1i(dahi, d16, 0xabce, d19)
+
+    "li $11, 16                                  \n\t" // Test DATI
+    r6ck_0dr1i(dati, d0, 0xc0de, d20)
+    r6ck_0dr1i(dati, d19, 0x8001, d21)
+
+    "li $11, 17                                  \n\t" // Test LDPC
+    "ld $5, dval                                 \n\t"
+    "nop                                         \n\t"
+    "ldpc $4, dval                               \n\t"
+    fp_assert($4, $5)
+
+    "li $11, 18                                  \n\t" // Test LWUPC
+    "lwu $5, dval1                               \n\t"
+    "lwupc $4, dval1                             \n\t"
+    fp_assert($4, $5)
+    "lwu $5, dval2                               \n\t"
+    "lwupc $4, dval2                             \n\t"
+    fp_assert($4, $5)
+
+    "li $11, 19                                  \n\t" // Test LLD
+    "ld $5, dval3                                \n\t"
+    "dla $3, dval4                               \n\t"
+    "lld $4, -248($3)                            \n\t"
+    fp_assert($4, $5)
+
+    "li $11, 20                                  \n\t" // Test SCD
+    "lld $4, -248($3)                            \n\t"
+    "dli $4, 0xafaf                              \n\t"
+    "scd $4, -248($3)                            \n\t"
+    "ld $5, dval3                                \n\t"
+    "dli $4, 0xafaf                              \n\t"
+    fp_assert($4, $5)
+
+    "Lend3:                                      \n\t"
+    "li $11, 0                                   \n\t"
+    "58:                                         \n\t"
+    "move %[err], $11                            \n\t"
+    ".set pop                                    \n\t"
+     : [err] "+r" (err) // outputs
+     :                  // inputs
+     : "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11" // clobbers
+  );
+
+  return err;
+}
+
+int test_r6()
+{
+  volatile int err = 0;
+
+  asm(
+  ".set push                                                   \n\t"
+  ".set noreorder                                              \n\t"
+  ".data                                                       \n\t"
+  "dval_1:  .word 0xabcd1234                                   \n\t"
+  "dval_2: .word 0x1234eeff                                    \n\t"
+  ".fill 248,1,0                                               \n\t"
+  "dval_3: .word 0x55555555                                    \n\t"
+  ".fill  260,1,0                                              \n\t"
+  "dval_4: .word 0xaaaaaaaa                                    \n\t"
+  ".text                                                       \n\t"
+  "li $11, 1                                                   \n\t" // Test MUL
+  r6ck_2r(mul, 7, 9, 63)
+  r6ck_2r(mul, -7, -9, 63)
+  r6ck_2r(mul, 61, -11, -671)
+  r6ck_2r(mul, 1001, 1234, 1235234)
+  r6ck_2r(mul, 123456789, 999999, 0x7eb1e22b)
+  r6ck_2r(mul, 0xaaaabbbb, 0xccccdddd, 0x56787f6f)
+  "li $11, 2                                                   \n\t" // Test MUH
+  r6ck_2r(muh, 61, -11, 0xffffffff)
+  r6ck_2r(muh, 1001, 1234, 0)
+  r6ck_2r(muh, 123456789, 999999, 0x7048)
+  r6ck_2r(muh, 0xaaaabbbb, 0xccccdddd, 0x111107f7)
+  "li $11, 3                                                   \n\t" // Test MULU
+  r6ck_2r(mulu, 7, 9, 63)
+  r6ck_2r(mulu, -7, -9, 63)
+  r6ck_2r(mulu, 61, -11, -671)
+  r6ck_2r(mulu, 1001, 1234, 1235234)
+  r6ck_2r(mulu, 123456789, 999999, 0x7eb1e22b)
+  r6ck_2r(mulu, 0xaaaabbbb, 0xccccdddd, 0x56787f6f)
+  "li $11, 4                                                   \n\t" // Test MUHU
+  r6ck_2r(muhu, 1001, 1234, 0)
+  r6ck_2r(muhu, 123456789, 999999, 0x7048)
+  r6ck_2r(muhu, 0xaaaabbbb, 0xccccdddd, 0x8888a18f)
+  r6ck_2r(muhu, 0xaaaabbbb, 0xccccdddd, 0x8888a18f)
+  "li $11, 5                                                   \n\t" // Test DIV
+  r6ck_2r(div, 10001, 10, 1000)
+  r6ck_2r(div, -123456, 560, -220)
+  r6ck_2r(div, 9, 100, 0)
+  "li $11, 6                                                   \n\t" // Test MOD
+  r6ck_2r(mod, 10001, 10, 1)
+  r6ck_2r(mod, -123456, 560, 0xffffff00)
+  r6ck_2r(mod, 9, 100, 9)
+  "li $11, 7                                                   \n\t" // Test DIVU
+  r6ck_2r(divu, 10001, 10, 1000)
+  r6ck_2r(divu, -123456, 560, 0x750674)
+  r6ck_2r(divu, 9, 100, 0)
+  r6ck_2r(divu, 0xaaaabbbb, 3, 0x38e393e9)
+  "li $11, 8                                                   \n\t" // Test MODU
+  r6ck_2r(modu, 10001, 10, 1)
+  r6ck_2r(modu, -123456, 560, 0)
+  r6ck_2r(modu, 9, 100, 9)
+  r6ck_2r(modu, 0xaaaabbbb, 5, 4)
+  "li $11, 9                                                   \n\t" // Test LSA
+  r6ck_2r1i(lsa, 1, 2, 2, 6)
+  r6ck_2r1i(lsa, 0x8000, 0xa000, 1, 0x1a000)
+  r6ck_2r1i(lsa, 0x82, 0x2000068, 4, 0x2000888)
+  "li $11, 10                                                   \n\t" // Test AUI
+  r6ck_1r1i(aui, 0x0000c0de, 0xdead, 0xdeadc0de)
+  r6ck_1r1i(aui, 0x00005678, 0x1234, 0x12345678)
+  r6ck_1r1i(aui, 0x0000eeff, 0xabab, 0xababeeff)
+  "li $11, 11                                                   \n\t" // Test SELEQZ
+  r6ck_2r(seleqz, 0x1234, 0, 0x1234)
+  r6ck_2r(seleqz, 0x1234, 4, 0)
+  r6ck_2r(seleqz, 0x80010001, 0, 0x80010001)
+  "li $11, 12                                                   \n\t" // Test SELNEZ
+  r6ck_2r(selnez, 0x1234, 0, 0)
+  r6ck_2r(selnez, 0x1234, 1, 0x1234)
+  r6ck_2r(selnez, 0x80010001, 0xffffffff, 0x80010001)
+  "li $11, 13                                                   \n\t" // Test ALIGN
+  r6ck_2r1i(align, 0xaabbccdd, 0xeeff0011, 1, 0xff0011aa)
+  r6ck_2r1i(align, 0xaabbccdd, 0xeeff0011, 3, 0x11aabbcc)
+  "li $11, 14                                                   \n\t" // Test BITSWAP
+  r6ck_1r(bitswap, 0xaabbccdd, 0x55dd33bb)
+  r6ck_1r(bitswap, 0x11884422, 0x88112244)
+  "li $11, 15                                                   \n\t" // Test CLZ
+  r6ck_1r(clz, 0x00012340, 15)
+  r6ck_1r(clz, 0x80012340, 0)
+  r6ck_1r(clz, 0x40012340, 1)
+  "li $11, 16                                                   \n\t" // Test CLO
+  r6ck_1r(clo, 0x00123050, 0)
+  r6ck_1r(clo, 0xff123050, 8)
+  r6ck_1r(clo, 0x8f123050, 1)
+  "li $11, 17                                                \n\t" // Test ADDIUPC
+  //fp_assert($4, $11)  //   ==== VERIFY: all good till this line. GetPC_2 call may cause issues =======
+  "jal GetPC_2                                               \n\t"
+  "nop                                                       \n\t"
+  "addiu $4, $6, 8                                           \n\t"
+  "addiupc $5, 4                                             \n\t"
+  fp_assert($4, $5)
+  "li $11, 18                                                \n\t" // Test AUIPC
+  "jal GetPC_2                                               \n\t"
+  "nop                                                       \n\t"
+  "addiu $4, $6, 8                                           \n\t"
+  "aui $4, $4, 8                                             \n\t"
+  "auipc $5, 8                                               \n\t"
+  fp_assert($4, $5)
+  "li $11, 19                                                \n\t" // Test ALUIPC
+  "jal GetPC_2                                               \n\t"
+  "nop                                                       \n\t"
+  "addiu $4, $6, 16                                          \n\t"
+  "aui $4, $4, 8                                             \n\t"
+  "li $7, 0xffff0000                                         \n\t"
+  "and $4, $4, $7                                            \n\t"
+  "aluipc $5, 8                                              \n\t"
+  fp_assert($4, $5)
+  "li $11, 20                                                \n\t" // Test LWPC
+  "lw $5, dval_1                                             \n\t"
+  "lwpc $4, dval_1                                           \n\t"
+  fp_assert($4, $5)
+  "lw $5, dval_2                                             \n\t"
+  "lwpc $4, dval_2                                           \n\t"
+  fp_assert($4, $5)
+  "li $11, 21                                                \n\t" // Test LL !! NOTE: May be redundant LL because SC already contains LL in its test
+  "lw $5, dval_2                                             \n\t"
+  "dla $3, dval_3                                            \n\t" // ammendment: 'la' -> 'dla' to load 64-bit address
+  "ll $4, -252($3)                                           \n\t"
+  fp_assert($4, $5)
+  "li $11, 22                                                \n\t" // Test SC
+  "ll $4, -252($3)                                           \n\t"
+  "li $4, 0xafaf                                             \n\t"
+  "sc $4, -252($3)                                           \n\t"
+  "lw $5, dval_2                                             \n\t"
+  "li $4, 0xafaf                                             \n\t"
+  fp_assert($4, $5)
+  "b Lend4                                                   \n\t"
+  "nop                                                       \n\t"
+  "GetPC_2:                                                  \n\t"
+  "move $6, $31                                              \n\t"
+  "jr $31                                                    \n\t"
+  "Lend4:                                                    \n\t"
+  "li $11, 0                                                 \n\t"
+  "58:                                                       \n\t"
+  "move %[err], $11                                          \n\t"
+  ".set pop                                                  \n\t"
+  : [err] "+r"(err)  // outputs
+  : // inputs
+  : "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$31"     // clobbers
+  );
+
+  return err;
+}
+
+
+// **bc1eq/eqz are enough
+
+int test_r6_fpu()
+{
+  volatile int err = 0;
+
+  asm(
+  ".set push                               \n\t"
+  ".set noreorder                          \n\t"
+  "li $11, 1                               \n\t" // Test qNaN format is 754-2008"
+  "li $4, 0x0                              \n\t"
+  "li $5, 0x0                              \n\t"
+  "li $6, 0x7fc00000                       \n\t"
+  "mtc1 $4, $f2                            \n\t"
+  "mtc1 $5, $f4                            \n\t"
+  "div.s $f6, $f2, $f4                     \n\t"
+  "mfc1 $8, $f6                            \n\t"
+  fp_assert($6, $8)
+  "li $11, 2                               \n\t"    // Test maddf.s
+  r6ck_3s(maddf.s, 0x0, 0x0, 0x0, 0x0)
+  r6ck_3s(maddf.s, 0x3f800000, 0x3f800000, 0x3f800000, 0x40000000)
+  r6ck_3s(maddf.s, 0xc0b1f5c3, 0x40490fd0, 0x402df854, 0x403e9f5d)
+
+  "li $11, 3                               \n\t"    // Test maddf.d
+  r6ck_3d(maddf.d, 0x0, 0x0, 0x0, 0x0)
+  r6ck_3d(maddf.d, 0x3ff0000000000000, 0x3ff0000000000000, 0x3ff0000000000000, 0x4000000000000000)
+  r6ck_3d(maddf.d, 0xc0163eb851eb851f, 0x400921f9f01b866e, 0x4005bf0a8b24919b,  0x4007d3ebc14f6cee)
+
+  "li $11, 4                               \n\t"    // Test msubf.s
+  r6ck_3s(msubf.s, 0x0, 0x0, 0x0, 0x0)
+  r6ck_3s(msubf.s, 0x3f800000, 0x3f800000, 0x3f800000, 0x0)
+  r6ck_3s(msubf.s, 0xc0b1f5c3, 0x40490fd0, 0x402df854, 0xc1619d9a)
+
+  "li $11, 5                               \n\t"    // Test msubf.d
+  r6ck_3d(msubf.d, 0x0, 0x0, 0x0, 0x0)
+  r6ck_3d(msubf.d, 0x3ff0000000000000, 0x3ff0000000000000, 0x3ff0000000000000, 0x0)
+  r6ck_3d(msubf.d, 0xc0163eb851eb851f, 0x400921f9f01b866e, 0x4005bf0a8b24919b,  0xc02c33b3423f605b)
+
+  "li $11, 6                               \n\t"    // Test cmp.af.s
+  r6ck_3s(cmp.af.s, 0x0, 0x3f800000, 0x3f800000, 0x0)
+  r6ck_3s(cmp.af.s, 0x0, 0x00000000, 0x3f800000, 0x0)
+
+  "li $11, 7                               \n\t"    // Test cmp.af.d
+  r6ck_3d(cmp.af.d, 0x0, 0x3ff0000000000000, 0x3ff0000000000000, 0x0)
+  r6ck_3d(cmp.af.d, 0x0, 0x0000000000000000, 0x3ff0000000000000, 0x0)
+
+  "li $11, 8                               \n\t"    // Test cmp.eq.s
+  r6ck_3s(cmp.eq.s, 0x0, 0x3f800000, 0x3f800000, 0xffffffff)
+  r6ck_3s(cmp.eq.s, 0x0, 0x00000000, 0x3f800000, 0x0)
+  r6ck_3s(cmp.eq.s, 0x0, 0x80000000, 0x00000000, 0xffffffff)
+  r6ck_3s(cmp.eq.s, 0x0, 0x7fc00000, 0x7fc00000, 0x0)
+  r6ck_3s(cmp.eq.s, 0x0, 0x7fc00000, 0xffc00000, 0x0)
+  r6ck_3s(cmp.eq.s, 0x0, 0x7fa00000, 0x7fa00000, 0x0)
+  r6ck_3s(cmp.eq.s, 0x0, 0x7fa00000, 0x7fc00000, 0x0)
+  r6ck_3s(cmp.eq.s, 0x0, 0x7f800000, 0x7f800000, 0xffffffff)
+  r6ck_3s(cmp.eq.s, 0x0, 0xff800000, 0xff800000, 0xffffffff)
+
+  "li $11, 9                               \n\t"    // Test cmp.eq.d
+  r6ck_3d(cmp.eq.d, 0x0, 0x3ff0000000000000, 0x3ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.eq.d, 0x0, 0x0000000000000000, 0x3ff0000000000000, 0x0)
+  r6ck_3d(cmp.eq.d, 0x0, 0x8000000000000000, 0x0000000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.eq.d, 0x0, 0x7ff8000000000000, 0x7ff8000000000000, 0x0)
+  r6ck_3d(cmp.eq.d, 0x0, 0x7ff8000000000000, 0xffc0000000000000, 0x0)
+  r6ck_3d(cmp.eq.d, 0x0, 0x7fa0000000000000, 0x7fa0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.eq.d, 0x0, 0x7fa0000000000000, 0x7ff8000000000000, 0x0)
+  r6ck_3d(cmp.eq.d, 0x0, 0x7ff0000000000000, 0x7ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.eq.d, 0x0, 0xfff0000000000000, 0xfff0000000000000, 0xffffffffffffffff)
+
+  "li $11, 10                               \n\t"    // Test cmp.ne.s
+  r6ck_3s(cmp.ne.s, 0x0, 0x3f800000, 0x3f800000, 0x0)
+  r6ck_3s(cmp.ne.s, 0x0, 0x00000000, 0x3f800000, 0xffffffff)
+  r6ck_3s(cmp.ne.s, 0x0, 0x80000000, 0x00000000, 0x0)
+  r6ck_3s(cmp.ne.s, 0x0, 0x7fc00000, 0x7fc00000, 0x0)
+  r6ck_3s(cmp.ne.s, 0x0, 0x7fc00000, 0xffc00000, 0x0)
+  r6ck_3s(cmp.ne.s, 0x0, 0x7fa00000, 0x7fa00000, 0x0)
+  r6ck_3s(cmp.ne.s, 0x0, 0x7fa00000, 0x7fc00000, 0x0)
+  r6ck_3s(cmp.ne.s, 0x0, 0x7f800000, 0x7f800000, 0x0)
+  r6ck_3s(cmp.ne.s, 0x0, 0xff800000, 0xff800000, 0x0)
+
+  "li $11, 11                               \n\t"    // Test cmp.ne.d
+  r6ck_3d(cmp.ne.d, 0x0, 0x3ff0000000000000, 0x3ff0000000000000, 0x0)
+  r6ck_3d(cmp.ne.d, 0x0, 0x0000000000000000, 0x3ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.ne.d, 0x0, 0x8000000000000000, 0x0000000000000000, 0x0)
+  r6ck_3d(cmp.ne.d, 0x0, 0x7ff8000000000000, 0x7ff8000000000000, 0x0)
+  r6ck_3d(cmp.ne.d, 0x0, 0x7ff8000000000000, 0xffc0000000000000, 0x0)
+  r6ck_3d(cmp.ne.d, 0x0, 0x7fa0000000000000, 0x7fa0000000000000, 0x0)
+  r6ck_3d(cmp.ne.d, 0x0, 0x7fa0000000000000, 0x7ff8000000000000, 0x0)
+  r6ck_3d(cmp.ne.d, 0x0, 0x7ff0000000000000, 0x7ff0000000000000, 0x0)
+  r6ck_3d(cmp.ne.d, 0x0, 0xfff0000000000000, 0xfff0000000000000, 0x0)
+  r6ck_3d(cmp.ne.d, 0x0, 0xab19546120965720, 0x92452014f194abc3, 0xffffffffffffffff)
+
+  "li $11, 12                               \n\t"    // Test cmp.lt.s
+  r6ck_3s(cmp.lt.s, 0x0, 0x3f800000, 0x3f800000, 0x0)
+  r6ck_3s(cmp.lt.s, 0x0, 0x00000000, 0x3f800000, 0xffffffff)
+  r6ck_3s(cmp.lt.s, 0x0, 0xbf800000, 0x3f800000, 0xffffffff)
+  r6ck_3s(cmp.lt.s, 0x0, 0x3f800000, 0xbf800000, 0x0)
+  r6ck_3s(cmp.lt.s, 0x0, 0xff800000, 0xbf800000, 0xffffffff)
+  r6ck_3s(cmp.lt.s, 0x0, 0xbf800000, 0x7f800000, 0xffffffff)
+  r6ck_3s(cmp.lt.s, 0x0, 0xbf800000, 0xff800000, 0x0)
+  r6ck_3s(cmp.lt.s, 0x0, 0x7f800000, 0xbf800000, 0x0)
+
+  "li $11, 13                               \n\t"    // Test cmp.lt.d
+  r6ck_3d(cmp.lt.d, 0x0, 0x3ff0000000000000, 0x3ff0000000000000, 0x0)
+  r6ck_3d(cmp.lt.d, 0x0, 0x0000000000000000, 0x3ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.lt.d, 0x0, 0xbff0000000000000, 0x3ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.lt.d, 0x0, 0x3ff0000000000000, 0xbff0000000000000, 0x0)
+  r6ck_3d(cmp.lt.d, 0x0, 0xfff0000000000000, 0xbff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.lt.d, 0x0, 0xbff0000000000000, 0x7ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.lt.d, 0x0, 0xbff0000000000000, 0xfff0000000000000, 0x0)
+  r6ck_3d(cmp.lt.d, 0x0, 0x7ff0000000000000, 0xbff0000000000000, 0x0)
+
+  "li $11, 14                               \n\t"    // Test cmp.le.s
+  r6ck_3s(cmp.le.s, 0x0, 0x3f800000, 0x3f800000, 0xffffffff)
+  r6ck_3s(cmp.le.s, 0x0, 0x00000000, 0x3f800000, 0xffffffff)
+  r6ck_3s(cmp.le.s, 0x0, 0xbf800000, 0x3f800000, 0xffffffff)
+  r6ck_3s(cmp.le.s, 0x0, 0x3f800000, 0xbf800000, 0x0)
+  r6ck_3s(cmp.le.s, 0x0, 0xff800000, 0xbf800000, 0xffffffff)
+  r6ck_3s(cmp.le.s, 0x0, 0xbf800000, 0x7f800000, 0xffffffff)
+  r6ck_3s(cmp.le.s, 0x0, 0xbf800000, 0xff800000, 0x0)
+  r6ck_3s(cmp.le.s, 0x0, 0x7f800000, 0xbf800000, 0x0)
+
+  "li $11, 15                               \n\t"    // Test cmp.le.d
+  r6ck_3d(cmp.le.d, 0x0, 0x3ff0000000000000, 0x3ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.le.d, 0x0, 0x0000000000000000, 0x3ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.le.d, 0x0, 0xbff0000000000000, 0x3ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.le.d, 0x0, 0x3ff0000000000000, 0xbff0000000000000, 0x0)
+  r6ck_3d(cmp.le.d, 0x0, 0xfff0000000000000, 0xbff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.le.d, 0x0, 0xbff0000000000000, 0x7ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.le.d, 0x0, 0xbff0000000000000, 0xfff0000000000000, 0x0)
+  r6ck_3d(cmp.le.d, 0x0, 0x7ff0000000000000, 0xbff0000000000000, 0x0)
+
+  "li $11, 16                               \n\t"    // Test cmp.un.s
+  r6ck_3s(cmp.un.s, 0x0, 0x3f800000, 0x3f800000, 0x0)
+  r6ck_3s(cmp.un.s, 0x0, 0x3f800000, 0xbf800000, 0x0)
+  r6ck_3s(cmp.un.s, 0x0, 0x3f800000, 0x7fc00000, 0xffffffff)
+  r6ck_3s(cmp.un.s, 0x0, 0x7fc01234, 0x7fc00000, 0xffffffff)
+  r6ck_3s(cmp.un.s, 0x0, 0x7fc00000, 0x7fc00000, 0xffffffff)
+  r6ck_3s(cmp.un.s, 0x0, 0x3f800000, 0xff800000, 0x0)
+  r6ck_3s(cmp.un.s, 0x0, 0x3f800000, 0x7f800000, 0x0)
+
+  "li $11, 17                               \n\t"    // Test cmp.un.d
+  r6ck_3d(cmp.un.d, 0x0, 0x3ff0000000000000, 0x3ff0000000000000, 0x0)
+  r6ck_3d(cmp.un.d, 0x0, 0x3ff0000000000000, 0xbff0000000000000, 0x0)
+  r6ck_3d(cmp.un.d, 0x0, 0x3ff0000000000000, 0x7ff8000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.un.d, 0x0, 0x7fc0123400000000, 0x7ff8000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.un.d, 0x0, 0x7ff8000000000000, 0x7ff8000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.un.d, 0x0, 0x3ff0000000000000, 0xfff0000000000000, 0x0)
+  r6ck_3d(cmp.un.d, 0x0, 0x3ff0000000000000, 0x7ff0000000000000, 0x0)
+
+  "li $11, 18                               \n\t"    // Test cmp.or.s
+  r6ck_3s(cmp.or.s, 0x0, 0x3f800000, 0x3f800000, 0xffffffff)
+  r6ck_3s(cmp.or.s, 0x0, 0xbf800000, 0x3f800000, 0xffffffff)
+  r6ck_3s(cmp.or.s, 0x0, 0x3f800000, 0x7fc00000, 0x0)
+  r6ck_3s(cmp.or.s, 0x0, 0x7fc00000, 0x3f800000, 0x0)
+  r6ck_3s(cmp.or.s, 0x0, 0xffc00000, 0x3f800000, 0x0)
+  r6ck_3s(cmp.or.s, 0x0, 0x7fc01234, 0x7fc00000, 0x0)
+  r6ck_3s(cmp.or.s, 0x0, 0xff800000, 0x00000000, 0xffffffff)
+  r6ck_3s(cmp.or.s, 0x0, 0x00000000, 0x7f800000, 0xffffffff)
+  r6ck_3s(cmp.or.s, 0x0, 0x00000000, 0xff800000, 0xffffffff)
+  r6ck_3s(cmp.or.s, 0x0, 0x7f800000, 0x00000000, 0xffffffff)
+  r6ck_3s(cmp.or.s, 0x0, 0x7f800000, 0x00000000, 0xffffffff)
+
+  "li $11, 19                               \n\t"    // Test cmp.or.d
+  r6ck_3d(cmp.or.d, 0x0, 0x3ff0000000000000, 0x3ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.or.d, 0x0, 0xbff0000000000000, 0x3ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.or.d, 0x0, 0x3ff0000000000000, 0x7ff8000000000000, 0x0)
+  r6ck_3d(cmp.or.d, 0x0, 0x7ff8000000000000, 0x3ff0000000000000, 0x0)
+  r6ck_3d(cmp.or.d, 0x0, 0xfff8000000000000, 0x3ff0000000000000, 0x0)
+  r6ck_3d(cmp.or.d, 0x0, 0x7ff8123492134352, 0x7ff8000000000000, 0x0)
+  r6ck_3d(cmp.or.d, 0x0, 0xfff0000000000000, 0x0000000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.or.d, 0x0, 0x0000000000000000, 0x7ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.or.d, 0x0, 0x0000000000000000, 0xfff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.or.d, 0x0, 0x7ff0000000000000, 0x0000000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.or.d, 0x0, 0x7ff0000000000000, 0x0000000000000000, 0xffffffffffffffff)
+
+  "li $11, 20                               \n\t"    // Test cmp.ueq.s
+  r6ck_3s(cmp.ueq.s, 0x0, 0x3f800000, 0x00000000, 0x0)
+  r6ck_3s(cmp.ueq.s, 0x0, 0x3f800000, 0x7fc00000, 0xffffffff)
+  r6ck_3s(cmp.ueq.s, 0x0, 0x7fc00000, 0x7fc00000, 0xffffffff)
+  r6ck_3s(cmp.ueq.s, 0x0, 0x3f800000, 0x3f800000, 0xffffffff)
+  r6ck_3s(cmp.ueq.s, 0x0, 0x00000000, 0x3f800000, 0x0)
+  r6ck_3s(cmp.ueq.s, 0x0, 0x80000000, 0x00000000, 0xffffffff)
+  r6ck_3s(cmp.ueq.s, 0x0, 0x7f800000, 0x7fc00000, 0xffffffff)
+  r6ck_3s(cmp.ueq.s, 0x0, 0xff800000, 0xff800000, 0xffffffff)
+
+  "li $11, 21                               \n\t"    // Test cmp.ueq.d
+  r6ck_3d(cmp.ueq.d, 0x0, 0x3ff0000000000000, 0x0000000000000000, 0x0)
+  r6ck_3d(cmp.ueq.d, 0x0, 0x3ff0000000000000, 0x7ff8000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.ueq.d, 0x0, 0x7ff8000000000000, 0x7ff8000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.ueq.d, 0x0, 0x3ff0000000000000, 0x3ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.ueq.d, 0x0, 0x0000000000000000, 0x3ff0000000000000, 0x0)
+  r6ck_3d(cmp.ueq.d, 0x0, 0x8000000000000000, 0x0000000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.ueq.d, 0x0, 0x7ff0000000000000, 0x7ff8000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.ueq.d, 0x0, 0xfff0000000000000, 0xfff0000000000000, 0xffffffffffffffff)
+
+  "li $11, 22                               \n\t"    // Test cmp.une.s
+  r6ck_3s(cmp.une.s, 0x0, 0x3f800000, 0x3f800000, 0x0)
+  r6ck_3s(cmp.une.s, 0x0, 0x3f800000, 0x7fc00000, 0xffffffff)
+  r6ck_3s(cmp.une.s, 0x0, 0x7fc00000, 0x7fc00000, 0xffffffff)
+  r6ck_3s(cmp.une.s, 0x0, 0x3f800000, 0x3f800000, 0x0)
+  r6ck_3s(cmp.une.s, 0x0, 0x00000000, 0x3f800000, 0xffffffff)
+  r6ck_3s(cmp.une.s, 0x0, 0x80000000, 0x00000000, 0x0)
+  r6ck_3s(cmp.une.s, 0x0, 0x7f800000, 0x7fc00000, 0xffffffff)
+  r6ck_3s(cmp.une.s, 0x0, 0xff800000, 0xff800000, 0x0)
+
+  "li $11, 23                               \n\t"    // Test cmp.une.d
+  r6ck_3d(cmp.une.d, 0x0, 0x3ff0000000000000, 0x3ff0000000000000, 0x0)
+  r6ck_3d(cmp.une.d, 0x0, 0x3ff0000000000000, 0x7ff8000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.une.d, 0x0, 0x7ff8000000000000, 0x7ff8000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.une.d, 0x0, 0x3ff0000000000000, 0x3ff0000000000000, 0x0)
+  r6ck_3d(cmp.une.d, 0x0, 0x0000000000000000, 0x3ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.une.d, 0x0, 0x8000000000000000, 0x0000000000000000, 0x0)
+  r6ck_3d(cmp.une.d, 0x0, 0x7ff0000000000000, 0x7ff8000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.une.d, 0x0, 0xfff0000000000000, 0xfff0000000000000, 0x0)
+
+  "li $11, 24                               \n\t"    // Test cmp.ult.s
+  r6ck_3s(cmp.ult.s, 0x0, 0x3f800000, 0x3f800000, 0x0)
+  r6ck_3s(cmp.ult.s, 0x0, 0x3f800000, 0x7fc00000, 0xffffffff)
+  r6ck_3s(cmp.ult.s, 0x0, 0x7fc00000, 0x7fc00000, 0xffffffff)
+  r6ck_3s(cmp.ult.s, 0x0, 0x00000000, 0x3f800000, 0xffffffff)
+  r6ck_3s(cmp.ult.s, 0x0, 0xbf800000, 0x3f800000, 0xffffffff)
+  r6ck_3s(cmp.ult.s, 0x0, 0x3f800000, 0xbf800000, 0x0)
+
+  "li $11, 25                               \n\t"    // Test cmp.ult.d
+  r6ck_3d(cmp.ult.d, 0x0, 0x3ff0000000000000, 0x3ff0000000000000, 0x0)
+  r6ck_3d(cmp.ult.d, 0x0, 0x3ff0000000000000, 0x7ff8000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.ult.d, 0x0, 0x7ff8000000000000, 0x7ff8000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.ult.d, 0x0, 0x0000000000000000, 0x3ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.ult.d, 0x0, 0xbff0000000000000, 0x3ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.ult.d, 0x0, 0x3ff0000000000000, 0xbff0000000000000, 0x0)
+
+  "li $11, 26                               \n\t"    // Test cmp.ule.s
+  r6ck_3s(cmp.ule.s, 0x0, 0x3f800000, 0x7fc00000, 0xffffffff)
+  r6ck_3s(cmp.ule.s, 0x0, 0x7fc00000, 0x7fc00000, 0xffffffff)
+  r6ck_3s(cmp.ule.s, 0x0, 0x3f800000, 0x3f800000, 0xffffffff)
+  r6ck_3s(cmp.ule.s, 0x0, 0x00000000, 0x3f800000, 0xffffffff)
+  r6ck_3s(cmp.ule.s, 0x0, 0xbf800000, 0x3f800000, 0xffffffff)
+  r6ck_3s(cmp.ule.s, 0x0, 0x3f800000, 0xbf800000, 0x0)
+  r6ck_3s(cmp.ule.s, 0x0, 0x3f800000, 0xff800000, 0x0)
+
+  "li $11, 27                               \n\t"    // Test cmp.ule.d
+  r6ck_3d(cmp.ule.d, 0x0, 0x3ff0000000000000, 0x7ff8000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.ule.d, 0x0, 0x7ff8000000000000, 0x7ff8000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.ule.d, 0x0, 0x3ff0000000000000, 0x3ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.ule.d, 0x0, 0x0000000000000000, 0x3ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.ule.d, 0x0, 0xbff0000000000000, 0x3ff0000000000000, 0xffffffffffffffff)
+  r6ck_3d(cmp.ule.d, 0x0, 0x3ff0000000000000, 0xbff0000000000000, 0x0)
+  r6ck_3d(cmp.ule.d, 0x0, 0x3ff0000000000000, 0xfff0000000000000, 0x0)
+
+  "li $11, 281                               \n\t"    // Test rint.s
+  r6ck_2s(rint.s, 0x0, 0x3fbf10cb, 0x3f800000)
+  "li $11, 282                               \n\t"    // Test rint.s
+  r6ck_2s(rint.s, 0x0, 0xb9011423, 0x0)
+  "li $11, 283                               \n\t"    // Test rint.s
+  r6ck_2s(rint.s, 0x0, 0x43fa4687, 0x43fa8000)
+  "li $11, 284                               \n\t"    // Test rint.s
+  r6ck_2s(rint.s, 0x0, 0x41380000, 0x41400000)
+  "li $11, 285                               \n\t"    // Test rint.s
+  r6ck_2s(rint.s, 0x0, 0x3ff33333, 0x40000000)
+
+  "li $11, 291                              \n\t"    // Test rint.d
+  r6ck_2d(rint.d, 0x0, 0x3ff1f9a6b50b0f28, 0x3ff0000000000000)
+  "li $11, 292                              \n\t"    // Test rint.d
+  r6ck_2d(rint.d, 0x0, 0xbf543bf727136a40, 0x0)
+  "li $11, 293                              \n\t"    // Test rint.d
+  r6ck_2d(rint.d, 0x0, 0x407f48d0e5604189, 0x407f500000000000)
+  "li $11, 294                              \n\t"    // Test rint.d
+  r6ck_2d(rint.d, 0x0, 0x5b7c2d43b93b0a8c, 0x5b7c2d43b93b0a8c)
+
+  "li $11, 30                               \n\t"    // Test class.s
+  r6ck_2s(class.s, 0x0, 0x7f800010, 0x1)
+  r6ck_2s(class.s, 0x0, 0x7fc00000, 0x2)
+  r6ck_2s(class.s, 0x0, 0xff800000, 0x4)
+  r6ck_2s(class.s, 0x0, 0xbf800000, 0x8)
+  r6ck_2s(class.s, 0x0, 0x80000001, 0x10)
+  r6ck_2s(class.s, 0x0, 0x80000000, 0x20)
+  r6ck_2s(class.s, 0x0, 0x7f800000, 0x40)
+  r6ck_2s(class.s, 0x0, 0x3f800000, 0x80)
+  r6ck_2s(class.s, 0x0, 0x00000001, 0x100)
+  r6ck_2s(class.s, 0x0, 0x00000000, 0x200)
+
+  "li $11, 31                               \n\t"    // Test class.d
+  r6ck_2d(class.d, 0x0, 0x7ff0000000000010, 0x1)
+  r6ck_2d(class.d, 0x0, 0x7ff8000000000000, 0x2)
+  r6ck_2d(class.d, 0x0, 0xfff0000000000000, 0x4)
+  r6ck_2d(class.d, 0x0, 0xbff0000000000000, 0x8)
+  r6ck_2d(class.d, 0x0, 0x8000000000000001, 0x10)
+  r6ck_2d(class.d, 0x0, 0x8000000000000000, 0x20)
+  r6ck_2d(class.d, 0x0, 0x7ff0000000000000, 0x40)
+  r6ck_2d(class.d, 0x0, 0x3ff0000000000000, 0x80)
+  r6ck_2d(class.d, 0x0, 0x0000000000000001, 0x100)
+  r6ck_2d(class.d, 0x0, 0x0000000000000000, 0x200)
+
+  "li $11, 32                               \n\t"    // Test min.s
+  r6ck_3s(min.s, 0x0, 0x3f800000, 0x0, 0x0)
+  r6ck_3s(min.s, 0x0, 0x0, 0x3f800000, 0x0)
+  r6ck_3s(min.s, 0x0, 0x7f800000, 0x3f800000, 0x3f800000)
+  r6ck_3s(min.s, 0x0, 0x3f800000, 0x7f800000, 0x3f800000)
+  r6ck_3s(min.s, 0x0, 0xff800000, 0xbf800000, 0xff800000)
+  r6ck_3s(min.s, 0x0, 0xbf800000, 0xff800000, 0xff800000)
+  r6ck_3s(min.s, 0x0, 0x7fffffff, 0x3f800000, 0x3f800000)
+  r6ck_3s(min.s, 0x0, 0x3f800000, 0x7fffffff, 0x3f800000)
+
+  "li $11, 33                               \n\t"    // Test min.d
+  r6ck_3d(min.d, 0x0, 0x3ff0000000000000, 0x0, 0x0)
+  r6ck_3d(min.d, 0x0, 0x0, 0x3ff0000000000000, 0x0)
+  r6ck_3d(min.d, 0x0, 0x7ff0000000000000, 0x3ff0000000000000, 0x3ff0000000000000)
+  r6ck_3d(min.d, 0x0, 0x3ff0000000000000, 0x7ff0000000000000, 0x3ff0000000000000)
+  r6ck_3d(min.d, 0x0, 0xfff0000000000000, 0xbff0000000000000, 0xfff0000000000000)
+  r6ck_3d(min.d, 0x0, 0xbff0000000000000, 0xfff0000000000000, 0xfff0000000000000)
+  r6ck_3d(min.d, 0x0, 0x7fffffffffffffff, 0x3ff0000000000000, 0x3ff0000000000000)
+  r6ck_3d(min.d, 0x0, 0x3ff0000000000000, 0x7fffffffffffffff, 0x3ff0000000000000)
+
+  "li $11, 34                               \n\t"    // Test max.s
+  r6ck_3s(max.s, 0x0, 0x3f800000, 0x0, 0x3f800000)
+  r6ck_3s(max.s, 0x0, 0x0, 0x3f800000, 0x3f800000)
+  r6ck_3s(max.s, 0x0, 0x7f800000, 0x3f800000, 0x7f800000)
+  r6ck_3s(max.s, 0x0, 0x3f800000, 0x7f800000, 0x7f800000)
+  r6ck_3s(max.s, 0x0, 0xff800000, 0xbf800000, 0xbf800000)
+  r6ck_3s(max.s, 0x0, 0xbf800000, 0xff800000, 0xbf800000)
+  r6ck_3s(max.s, 0x0, 0x7fffffff, 0x3f800000, 0x3f800000)
+  r6ck_3s(max.s, 0x0, 0x3f800000, 0x7fffffff, 0x3f800000)
+
+  "li $11, 35                               \n\t"    // Test max.d
+  r6ck_3d(max.d, 0x0, 0x3ff0000000000000, 0x0, 0x3ff0000000000000)
+  r6ck_3d(max.d, 0x0, 0x0, 0x3ff0000000000000, 0x3ff0000000000000)
+  r6ck_3d(max.d, 0x0, 0x7ff0000000000000, 0x3ff0000000000000, 0x7ff0000000000000)
+  r6ck_3d(max.d, 0x0, 0x3ff0000000000000, 0x7ff0000000000000, 0x7ff0000000000000)
+  r6ck_3d(max.d, 0x0, 0xfff0000000000000, 0xbff0000000000000, 0xbff0000000000000)
+  r6ck_3d(max.d, 0x0, 0xbff0000000000000, 0xfff0000000000000, 0xbff0000000000000)
+  r6ck_3d(max.d, 0x0, 0x7fffffffffffffff, 0x3ff0000000000000, 0x3ff0000000000000)
+  r6ck_3d(max.d, 0x0, 0x3ff0000000000000, 0x7fffffffffffffff, 0x3ff0000000000000)
+
+  "li $11, 36                               \n\t"    // Test mina.s
+  r6ck_3s(mina.s, 0x0, 0x3f800000, 0x0, 0x0)
+  r6ck_3s(mina.s, 0x0, 0x0, 0x3f800000, 0x0)
+  r6ck_3s(mina.s, 0x0, 0x7f800000, 0x3f800000, 0x3f800000)
+  r6ck_3s(mina.s, 0x0, 0x3f800000, 0x7f800000, 0x3f800000)
+  r6ck_3s(mina.s, 0x0, 0xff800000, 0xbf800000, 0xbf800000)
+  r6ck_3s(mina.s, 0x0, 0xbf800000, 0xff800000, 0xbf800000)
+  r6ck_3s(mina.s, 0x0, 0x7fffffff, 0x3f800000, 0x3f800000)
+  r6ck_3s(mina.s, 0x0, 0x3f800000, 0x7fffffff, 0x3f800000)
+  r6ck_3s(mina.s, 0x0, 0xc0000000, 0x3f800000, 0x3f800000)
+  r6ck_3s(mina.s, 0x0, 0x3f800000, 0xc0000000, 0x3f800000)
+
+  "li $11, 37                               \n\t"    // Test mina.d
+  r6ck_3d(mina.d, 0x0, 0x3ff0000000000000, 0x0, 0x0)
+  r6ck_3d(mina.d, 0x0, 0x0, 0x3ff0000000000000, 0x0)
+  r6ck_3d(mina.d, 0x0, 0x7ff0000000000000, 0x3ff0000000000000, 0x3ff0000000000000)
+  r6ck_3d(mina.d, 0x0, 0x3ff0000000000000, 0x7ff0000000000000, 0x3ff0000000000000)
+  r6ck_3d(mina.d, 0x0, 0xfff0000000000000, 0xbff0000000000000, 0xbff0000000000000)
+  r6ck_3d(mina.d, 0x0, 0xbff0000000000000, 0xfff0000000000000, 0xbff0000000000000)
+  r6ck_3d(mina.d, 0x0, 0x7fffffffffffffff, 0x3ff0000000000000, 0x3ff0000000000000)
+  r6ck_3d(mina.d, 0x0, 0x3ff0000000000000, 0x7fffffffffffffff, 0x3ff0000000000000)
+  r6ck_3d(mina.d, 0x0, 0xc000000000000000, 0x3ff0000000000000, 0x3ff0000000000000)
+  r6ck_3d(mina.d, 0x0, 0x3ff0000000000000, 0xc000000000000000, 0x3ff0000000000000)
+
+  "li $11, 38                               \n\t"    // Test maxa.s
+  r6ck_3s(maxa.s, 0x0, 0x3f800000, 0x0, 0x3f800000)
+  r6ck_3s(maxa.s, 0x0, 0x0, 0x3f800000, 0x3f800000)
+  r6ck_3s(maxa.s, 0x0, 0x7f800000, 0x3f800000, 0x7f800000)
+  r6ck_3s(maxa.s, 0x0, 0x3f800000, 0x7f800000, 0x7f800000)
+  r6ck_3s(maxa.s, 0x0, 0xff800000, 0xbf800000, 0xff800000)
+  r6ck_3s(maxa.s, 0x0, 0xbf800000, 0xff800000, 0xff800000)
+  r6ck_3s(maxa.s, 0x0, 0x7fffffff, 0x3f800000, 0x3f800000)
+  r6ck_3s(maxa.s, 0x0, 0x3f800000, 0x7fffffff, 0x3f800000)
+  r6ck_3s(maxa.s, 0x0, 0xc0000000, 0x3f800000, 0xc0000000)
+  r6ck_3s(maxa.s, 0x0, 0x3f800000, 0xc0000000, 0xc0000000)
+
+  "li $11, 39                               \n\t"    // Test maxa.d
+  r6ck_3d(maxa.d, 0x0, 0x3ff0000000000000, 0x0, 0x3ff0000000000000)
+  r6ck_3d(maxa.d, 0x0, 0x0, 0x3ff0000000000000, 0x3ff0000000000000)
+  r6ck_3d(maxa.d, 0x0, 0x7ff0000000000000, 0x3ff0000000000000, 0x7ff0000000000000)
+  r6ck_3d(maxa.d, 0x0, 0x3ff0000000000000, 0x7ff0000000000000, 0x7ff0000000000000)
+  r6ck_3d(maxa.d, 0x0, 0xfff0000000000000, 0xbff0000000000000, 0xfff0000000000000)
+  r6ck_3d(maxa.d, 0x0, 0xbff0000000000000, 0xfff0000000000000, 0xfff0000000000000)
+  r6ck_3d(maxa.d, 0x0, 0x7fffffffffffffff, 0x3ff0000000000000, 0x3ff0000000000000)
+  r6ck_3d(maxa.d, 0x0, 0x3ff0000000000000, 0x7fffffffffffffff, 0x3ff0000000000000)
+  r6ck_3d(maxa.d, 0x0, 0xc000000000000000, 0x3ff0000000000000, 0xc000000000000000)
+  r6ck_3d(maxa.d, 0x0, 0x3ff0000000000000, 0xc000000000000000, 0xc000000000000000)
+
+  "li $11, 40                               \n\t"    // Test sel.s
+  r6ck_3s(sel.s, 0x0, 0xabcdef12, 0x12345678, 0xabcdef12)
+  r6ck_3s(sel.s, 0x1, 0xdeadbeef, 0xcafe1234, 0xcafe1234)
+  r6ck_3s(sel.s, 0xfffffffe, 0xbadcafe0, 0x12345678, 0xbadcafe0)
+  r6ck_3s(sel.s, 0xffffffff, 0xdeadbeef, 0xcadf00ab, 0xcadf00ab)
+
+  "li $11, 41                               \n\t"    // Test sel.d
+  r6ck_3d(sel.d, 0x0, 0xabcdef123456789, 0x12345678abcdefa, 0xabcdef123456789)
+  r6ck_3d(sel.d, 0x1, 0xdeadbeef1534567, 0xcafe12340145279, 0xcafe12340145279)
+  r6ck_3d(sel.d, 0xfffffffffffffffe, 0xbadcafe00efacdab, 0x1234567887654321, 0xbadcafe00efacdab)
+  r6ck_3d(sel.d, 0xffffffffffffffff, 0xdeadbeeffeebdaed, 0xcadf00abba00fdac, 0xcadf00abba00fdac)
+
+  "li $11, 42                               \n\t"    // Test seleqz.s
+  r6ck_3s(seleqz.s, 0x0, 0x1234abcd, 0x0, 0x1234abcd)
+  r6ck_3s(seleqz.s, 0x0, 0xabcdef01, 0x1, 0x0)
+  r6ck_3s(seleqz.s, 0x0, 0xffeebbcc, 0xfffffffe, 0xffeebbcc)
+  r6ck_3s(seleqz.s, 0x0, 0x12345678, 0xffffffff, 0)
+
+  "li $11, 43                               \n\t"    // Test seleqz.d
+  r6ck_3d(seleqz.d, 0x0, 0x1234abcddcba4321, 0x0, 0x1234abcddcba4321)
+  r6ck_3d(seleqz.d, 0x0, 0xabcdef0110fedcba, 0x1, 0x0)
+  r6ck_3d(seleqz.d, 0x0, 0xffeebbccccbbeeff, 0xfffffffffffffffe, 0xffeebbccccbbeeff)
+  r6ck_3d(seleqz.d, 0x0, 0x1234567887654321, 0xffffffffffffffff, 0x0)
+
+  "li $11, 44                               \n\t"    // Test selnez.s
+  r6ck_3s(selnez.s, 0x0, 0x1234abcd, 0x0, 0x0)
+  r6ck_3s(selnez.s, 0x0, 0xabcdef01, 0x1, 0xabcdef01)
+  r6ck_3s(selnez.s, 0x0, 0xffeebbcc, 0xfffffffe, 0x0)
+  r6ck_3s(selnez.s, 0x0, 0x12345678, 0xffffffff, 0x12345678)
+
+  "li $11, 45                               \n\t"    // Test selnez.d
+  r6ck_3d(selnez.d, 0x0, 0x1234abcddcba4321, 0x0, 0x0)
+  r6ck_3d(selnez.d, 0x0, 0xabcdef0110fedcba, 0x1, 0xabcdef0110fedcba)
+  r6ck_3d(selnez.d, 0x0, 0xffeebbccccbbeeff, 0xfffffffffffffffe, 0x0)
+  r6ck_3d(selnez.d, 0x0, 0x1234567887654321, 0xffffffffffffffff, 0x1234567887654321)
+
+  "li $11, 46                               \n\t"  // Test bc1eqz"
+  "li $10, 0x01                             \n\t"
+  "mtc1 $10, $f2                            \n\t"
+  "mtc1 $0, $f4                             \n\t"
+  "bc1eqz $f2, 58f                          \n\t"
+  "nop                                      \n\t"
+  "bc1eqz $f4, L62                          \n\t"
+  "nop                                      \n\t"
+  "b 58f                                    \n\t"
+  "nop                                      \n\t"
+"L62:                                       \n\t"
+  "li $11, 47                               \n\t"  // Test bc1nez
+  "bc1nez $f4, 58f                          \n\t"
+  "nop                                      \n\t"
+  "bc1nez $f2, Lend8                        \n\t"
+  "nop                                      \n\t"
+  "b 58f                                    \n\t"
+  "nop                                      \n\t"
+"Lend8:                                     \n\t"
+  "li $11, 0                                \n\t"
+  "58:                                      \n\t"
+  "move %[err], $11                         \n\t"
+  ".set pop                                 \n\t"
+  : [err] "+r"(err)  // outputs
+  :                  // inputs
+  : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$31", "$s0", "$f2", "$f4", "$f6"  // clobbers
+  );
+
+  return err;
+}
+
+
+
+
+// R6 specific tests for mips64 (64-bit)
+int test_r6_llsc_dp()
+{
+  volatile int err = 0;
+
+  asm(
+    ".set push                                            \n\t"
+    ".set noreorder                                       \n\t"
+    ".data                                                \n\t"
+    ".align 16                                             \n\t"
+    "test_data:                                             \n\t"
+    ".word 0xaaaaaaaa                                      \n\t"
+    ".word 0xbbbbbbbb                                      \n\t"
+    ".word 0xcccccccc                                      \n\t"
+    ".word 0xdddddddd                                      \n\t"
+    ".align 16                                              \n\t"
+    "end_check:                                             \n\t"
+    ".byte 0                                               \n\t"
+    ".byte 0                                               \n\t"
+    ".byte 0                                               \n\t"
+    ".byte 0x1                                             \n\t"
+    ".text                                                \n\t"
+    "li $11, 1                                            \n\t" // Test LLWP
+    "llwp $2, $3, test_data                               \n\t"
+    checkpair_dword($2, $3, test_data, end_check)
+    "sll $2, $2, 1                                        \n\t"
+    "srl $3, $3, 1                                        \n\t"
+    "move  $s0, $2                                        \n\t"
+    "scwp $2, $3, test_data                               \n\t"
+    check32($2, 1)
+    checkpair_dword($s0, $3, test_data, end_check)
+    "li $11, 2                                            \n\t" // Test SCWP, done
+    "li $11, 3                                            \n\t" // Test LLDP
+    "lldp $2, $3, test_data                               \n\t"
+    checkpair_qword($2, $3, test_data, end_check)
+    "dsll $2, $2, 1                                       \n\t"
+    "dsrl $3, $3, 1                                       \n\t"
+    "move $s0, $2                                         \n\t"
+    "scdp $2, $3, test_data                               \n\t"
+    check32($2, 1)
+    checkpair_qword($s0, $3, test_data, end_check)
+    "li $11, 4                                            \n\t" // Test SCDP, done
+    "Lend5:                                                    \n\t"
+    "li $11, 0                                                 \n\t"
+    "58:                                                       \n\t"
+    "move %[err], $11                                          \n\t"
+    ".set pop                                                  \n\t"
+    : [err] "+r"(err) // outputs
+    : // inputs
+    : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$31", "$s0"  // clobbers
+  );
+
+  return err;
+}
+
+
+/* R6 specific tests for mips32 (32-bit) */
+int test_r6_llsc_wp()
+{
+  volatile int err = 0;
+
+  asm(
+    ".set push                                                      \n\t"
+    ".set noreorder                                                 \n\t"
+    ".data                                                          \n\t"
+    ".align 8                                                       \n\t" // p2align
+    "test_data_2:                                                   \n\t"
+    ".word 0xaaaaaaaa                                               \n\t"
+    ".word 0xbbbbbbbb                                               \n\t"
+    ".align 8                                                       \n\t"
+    "end_check_2:                                                   \n\t"
+    ".byte 0                                                        \n\t"
+    ".byte 0                                                        \n\t"
+    ".byte 0                                                        \n\t"
+    ".byte 0x1                                                      \n\t"
+    ".text                                                          \n\t"
+    "li $11, 1                                                      \n\t" // Test LLWP
+    "llwp $2, $3, test_data_2                                       \n\t"
+    checkpair_dword($2, $3, test_data_2, end_check_2)
+    "sll $2, $2, 1                                                  \n\t"
+    "srl $3, $3, 1                                                  \n\t"
+    "move  $s0, $2                                                  \n\t"
+    "scwp $2, $3, test_data_2                                       \n\t"
+    check32($2, 1)
+    checkpair_dword($s0, $3, test_data_2, end_check_2)
+    "li $11, 2                                                      \n\t" // Test SCWP, done
+    "Lend6:                                                         \n\t"
+    "li $11, 0                                                      \n\t"
+    "58:                                                            \n\t"
+    "move %[err], $11                                               \n\t"
+    ".set pop                                                       \n\t"
+    : [err] "+r"(err) // outputs
+    : // inputs
+    : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$31", "$s0"  // clobbers
+  );
+
+  return err;
+}
+
+
+
+/*
+ * Any test_r6_* function returns non-zero => failure
+ */
+#define EXPECT(X) if ((X)) abort ();
+
+
+main ()
+{
+  EXPECT(test_r6_branch());
+
+  EXPECT(test_r6_forbidden());
+
+  EXPECT(test_r6_64());
+
+  EXPECT(test_r6());
+
+  EXPECT(test_r6_fpu());
+
+
+  EXPECT(test_r6_llsc_dp());
+
+
+  EXPECT(test_r6_llsc_wp());
+}
diff --git a/gdb/testsuite/gdb.arch/mips-64-r6.exp b/gdb/testsuite/gdb.arch/mips-64-r6.exp
new file mode 100644
index 00000000000..1ab04daddd5
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/mips-64-r6.exp
@@ -0,0 +1,99 @@ 
+# Copyright (C) 2012-2023 Free Software Foundation, Inc.
+
+# 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 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+
+# Test mips release 6 patch.
+
+require {istarget "*mips*"}
+
+proc single_step {} {
+    global gdb_prompt
+
+    send_gdb "si\n"
+    gdb_expect {
+	-re "$gdb_prompt \$" {
+	    return 1
+	}
+	-re ".*Breakpoint.*test_.*" {
+	    return 2
+	}
+	-re ".*exited normally.*" {
+	    return 3
+	}
+	-re ".*The program is not being run.*" {
+	    return 4
+	}
+    }
+    return 0
+}
+
+set testfile "mips-64-r6"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+verbose -log "\[DEBUG\] testfile=${testfile}\n"
+verbose -log "\[DEBUG\] srcfile=${srcfile}\n"
+verbose -log "\[DEBUG\] binfile=${binfile}\n"
+verbose -log "\[DEBUG\] srcdir/subdir/srcfile=${srcdir}/${subdir}/${srcfile}\n\n"
+
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug nowarnings}] != "" } {
+     fail "compilation"
+     return
+}
+
+pass "compilation"
+
+clean_restart $binfile
+# Native needs run.
+runto_main
+
+set tests ""
+foreach n [list "r6_branch" "r6_forbidden" "r6_64" "r6" "r6_fpu" "r6_llsc_dp" "r6_llsc_wp"] {
+    lappend tests "test_$n"
+}
+
+# put breakpoint on each test-function
+foreach func $tests {
+    gdb_test "break $func" "Breakpoint.*at.*" "set breakpoint on $func"
+}
+
+
+set rt [single_step]
+if { $rt == 0 } {
+    fail "single_step returned $rt"
+}
+
+set start [timestamp]
+global timeout
+while { $rt != 0 && [timestamp] - $start < 3*$timeout } {
+
+     if { $rt == 3 } {
+	pass "all tests are fine"
+	return
+    } elseif { $rt == 4 } {
+	fail "Program exited abnormally"
+	return
+    }
+#    elseif { $rt == 1 || $rt == 2 } { # 1->got gdb_prompt ; 2->hit breakpoint
+#   	verbose -log "\[DEBUG_\] 'single_step' returned rt=$rt ; timeout = $timeout"
+#    }
+
+    set rt [single_step]
+}
+
+if {$rt == 0 } {
+    fail "stepi"
+}
+
+