diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index f95c775..8b4b915 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -1486,6 +1486,56 @@ riscv_handle_implicit_zero_offset (expressionS *ep, const char *s)
   return FALSE;
 }
 
+/* All RISC-V CSR instructions belong to one of these classes.  */
+
+enum csr_insn_type
+{
+  INSN_NOT_CSR,
+  INSN_CSRRW,
+  INSN_CSRRS,
+  INSN_CSRRC
+};
+
+/* Return which CSR instruciton is checking.  */
+
+static enum csr_insn_type
+riscv_csr_insn_type (insn_t insn)
+{
+  if (((insn ^ MATCH_CSRRW) & MASK_CSRRW) == 0
+      || ((insn ^ MATCH_CSRRWI) & MASK_CSRRWI) == 0)
+    return INSN_CSRRW;
+  else if (((insn ^ MATCH_CSRRS) & MASK_CSRRS) == 0
+	   || ((insn ^ MATCH_CSRRSI) & MASK_CSRRSI) == 0)
+    return INSN_CSRRS;
+  else if (((insn ^ MATCH_CSRRC) & MASK_CSRRC) == 0
+	   || ((insn ^ MATCH_CSRRCI) & MASK_CSRRCI) == 0)
+    return INSN_CSRRC;
+  else
+    return INSN_NOT_CSR;
+}
+
+/* CSRRW and CSRRWI always write CSR.  CSRRS, CSRRC, CSRRSI and CSRRCI write
+   CSR when RS1 isn't zero.  The CSR is read only if the [11:10] bits of
+   CSR address is 0x3.  */
+
+static bfd_boolean
+riscv_csr_read_only_check (insn_t insn)
+{
+  int csr = (insn & (OP_MASK_CSR << OP_SH_CSR)) >> OP_SH_CSR;
+  int rs1 = (insn & (OP_MASK_RS1 << OP_SH_RS1)) >> OP_SH_RS1;
+  int readonly = (((csr & (0x3 << 10)) >> 10) == 0x3);
+  enum csr_insn_type csr_insn = riscv_csr_insn_type (insn);
+
+  if (readonly
+      && (((csr_insn == INSN_CSRRS
+	    || csr_insn == INSN_CSRRC)
+	   && rs1 != 0)
+	  || csr_insn == INSN_CSRRW))
+    return FALSE;
+
+  return TRUE;
+}
+
 /* This routine assembles an instruction into its binary format.  As a
    side effect, it sets the global variable imm_reloc to the type of
    relocation to do if one of the operands is an address expression.  */
@@ -1504,6 +1554,8 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
   int argnum;
   const struct percent_op_match *p;
   const char *error = "unrecognized opcode";
+  /* Indicate we are assembling instruction with CSR.  */
+  bfd_boolean insn_with_csr = FALSE;
 
   /* Parse the name of the instruction.  Terminate the string if whitespace
      is found so that hash_find only sees the name part of the string.  */
@@ -1550,11 +1602,26 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
 					 : insn->match) == 2
 		      && !riscv_opts.rvc)
 		    break;
+
+		  /* Check if we write a read-only CSR by the CSR
+		     instruction.  */
+		  if (insn_with_csr
+		      && riscv_opts.csr_check
+		      && !riscv_csr_read_only_check (ip->insn_opcode))
+		    {
+		      /* Restore the character in advance, since we want to
+			 report the detailed warning message here.  */
+		      if (save_c)
+			*(argsStart - 1) = save_c;
+		      as_warn (_("Read-only CSR is written `%s'"), str);
+		      insn_with_csr = FALSE;
+		    }
 		}
 	      if (*s != '\0')
 		break;
 	      /* Successful assembly.  */
 	      error = NULL;
+	      insn_with_csr = FALSE;
 	      goto out;
 
 	    case 'C': /* RVC */
@@ -1899,6 +1966,7 @@ rvc_lui:
 	      continue;
 
 	    case 'E':		/* Control register.  */
+	      insn_with_csr = TRUE;
 	      if (reg_lookup (&s, RCLASS_CSR, &regno))
 		INSERT_OPERAND (CSR, *ip, regno);
 	      else
@@ -2219,6 +2287,7 @@ jump:
 	}
       s = argsStart;
       error = _("illegal operands");
