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

Message ID PR3PR09MB4361342BC48F646B3668236C8FE12@PR3PR09MB4361.eurprd09.prod.outlook.com
State New
Headers
Series [PATCH^9] gdb: mips: Add MIPSR6 support |

Checks

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

Commit Message

Milica Matic Jan. 22, 2025, 9:06 p.m. UTC
  HTEC Proprietary

Thank you so much for your suggestions.


Kind Regards,
Milica
  

Comments

Sam James Jan. 22, 2025, 9:29 p.m. UTC | #1
Milica Matic <milica.matic@htecgroup.com> writes:

> HTEC Proprietary
>

What does this mean? Is it some email signature? Please remove it.

> Thank you so much for your suggestions.
>
>
> Kind Regards,
> Milica
>
> [2. 0001-PATCH-9-gdb-mips-Add-MIPSR6-support.patch --- text/x-patch; 0001-PATCH-9-gdb-mips-Add-MIPSR6-support.patch]...

Could you send the patch inline (possibly with git-send-email) to make
it easier to comment on it?
  
Kevin Buettner Jan. 24, 2025, 7:52 p.m. UTC | #2
Hi Milica,

While things are looking much better, I still see some formatting nits. 
See below.

Kevin

On Wed, 22 Jan 2025 21:06:44 +0000
Milica Matic <milica.matic@htecgroup.com> wrote:

> @@ -1074,21 +1090,26 @@ mips_register_type (struct gdbarch *gdbarch, int regnum)
>        else if (gdbarch_osabi (gdbarch) != GDB_OSABI_LINUX
>  	       && rawnum >= MIPS_FIRST_EMBED_REGNUM
>  	       && rawnum <= MIPS_LAST_EMBED_REGNUM)
> +	{
>  	/* The pseudo/cooked view of the embedded registers is always
>  	   32-bit.  The raw view is handled below.  */
> -	return builtin_type (gdbarch)->builtin_int32;
> +	  return builtin_type (gdbarch)->builtin_int32;
> +	}

You've added curly braces here and have correctly indented the return
statement, but forgot to also indent the comment to match the
indentation level of the return statement.

>        else if (tdep->mips64_transfers_32bit_regs_p)
> +	{
>  	/* The target, while possibly using a 64-bit register buffer,
>  	   is only transferring 32-bits of each integer register.
>  	   Reflect this in the cooked/pseudo (ABI) register value.  */
> -	return builtin_type (gdbarch)->builtin_int32;
> +	  return builtin_type (gdbarch)->builtin_int32;
> +	}

Likewise.

>        else if (mips_abi_regsize (gdbarch) == 4)
> +	{
>  	/* The ABI is restricted to 32-bit registers (the ISA could be
>  	   32- or 64-bit).  */
> -	return builtin_type (gdbarch)->builtin_int32;
> +	  return builtin_type (gdbarch)->builtin_int32;
> +	}

Here too.

>        else
> -	/* 64-bit ABI.  */
> -	return builtin_type (gdbarch)->builtin_int64;
> +	return builtin_type (gdbarch)->builtin_int64; /* 64-bit ABI.  */

For this one, I think you should leave the comment on a line of its own
and add the curly braces.  Rationale:

https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards#Prefer_Function-Body_Comments_On_Lines_By_Themselves

> @@ -1593,8 +1636,10 @@ mips32_bc1_pc (struct gdbarch *gdbarch, struct regcache *regcache,
>    int cond;
>  
>    if (fcsr == -1)
> -    /* No way to handle; it'll most likely trap anyway.  */
> -    return pc;
> +    {
> +      /* No way to handle; it'll most likely trap anyway.  */
> +      return pc;
> +    }

This one is correct - do the ones above like this one.

> +/* Detects whether overflow occurs when adding two 32-bit integers.  */
> +
> +static bool
> +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);

FWIW, for the ">= 0" cases on the line above, I don't think that
overflow can occur when either a or b is 0.

> @@ -1645,14 +1760,18 @@ mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
>    struct gdbarch *gdbarch = regcache->arch ();
>    unsigned long inst;
>    int op;
> +  int mips64bitreg = 0;

I think that the type of mips64bitreg could be 'bool' instead of 'int'.

> +
> +  if (mips_isa_regsize (gdbarch) == 8)
> +    mips64bitreg = 1;

And, of course, you'd then use 'true' here instead of '1'.

> +	      if (taken)
> +		 pc += mips32_relative_offset (inst) + 4;
> +	      else
> +		{
> +		/* Step through the forbidden slot to avoid repeated exceptions

It seems like there ought to be some kind of punctuation (a period, hyphen,
or semicolon) after "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);
> +	      bool 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

Likewise, here.

> +		   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
> +	    {
> +	      /* Not a branch, next instruction is easy.  */
> +	      pc += 4;
> +	    }
> +	}
>        else
>  	pc += 4;		/* Not a branch, next instruction is easy.  */
>      }
>    else
> -    {				/* This gets way messy.  */
> -
> -      /* Further subdivide into SPECIAL, REGIMM and other.  */
> +    {  /* This gets way messy.
> +	  Further subdivide into SPECIAL, REGIMM and other.  */

I think that the comment should be on a line of its own instead of on
the same line as the left curly brace.  As is, I suspect that the
indentation for the following line isn't quite right either, but
that'll presumably get fixed if you separate the comment from the
curly brace line.

> @@ -1766,22 +2037,33 @@ 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;

I'm guessing that you're introducing delay_slot_size here so that
things are more readable later on when doing "pc += delay_slot_size;"
(instead of "pc += 4") later on.  It appears that it's never modified,
nor should it be.  So, maybe make it a "const int" instead of "int" ?

When I search for "delay_slot_size" in the rest of your patch, I see
that 'delay_slot_size' is also defined in mips32_blez_pc also, so
perhaps 'delay_slot_size" should be at the global (file-scope) level
and should be defined via either #define or const ? (That way you're
not defining it repeatedly in each function where it's needed.)

>  
>  		    if (dspctl == -1)
> +		      {
>  		      /* No way to handle; it'll most likely trap anyway.  */
> -		      break;
> +			break;
> +		      }

I think that the comment in the block above should be indented so that
it's at the same indentation level as the break.

> +
> +		    /* BPOSGE32C  */
> +		    if (op == 0x1d)
> +		      {
> +			if (!is_mipsr6_isa (gdbarch))
> +			  break;
> +		      }
>  
>  		    if ((regcache_raw_get_unsigned (regcache,
>  						    dspctl) & 0x7f) >= pos)
>  		      pc += mips32_relative_offset (inst);
>  		    else
> -		      pc += 4;
> +		      pc += delay_slot_size;

Here's where delay_slot_size is used.  FWIW, I like this change since
it make it clear what's going on without the need for a comment.

>  		  }
>  		break;
>  		/* All of the other instructions in the REGIMM category */
> @@ -1789,9 +2071,9 @@ mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
>  		pc += 4;
>  	      }
>  	  }
> -	  break;		/* end REGIMM */
> -	case 2:		/* J */
> -	case 3:		/* JAL */
> +	  break;  /* end REGIMM */
> +	case 2: 	/* J */
> +	case 3: 	/* JAL */

The above seems to replace some tabs with spaces prior to the comment.
In particular, the case statements originally had two tabs and they
now have a space and then a tab.  I'm wondering about why this was done?

I don't think the GDB coding standard addresses this case though, so
I'm not asking you to change it.  (Though I will say that changes like this
make the patch harder to review.)

