diff --git a/target/hexagon/gen_masked.c b/target/hexagon/gen_masked.c
new file mode 100644
index 0000000000..faffee2e13
--- /dev/null
+++ b/target/hexagon/gen_masked.c
@@ -0,0 +1,44 @@
+/*
+ *  Copyright(c) 2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ *  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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "tcg/tcg-op.h"
+#include "gen_masked.h"
+
+void gen_masked_reg_write(TCGv cur_val, TCGv in_val, TCGv out_val,
+    target_ulong reg_mask) {
+    TCGv set_bits = tcg_temp_new();
+    TCGv cleared_bits = tcg_temp_new();
+
+    /*
+     * set_bits = in_val & reg_mask
+     * cleared_bits = (~in_val) & reg_mask
+     */
+    tcg_gen_andi_tl(set_bits, in_val, reg_mask);
+    tcg_gen_not_tl(cleared_bits, in_val);
+    tcg_gen_andi_tl(cleared_bits, cleared_bits, reg_mask);
+
+    /*
+     * result = (reg_cur | set_bits) & (~cleared_bits)
+     */
+    tcg_gen_not_tl(cleared_bits, cleared_bits);
+    tcg_gen_or_tl(set_bits, set_bits, cur_val);
+    tcg_gen_and_tl(out_val, set_bits, cleared_bits);
+
+    tcg_temp_free(set_bits);
+    tcg_temp_free(cleared_bits);
+}
diff --git a/target/hexagon/gen_masked.h b/target/hexagon/gen_masked.h
new file mode 100644
index 0000000000..71f4b2818b
--- /dev/null
+++ b/target/hexagon/gen_masked.h
@@ -0,0 +1,26 @@
+/*
+ *  Copyright(c) 2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ *  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 2 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/>.
+ */
+
+#ifndef GEN_MASKED_H
+#define GEN_MASKED_H
+
+#include "tcg/tcg-op.h"
+
+void gen_masked_reg_write(TCGv cur_val, TCGv in_val, TCGv out_val,
+    target_ulong reg_mask);
+
+#endif /* GEN_MASKED_H */
diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c
index 8a334ba07b..21385f556e 100644
--- a/target/hexagon/genptr.c
+++ b/target/hexagon/genptr.c
@@ -29,6 +29,7 @@
 #undef QEMU_GENERATE
 #include "gen_tcg.h"
 #include "gen_tcg_hvx.h"
+#include "gen_masked.h"
 
 static inline void gen_log_predicated_reg_write(int rnum, TCGv val, int slot)
 {
@@ -53,9 +54,24 @@ static inline void gen_log_predicated_reg_write(int rnum, TCGv val, int slot)
     tcg_temp_free(slot_mask);
 }
 
+static const hexagon_mut_entry gpr_mut_masks[HEX_REG_LAST_VALUE] = {
+    [HEX_REG_PC] = {true, 0x00000000},
+    [HEX_REG_GP] = {true, 0xffffffc0},
+    [HEX_REG_USR] = {true, 0x3ecfff3f},
+    [HEX_REG_UTIMERLO] = {true, 0x00000000},
+    [HEX_REG_UTIMERHI] = {true, 0x00000000},
+};
+
+
 static inline void gen_log_reg_write(int rnum, TCGv val)
 {
-    tcg_gen_mov_tl(hex_new_value[rnum], val);
+    const hexagon_mut_entry entry = gpr_mut_masks[rnum];
+    if (entry.present) {
+        gen_masked_reg_write(hex_gpr[rnum], val, hex_new_value[rnum],
+            entry.mask);
+    } else {
+        tcg_gen_mov_tl(hex_new_value[rnum], val);
+    }
     if (HEX_DEBUG) {
         /* Do this so HELPER(debug_commit_end) will know */
         tcg_gen_movi_tl(hex_reg_written[rnum], 1);
@@ -64,18 +80,32 @@ static inline void gen_log_reg_write(int rnum, TCGv val)
 
 static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val, int slot)
 {
+    const hexagon_mut_entry entry0 = gpr_mut_masks[rnum];
+    const hexagon_mut_entry entry1 = gpr_mut_masks[rnum + 1];
     TCGv val32 = tcg_temp_new();
     TCGv zero = tcg_constant_tl(0);
     TCGv slot_mask = tcg_temp_new();
+    TCGv tmp_val = tcg_temp_new();
 
     tcg_gen_andi_tl(slot_mask, hex_slot_cancelled, 1 << slot);
+
     /* Low word */
     tcg_gen_extrl_i64_i32(val32, val);
+    if (entry0.present) {
+        tcg_gen_mov_tl(tmp_val, val32);
+        gen_masked_reg_write(hex_gpr[rnum], tmp_val, val32, entry0.mask);
+        tcg_temp_free(tmp_val);
+    }
     tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum],
                        slot_mask, zero,
                        val32, hex_new_value[rnum]);
+
     /* High word */
     tcg_gen_extrh_i64_i32(val32, val);
+    if (entry1.present) {
+        tcg_gen_mov_tl(tmp_val, val32);
+        gen_masked_reg_write(hex_gpr[rnum], tmp_val, val32, entry1.mask);
+    }
     tcg_gen_movcond_tl(TCG_COND_EQ, hex_new_value[rnum + 1],
                        slot_mask, zero,
                        val32, hex_new_value[rnum + 1]);