+      insn_with_csr = FALSE;
     }
 
 out:
diff --git a/gas/testsuite/gas/riscv/priv-reg-fail-read-only-01.d b/gas/testsuite/gas/riscv/priv-reg-fail-read-only-01.d
new file mode 100644
index 0000000..ae190c0
--- /dev/null
+++ b/gas/testsuite/gas/riscv/priv-reg-fail-read-only-01.d
@@ -0,0 +1,3 @@
+#as: -march=rv32if -mcsr-check
+#source: priv-reg-fail-read-only-01.s
+#warning_output: priv-reg-fail-read-only-01.l
diff --git a/gas/testsuite/gas/riscv/priv-reg-fail-read-only-01.l b/gas/testsuite/gas/riscv/priv-reg-fail-read-only-01.l
new file mode 100644
index 0000000..7e52bd7
--- /dev/null
+++ b/gas/testsuite/gas/riscv/priv-reg-fail-read-only-01.l
@@ -0,0 +1,69 @@
+.*Assembler messages:
+.*Warning: Read-only CSR is written `csrw cycle,a1'
+.*Warning: Read-only CSR is written `csrw time,a1'
+.*Warning: Read-only CSR is written `csrw instret,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter3,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter4,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter5,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter6,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter7,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter8,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter9,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter10,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter11,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter12,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter13,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter14,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter15,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter16,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter17,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter18,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter19,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter20,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter21,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter22,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter23,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter24,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter25,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter26,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter27,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter28,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter29,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter30,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter31,a1'
+.*Warning: Read-only CSR is written `csrw cycleh,a1'
+.*Warning: Read-only CSR is written `csrw timeh,a1'
+.*Warning: Read-only CSR is written `csrw instreth,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter3h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter4h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter5h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter6h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter7h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter8h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter9h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter10h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter11h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter12h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter13h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter14h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter15h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter16h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter17h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter18h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter19h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter20h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter21h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter22h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter23h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter24h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter25h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter26h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter27h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter28h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter29h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter30h,a1'
+.*Warning: Read-only CSR is written `csrw hpmcounter31h,a1'
+.*Warning: Read-only CSR is written `csrw mvendorid,a1'
+.*Warning: Read-only CSR is written `csrw marchid,a1'
+.*Warning: Read-only CSR is written `csrw mimpid,a1'
+.*Warning: Read-only CSR is written `csrw mhartid,a1'
diff --git a/gas/testsuite/gas/riscv/priv-reg-fail-read-only-01.s b/gas/testsuite/gas/riscv/priv-reg-fail-read-only-01.s
new file mode 100644
index 0000000..501a52e
--- /dev/null
+++ b/gas/testsuite/gas/riscv/priv-reg-fail-read-only-01.s
@@ -0,0 +1,269 @@
+	.macro csr val
+	csrw \val, a1
+	.endm
+# 1.9.1 registers
+	csr ustatus
+	csr uie
+	csr utvec
+
+	csr uscratch
+	csr uepc
+	csr ucause
+	csr ubadaddr
+	csr uip
+
+	csr fflags
+	csr frm
+	csr fcsr
+
+	csr cycle
+	csr time
+	csr instret
+	csr hpmcounter3
+	csr hpmcounter4
+	csr hpmcounter5
+	csr hpmcounter6
+	csr hpmcounter7
+	csr hpmcounter8
+	csr hpmcounter9
+	csr hpmcounter10
+	csr hpmcounter11
+	csr hpmcounter12
+	csr hpmcounter13
+	csr hpmcounter14
+	csr hpmcounter15
+	csr hpmcounter16
+	csr hpmcounter17
+	csr hpmcounter18
+	csr hpmcounter19
+	csr hpmcounter20
+	csr hpmcounter21
+	csr hpmcounter22
+	csr hpmcounter23
+	csr hpmcounter24
+	csr hpmcounter25
+	csr hpmcounter26
+	csr hpmcounter27
+	csr hpmcounter28
+	csr hpmcounter29
+	csr hpmcounter30
+	csr hpmcounter31
+	csr cycleh
+	csr timeh
+	csr instreth
+	csr hpmcounter3h
+	csr hpmcounter4h
+	csr hpmcounter5h
+	csr hpmcounter6h
+	csr hpmcounter7h
+	csr hpmcounter8h
+	csr hpmcounter9h
+	csr hpmcounter10h
+	csr hpmcounter11h
+	csr hpmcounter12h
+	csr hpmcounter13h
+	csr hpmcounter14h
+	csr hpmcounter15h
+	csr hpmcounter16h
+	csr hpmcounter17h
+	csr hpmcounter18h
+	csr hpmcounter19h
+	csr hpmcounter20h
+	csr hpmcounter21h
+	csr hpmcounter22h
+	csr hpmcounter23h
+	csr hpmcounter24h
+	csr hpmcounter25h
+	csr hpmcounter26h
+	csr hpmcounter27h
+	csr hpmcounter28h
+	csr hpmcounter29h
+	csr hpmcounter30h
+	csr hpmcounter31h
+
+	csr sstatus
+	csr sedeleg
+	csr sideleg
+	csr sie
+	csr stvec
+
+	csr sscratch
+	csr sepc
+	csr scause
+	csr sbadaddr
+	csr sip
+
+	csr sptbr
+
+	csr hstatus
+	csr hedeleg
+	csr hideleg
+	csr hie
+	csr htvec
+
+	csr hscratch
+	csr hepc
+	csr hcause
+	csr hbadaddr
+	csr hip
+
+	csr mvendorid
+	csr marchid
+	csr mimpid
+	csr mhartid
+
+	csr mstatus
+	csr misa
+	csr medeleg
+	csr mideleg
+	csr mie
+	csr mtvec
+
+	csr mscratch
+	csr mepc
+	csr mcause
+	csr mbadaddr
+	csr mip
+
+	csr mbase
+	csr mbound
+	csr mibase
+	csr mibound
+	csr mdbase
+	csr mdbound
+
+	csr mcycle
+	csr minstret
+	csr mhpmcounter3
+	csr mhpmcounter4
+	csr mhpmcounter5
+	csr mhpmcounter6
+	csr mhpmcounter7
+	csr mhpmcounter8
+	csr mhpmcounter9
+	csr mhpmcounter10
+	csr mhpmcounter11
+	csr mhpmcounter12
+	csr mhpmcounter13
+	csr mhpmcounter14
+	csr mhpmcounter15
+	csr mhpmcounter16
+	csr mhpmcounter17
+	csr mhpmcounter18
+	csr mhpmcounter19
+	csr mhpmcounter20
+	csr mhpmcounter21
+	csr mhpmcounter22
+	csr mhpmcounter23
+	csr mhpmcounter24
+	csr mhpmcounter25
+	csr mhpmcounter26
+	csr mhpmcounter27
+	csr mhpmcounter28
+	csr mhpmcounter29
+	csr mhpmcounter30
+	csr mhpmcounter31
+	csr mcycleh
+	csr minstreth
+	csr mhpmcounter3h
+	csr mhpmcounter4h
+	csr mhpmcounter5h
+	csr mhpmcounter6h
+	csr mhpmcounter7h
+	csr mhpmcounter8h
+	csr mhpmcounter9h
+	csr mhpmcounter10h
+	csr mhpmcounter11h
+	csr mhpmcounter12h
+	csr mhpmcounter13h
+	csr mhpmcounter14h
+	csr mhpmcounter15h
+	csr mhpmcounter16h
+	csr mhpmcounter17h
+	csr mhpmcounter18h
+	csr mhpmcounter19h
+	csr mhpmcounter20h
+	csr mhpmcounter21h
+	csr mhpmcounter22h
+	csr mhpmcounter23h
+	csr mhpmcounter24h
+	csr mhpmcounter25h
+	csr mhpmcounter26h
+	csr mhpmcounter27h
+	csr mhpmcounter28h
+	csr mhpmcounter29h
+	csr mhpmcounter30h
+	csr mhpmcounter31h
+
+	csr mucounteren
+	csr mscounteren
+	csr mhcounteren
+
+	csr mhpmevent3
+	csr mhpmevent4
+	csr mhpmevent5
+	csr mhpmevent6
+	csr mhpmevent7
+	csr mhpmevent8
+	csr mhpmevent9
+	csr mhpmevent10
+	csr mhpmevent11
+	csr mhpmevent12
+	csr mhpmevent13
+	csr mhpmevent14
+	csr mhpmevent15
+	csr mhpmevent16
+	csr mhpmevent17
+	csr mhpmevent18
+	csr mhpmevent19
+	csr mhpmevent20
+	csr mhpmevent21
+	csr mhpmevent22
+	csr mhpmevent23
+	csr mhpmevent24
+	csr mhpmevent25
+	csr mhpmevent26
+	csr mhpmevent27
+	csr mhpmevent28
+	csr mhpmevent29
+	csr mhpmevent30
+	csr mhpmevent31
+
+	csr tselect
+	csr tdata1
+	csr tdata2
+	csr tdata3
+
+	csr dcsr
+	csr dpc
+	csr dscratch
+# 1.10 registers
+	csr utval
+
+	csr scounteren
+	csr stval
+	csr satp
+
+	csr mcounteren
+	csr mtval
+
+	csr pmpcfg0
+	csr pmpcfg1
+	csr pmpcfg2
+	csr pmpcfg3
+	csr pmpaddr0
+	csr pmpaddr1
+	csr pmpaddr2
+	csr pmpaddr3
+	csr pmpaddr4
+	csr pmpaddr5
+	csr pmpaddr6
+	csr pmpaddr7
+	csr pmpaddr8
+	csr pmpaddr9
+	csr pmpaddr10
+	csr pmpaddr11
+	csr pmpaddr12
+	csr pmpaddr13
+	csr pmpaddr14
+	csr pmpaddr15
diff --git a/gas/testsuite/gas/riscv/priv-reg-fail-read-only-02.d b/gas/testsuite/gas/riscv/priv-reg-fail-read-only-02.d
new file mode 100644
index 0000000..3c4715f
--- /dev/null
+++ b/gas/testsuite/gas/riscv/priv-reg-fail-read-only-02.d
@@ -0,0 +1,3 @@
+#as: -march=rv32if -mcsr-check
+#source: priv-reg-fail-read-only-02.s
+#warning_output: priv-reg-fail-read-only-02.l
diff --git a/gas/testsuite/gas/riscv/priv-reg-fail-read-only-02.l b/gas/testsuite/gas/riscv/priv-reg-fail-read-only-02.l
new file mode 100644
index 0000000..660f19d
--- /dev/null
+++ b/gas/testsuite/gas/riscv/priv-reg-fail-read-only-02.l
@@ -0,0 +1,25 @@
+.*Assembler messages:
+.*Warning: Read-only CSR is written `csrrw a0,cycle,a1'
+.*Warning: Read-only CSR is written `csrrw a0,cycle,zero'
+.*Warning: Read-only CSR is written `csrrw zero,cycle,a1'
+.*Warning: Read-only CSR is written `csrrw zero,cycle,zero'
+.*Warning: Read-only CSR is written `csrw cycle,a1'
+.*Warning: Read-only CSR is written `csrw cycle,zero'
+.*Warning: Read-only CSR is written `csrrwi a0,cycle,0xb'
+.*Warning: Read-only CSR is written `csrrwi a0,cycle,0x0'
+.*Warning: Read-only CSR is written `csrrwi zero,cycle,0xb'
+.*Warning: Read-only CSR is written `csrrwi zero,cycle,0x0'
+.*Warning: Read-only CSR is written `csrwi cycle,0xb'
+.*Warning: Read-only CSR is written `csrwi cycle,0x0'
+.*Warning: Read-only CSR is written `csrrs a0,cycle,a1'
+.*Warning: Read-only CSR is written `csrrs zero,cycle,a1'
+.*Warning: Read-only CSR is written `csrs cycle,a0'
+.*Warning: Read-only CSR is written `csrrsi a0,cycle,0xb'
+.*Warning: Read-only CSR is written `csrrsi zero,cycle,0xb'
+.*Warning: Read-only CSR is written `csrsi cycle,0xb'
+.*Warning: Read-only CSR is written `csrrc a0,cycle,a1'
+.*Warning: Read-only CSR is written `csrrc zero,cycle,a1'
+.*Warning: Read-only CSR is written `csrc cycle,a0'
+.*Warning: Read-only CSR is written `csrrci a0,cycle,0xb'
+.*Warning: Read-only CSR is written `csrrci zero,cycle,0xb'
+.*Warning: Read-only CSR is written `csrci cycle,0xb'
diff --git a/gas/testsuite/gas/riscv/priv-reg-fail-read-only-02.s b/gas/testsuite/gas/riscv/priv-reg-fail-read-only-02.s
new file mode 100644
index 0000000..7afb26e
--- /dev/null
+++ b/gas/testsuite/gas/riscv/priv-reg-fail-read-only-02.s
@@ -0,0 +1,90 @@
+# CSRRW and CSRRWI always write CSR
+# CSRRS, CSRRC, CSRRSI and CSRRCI write CSR when rs isn't zero.
+
+# csrrw rd, csr, rs
+	csrrw	a0, ustatus, a1
+	csrrw	a0, cycle, a1
+	csrrw	a0, cycle, zero
+	csrrw	zero, cycle, a1
+	csrrw	zero, cycle, zero
+	fscsr	a0, a1
+	fsrm	a0, a1
+	fsflags a0, a1
+# csrrw zero, csr, rs
+	csrw	ustatus, a1
+	csrw	cycle, a1
+	csrw	cycle, zero
+	fscsr	a1
+	fsrm	a1
+	fsflags a1
+# csrrwi rd, csr, imm
+	csrrwi	a0, ustatus, 0xb
+	csrrwi	a0, cycle, 0xb
+	csrrwi	a0, cycle, 0x0
+	csrrwi	zero, cycle, 0xb
+	csrrwi	zero, cycle, 0x0
+# csrrwi zero, csr, imm
+	csrwi   ustatus, 0xb
+	csrwi   cycle, 0xb
+	csrwi   cycle, 0x0
+
+# csrrs rd, csr, rs
+	csrrs	a0, ustatus, a1
+	csrrs	a0, cycle, a1
+	csrrs	a0, cycle, zero
+	csrrs	zero, cycle, a1
+	csrrs	zero, cycle, zero
+# csrrs rd, csr, zero
+	csrr	a0, ustatus
+	csrr	a0, cycle
+	csrr	zero, cycle
+	rdinstret  a0
+	rdinstret  zero
+	rdinstreth a0
+	rdinstreth zero
+	rdcycle	   a0
+	rdcycle    zero
+	rdcycleh   a0
+	rdcycleh   zero
+	rdtime	a0
+	rdtime  zero
+	rdtimeh	a0
+	rdtimeh zero
+	frcsr	a0
+	frrm	a0
+	frflags a0
+# csrrs zero, csr, rs
+	csrs	ustatus, a0
+	csrs	cycle, a0
+	csrs	cycle, zero
+# csrrsi rd, csr, imm
+	csrrsi	a0, ustatus, 0xb
+	csrrsi	a0, cycle, 0xb
+	csrrsi	a0, cycle, 0x0
+	csrrsi	zero, cycle, 0xb
+	csrrsi	zero, cycle, 0x0
+# csrrsi zero, csr, imm
+	csrsi	ustatus, 0xb
+	csrsi	cycle, 0xb
+	csrsi	cycle, 0x0
+
+# csrrc a0, csr, a1
+	csrrc	a0, ustatus, a1
+	csrrc	a0, cycle, a1
+	csrrc	a0, cycle, zero
+	csrrc	zero, cycle, a1
+	csrrc	zero, cycle, zero
+# csrrc zero, csr, rs
+	csrc	ustatus, a0
+	csrc	cycle, a0
+	csrc	cycle, zero
+# csrrci rd, csr, imm
+	csrrci	a0, ustatus, 0xb
+	csrrci	a0, cycle, 0xb
+	csrrci	a0, cycle, 0x0
+	csrrci	zero, cycle, 0xb
+	csrrci	zero, cycle, 0x0
+# csrrci zero, csr, imm
+	csrci	ustatus, 0xb
+	csrci	cycle, 0xb
+	csrci	cycle, 0x0