> @@ -2600,10 +2940,12 @@ mips16_scan_prologue (struct gdbarch *gdbarch,
>  	  if (offset < 0)	/* Negative stack adjustment?  */
>  	    frame_offset -= offset;
>  	  else
> +	    {
>  	    /* Exit loop if a positive stack adjustment is found, which
>  	       usually means that the stack cleanup code in the function
>  	       epilogue is reached.  */
> -	    break;
> +	      break;
> +	    }

I think this is another place where the comment needs to be indented
to the same level as the code enclosed within the curly braces.

>  	}
>        else if ((inst & 0xf800) == 0xd000)	/* sw reg,n($sp) */
>  	{
> @@ -2888,7 +3230,7 @@ mips_insn16_frame_cache (const frame_info_ptr &this_frame, void **this_cache)
>      mips16_scan_prologue (gdbarch, start_addr, pc, this_frame,
>  			  (struct mips_frame_cache *) *this_cache);
>    }
> -  
> +
>    /* gdbarch_sp_regnum contains the value and not the address.  */
>    cache->saved_regs[gdbarch_num_regs (gdbarch)
>  		    + MIPS_SP_REGNUM].set_value (cache->base);
> @@ -3063,7 +3405,7 @@ micromips_scan_prologue (struct gdbarch *gdbarch,
>  		  && dreg == MIPS_SP_REGNUM && sreg == MIPS_SP_REGNUM
>  		  && treg == 3)
>  				/* (D)SUBU $sp, $v1 */
> -		    sp_adj = v1_off;
> +		sp_adj = v1_off;
>  	      else if (op != 0x150
>  				/* ADDU: bits 000000 00101010000 */
>  				/* DADDU: bits 010110 00101010000 */
> @@ -3292,7 +3634,7 @@ micromips_scan_prologue (struct gdbarch *gdbarch,
>  
>  /* Heuristic unwinder for procedures using microMIPS instructions.
>     Procedures that use the 32-bit instruction set are handled by the
> -   mips_insn32 unwinder.  Likewise MIPS16 and the mips_insn16 unwinder. */
> +   mips_insn32 unwinder.  Likewise MIPS16 and the mips_insn16 unwinder.  */
>  
>  static struct mips_frame_cache *
>  mips_micro_frame_cache (const frame_info_ptr &this_frame, void **this_cache)
> @@ -3425,7 +3767,7 @@ reset_saved_regs (struct gdbarch *gdbarch, struct mips_frame_cache *this_cache)
>  }
>  
>  /* Analyze the function prologue from START_PC to LIMIT_PC.  Builds
> -   the associated FRAME_CACHE if not null.  
> +   the associated FRAME_CACHE if not null.
>     Return the address of the first instruction past the prologue.  */
>  
>  static CORE_ADDR
> @@ -3493,16 +3835,19 @@ 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))

I think this should be indented so that the leading '&' appears under
the 'h' in "high_word".

>  	  || high_word == 0x67bd)	/* daddiu $sp,$sp,-i */
>  	{
>  	  if (offset < 0)		/* Negative stack adjustment?  */
>  	    frame_offset -= offset;
>  	  else
> -	    /* Exit loop if a positive stack adjustment is found, which
> -	       usually means that the stack cleanup code in the function
> -	       epilogue is reached.  */
> -	    break;
> +	    {
> +	     /* Exit loop if a positive stack adjustment is found, which
> +		usually means that the stack cleanup code in the function
> +		epilogue is reached.  */
> +	      break;
> +	    }

The first line of the comment in the block above is indented by one
tab and five spaces.  It should be one tab and six spaces, in order to
match the break below it.  I think that the other two lines of the
comment will require some adjustment too.

> @@ -3981,28 +4394,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);

Check the indentation of the comments for the expression of the
is_branch assignment, above.  Indentation of the rest of it looks
correct to me though.

> @@ -7352,7 +7826,7 @@ mips_segment_boundary (CORE_ADDR bpaddr)
>  }
>  
>  /* Move the breakpoint at BPADDR out of any branch delay slot by shifting
> -   it backwards if necessary.  Return the address of the new location.  */
> +   it backwards if necessary. Return the address of the new location.  */

The original line was correct.  There should be two spaces (instead of
just one) following the period after "necessary".  See:

  https://www.gnu.org/prep/standards/standards.html#Comments

> @@ -7404,10 +7889,16 @@ mips_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
>  	return bpaddr;
>  
>        /* If the previous instruction has a branch delay slot, we have
> -	 to move the breakpoint to the branch instruction. */
> +	 to move the breakpoint to the branch instruction.  */
>        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.  */

Check indentation of the three comment lines above.  As written, I don't
think that they line up under the 'I' in "If" on the first line of the
comment.

> @@ -7437,18 +7928,23 @@ mips_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
>  	    break;
>  	  addr -= MIPS_INSN16_SIZE;
>  	  if (i == 1 && insn_at_pc_has_delay_slot (gdbarch, addr, 0))
> +	    {
>  	    /* Looks like a JR/JALR at [target-1], but it could be
>  	       the second word of a previous JAL/JALX, so record it
>  	       and check back one more.  */
> -	    jmpaddr = addr;
> +	      jmpaddr = addr;
> +	    }

Another case where the comment needs to be indented within the block.

>  	  else if (i > 1 && insn_at_pc_has_delay_slot (gdbarch, addr, 1))
>  	    {
>  	      if (i == 2)
> +		{
>  		/* Looks like a JAL/JALX at [target-2], but it could also
>  		   be the second word of a previous JAL/JALX, record it,
>  		   and check back one more.  */
> -		jmpaddr = addr;
> +		  jmpaddr = addr;
> +		}

Same here.

>  	      else
> +		{
>  		/* Looks like a JAL/JALX at [target-3], so any previously
>  		   recorded JAL/JALX or JR/JALR must be wrong, because:
>  
> @@ -7466,7 +7962,8 @@ mips_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
>  		    -2: bdslot (can't be jmp)
>  		    -1: JR/JALR
>  		     0: target insn  */
> -		jmpaddr = 0;
> +		  jmpaddr = 0;
> +		}

And here too.

>  	    }
>  	  else
>  	    {
> @@ -7733,15 +8230,19 @@ mips_skip_mips16_trampoline_code (const frame_info_ptr &frame, CORE_ADDR pc)
>  	       && mips_is_stub_suffix (name + prefixlen + 3, 0))
>  	{
>  	  if (pc == start_addr)
> +	    {
>  	    /* This is the 'call' part of a call stub.  The return
>  	       address is in $2.  */
> -	    return get_frame_register_signed
> +	      return get_frame_register_signed
>  		     (frame, gdbarch_num_regs (gdbarch) + MIPS_V0_REGNUM);
> +	    }

Likewise.

>  	  else
> +	    {
>  	    /* This is the 'return' part of a call stub.  The return
>  	       address is in $18.  */
> -	    return get_frame_register_signed
> +	      return get_frame_register_signed
>  		     (frame, gdbarch_num_regs (gdbarch) + MIPS_S2_REGNUM);
> +	    }
>  	}

Likewise.