@@ -95,6 +125,7 @@ static void gen_log_predicated_reg_write_pair(int rnum, TCGv_i64 val, int slot)
 
     tcg_temp_free(val32);
     tcg_temp_free(slot_mask);
+    tcg_temp_free(tmp_val);
 }
 
 static void gen_log_reg_write_pair(int rnum, TCGv_i64 val)
diff --git a/target/hexagon/hex_regs.h b/target/hexagon/hex_regs.h
index a63c2c0fd5..db48cff96e 100644
--- a/target/hexagon/hex_regs.h
+++ b/target/hexagon/hex_regs.h
@@ -79,6 +79,12 @@ enum {
     HEX_REG_QEMU_HVX_CNT      = 54,
     HEX_REG_UTIMERLO          = 62,
     HEX_REG_UTIMERHI          = 63,
+    HEX_REG_LAST_VALUE        = 64,
 };
 
+
+typedef struct {
+    bool present;
+    target_ulong mask;
+} hexagon_mut_entry;
 #endif
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
index b61243103f..ea1f66982a 100644
--- a/target/hexagon/meson.build
+++ b/target/hexagon/meson.build
@@ -168,6 +168,7 @@ hexagon_ss.add(files(
     'op_helper.c',
     'gdbstub.c',
     'genptr.c',
+    'gen_masked.c',
     'reg_fields.c',
     'decode.c',
     'iclass.c',
diff --git a/tests/tcg/hexagon/Makefile.target b/tests/tcg/hexagon/Makefile.target
index 96a4d7a614..385d787a00 100644
--- a/tests/tcg/hexagon/Makefile.target
+++ b/tests/tcg/hexagon/Makefile.target
@@ -43,6 +43,7 @@ HEX_TESTS += load_align
 HEX_TESTS += atomics
 HEX_TESTS += fpstuff
 HEX_TESTS += overflow
+HEX_TESTS += reg_mut
 
 TESTS += $(HEX_TESTS)
 
diff --git a/tests/tcg/hexagon/reg_mut.c b/tests/tcg/hexagon/reg_mut.c
new file mode 100644
index 0000000000..7e81ec6bf3
--- /dev/null
+++ b/tests/tcg/hexagon/reg_mut.c
@@ -0,0 +1,107 @@
+/*
+ *  Copyright(c) 2022 Qualcomm Innovation Center, Inc. All Rights Reserved.
+ *
+ *  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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+
+int err;
+
+#define check_ne(N, EXPECT) \
+    { uint32_t value = N; \
+        if (value == EXPECT) { \
+            printf("ERROR: \"%s\" 0x%04x == 0x%04x at %s:%d\n", #N, value, \
+                EXPECT, __FILE__, __LINE__); \
+            err++; \
+        } \
+    }
+
+#define check(N, EXPECT) \
+    { uint32_t value = N; \
+        if (value != EXPECT) { \
+            printf("ERROR: \"%s\" 0x%04x != 0x%04x at %s:%d\n", #N, value, \
+                  EXPECT, __FILE__, __LINE__); \
+            err++; \
+        } \
+    }
+
+#define READ_REG(reg_name, out_reg) \
+  asm volatile ("%0 = " reg_name "\n\t" \
+                : "=r"(out_reg) \
+                : \
+                : \
+                ); \
+
+#define WRITE_REG(reg_name, out_reg, in_reg) \
+  asm volatile (reg_name " = %1\n\t" \
+                "%0 = " reg_name "\n\t" \
+                : "=r"(out_reg) \
+                : "r"(in_reg) \
+                : reg_name \
+                ); \
+
+   /*
+    * Instruction word: { pc = r0 }
+    *
+    * This instruction is barred by the assembler.
+    *
+    *    3                   2                   1
+    *  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    * |    Opc[A2_tfrrcr]   | Src[R0] |P P|                 |  C9/PC  |
+    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    */
+#define PC_EQ_R0 ".word 0x6220c009\n\t"
+
+static inline uint32_t set_pc(uint32_t in_reg)
+{
+    uint32_t out_reg;
+    asm volatile("r0 = %1\n\t"
+                 PC_EQ_R0
+                 "%0 = pc\n\t"
+                : "=r"(out_reg)
+                : "r"(in_reg)
+                : "r0");
+    return out_reg;
+}
+
+static inline uint32_t set_usr(uint32_t in_reg)
+{
+    uint32_t out_reg;
+    WRITE_REG("usr", out_reg, in_reg);
+    return out_reg;
+}
+
+int main()
+{
+    check(set_usr(0x00),       0x00);
+    check(set_usr(0xffffffff), 0x3ecfff3f);
+    check(set_usr(0x00),       0x00);
+    check(set_usr(0x01),       0x01);
+    check(set_usr(0xff),       0x3f);
+
+    /*
+     * PC is special.  Setting it to these values
+     * should cause an instruction fetch miss.
+     */
+    check_ne(set_pc(0x00000000), 0x00000000);
+    check_ne(set_pc(0xffffffff), 0xffffffff);
+    check_ne(set_pc(0x00000001), 0x00000001);
+    check_ne(set_pc(0x000000ff), 0x000000ff);
+
+    puts(err ? "FAIL" : "PASS");
+    return err;
+}