>        else
>  	return 0;		/* Not a stub.  */
> @@ -7753,15 +8254,19 @@ mips_skip_mips16_trampoline_code (const frame_info_ptr &frame, CORE_ADDR pc)
>        || startswith (name, mips_str_call_stub))
>      {
>        if (pc == start_addr)
> +	{
>  	/* This is the 'call' part of a call stub.  Call this helper
>  	   to scan through this code for interesting instructions
>  	   and determine the final PC.  */
> -	return mips_get_mips16_fn_stub_pc (frame, pc);
> +	  return mips_get_mips16_fn_stub_pc (frame, pc);
> +	}

Likewise.

>        else
> +	{
>  	/* This is the 'return' part of a call stub.  The return address
>  	   is in $18.  */
> -	return get_frame_register_signed
> +	  return get_frame_register_signed
>  		 (frame, gdbarch_num_regs (gdbarch) + MIPS_S2_REGNUM);
> +	}

Likewise.
  

Patch

From 8dd9c77870ba90ed5556a570111358a9def09f84 Mon Sep 17 00:00:00 2001
From: Milica Matic <milica.matic@htecgroup.com>
Date: Wed, 22 Jan 2025 17:52:44 +0100
Subject: [PATCH^9] gdb: mips: Add MIPSR6 support

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 v8: Apply suggestions provided by Kevin Buettner and Maciej W. Rozycki.
Additionaly, format mips-tdep.c code as described on link :
https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards

[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
2025-01-22
Andrew Bennett  <andrew.bennett@imgtec.com>
Matthew Fortune  <matthew.fortune@mips.com>
Faraz Shahbazker  <fshahbazker@wavecomp.com>
---
 gdb/mips-tdep.c                       | 846 +++++++++++++++++++-----
 gdb/testsuite/gdb.arch/mips-64-r6.c   | 916 ++++++++++++++++++++++++++
 gdb/testsuite/gdb.arch/mips-64-r6.exp |  76 +++
 3 files changed, 1666 insertions(+), 172 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 a28c99d3366..7ab27e9265e 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -1,6 +1,6 @@ 
 /* Target-dependent code for the MIPS architecture, for GDB, the GNU Debugger.
 
-   Copyright (C) 1988-2024 Free Software Foundation, Inc.
+   Copyright (C) 1988-2025 Free Software Foundation, Inc.
 
    Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
    and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin.
@@ -76,8 +76,12 @@  static int mips16_insn_at_pc_has_delay_slot (struct gdbarch *gdbarch,
 static void mips_print_float_info (struct gdbarch *, struct ui_file *,
 				   const frame_info_ptr &, const char *);
 
-/* 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.  */
+static void
+mips_read_fp_register_single (const frame_info_ptr &frame, int regno,
+			      gdb::array_view<gdb_byte> rare_buffer);
+
+/* 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)
 
 /* The sizes of floating point registers.  */
@@ -220,6 +224,7 @@  static std::string mips_disassembler_options;
    to the ABI we have selected, perhaps via a `set mips abi ...'
    override, rather than ones inferred from the ABI set in the ELF
    headers of the binary file selected for debugging.  */
+
 static const char mips_disassembler_options_o32[] = "gpr-names=32";
 static const char mips_disassembler_options_n32[] = "gpr-names=n32";
 static const char mips_disassembler_options_n64[] = "gpr-names=64";
@@ -325,6 +330,17 @@  mips_abi_regsize (struct gdbarch *gdbarch)
     }
 }
 
+/* Return true if the gdbarch is based on MIPS Release 6.  */
+
+static bool
+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);
+}
+
 /* MIPS16/microMIPS function addresses are odd (bit 0 is set).  Here
    are some functions to handle addresses associated with compressed
    code including but not limited to testing, setting, or clearing
@@ -633,7 +649,6 @@  static const char * const mips_linux_reg_names[NUM_MIPS_PROCESSOR_REGS] = {
   "fsr", "fir"
 };
 
-
 /* Return the name of the register corresponding to REGNO.  */
 static const char *
 mips_register_name (struct gdbarch *gdbarch, int regno)
@@ -657,7 +672,7 @@  mips_register_name (struct gdbarch *gdbarch, int regno)
 
   enum mips_abi abi = mips_abi (gdbarch);
 
-  /* Map [gdbarch_num_regs .. 2*gdbarch_num_regs) onto the raw registers, 
+  /* Map [gdbarch_num_regs .. 2*gdbarch_num_regs) onto the raw registers,
      but then don't make the raw register names visible.  This (upper)
      range of user visible register numbers are the pseudo-registers.
 
@@ -668,6 +683,7 @@  mips_register_name (struct gdbarch *gdbarch, int regno)
      configured to be 32-bits wide.  The registers that the user
      sees - the pseudo registers - match the users expectations
      given the programming model being used.  */
+
   int rawnum = regno % gdbarch_num_regs (gdbarch);
   if (regno < gdbarch_num_regs (gdbarch))
     return "";
@@ -1005,7 +1021,7 @@  mips_value_to_register (const frame_info_ptr &frame, int regnum,
       size_t len = type->length ();
       frame_info_ptr next_frame = get_next_frame_sentinel_okay (frame);
 
-      /* Sign extend values, irrespective of type, that are stored to 
+      /* Sign extend values, irrespective of type, that are stored to
 	 a 64-bit general purpose register.  (32-bit unsigned values
 	 are stored as signed quantities within a 64-bit register.
 	 When performing an operation, in compiled code, that combines
@@ -1074,21 +1090,26 @@  mips_register_type (struct gdbarch *gdbarch, int regnum)
       else if (gdbarch_osabi (gdbarch) != GDB_OSABI_LINUX
 	       && rawnum >= MIPS_FIRST_EMBED_REGNUM
 	       && rawnum <= MIPS_LAST_EMBED_REGNUM)
+	{
 	/* The pseudo/cooked view of the embedded registers is always
 	   32-bit.  The raw view is handled below.  */
-	return builtin_type (gdbarch)->builtin_int32;
+	  return builtin_type (gdbarch)->builtin_int32;
+	}
       else if (tdep->mips64_transfers_32bit_regs_p)
+	{
 	/* The target, while possibly using a 64-bit register buffer,
 	   is only transferring 32-bits of each integer register.
 	   Reflect this in the cooked/pseudo (ABI) register value.  */
-	return builtin_type (gdbarch)->builtin_int32;
+	  return builtin_type (gdbarch)->builtin_int32;
+	}
       else if (mips_abi_regsize (gdbarch) == 4)
+	{
 	/* The ABI is restricted to 32-bit registers (the ISA could be
 	   32- or 64-bit).  */
-	return builtin_type (gdbarch)->builtin_int32;
+	  return builtin_type (gdbarch)->builtin_int32;
+	}
       else
-	/* 64-bit ABI.  */
-	return builtin_type (gdbarch)->builtin_int64;
+	return builtin_type (gdbarch)->builtin_int64; /* 64-bit ABI.  */
     }
 }
 
@@ -1236,6 +1257,7 @@  mips_pc_is_mips16 (struct gdbarch *gdbarch, CORE_ADDR memaddr)
      elfread.c in the high bit of the info field.  Use this to decide
      if the function is MIPS16.  Otherwise if bit 0 of the address is
      set, then ELF file flags will tell if this is a MIPS16 function.  */
+
   bound_minimal_symbol sym
     = lookup_minimal_symbol_by_pc (make_compact_addr (memaddr));
   if (sym.minsym)
@@ -1254,6 +1276,7 @@  mips_pc_is_micromips (struct gdbarch *gdbarch, CORE_ADDR memaddr)
      if the function is microMIPS.  Otherwise if bit 0 of the address
      is set, then ELF file flags will tell if this is a microMIPS
      function.  */
+
   bound_minimal_symbol sym
     = lookup_minimal_symbol_by_pc (make_compact_addr (memaddr));
   if (sym.minsym)
@@ -1273,6 +1296,7 @@  mips_pc_isa (struct gdbarch *gdbarch, CORE_ADDR memaddr)
      this to decide if the function is MIPS16 or microMIPS or normal
      MIPS.  Otherwise if bit 0 of the address is set, then ELF file
      flags will tell if this is a MIPS16 or a microMIPS function.  */
+
   bound_minimal_symbol sym
     = lookup_minimal_symbol_by_pc (make_compact_addr (memaddr));
   if (sym.minsym)
@@ -1541,6 +1565,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)
@@ -1566,7 +1591,7 @@  mips_insn_size (enum mips_isa isa, ULONGEST insn)
       else
 	return MIPS_INSN16_SIZE;
     case ISA_MIPS:
-	return MIPS_INSN32_SIZE;
+      return MIPS_INSN32_SIZE;
     }
   internal_error (_("invalid ISA"));
 }
@@ -1577,6 +1602,24 @@  mips32_relative_offset (ULONGEST inst)
   return ((itype_immediate (inst) ^ 0x8000) - 0x8000) << 2;
 }
 
+/* Calculates pc-relative offset from lower 21 bits of instruction.
+   Used by BEQZC, BNEZC.  */
+
+static LONGEST
+mips32_relative_offset21 (ULONGEST insn)
+{
+  return ((b0s21_imm (insn) ^ 0x100000) - 0x100000) << 2;
+}
+
+/* Calculates pc-relative offset from lower 26 bits of an instruction.
+   Used by BC, BALC.  */
+
+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.  */
@@ -1593,8 +1636,10 @@  mips32_bc1_pc (struct gdbarch *gdbarch, struct regcache *regcache,
   int cond;
 
   if (fcsr == -1)
-    /* No way to handle; it'll most likely trap anyway.  */
-    return pc;
+    {
+      /* No way to handle; it'll most likely trap anyway.  */
+      return pc;
+    }
 
   fcs = regcache_raw_get_unsigned (regcache, fcsr);
   cond = ((fcs >> 24) & 0xfe) | ((fcs >> 23) & 0x01);
@@ -1626,15 +1671,85 @@  is_octeon_bbit_op (int op, struct gdbarch *gdbarch)
 {
   if (!is_octeon (gdbarch))
     return 0;
-  /* BBIT0 is encoded as LWC2: 110 010.  */
-  /* BBIT032 is encoded as LDC2: 110 110.  */
-  /* BBIT1 is encoded as SWC2: 111 010.  */
-  /* BBIT132 is encoded as SDC2: 111 110.  */
+  /* BBIT0 is encoded as LWC2: 110 010.
+     BBIT032 is encoded as LDC2: 110 110.
+     BBIT1 is encoded as SWC2: 111 010.
+     BBIT132 is encoded as SDC2: 111 110.  */
   if (op == 50 || op == 54 || op == 58 || op == 62)
     return 1;
   return 0;
 }
 
+/* Detects whether overflow occurs when adding two 32-bit integers.  */
+
+static bool
+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);
+}
+
+/* Helper function for BOVC and BNVC instructions which are introduced in
+   MIPS Release 6.
+
+   BOVC performs a signed 32-bit addition of two registers. BOVC discards the
+   sum, but detects signed 32-bit integer overflow of the sum (and the inputs,
+   in MIPS64), and branches if such overflow is detected.
+
+   BNVC does the opposite, i.e. branches if such overflow is not detected.  */
+
+static bool
+is_add64bit_overflow (int64_t a, int64_t b)
+{
+  if (a != (int32_t) a)
+    return true;
+  if (b != (int32_t) b)
+    return true;
+  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);
+  bool taken = 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);
+    }
+
+  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.  */
@@ -1645,14 +1760,18 @@  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 ((inst & 0xe0000000) != 0) /* Not a special, jump or branch instruction.  */
     {
-      if (op >> 2 == 5)
-	/* BEQL, BNEL, BLEZL, BGTZL: bits 0101xx */
+      if (op >> 2 == 5 && ((op & 0x02) == 0 || itype_rt (inst) == 0))
 	{
+	  /* BEQL, BNEL, BLEZL, BGTZL: bits 0101xx */
 	  switch (op & 0x03)
 	    {
 	    case 0:		/* BEQL */
@@ -1660,7 +1779,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:
@@ -1668,20 +1787,30 @@  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
-	       && (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)
-	/* BC1ANY4F, BC1ANY4T: 010001 01010 xxx0x */
-	pc = mips32_bc1_pc (gdbarch, regcache, inst, pc + 4, 4);
-      else if (op == 29)
-	/* JALX: 011101 */
-	/* The new PC will be alternate mode.  */
 	{
+	  /* BC1F, BC1FL, BC1T, BC1TL: 010001 01000 */
+	  pc = mips32_bc1_pc (gdbarch, regcache, inst, pc + 4, 1);
+	}
+      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 (!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 (!is_mipsr6_isa (gdbarch) && op == 29)
+	{
+	  /* JALX: 011101
+	     The new PC will be alternate mode.  */
 	  unsigned long reg;
 
 	  reg = jtype_target (inst) << 2;
@@ -1695,28 +1824,171 @@  mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
 	  branch_if = op == 58 || op == 62;
 	  bit = itype_rt (inst);
 
-	  /* Take into account the *32 instructions.  */
 	  if (op == 54 || op == 62)
-	    bit += 32;
+	    {
+	      /* Take into account the *32 instructions.  */
+	      bit += 32;
+	    }
 
 	  if (((regcache_raw_get_signed (regcache,
 					 itype_rs (inst)) >> bit) & 1)
 	      == branch_if)
 	    pc += mips32_relative_offset (inst) + 4;
 	  else
-	    pc += 8;        /* After the delay slot.  */
+	    {
+	      /* After the delay slot.  */
+	      pc += 8;
+	    }
 	}
+      else if (is_mipsr6_isa (gdbarch))
+	{
+	  if (op == 8 || op == 24)
+	    {
+	      /* BOVC, BEQZALC, BEQC and BNVC, BNEZALC, BNEC  */
+	      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);
+	      bool taken = false;
+	      if (rs >= rt)
+		{
+		  /* BOVC (BNVC)  */
+		  if (mips64bitreg == 1)
+		    taken = is_add64bit_overflow (val_rs, val_rt);
+		  else
+		    taken = is_add32bit_overflow (val_rs, val_rt);
+		}
+	      else if (rs < rt && rs == 0)
+		{
+		  /* BEQZALC (BNEZALC)  */
+		  taken = (val_rt == 0);
+		}
+	      else
+		{
+		  /* BEQC (BNEC)  */
+		  taken = (val_rs == val_rt);
+		}
+
+	      if (op == 24)
+		{
+		  /* BNVC, BNEZALC, BNEC  */
+		  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 == 17 && (itype_rs (inst) == 9 || itype_rs (inst) == 13))
+	    {
+	      /* BC1EQZ, BC1NEZ  */
+	      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 *buf_tmp = (gdb_byte *) alloca (sizeof (gdb_byte) * 4);
+	      gdb::array_view<gdb_byte> raw_buffer = gdb::make_array_view (buf_tmp, 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[0];
+
+	      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);
+	      bool taken = false;
+	      /* 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);
+	      bool 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
+	    {
+	      /* Not a branch, next instruction is easy.  */
+	      pc += 4;
+	    }
+	}
       else
 	pc += 4;		/* Not a branch, next instruction is easy.  */
     }
   else
-    {				/* This gets way messy.  */
-
-      /* Further subdivide into SPECIAL, REGIMM and other.  */
+    {  /* This gets way messy.
+	  Further subdivide into SPECIAL, REGIMM and other.  */
       switch (op & 0x07)	/* Extract bits 28,27,26.  */
 	{
-	case 0:		/* SPECIAL */
+	case 0:  /* SPECIAL */
 	  op = rtype_funct (inst);
 	  switch (op)
 	    {
@@ -1725,7 +1997,7 @@  mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
 	      /* Set PC to that address.  */
 	      pc = regcache_raw_get_signed (regcache, rtype_rs (inst));
 	      break;
-	    case 12:            /* SYSCALL */
+	    case 12:	    /* SYSCALL */
 	      {
 		mips_gdbarch_tdep *tdep
 		  = gdbarch_tdep<mips_gdbarch_tdep> (gdbarch);
@@ -1740,17 +2012,16 @@  mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
 	      pc += 4;
 	    }
 
-	  break;		/* end SPECIAL */
-	case 1:			/* REGIMM */
+	  break;  /* end SPECIAL */
+	case 1:  /* REGIMM */
 	  {
-	    op = itype_rt (inst);	/* branch condition */
+	    op = itype_rt (inst);  /* branch condition */
 	    switch (op)
 	      {
 	      case 0:		/* BLTZ */
 	      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
@@ -1766,22 +2037,33 @@  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;
+			break;
+		      }
+
+		    /* BPOSGE32C  */
+		    if (op == 0x1d)
+		      {
+			if (!is_mipsr6_isa (gdbarch))
+			  break;
+		      }
 
 		    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 */
@@ -1789,9 +2071,9 @@  mips32_next_pc (struct regcache *regcache, CORE_ADDR pc)
 		pc += 4;
 	      }
 	  }
-	  break;		/* end REGIMM */
-	case 2:		/* J */
-	case 3:		/* JAL */
+	  break;  /* end REGIMM */
+	case 2: 	/* J */
+	case 3: 	/* JAL */
 	  {
 	    unsigned long reg;
 	    reg = jtype_target (inst) << 2;
@@ -1815,19 +2097,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 */
@@ -1889,8 +2166,10 @@  micromips_bc1_pc (struct gdbarch *gdbarch, struct regcache *regcache,
   int cond;
 
   if (fcsr == -1)
-    /* No way to handle; it'll most likely trap anyway.  */
-    return pc;
+    {
+      /* No way to handle; it'll most likely trap anyway.  */
+      return pc;
+    }
 
   fcs = regcache_raw_get_unsigned (regcache, fcsr);
   cond = ((fcs >> 24) & 0xfe) | ((fcs >> 23) & 0x01);
@@ -2004,8 +2283,10 @@  micromips_next_pc (struct regcache *regcache, CORE_ADDR pc)
 	    case 0x14: /* BC2F: bits 010000 10100 xxx00 */
 	    case 0x15: /* BC2T: bits 010000 10101 xxx00 */
 	      if (((insn >> 16) & 0x3) == 0x0)
-		/* BC2F, BC2T: don't know how to handle these.  */
-		break;
+		{
+		  /* BC2F, BC2T: don't know how to handle these.  */
+		  break;
+		}
 	      break;
 
 	    case 0x1a: /* BPOSGE64: bits 010000 11010 */
@@ -2015,8 +2296,10 @@  micromips_next_pc (struct regcache *regcache, CORE_ADDR pc)
 		int dspctl = mips_regnum (gdbarch)->dspctl;
 
 		if (dspctl == -1)
-		  /* No way to handle; it'll most likely trap anyway.  */
-		  break;
+		  {
+		    /* No way to handle; it'll most likely trap anyway.  */
+		    break;
+		  }
 
 		if ((regcache_raw_get_unsigned (regcache,
 						dspctl) & 0x7f) >= pos)
@@ -2046,27 +2329,27 @@  micromips_next_pc (struct regcache *regcache, CORE_ADDR pc)
 	case 0x1d: /* JALS: bits 011101 */
 	case 0x35: /* J: bits 110101 */
 	case 0x3d: /* JAL: bits 111101 */
-	    pc = ((pc | 0x7fffffe) ^ 0x7fffffe) | (b0s26_imm (insn) << 1);
+	  pc = ((pc | 0x7fffffe) ^ 0x7fffffe) | (b0s26_imm (insn) << 1);
 	  break;
 
 	case 0x25: /* BEQ: bits 100101 */
-	    if (regcache_raw_get_signed (regcache, b0s5_reg (insn >> 16))
+	  if (regcache_raw_get_signed (regcache, b0s5_reg (insn >> 16))
 		== regcache_raw_get_signed (regcache, b5s5_reg (insn >> 16)))
-	      pc += micromips_relative_offset16 (insn);
-	    else
-	      pc += micromips_pc_insn_size (gdbarch, pc);
+	    pc += micromips_relative_offset16 (insn);
+	  else
+	    pc += micromips_pc_insn_size (gdbarch, pc);
 	  break;
 
 	case 0x2d: /* BNE: bits 101101 */
 	  if (regcache_raw_get_signed (regcache, b0s5_reg (insn >> 16))
 		!= regcache_raw_get_signed (regcache, b5s5_reg (insn >> 16)))
-	      pc += micromips_relative_offset16 (insn);
+	    pc += micromips_relative_offset16 (insn);
 	  else
-	      pc += micromips_pc_insn_size (gdbarch, pc);
+	    pc += micromips_pc_insn_size (gdbarch, pc);
 	  break;
 
 	case 0x3c: /* JALX: bits 111100 */
-	    pc = ((pc | 0xfffffff) ^ 0xfffffff) | (b0s26_imm (insn) << 2);
+	  pc = ((pc | 0xfffffff) ^ 0xfffffff) | (b0s26_imm (insn) << 2);
 	  break;
 	}
       break;
@@ -2077,11 +2360,15 @@  micromips_next_pc (struct regcache *regcache, CORE_ADDR pc)
 	{
 	case 0x11: /* POOL16C: bits 010001 */
 	  if ((b5s5_op (insn) & 0x1c) == 0xc)
-	    /* JR16, JRC, JALR16, JALRS16: 010001 011xx */
-	    pc = regcache_raw_get_signed (regcache, b0s5_reg (insn));
+	    {
+	      /* JR16, JRC, JALR16, JALRS16: 010001 011xx */
+	      pc = regcache_raw_get_signed (regcache, b0s5_reg (insn));
+	    }
 	  else if (b5s5_op (insn) == 0x18)
-	    /* JRADDIUSP: bits 010001 11000 */
-	    pc = regcache_raw_get_signed (regcache, MIPS_RA_REGNUM);
+	    {
+	      /* JRADDIUSP: bits 010001 11000 */
+	      pc = regcache_raw_get_signed (regcache, MIPS_RA_REGNUM);
+	    }
 	  break;
 
 	case 0x23: /* BEQZ16: bits 100011 */
@@ -2159,7 +2446,6 @@  struct upk_mips16
   unsigned int regy;
 };
 
-
 /* The EXT-I, EXT-ri nad EXT-I8 instructions all have the same format
    for the bits which make up the immediate extension.  */
 
@@ -2267,7 +2553,6 @@  unpack_mips16 (struct gdbarch *gdbarch, CORE_ADDR pc,
   upk->regy = regy;
 }
 
-
 /* Calculate the destination of a branch whose 16-bit opcode word is at PC,
    and having a signed 16-bit OFFSET.  */
 
@@ -2450,6 +2735,63 @@  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))
+    {
+    case 50: /* BC  */
+    case 58: /* BALC  */
+      if (is_mipsr6_isa (gdbarch))
+	return 1;
+      break;
+    case 8: /* BOVC, BEQZALC, BEQC  */
+    case 24: /* BNVC, BNEZALC, BNEC  */
+      if (is_mipsr6_isa (gdbarch))
+	return 2;
+      break;
+    case 54: /* BEQZC, JIC  */
+    case 62: /* BNEZC, JIALC  */
+      if (is_mipsr6_isa (gdbarch))
+	{
+	  /* JIC, JIALC are unconditional  */
+	  return (itype_rs (insn) == 0) ? 1 : 2;
+	}
+      break;
+    case 22: /* BLEZC, BGEZC, BGEC  */
+    case 23: /* BGTZC, BLTZC, BLTC  */
+    case 6: /* BLEZALC, BGEZALC, BGEUC  */
+    case 7: /* BGTZALC, BLTZALC, BLTUC  */
+      if (is_mipsr6_isa (gdbarch)
+	  && itype_rt (insn) != 0)
+	return 2;
+      break;
+    case 1: /* BPOSGE32C  */
+      if (is_mipsr6_isa (gdbarch)
+	  && itype_rt (insn) == 0x1d && itype_rs (insn) == 0)
+	return 2;
+    }
+  return 0;
+}
+
+/* Return true if a standard MIPS instruction at ADDR has a branch
+   forbidden slot (i.e. it is a conditional compact branch instruction).  */
+
+static bool
+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 false;
+
+  return mips32_instruction_is_compact_branch (gdbarch, insn) == 2;
+}
+
 struct mips_frame_cache
 {
   CORE_ADDR base;
@@ -2482,7 +2824,6 @@  set_reg_offset (struct gdbarch *gdbarch, struct mips_frame_cache *this_cache,
     }
 }
 
-
 /* Fetch the immediate value from a MIPS16 instruction.
    If the previous instruction was an EXTEND, use it to extend
    the upper bits of the immediate value.  This is a helper function
@@ -2517,7 +2858,6 @@  mips16_get_imm (unsigned short prev_inst,	/* previous instruction */
     }
 }
 
-
 /* Analyze the function prologue from START_PC to LIMIT_PC. Builds
    the associated FRAME_CACHE if not null.
    Return the address of the first instruction past the prologue.  */
@@ -2535,8 +2875,8 @@  mips16_scan_prologue (struct gdbarch *gdbarch,
   CORE_ADDR cur_pc;
   CORE_ADDR frame_addr = 0;	/* Value of $r17, used as frame pointer.  */
   CORE_ADDR sp;
-  long frame_offset = 0;        /* Size of stack frame.  */
-  long frame_adjust = 0;        /* Offset of FP from SP.  */
+  long frame_offset = 0;	/* Size of stack frame.  */
+  long frame_adjust = 0;	/* Offset of FP from SP.  */
   int frame_reg = MIPS_SP_REGNUM;
   unsigned short prev_inst = 0;	/* saved copy of previous instruction.  */
   unsigned inst = 0;		/* current instruction */
@@ -2600,10 +2940,12 @@  mips16_scan_prologue (struct gdbarch *gdbarch,
 	  if (offset < 0)	/* Negative stack adjustment?  */
 	    frame_offset -= offset;
 	  else
+	    {
 	    /* Exit loop if a positive stack adjustment is found, which
 	       usually means that the stack cleanup code in the function
 	       epilogue is reached.  */
-	    break;
+	      break;
+	    }
 	}
       else if ((inst & 0xf800) == 0xd000)	/* sw reg,n($sp) */
 	{
@@ -2888,7 +3230,7 @@  mips_insn16_frame_cache (const frame_info_ptr &this_frame, void **this_cache)
     mips16_scan_prologue (gdbarch, start_addr, pc, this_frame,
 			  (struct mips_frame_cache *) *this_cache);
   }
-  
+
   /* gdbarch_sp_regnum contains the value and not the address.  */
   cache->saved_regs[gdbarch_num_regs (gdbarch)
 		    + MIPS_SP_REGNUM].set_value (cache->base);
@@ -3063,7 +3405,7 @@  micromips_scan_prologue (struct gdbarch *gdbarch,
 		  && dreg == MIPS_SP_REGNUM && sreg == MIPS_SP_REGNUM
 		  && treg == 3)
 				/* (D)SUBU $sp, $v1 */
-		    sp_adj = v1_off;
+		sp_adj = v1_off;
 	      else if (op != 0x150
 				/* ADDU: bits 000000 00101010000 */
 				/* DADDU: bits 010110 00101010000 */
@@ -3292,7 +3634,7 @@  micromips_scan_prologue (struct gdbarch *gdbarch,
 
 /* Heuristic unwinder for procedures using microMIPS instructions.
    Procedures that use the 32-bit instruction set are handled by the
-   mips_insn32 unwinder.  Likewise MIPS16 and the mips_insn16 unwinder. */
+   mips_insn32 unwinder.  Likewise MIPS16 and the mips_insn16 unwinder.  */
 
 static struct mips_frame_cache *
 mips_micro_frame_cache (const frame_info_ptr &this_frame, void **this_cache)
@@ -3425,7 +3767,7 @@  reset_saved_regs (struct gdbarch *gdbarch, struct mips_frame_cache *this_cache)
 }
 
 /* Analyze the function prologue from START_PC to LIMIT_PC.  Builds
-   the associated FRAME_CACHE if not null.  
+   the associated FRAME_CACHE if not null.
    Return the address of the first instruction past the prologue.  */
 
 static CORE_ADDR
@@ -3493,16 +3835,19 @@  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?  */
 	    frame_offset -= offset;
 	  else
-	    /* Exit loop if a positive stack adjustment is found, which
-	       usually means that the stack cleanup code in the function
-	       epilogue is reached.  */
-	    break;
+	    {
+	     /* Exit loop if a positive stack adjustment is found, which
+		usually means that the stack cleanup code in the function
+		epilogue is reached.  */
+	      break;
+	    }
 	  seen_sp_adjust = 1;
 	}
       else if (((high_word & 0xFFE0) == 0xafa0) /* sw reg,offset($sp) */
@@ -3631,7 +3976,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;
@@ -3641,7 +3988,7 @@  mips32_scan_prologue (struct gdbarch *gdbarch,
 
   if (this_cache != NULL)
     {
-      this_cache->base = 
+      this_cache->base =
 	(get_frame_register_signed (this_frame,
 				    gdbarch_num_regs (gdbarch) + frame_reg)
 	 + frame_offset);
@@ -3660,7 +4007,7 @@  mips32_scan_prologue (struct gdbarch *gdbarch,
      its address instead.  */
   end_prologue_addr
     = prev_non_prologue_insn || prev_delay_slot ? prev_pc : cur_pc;
-     
+
   /* In a frameless function, we might have incorrectly
      skipped some load immediate instructions.  Undo the skipping
      if the load immediate was not followed by a stack adjustment.  */
@@ -3673,7 +4020,7 @@  mips32_scan_prologue (struct gdbarch *gdbarch,
 /* Heuristic unwinder for procedures using 32-bit instructions (covers
    both 32-bit and 64-bit MIPS ISAs).  Procedures using 16-bit
    instructions (a.k.a. MIPS16) are handled by the mips_insn16
-   unwinder.  Likewise microMIPS and the mips_micro unwinder. */
+   unwinder.  Likewise microMIPS and the mips_micro unwinder.  */
 
 static struct mips_frame_cache *
 mips_insn32_frame_cache (const frame_info_ptr &this_frame, void **this_cache)
@@ -3704,7 +4051,7 @@  mips_insn32_frame_cache (const frame_info_ptr &this_frame, void **this_cache)
     mips32_scan_prologue (gdbarch, start_addr, pc, this_frame,
 			  (struct mips_frame_cache *) *this_cache);
   }
-  
+
   /* gdbarch_sp_regnum contains the value and not the address.  */
   cache->saved_regs[gdbarch_num_regs (gdbarch)
 		    + MIPS_SP_REGNUM].set_value (cache->base);
@@ -3904,30 +4251,31 @@  mips_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR addr)
   mips_gdbarch_tdep *tdep = gdbarch_tdep<mips_gdbarch_tdep> (gdbarch);
 
   if (mips_mask_address_p (tdep) && (((ULONGEST) addr) >> 32 == 0xffffffffUL))
-    /* This hack is a work-around for existing boards using PMON, the
-       simulator, and any other 64-bit targets that doesn't have true
-       64-bit addressing.  On these targets, the upper 32 bits of
-       addresses are ignored by the hardware.  Thus, the PC or SP are
-       likely to have been sign extended to all 1s by instruction
-       sequences that load 32-bit addresses.  For example, a typical
-       piece of code that loads an address is this:
-
-       lui $r2, <upper 16 bits>
-       ori $r2, <lower 16 bits>
-
-       But the lui sign-extends the value such that the upper 32 bits
-       may be all 1s.  The workaround is simply to mask off these
-       bits.  In the future, gcc may be changed to support true 64-bit
-       addressing, and this masking will have to be disabled.  */
-    return addr &= 0xffffffffUL;
+    {
+      /* This hack is a work-around for existing boards using PMON, the
+	 simulator, and any other 64-bit targets that doesn't have true
+	 64-bit addressing.  On these targets, the upper 32 bits of
+	 addresses are ignored by the hardware.  Thus, the PC or SP are
+	 likely to have been sign extended to all 1s by instruction
+	 sequences that load 32-bit addresses.  For example, a typical
+	 piece of code that loads an address is this:
+
+	 lui $r2, <upper 16 bits>
+	 ori $r2, <lower 16 bits>
+
+	 But the lui sign-extends the value such that the upper 32 bits
+	 may be all 1s.  The workaround is simply to mask off these
+	 bits.  In the future, gcc may be changed to support true 64-bit
+	 addressing, and this masking will have to be disabled.  */
+      return addr &= 0xffffffffUL;
+    }
   else
     return addr;
 }
 
-
 /* Checks for an atomic sequence of instructions beginning with a LL/LLD
    instruction and ending with a SC/SCD instruction.  If such a sequence
-   is found, attempt to step through it.  A breakpoint is placed at the end of 
+   is found, attempt to step through it.  A breakpoint is placed at the end of
    the sequence.  */
 
 /* Instructions used during single-stepping of atomic sequences, standard
@@ -3936,6 +4284,70 @@  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
+
+/* Determine whether instruction 'insn' is of 'load linked X' type.
+   LL/SC instructions provide primitives to implement atomic
+   read-modify-write operations for synchronizable memory locations.  */
+
+static bool
+is_ll_insn (struct gdbarch *gdbarch, ULONGEST insn)
+{
+  if (itype_op (insn) == LL_OPCODE
+      || itype_op (insn) == LLD_OPCODE)
+    return true;
+
+  if (rtype_op (insn) == LLSC_R6_OPCODE
+      && rtype_funct (insn) == LLE_FUNCT
+      && (insn & 0x40) == 0)
+    return true;
+
+  /* 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 true;
+
+  return false;
+}
+
+/* Determine whether instruction 'insn' is of 'store conditional X' type.
+   SC instructions and varieties perform completion of read-modify-write
+   atomic sequence.  */
+
+static bool
+is_sc_insn (struct gdbarch *gdbarch, ULONGEST insn)
+{
+  if (itype_op (insn) == SC_OPCODE
+      || itype_op (insn) == SCD_OPCODE)
+    return true;
+
+  if (rtype_op (insn) == LLSC_R6_OPCODE
+      && rtype_funct (insn) == SCE_FUNCT
+      && (insn & 0x40) == 0)
+    return true;
+
+  /* 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 true;
+
+  return false;
+}
+
+/* Handle mips atomic sequence which starts with LL/LLD and ends with
+   SC/SCD instruction.  */
 
 static std::vector<CORE_ADDR>
 mips_deal_with_atomic_sequence (struct gdbarch *gdbarch, CORE_ADDR pc)
@@ -3946,15 +4358,16 @@  mips_deal_with_atomic_sequence (struct gdbarch *gdbarch, CORE_ADDR pc)
   ULONGEST insn;
   int insn_count;
   int index;
-  int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed).  */  
+  int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed).  */
   const int atomic_sequence_length = 16; /* Instruction sequence length.  */
+  bool 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" 
+  /* Assume that no atomic sequence is longer than "atomic_sequence_length"
      instructions.  */
   for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count)
     {
@@ -3981,28 +4394,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 != 0)
 	    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)
+      if (is_branch != 0)
 	{
-	  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.  */
@@ -4010,12 +4467,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;
@@ -4130,7 +4587,7 @@  micromips_deal_with_atomic_sequence (struct gdbarch *gdbarch,
 	    case 0x35: /* J: bits 110101 */
 	    case 0x3d: /* JAL: bits 111101 */
 	    case 0x3c: /* JALX: bits 111100 */
-	      return {}; /* Fall back to the standard single-step code. */
+	      return {}; /* Fall back to the standard single-step code.  */
 
 	    case 0x18: /* POOL32C: bits 011000 */
 	      if ((b12s4_op (insn) & 0xb) == 0xb)
@@ -4157,14 +4614,14 @@  micromips_deal_with_atomic_sequence (struct gdbarch *gdbarch,
 		  && b5s5_op (insn) != 0x18)
 				/* JRADDIUSP: bits 010001 11000 */
 		break;
-	      return {}; /* Fall back to the standard single-step code. */
+	      return {}; /* Fall back to the standard single-step code.  */
 
 	    case 0x33: /* B16: bits 110011 */
-	      return {}; /* Fall back to the standard single-step code. */
+	      return {}; /* Fall back to the standard single-step code.  */
 	    }
 	  break;
 	}
-      if (is_branch)
+      if (is_branch != 0)
 	{
 	  if (last_breakpoint >= 1)
 	    return {}; /* More than one branch found, fallback to the
@@ -4240,10 +4697,15 @@  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);
+}
 
 /* This fencepost looks highly suspicious to me.  Removing it also
    seems suspicious as it could affect remote debugging across serial
@@ -4817,7 +5279,7 @@  mips_eabi_return_value (struct gdbarch *gdbarch, struct value *function,
     {
       if (type->code () == TYPE_CODE_FLT)
 	fp_return_type = 1;
-      /* Structs with a single field of float type 
+      /* Structs with a single field of float type
 	 are returned in a floating point register.  */
       if ((type->code () == TYPE_CODE_STRUCT
 	   || type->code () == TYPE_CODE_UNION)
@@ -4830,7 +5292,7 @@  mips_eabi_return_value (struct gdbarch *gdbarch, struct value *function,
 	}
     }
 
-  if (fp_return_type)      
+  if (fp_return_type)
     {
       /* A floating-point value belongs in the least significant part
 	 of FP0/FP1.  */
@@ -4838,7 +5300,7 @@  mips_eabi_return_value (struct gdbarch *gdbarch, struct value *function,
 	gdb_printf (gdb_stderr, "Return float in $fp0\n");
       regnum = mips_regnum (gdbarch)->fp0;
     }
-  else 
+  else
     {
       /* An integer value goes in V0/V1.  */
       if (mips_debug)
@@ -4861,7 +5323,6 @@  mips_eabi_return_value (struct gdbarch *gdbarch, struct value *function,
   return RETURN_VALUE_REGISTER_CONVENTION;
 }
 
-
 /* N32/N64 ABI stuff.  */
 
 /* Search for a naturally aligned double at OFFSET inside a struct
@@ -6525,7 +6986,6 @@  print_fp_register_row (struct ui_file *file, const frame_info_ptr &frame,
   return regnum + 1;
 }
 
-
 /* Print a row's worth of GP (int) registers, with name labels above.  */
 
 static int
@@ -6723,7 +7183,7 @@  mips_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
      that bound, then use an arbitrary large number as the upper bound.  */
   limit_pc = skip_prologue_using_sal (gdbarch, pc);
   if (limit_pc == 0)
-    limit_pc = pc + 100;          /* Magic.  */
+    limit_pc = pc + 100;	  /* Magic.  */
 
   if (mips_pc_is_mips16 (gdbarch, pc))
     return mips16_scan_prologue (gdbarch, pc, limit_pc, NULL, NULL);
@@ -6761,7 +7221,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;
 	}
@@ -6964,7 +7426,6 @@  show_mipsfpu_command (const char *args, int from_tty)
       ("The MIPS floating-point coprocessor is assumed to be %s\n", fpu);
 }
 
-
 static void
 set_mipsfpu_single_command (const char *args, int from_tty)
 {
@@ -7140,22 +7601,31 @@  mips32_instruction_has_delay_slot (struct gdbarch *gdbarch, ULONGEST inst)
   int op;
   int rs;
   int rt;
+  bool 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  */
@@ -7174,7 +7644,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;
       }
@@ -7352,7 +7826,7 @@  mips_segment_boundary (CORE_ADDR bpaddr)
 }
 
 /* Move the breakpoint at BPADDR out of any branch delay slot by shifting
-   it backwards if necessary.  Return the address of the new location.  */
+   it backwards if necessary. Return the address of the new location.  */
 
 static CORE_ADDR
 mips_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
@@ -7386,7 +7860,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);
 
@@ -7404,10 +7889,16 @@  mips_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
 	return bpaddr;
 
       /* If the previous instruction has a branch delay slot, we have
-	 to move the breakpoint to the branch instruction. */
+	 to move the breakpoint to the branch instruction.  */
       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
     {
@@ -7437,18 +7928,23 @@  mips_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
 	    break;
 	  addr -= MIPS_INSN16_SIZE;
 	  if (i == 1 && insn_at_pc_has_delay_slot (gdbarch, addr, 0))
+	    {
 	    /* Looks like a JR/JALR at [target-1], but it could be
 	       the second word of a previous JAL/JALX, so record it
 	       and check back one more.  */
-	    jmpaddr = addr;
+	      jmpaddr = addr;
+	    }
 	  else if (i > 1 && insn_at_pc_has_delay_slot (gdbarch, addr, 1))
 	    {
 	      if (i == 2)
+		{
 		/* Looks like a JAL/JALX at [target-2], but it could also
 		   be the second word of a previous JAL/JALX, record it,
 		   and check back one more.  */
-		jmpaddr = addr;
+		  jmpaddr = addr;
+		}
 	      else
+		{
 		/* Looks like a JAL/JALX at [target-3], so any previously
 		   recorded JAL/JALX or JR/JALR must be wrong, because:
 
@@ -7466,7 +7962,8 @@  mips_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
 		    -2: bdslot (can't be jmp)
 		    -1: JR/JALR
 		     0: target insn  */
-		jmpaddr = 0;
+		  jmpaddr = 0;
+		}
 	    }
 	  else
 	    {
@@ -7733,15 +8230,19 @@  mips_skip_mips16_trampoline_code (const frame_info_ptr &frame, CORE_ADDR pc)
 	       && mips_is_stub_suffix (name + prefixlen + 3, 0))
 	{
 	  if (pc == start_addr)
+	    {
 	    /* This is the 'call' part of a call stub.  The return
 	       address is in $2.  */
-	    return get_frame_register_signed
+	      return get_frame_register_signed
 		     (frame, gdbarch_num_regs (gdbarch) + MIPS_V0_REGNUM);
+	    }
 	  else
+	    {
 	    /* This is the 'return' part of a call stub.  The return
 	       address is in $18.  */
-	    return get_frame_register_signed
+	      return get_frame_register_signed
 		     (frame, gdbarch_num_regs (gdbarch) + MIPS_S2_REGNUM);
+	    }
 	}
       else
 	return 0;		/* Not a stub.  */
@@ -7753,15 +8254,19 @@  mips_skip_mips16_trampoline_code (const frame_info_ptr &frame, CORE_ADDR pc)
       || startswith (name, mips_str_call_stub))
     {
       if (pc == start_addr)
+	{
 	/* This is the 'call' part of a call stub.  Call this helper
 	   to scan through this code for interesting instructions
 	   and determine the final PC.  */
-	return mips_get_mips16_fn_stub_pc (frame, pc);
+	  return mips_get_mips16_fn_stub_pc (frame, pc);
+	}
       else
+	{
 	/* This is the 'return' part of a call stub.  The return address
 	   is in $18.  */
-	return get_frame_register_signed
+	  return get_frame_register_signed
 		 (frame, gdbarch_num_regs (gdbarch) + MIPS_S2_REGNUM);
+	}
     }
 
   return 0;			/* Not a stub.  */
@@ -7922,7 +8427,6 @@  mips_stab_reg_to_regnum (struct gdbarch *gdbarch, int num)
   return gdbarch_num_regs (gdbarch) + regnum;
 }
 
-
 /* Convert a dwarf, dwarf2, or ecoff register number to a GDB [1 *
    gdbarch_num_regs .. 2 * gdbarch_num_regs) REGNUM.  */
 
@@ -7960,7 +8464,6 @@  mips_register_sim_regno (struct gdbarch *gdbarch, int regnum)
     return LEGACY_SIM_REGNO_IGNORE;
 }
 
-
 /* Convert an integer into an address.  Extracting the value signed
    guarantees a correctly sign extended address.  */
 
@@ -8361,7 +8864,6 @@  mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 	valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), i,
 					    mips_gprs[i]);
 
-
       valid_p &= tdesc_numbered_register (feature, tdesc_data.get (),
 					  mips_regnum.lo, "lo");
       valid_p &= tdesc_numbered_register (feature, tdesc_data.get (),
@@ -8832,7 +9334,7 @@  mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   for (i = 0; i < ARRAY_SIZE (mips_numeric_register_aliases); i++)
     user_reg_add (gdbarch, mips_numeric_register_aliases[i].name,
-		  value_of_mips_user_reg, 
+		  value_of_mips_user_reg,
 		  &mips_numeric_register_aliases[i].regnum);
 
   return gdbarch;
@@ -8860,7 +9362,7 @@  show_mips_abi (struct ui_file *file,
   if (gdbarch_bfd_arch_info (current_inferior ()->arch  ())->arch
       != bfd_arch_mips)
     gdb_printf
-      (file, 
+      (file,
        "The MIPS ABI is unknown because the current architecture "
        "is not MIPS.\n");
   else
@@ -8871,7 +9373,7 @@  show_mips_abi (struct ui_file *file,
 
       if (global_abi == MIPS_ABI_UNKNOWN)
 	gdb_printf
-	  (file, 
+	  (file,
 	   "The MIPS ABI is set automatically (currently \"%s\").\n",
 	   actual_abi_str);
       else if (global_abi == actual_abi)
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..e1a1dd041cc
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/mips-64-r6.c
@@ -0,0 +1,916 @@ 
+/*
+   Copyright 2023-2025 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/>.
+*/
+
+#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, indicating error.  */
+#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" \
+  "dla $4, 1b              \n\t" \
+  "dla $5, 2b              \n\t" \
+  "dla $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" \
+  "dla $4, 1b                            \n\t" \
+  "dla $5, 2b                            \n\t" \
+  "dla $6, 3b                            \n\t" \
+  "dla $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"
+
+/* 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" \
+  "dla   $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);
+
+/* Tests branch instructions.  */
+
+int
+test_r6_branch (void)
+{
+/* Using volatile to prevent certain optimizations which could cause
+   instruction deletion.
+   'err' identifies instruction which (eventually) caused error.
+   (err == 0) ==> all instructions executed successfully.  */
+
+  volatile int err = -1;
+  volatile int a14 = 0xffffffff;
+  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;
+}
+
+/* Tests forbidden slot branching i.e. conditional compact branch
+   instructions.  */
+
+int
+test_r6_forbidden (void)
+{
+  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"
+/* Test if FS is ignored when branch is taken */
+  "li %[err], 1                      \n\t"
+  "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"
+/* Test if FS is used when branch is not taken */
+  "li %[err], 2                      \n\t"
+  "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"
+  "li %[a4], 3                       \n\t"
+  "beqzalc %[a4], Lfail2             \n\t"
+/* Note: 'bc L45' instead nop would cause SegFault: Illegal instruction:
+   Forbidden slot causes an error when it contains a branch.  */
+  "nop                               \n\t"
+  "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 (void)
+{
+  volatile int err = 0;
+
+  asm (
+  ".set push                                   \n\t"
+  ".set noreorder                              \n\t"
+  ".data                                       \n\t"
+  "dval: .dword 0xaa55bb66cc77dd88             \n\t"
+  "d1:   .dword 0xaaaabbbbccccdddd             \n\t"
+  "d5:   .dword 0x00000000000000dd             \n\t"
+  "d7:   .dword 0xeeeeffff00001111             \n\t"
+  "d8:   .dword 0xbbccccddddeeeeff             \n\t"
+  "d9:   .dword 0x000000ddaaaabbbb             \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"
+
+/* Register $11 stores instruction currently being tested and hence
+ * identifies error if it occurs.  */
+  ".text                                       \n\t"
+
+  "li $11, 1                                   \n\t" /* Test DALIGN */
+  r6ck_2dr1i (dalign, d7, d1, 3, d8)
+  r6ck_2dr1i (dalign, d1, d5, 4, d9)
+
+  "li $11, 2                                   \n\t" /* Test LDPC */
+  "ld $5, dval                                 \n\t"
+  "nop                                         \n\t"
+  "ldpc $4, dval                               \n\t"
+  fp_assert ($4, $5)
+
+  "li $11, 3                                   \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, 4                                   \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, 5                                   \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", "$11" /* clobbers */
+  );
+
+  return err;
+}
+
+int
+test_r6 (void)
+{
+  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" /* ADDIUPC */
+  "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, 2            \n\t" /* 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, 3            \n\t" /* 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, 4            \n\t" /* 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)
+
+/* Testing LL follows.
+ * NOTE: May be redundant because SC already contains LL in its test.  */
+  "li $11, 5                                                \n\t"
+  "lw $5, dval_2                                             \n\t"
+  "dla $3, dval_3                                            \n\t"
+  "ll $4, -252($3)                                           \n\t"
+  fp_assert ($4, $5)
+
+  "li $11, 6        \n\t"    /* LL-SC sequence */
+  "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;
+}
+
+/* For fpu-branching testing, bc1eq/eqz are enough.  */
+
+int
+test_r6_fpu (void)
+{
+  volatile int err = 0;
+
+  asm (
+  ".set push                               \n\t"
+  ".set noreorder                          \n\t"
+/* Test qNaN format is 754-2008 */
+  "li $11, 1                               \n\t"
+  "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"  /* 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, 3                                \n\t"  /* 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 */
+  : "$4", "$5", "$6", "$8", "$10", "$11", "$31",
+    "$f2", "$f4", "$f6" /* clobbers */
+  );
+
+  return err;
+}
+
+/* R6 specific tests for mips64 (64-bit).  */
+
+int
+test_r6_llsc_dp (void)
+{
+  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" /* 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)
+  /* Test SCWP, done */
+  "li $11, 2                                            \n\t"
+  "li $11, 3                                            \n\t" /* 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" /* 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 (void)
+{
+  volatile int err = 0;
+
+  asm (
+  ".set push                                            \n\t"
+  ".set noreorder                                       \n\t"
+  ".data                                                \n\t"
+  ".align 8                                             \n\t"
+  "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)
+/* Test SCWP, done.  */
+  "li $11, 2                                            \n\t"
+  "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;
+}
+
+/* If any test_r6_* function returns non-zero, it's a failure.  */
+#define EXPECT(X) if ((X)) abort ();
+
+int
+main (void)
+{
+  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 ());
+
+  return 0;
+}
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..710da94c542
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/mips-64-r6.exp
@@ -0,0 +1,76 @@ 
+# Copyright (C) 2023-2025 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/>.
+
+################################################################
+################## MIPS Release 6 patch tests ##################
+################################################################
+
+# Send 'si' to gdb until inferior exits.
+proc stepi {} {
+    global gdb_prompt
+    set timeout [get_largest_timeout]
+    set start [timestamp]
+    while { [timestamp] - $start < 3*$timeout } {
+	gdb_test_multiple "stepi" "" {
+	    -re ".*exited normally.*" {
+		pass "success"
+		return
+	    }
+	    -re ".*The program is not being run.*" {
+		fail "failure"
+		return
+	    }
+	    -re ".*Breakpoint.*test_.*$gdb_prompt $" {
+	    }
+	    -re "$gdb_prompt.*" {
+	    }
+	}
+    }
+    fail "test failed"
+    return
+}
+
+require {istarget "*mips*"}
+
+set testfile "mips-64-r6"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+if {[prepare_for_testing "failed to prepare" "${binfile}" "${srcfile}" {debug nowarnings}]} {
+    untested "failed to prepare"
+    return
+}
+
+# Native needs run.
+if { ![runto_main] } {
+    untested "couldn't run to 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 {
+    if {![gdb_breakpoint "$func"]} {
+	untested "couldn't put breakpoint to $func"
+	return
+    }
+}
+
+# Step through the binary
+stepi
-- 
2.34.1