[PATCH] RISC-V: Add support for XW extension on some WCH cores
Kito Cheng
kito.cheng@gmail.com
Mon Nov 24 06:09:14 GMT 2025
Also could you create a PR to
https://github.com/riscv-non-isa/riscv-toolchain-conventions/blob/main/src/toolchain-conventions.adoc#list-of-vendor-prefixes
?
On Mon, Nov 24, 2025 at 10:39 AM Kito Cheng <kito.cheng@gmail.com> wrote:
>
> Why it's xwchc in LLVM but xw here?
>
> On Mon, Nov 24, 2025 at 3:50 AM Andy Lin <andylinpersonal@gmail.com> wrote:
> >
> > This patch implements the xw extension found on some QingKe cores from
> > QinHeng (WCH). BTW, there is one divergence between this patch and vendor's
> > toolchain (based on older binutils 2.38.0) when using `norvc', `rvc' and
> > `arch' directives:
> >
> > Vendor's toolchain:
> >
> > `-march' with `_xw':
> > After `.option rvc', xw opcodes are available implicitly.
> >
> > `-march' without `_xw':
> > After `.option rvc', xw opcodes are NOT available, even if we explicitly
> > add the `.option arch,+xw'.
> >
> > This patch:
> >
> > `-march' with or without `_xw':
> > After `.option rvc', xw opcodes are not available implicitly, but user
> > can add `.option arch,+xw' to enable it. This behavior is consistent
> > with other Zc* extensions not covered by the existing C extension.
> >
> > [1] Specs: http://web.archive.org/web/20251121133229/https://discourse.llvm.org/t/rfc-supporting-wch-qingke-xw-compressed-opcodes/79392/12
> > [2] LLVM's merged patch: https://github.com/llvm/llvm-project/pull/97925/files
> >
> > bfd/ChangeLog:
> >
> > * elfxx-riscv.c (riscv_multi_subset_supports): Add support for
> > XW extension.
> > * (riscv_multi_subset_supports_ext): Likewise.
> > * (riscv_update_subset_norvc): XW should not be emitted
> > under `norvc' mode.
> >
> > gas/ChangeLog:
> >
> > * config/tc-riscv.c (riscv_ip): Add XW to assembler.
> > * config/tc-riscv.c (validate_riscv_insn): Add XW.
> > * doc/c-riscv.texi: Note XW as an additional ISA extension for some
> > WCH's QingKe RISC-V MCU cores.
> > * testsuite/gas/riscv/march-help.l: Add '-xw' string.
> > * testsuite/gas/riscv/x-wch-qk-xw.d: New tests.
> > * testsuite/gas/riscv/x-wch-qk-xw.s: Likewise.
> > * testsuite/gas/riscv/x-wch-qk-xw-fail.d: Likewise.
> > * testsuite/gas/riscv/x-wch-qk-xw-fail.l: Likewise.
> > * testsuite/gas/riscv/x-wch-qk-xw-fail.s: Likewise.
> > * testsuite/gas/riscv/x-wch-qk-xw-norvc.d: New test for `norvc'.
> > * testsuite/gas/riscv/x-wch-qk-xw-norvc.s: Likewise.
> >
> > include/ChangeLog:
> >
> > * opcode/riscv-opc.h: Add MATCH and MASK opcode macros for XW.
> > * opcode/riscv.h (riscv_insn_class): Add INSN_CLASS_XWCH_QK.
> >
> > opcodes/ChangeLog:
> >
> > * riscv-opc.c (riscv_opcodes): Add XW opcodes and aliases.
> > * riscv-dis.c (print_insn_args): Add XW opcode to disassembler.
> >
> > Signed-off-by: Andy Lin <andylinpersonal@gmail.com>
> > ---
> > bfd/ChangeLog | 8 ++
> > bfd/elfxx-riscv.c | 13 +++-
> > gas/ChangeLog | 15 ++++
> > gas/NEWS | 7 +-
> > gas/config/tc-riscv.c | 62 ++++++++++++++-
> > gas/doc/c-riscv.texi | 6 ++
> > gas/testsuite/gas/riscv/march-help.l | 1 +
> > gas/testsuite/gas/riscv/x-wch-qk-xw-fail.d | 3 +
> > gas/testsuite/gas/riscv/x-wch-qk-xw-fail.l | 33 ++++++++
> > gas/testsuite/gas/riscv/x-wch-qk-xw-fail.s | 39 ++++++++++
> > gas/testsuite/gas/riscv/x-wch-qk-xw-norvc.d | 26 +++++++
> > gas/testsuite/gas/riscv/x-wch-qk-xw-norvc.s | 20 +++++
> > gas/testsuite/gas/riscv/x-wch-qk-xw.d | 81 +++++++++++++++++++
> > gas/testsuite/gas/riscv/x-wch-qk-xw.s | 86 +++++++++++++++++++++
> > include/ChangeLog | 5 ++
> > include/opcode/riscv-opc.h | 26 +++++++
> > include/opcode/riscv.h | 24 ++++++
> > opcodes/ChangeLog | 5 ++
> > opcodes/riscv-dis.c | 23 ++++++
> > opcodes/riscv-opc.c | 18 +++++
> > 20 files changed, 497 insertions(+), 4 deletions(-)
> > create mode 100644 gas/testsuite/gas/riscv/x-wch-qk-xw-fail.d
> > create mode 100644 gas/testsuite/gas/riscv/x-wch-qk-xw-fail.l
> > create mode 100644 gas/testsuite/gas/riscv/x-wch-qk-xw-fail.s
> > create mode 100644 gas/testsuite/gas/riscv/x-wch-qk-xw-norvc.d
> > create mode 100644 gas/testsuite/gas/riscv/x-wch-qk-xw-norvc.s
> > create mode 100644 gas/testsuite/gas/riscv/x-wch-qk-xw.d
> > create mode 100644 gas/testsuite/gas/riscv/x-wch-qk-xw.s
> >
> > diff --git a/bfd/ChangeLog b/bfd/ChangeLog
> > index 1bd99a9b042..c41ae349f71 100644
> > --- a/bfd/ChangeLog
> > +++ b/bfd/ChangeLog
> > @@ -1,3 +1,11 @@
> > +2025-11-23 Andy Lin <andylinpersonal@gmail.com>
> > +
> > + * elfxx-riscv.c (riscv_multi_subset_supports): Add support for
> > + XW extension.
> > + * (riscv_multi_subset_supports_ext): Likewise.
> > + * (riscv_update_subset_norvc): XW should not be emitted
> > + under `norvc' mode.
> > +
> > 2025-09-16 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
> >
> > * config.bfd <powerpc-*-solaris2*>: Remove.
> > diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
> > index 3b92fbed5f0..5c2948b5b93 100644
> > --- a/bfd/elfxx-riscv.c
> > +++ b/bfd/elfxx-riscv.c
> > @@ -1641,6 +1641,7 @@ static const struct riscv_supported_ext riscv_supported_vendor_x_ext[] =
> > {"xmipscmov", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
> > {"xmipsexectl", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
> > {"xmipslsp", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
> > + {"xw", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
> > {NULL, 0, 0, 0, 0}
> > };
> >
> > @@ -2291,6 +2292,12 @@ riscv_parse_check_conflicts (riscv_parse_subset_t *rps)
> > xlen);
> > no_conflict = false;
> > }
> > + if (riscv_subset_supports (rps, "xw")
> > + && (riscv_subset_supports (rps, "d") || riscv_subset_supports (rps, "zcb")))
> > + {
> > + rps->error_handler (_("xw' is conflict with the `d/zcb' extension"));
> > + no_conflict = false;
> > + }
> >
> > bool support_zve = false;
> > bool support_zvl = false;
> > @@ -2776,7 +2783,7 @@ riscv_update_subset_norvc (riscv_parse_subset_t *rps)
> > {
> > return riscv_update_subset1 (rps, rps->subset_list->head,
> > "-c,-zca,-zcd,-zcf,-zcb,-zce,-zcmp,-zcmt,"
> > - "-zcmop,-zclsd");
> > + "-zcmop,-zclsd,-xw");
> > }
> >
> > /* Check if the FEATURE subset is supported or not in the subset list.
> > @@ -3059,6 +3066,8 @@ riscv_multi_subset_supports (riscv_parse_subset_t *rps,
> > return riscv_subset_supports (rps, "xmipsexectl");
> > case INSN_CLASS_XMIPSLSP:
> > return riscv_subset_supports (rps, "xmipslsp");
> > + case INSN_CLASS_XWCH_QK:
> > + return riscv_subset_supports (rps, "xw");
> > default:
> > rps->error_handler
> > (_("internal: unreachable INSN_CLASS_*"));
> > @@ -3362,6 +3371,8 @@ riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps,
> > return "xsfvqmaccdod";
> > case INSN_CLASS_XSFVFNRCLIPXFQF:
> > return "xsfvfnrclipxfqf";
> > + case INSN_CLASS_XWCH_QK:
> > + return "xw";
> > default:
> > rps->error_handler
> > (_("internal: unreachable INSN_CLASS_*"));
> > diff --git a/gas/ChangeLog b/gas/ChangeLog
> > index dd7691593f1..ff10bca004b 100644
> > --- a/gas/ChangeLog
> > +++ b/gas/ChangeLog
> > @@ -1,3 +1,18 @@
> > +2025-11-23 Andy Lin <andylinpersonal@gmail.com>
> > +
> > + * config/tc-riscv.c (riscv_ip): Add XW to assembler.
> > + * config/tc-riscv.c (validate_riscv_insn): Add XW.
> > + * doc/c-riscv.texi: Note XW as an additional ISA extension for some
> > + WCH's QingKe RISC-V MCU cores.
> > + * testsuite/gas/riscv/march-help.l: Add '-xw' string.
> > + * testsuite/gas/riscv/x-wch-qk-xw.d: New tests.
> > + * testsuite/gas/riscv/x-wch-qk-xw.s: Likewise.
> > + * testsuite/gas/riscv/x-wch-qk-xw-fail.d: Likewise.
> > + * testsuite/gas/riscv/x-wch-qk-xw-fail.l: Likewise.
> > + * testsuite/gas/riscv/x-wch-qk-xw-fail.s: Likewise.
> > + * testsuite/gas/riscv/x-wch-qk-xw-norvc.d: New test for `norvc'.
> > + * testsuite/gas/riscv/x-wch-qk-xw-norvc.s: Likewise.
> > +
> > 2025-09-16 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
> >
> > * NEWS: Mention Solaris/PowerPC removal.
> > diff --git a/gas/NEWS b/gas/NEWS
> > index 4bd3d747aa5..ffeeb93aad8 100644
> > --- a/gas/NEWS
> > +++ b/gas/NEWS
> > @@ -1,5 +1,8 @@
> > -*- text -*-
> >
> > +* Add support for RISC-V vendor extension:
> > + QinHeng (WCH): xw v1.0.
> > +
> > * Emit an SFrame FRE with zero offsets to convey an undefined return address
> > in the SFrame stack trace format.
> >
> > @@ -133,7 +136,7 @@ Changes in 2.43:
> >
> > * Add a .base64 directive to the assembler which allows base64 encoded
> > binary data to be provided as strings.
> > -
> > +
> > * Add support for 'armv9.5-a' for -march in AArch64 GAS.
> >
> > * In x86 Intel syntax undue mnemonic suffixes are now warned about. This is
> > @@ -143,7 +146,7 @@ Changes in 2.43:
> > the syntax \+ to access the number of times a given macro has been executed.
> > This is similar to the already existing \@ syntax, except that the count is
> > maintained on a per-macro basis.
> > -
> > +
> > * Support the NF feature in Intel APX.
> >
> > * Remove KEYLOCKER and SHA promotions from EVEX MAP4.
> > diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
> > index df60c206b82..28bfc87a7f8 100644
> > --- a/gas/config/tc-riscv.c
> > +++ b/gas/config/tc-riscv.c
> > @@ -1771,6 +1771,17 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
> > goto unknown_validate_operand;
> > }
> > break;
> > + case 'w': /* Vendor-specific (Qinheng QingKe Xw) operands. */
> > + switch(*++oparg)
> > + {
> > + case 'b': used_bits |= ENCODE_WCH_QK_UIMM5 (-1); break; /* Xwb */
> > + case '6': used_bits |= ENCODE_WCH_QK_UIMM6_LSB0 (-1); break; /* Xw6 */
> > + case '4': used_bits |= ENCODE_WCH_QK_UIMM4 (-1); break; /* Xw4 */
> > + case '5': used_bits |= ENCODE_WCH_QK_UIMM5_LSB0 (-1); break; /* Xw5 */
> > + default:
> > + goto unknown_validate_operand;
> > + }
> > + break;
> > default:
> > goto unknown_validate_operand;
> > }
> > @@ -4287,6 +4298,54 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
> > }
> > break;
> >
> > + case 'w': /* Vendor-specific (Qinheng QingKe Xw) operands. */
> > + switch (*++oparg)
> > + {
> > + case 'b': /* Xwb: uimm5 0-31. */
> > + /* For qk.c.lbu and qk.c.sb. */
> > + if (riscv_handle_implicit_zero_offset (imm_expr, asarg))
> > + continue;
> > + if (my_getSmallExpression (imm_expr, imm_reloc, asarg, p)
> > + || imm_expr->X_op != O_constant
> > + || !VALID_WCH_QK_UIMM5 ((valueT) imm_expr->X_add_number))
> > + break;
> > + ip->insn_opcode |= ENCODE_WCH_QK_UIMM5(imm_expr->X_add_number);
> > + goto rvc_imm_done;
> > + case '6': /* Xw6: uimm6_lsb0 0-62. Must be multiple of 2. */
> > + /* For qk.c.lhu and qk.c.sh. */
> > + if (riscv_handle_implicit_zero_offset (imm_expr, asarg))
> > + continue;
> > + if (my_getSmallExpression (imm_expr, imm_reloc, asarg, p)
> > + || imm_expr->X_op != O_constant
> > + || !VALID_WCH_QK_UIMM6_LSB0 ((valueT) imm_expr->X_add_number))
> > + break;
> > + ip->insn_opcode |= ENCODE_WCH_QK_UIMM6_LSB0(imm_expr->X_add_number);
> > + goto rvc_imm_done;
> > + case '4': /* Xw4: uimm4 0-15. */
> > + /* For qk.c.lbusp and qk.c.sbsp. */
> > + if (riscv_handle_implicit_zero_offset (imm_expr, asarg))
> > + continue;
> > + if (my_getSmallExpression (imm_expr, imm_reloc, asarg, p)
> > + || imm_expr->X_op != O_constant
> > + || !VALID_WCH_QK_UIMM4 ((valueT) imm_expr->X_add_number))
> > + break;
> > + ip->insn_opcode |= ENCODE_WCH_QK_UIMM4(imm_expr->X_add_number);
> > + goto rvc_imm_done;
> > + case '5': /* Xw5: uimm5_lsb0 0-30. Must be multiple of 2. */
> > + /* For qk.c.lhusp and qk.c.shsp. */
> > + if (riscv_handle_implicit_zero_offset (imm_expr, asarg))
> > + continue;
> > + if (my_getSmallExpression (imm_expr, imm_reloc, asarg, p)
> > + || imm_expr->X_op != O_constant
> > + || !VALID_WCH_QK_UIMM5_LSB0 ((valueT) imm_expr->X_add_number))
> > + break;
> > + ip->insn_opcode |= ENCODE_WCH_QK_UIMM5_LSB0(imm_expr->X_add_number);
> > + goto rvc_imm_done;
> > + default:
> > + goto unknown_riscv_ip_operand;
> > + }
> > + break;
> > +
> > default:
> > goto unknown_riscv_ip_operand;
> > }
> > @@ -5109,7 +5168,8 @@ s_riscv_option (int x ATTRIBUTE_UNUSED)
> > riscv_arch_str (xlen, riscv_rps_as.subset_list, true/* update */);
> >
> > riscv_set_rvc (riscv_subset_supports (&riscv_rps_as, "c")
> > - || riscv_subset_supports (&riscv_rps_as, "zca"));
> > + || riscv_subset_supports (&riscv_rps_as, "zca")
> > + || riscv_subset_supports (&riscv_rps_as, "xw"));
> >
> > if (riscv_subset_supports (&riscv_rps_as, "ztso"))
> > riscv_set_tso ();
> > diff --git a/gas/doc/c-riscv.texi b/gas/doc/c-riscv.texi
> > index ea4be32a8ff..d843bfd9d50 100644
> > --- a/gas/doc/c-riscv.texi
> > +++ b/gas/doc/c-riscv.texi
> > @@ -918,4 +918,10 @@ The XMipsSlsp extension provides instructions mips.ldp, mips.lwp, mips.sdp and m
> >
> > It is documented in @url{https://mips.com/wp-content/uploads/2025/03/P8700-F_Programmers_Reference_Manual_Rev1.82_3-19-2025.pdf}.
> >
> > +@item XW
> > +
> > +The XW extension provide additional compressed opcodes present in some QingKe cores from Nanjing Qinheng Microelectronics Co., Ltd. (WCH).
> > +
> > +It is documented in @url{http://web.archive.org/web/20251121133229/https://discourse.llvm.org/t/rfc-supporting-wch-qingke-xw-compressed-opcodes/79392/12}
> > +
> > @end table
> > diff --git a/gas/testsuite/gas/riscv/march-help.l b/gas/testsuite/gas/riscv/march-help.l
> > index 0ce2f896735..aa1632ef606 100644
> > --- a/gas/testsuite/gas/riscv/march-help.l
> > +++ b/gas/testsuite/gas/riscv/march-help.l
> > @@ -186,3 +186,4 @@ All available -march extensions for RISC-V:
> > xmipscmov 1.0
> > xmipsexectl 1.0
> > xmipslsp 1.0
> > + xw 1.0
> > diff --git a/gas/testsuite/gas/riscv/x-wch-qk-xw-fail.d b/gas/testsuite/gas/riscv/x-wch-qk-xw-fail.d
> > new file mode 100644
> > index 00000000000..322c943e00b
> > --- /dev/null
> > +++ b/gas/testsuite/gas/riscv/x-wch-qk-xw-fail.d
> > @@ -0,0 +1,3 @@
> > +#as: -march=rv32ic_xw
> > +#source: x-wch-qk-xw-fail.s
> > +#error_output: x-wch-qk-xw-fail.l
> > diff --git a/gas/testsuite/gas/riscv/x-wch-qk-xw-fail.l b/gas/testsuite/gas/riscv/x-wch-qk-xw-fail.l
> > new file mode 100644
> > index 00000000000..8c17e84dc24
> > --- /dev/null
> > +++ b/gas/testsuite/gas/riscv/x-wch-qk-xw-fail.l
> > @@ -0,0 +1,33 @@
> > +.*: Assembler messages:
> > +.*: Error: unrecognized opcode `wchqk.c.lbu x8,0\(x8\)', extension `xw' required
> > +.*: Error: unrecognized opcode `wchqk.c.sb x8,0\(x8\)', extension `xw' required
> > +.*: Error: unrecognized opcode `wchqk.c.sb x8,-2\(x8\)', extension `xw' required
> > +.*: Error: unrecognized opcode `wchqk.c.sb x8,0\(x7\)', extension `xw' required
> > +.*: Error: illegal operands `wchqk.c.sb x7,0\(x8\)'
> > +.*: Error: illegal operands `wchqk.c.sb x7,-2\(x20\)'
> > +.*: Error: illegal operands `wchqk.c.lhu x8,1\(x8\)'
> > +.*: Error: illegal operands `wchqk.c.lhu x8,64\(x8\)'
> > +.*: Error: illegal operands `wchqk.c.sh x8,1\(x8\)'
> > +.*: Error: illegal operands `wchqk.c.sh x8,64\(x8\)'
> > +.*: Error: illegal operands `wchqk.c.sh x8,-1\(x8\)'
> > +.*: Error: illegal operands `wchqk.c.sh x8,-2\(x8\)'
> > +.*: Error: illegal operands `wchqk.c.sh x8,0\(x7\)'
> > +.*: Error: illegal operands `wchqk.c.sh x7,0\(x8\)'
> > +.*: Error: illegal operands `wchqk.c.sh x7,-2\(x20\)'
> > +.*: Error: illegal operands `wchqk.c.lbusp x8,0\(x8\)'
> > +.*: Error: illegal operands `wchqk.c.lbusp x8,32\(sp\)'
> > +.*: Error: illegal operands `wchqk.c.sbsp x8,0\(x8\)'
> > +.*: Error: illegal operands `wchqk.c.sbsp x8,32\(sp\)'
> > +.*: Error: illegal operands `wchqk.c.sbsp x8,-2\(sp\)'
> > +.*: Error: illegal operands `wchqk.c.sbsp x7,0\(sp\)'
> > +.*: Error: illegal operands `wchqk.c.sbsp x7,-2\(sp\)'
> > +.*: Error: illegal operands `wchqk.c.lhusp x8,0\(x8\)'
> > +.*: Error: illegal operands `wchqk.c.lhusp x8,1\(sp\)'
> > +.*: Error: illegal operands `wchqk.c.lhusp x8,32\(sp\)'
> > +.*: Error: illegal operands `wchqk.c.shsp x8,0\(x8\)'
> > +.*: Error: illegal operands `wchqk.c.shsp x8,1\(sp\)'
> > +.*: Error: illegal operands `wchqk.c.shsp x8,32\(sp\)'
> > +.*: Error: illegal operands `wchqk.c.shsp x8,-1\(sp\)'
> > +.*: Error: illegal operands `wchqk.c.shsp x8,-2\(sp\)'
> > +.*: Error: illegal operands `wchqk.c.shsp x7,0\(sp\)'
> > +.*: Error: illegal operands `wchqk.c.shsp x7,-2\(sp\)'
> > diff --git a/gas/testsuite/gas/riscv/x-wch-qk-xw-fail.s b/gas/testsuite/gas/riscv/x-wch-qk-xw-fail.s
> > new file mode 100644
> > index 00000000000..0f2323ffe0c
> > --- /dev/null
> > +++ b/gas/testsuite/gas/riscv/x-wch-qk-xw-fail.s
> > @@ -0,0 +1,39 @@
> > +target:
> > +.option norvc
> > + wchqk.c.lbu x8, 0(x8)
> > + wchqk.c.sb x8, 0(x8)
> > +.option rvc
> > + wchqk.c.sb x8, -2(x8)
> > + wchqk.c.sb x8, 0(x7)
> > +.option arch,+xw
> > + wchqk.c.sb x7, 0(x8)
> > + wchqk.c.sb x7, -2(x20)
> > +
> > + wchqk.c.lhu x8, 1(x8)
> > + wchqk.c.lhu x8, 64(x8)
> > + wchqk.c.sh x8, 1(x8)
> > + wchqk.c.sh x8, 64(x8)
> > + wchqk.c.sh x8, -1(x8)
> > + wchqk.c.sh x8, -2(x8)
> > + wchqk.c.sh x8, 0(x7)
> > + wchqk.c.sh x7, 0(x8)
> > + wchqk.c.sh x7, -2(x20)
> > +
> > + wchqk.c.lbusp x8, 0(x8)
> > + wchqk.c.lbusp x8, 32(sp)
> > + wchqk.c.sbsp x8, 0(x8)
> > + wchqk.c.sbsp x8, 32(sp)
> > + wchqk.c.sbsp x8, -2(sp)
> > + wchqk.c.sbsp x7, 0(sp)
> > + wchqk.c.sbsp x7, -2(sp)
> > +
> > + wchqk.c.lhusp x8, 0(x8)
> > + wchqk.c.lhusp x8, 1(sp)
> > + wchqk.c.lhusp x8, 32(sp)
> > + wchqk.c.shsp x8, 0(x8)
> > + wchqk.c.shsp x8, 1(sp)
> > + wchqk.c.shsp x8, 32(sp)
> > + wchqk.c.shsp x8, -1(sp)
> > + wchqk.c.shsp x8, -2(sp)
> > + wchqk.c.shsp x7, 0(sp)
> > + wchqk.c.shsp x7, -2(sp)
> > diff --git a/gas/testsuite/gas/riscv/x-wch-qk-xw-norvc.d b/gas/testsuite/gas/riscv/x-wch-qk-xw-norvc.d
> > new file mode 100644
> > index 00000000000..ab6518dc1e7
> > --- /dev/null
> > +++ b/gas/testsuite/gas/riscv/x-wch-qk-xw-norvc.d
> > @@ -0,0 +1,26 @@
> > +#as: -march=rv32ic_xw
> > +#source: x-wch-qk-xw-norvc.s
> > +#objdump: -d -Mno-aliases
> > +
> > +.*:[ ]+file format .*
> > +
> > +
> > +Disassembly of section .text:
> > +
> > +0+000 <target>:
> > +[ ]+[0-9a-f]+:[ ]+30c0[ ]+wchqk.c.lbu[ ]+s0,5\(s1\)
> > +[ ]+[0-9a-f]+:[ ]+3d60[ ]+wchqk.c.lbu[ ]+s0,31\(a0\)
> > +[ ]+[0-9a-f]+:[ ]+2000[ ]+wchqk.c.lbu[ ]+s0,0\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+3000[ ]+wchqk.c.lbu[ ]+s0,1\(s0\)
> > +
> > +[0-9a-f]+ <norvc>:
> > +[ ]+[0-9a-f]+:[ ]+0054c403[ ]+lbu[ ]+s0,5\(s1\)
> > +[ ]+[0-9a-f]+:[ ]+01f54403[ ]+lbu[ ]+s0,31\(a0\)
> > +
> > +[0-9a-f]+ <rvc>:
> > +[ ]+[0-9a-f]+:[ ]+0054c403[ ]+lbu[ ]+s0,5\(s1\)
> > +[ ]+[0-9a-f]+:[ ]+01f54403[ ]+lbu[ ]+s0,31\(a0\)
> > +
> > +[0-9a-f]+ <rvc_xw>:
> > +[ ]+[0-9a-f]+:[ ]+30c0[ ]+wchqk.c.lbu[ ]+s0,5\(s1\)
> > +[ ]+[0-9a-f]+:[ ]+3d60[ ]+wchqk.c.lbu[ ]+s0,31\(a0\)
> > diff --git a/gas/testsuite/gas/riscv/x-wch-qk-xw-norvc.s b/gas/testsuite/gas/riscv/x-wch-qk-xw-norvc.s
> > new file mode 100644
> > index 00000000000..73ca3ac9e06
> > --- /dev/null
> > +++ b/gas/testsuite/gas/riscv/x-wch-qk-xw-norvc.s
> > @@ -0,0 +1,20 @@
> > +target:
> > + lbu s0, 5(s1)
> > + lbu s0, 31(a0)
> > + wchqk.c.lbu s0, 0(s0)
> > + wchqk.c.lbu s0, 1(s0)
> > +
> > +norvc:
> > +.option norvc
> > + lbu s0, 5(s1)
> > + lbu s0, 31(a0)
> > +
> > +rvc:
> > +.option rvc
> > + lbu s0, 5(s1)
> > + lbu s0, 31(a0)
> > +
> > +rvc_xw:
> > +.option arch,+xw
> > + lbu s0, 5(s1)
> > + lbu s0, 31(a0)
> > diff --git a/gas/testsuite/gas/riscv/x-wch-qk-xw.d b/gas/testsuite/gas/riscv/x-wch-qk-xw.d
> > new file mode 100644
> > index 00000000000..510e04f1b47
> > --- /dev/null
> > +++ b/gas/testsuite/gas/riscv/x-wch-qk-xw.d
> > @@ -0,0 +1,81 @@
> > +#as: -march=rv32ic_xw
> > +#source: x-wch-qk-xw.s
> > +#objdump: -d -Mno-aliases
> > +
> > +.*:[ ]+file format .*
> > +
> > +
> > +Disassembly of section .text:
> > +
> > +0+000 <implicit_xw>:
> > +[ ]+[0-9a-f]+:[ ]+30c0[ ]+wchqk.c.lbu[ ]+s0,5\(s1\)
> > +[ ]+[0-9a-f]+:[ ]+3d60[ ]+wchqk.c.lbu[ ]+s0,31\(a0\)
> > +[ ]+[0-9a-f]+:[ ]+2100[ ]+wchqk.c.lbu[ ]+s0,0\(a0\)
> > +[ ]+[0-9a-f]+:[ ]+00094403[ ]+lbu[ ]+s0,0\(s2\)
> > +[ ]+[0-9a-f]+:[ ]+02044403[ ]+lbu[ ]+s0,32\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+b0c0[ ]+wchqk.c.sb[ ]+s0,5\(s1\)
> > +[ ]+[0-9a-f]+:[ ]+bd60[ ]+wchqk.c.sb[ ]+s0,31\(a0\)
> > +[ ]+[0-9a-f]+:[ ]+a100[ ]+wchqk.c.sb[ ]+s0,0\(a0\)
> > +[ ]+[0-9a-f]+:[ ]+00890023[ ]+sb[ ]+s0,0\(s2\)
> > +[ ]+[0-9a-f]+:[ ]+02840023[ ]+sb[ ]+s0,32\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+24a2[ ]+wchqk.c.lhu[ ]+s0,10\(s1\)
> > +[ ]+[0-9a-f]+:[ ]+3d62[ ]+wchqk.c.lhu[ ]+s0,62\(a0\)
> > +[ ]+[0-9a-f]+:[ ]+2102[ ]+wchqk.c.lhu[ ]+s0,0\(a0\)
> > +[ ]+[0-9a-f]+:[ ]+00095403[ ]+lhu[ ]+s0,0\(s2\)
> > +[ ]+[0-9a-f]+:[ ]+00145403[ ]+lhu[ ]+s0,1\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+04045403[ ]+lhu[ ]+s0,64\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+a4a2[ ]+wchqk.c.sh[ ]+s0,10\(s1\)
> > +[ ]+[0-9a-f]+:[ ]+bd62[ ]+wchqk.c.sh[ ]+s0,62\(a0\)
> > +[ ]+[0-9a-f]+:[ ]+a102[ ]+wchqk.c.sh[ ]+s0,0\(a0\)
> > +[ ]+[0-9a-f]+:[ ]+00891023[ ]+sh[ ]+s0,0\(s2\)
> > +[ ]+[0-9a-f]+:[ ]+008410a3[ ]+sh[ ]+s0,1\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+04841023[ ]+sh[ ]+s0,64\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+8010[ ]+wchqk.c.lbusp[ ]+a2,0\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+8390[ ]+wchqk.c.lbusp[ ]+a2,7\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+8790[ ]+wchqk.c.lbusp[ ]+a2,15\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+00014903[ ]+lbu[ ]+s2,0\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+01014403[ ]+lbu[ ]+s0,16\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+8050[ ]+wchqk.c.sbsp[ ]+a2,0\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+83d0[ ]+wchqk.c.sbsp[ ]+a2,7\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+87d0[ ]+wchqk.c.sbsp[ ]+a2,15\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+01210023[ ]+sb[ ]+s2,0\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+00810823[ ]+sb[ ]+s0,16\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+8030[ ]+wchqk.c.lhusp[ ]+a2,0\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+8730[ ]+wchqk.c.lhusp[ ]+a2,14\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+87b0[ ]+wchqk.c.lhusp[ ]+a2,30\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+00015903[ ]+lhu[ ]+s2,0\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+00115903[ ]+lhu[ ]+s2,1\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+02015403[ ]+lhu[ ]+s0,32\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+8070[ ]+wchqk.c.shsp[ ]+a2,0\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+8770[ ]+wchqk.c.shsp[ ]+a2,14\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+87f0[ ]+wchqk.c.shsp[ ]+a2,30\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+01211023[ ]+sh[ ]+s2,0\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+012110a3[ ]+sh[ ]+s2,1\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+02811023[ ]+sh[ ]+s0,32\(sp\)
> > +
> > +[0-9a-f]+ <explicit_xw>:
> > +[ ]+[0-9a-f]+:[ ]+2000[ ]+wchqk.c.lbu[ ]+s0,0\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+2000[ ]+wchqk.c.lbu[ ]+s0,0\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+3000[ ]+wchqk.c.lbu[ ]+s0,1\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+2800[ ]+wchqk.c.lbu[ ]+s0,16\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+a000[ ]+wchqk.c.sb[ ]+s0,0\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+a000[ ]+wchqk.c.sb[ ]+s0,0\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+a800[ ]+wchqk.c.sb[ ]+s0,16\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+2002[ ]+wchqk.c.lhu[ ]+s0,0\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+2002[ ]+wchqk.c.lhu[ ]+s0,0\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+3002[ ]+wchqk.c.lhu[ ]+s0,32\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+a002[ ]+wchqk.c.sh[ ]+s0,0\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+a002[ ]+wchqk.c.sh[ ]+s0,0\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+b002[ ]+wchqk.c.sh[ ]+s0,32\(s0\)
> > +[ ]+[0-9a-f]+:[ ]+8000[ ]+wchqk.c.lbusp[ ]+s0,0\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+8000[ ]+wchqk.c.lbusp[ ]+s0,0\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+8400[ ]+wchqk.c.lbusp[ ]+s0,8\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+8040[ ]+wchqk.c.sbsp[ ]+s0,0\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+8040[ ]+wchqk.c.sbsp[ ]+s0,0\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+8440[ ]+wchqk.c.sbsp[ ]+s0,8\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+8020[ ]+wchqk.c.lhusp[ ]+s0,0\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+8020[ ]+wchqk.c.lhusp[ ]+s0,0\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+80a0[ ]+wchqk.c.lhusp[ ]+s0,16\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+8060[ ]+wchqk.c.shsp[ ]+s0,0\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+8060[ ]+wchqk.c.shsp[ ]+s0,0\(sp\)
> > +[ ]+[0-9a-f]+:[ ]+80e0[ ]+wchqk.c.shsp[ ]+s0,16\(sp\)
> > diff --git a/gas/testsuite/gas/riscv/x-wch-qk-xw.s b/gas/testsuite/gas/riscv/x-wch-qk-xw.s
> > new file mode 100644
> > index 00000000000..a85981371c6
> > --- /dev/null
> > +++ b/gas/testsuite/gas/riscv/x-wch-qk-xw.s
> > @@ -0,0 +1,86 @@
> > +implicit_xw:
> > + lbu s0, 5(s1)
> > + lbu s0, 31(a0)
> > + lbu s0, (a0)
> > + lbu s0, 0(s2)
> > + lbu s0, 32(s0)
> > +
> > + sb s0, 5(s1)
> > + sb s0, 31(a0)
> > + sb s0, (a0)
> > + sb s0, 0(s2)
> > + sb s0, 32(s0)
> > +
> > + lhu s0, 10(s1)
> > + lhu s0, 62(a0)
> > + lhu s0, (a0)
> > + lhu s0, 0(s2)
> > + lhu s0, 1(s0)
> > + lhu s0, 64(s0)
> > +
> > + sh s0, 10(s1)
> > + sh s0, 62(a0)
> > + sh s0, (a0)
> > + sh s0, 0(s2)
> > + sh s0, 1(s0)
> > + sh s0, 64(s0)
> > +
> > + lbu a2, (sp)
> > + lbu a2, 7(sp)
> > + lbu a2, 15(sp)
> > + lbu s2, 0(sp)
> > + lbu s0, 16(sp)
> > +
> > + sb a2, (sp)
> > + sb a2, 7(sp)
> > + sb a2, 15(sp)
> > + sb s2, 0(sp)
> > + sb s0, 16(sp)
> > +
> > + lhu a2, (sp)
> > + lhu a2, 14(sp)
> > + lhu a2, 30(sp)
> > + lhu s2, 0(sp)
> > + lhu s2, 1(sp)
> > + lhu s0, 32(sp)
> > +
> > + sh a2, (sp)
> > + sh a2, 14(sp)
> > + sh a2, 30(sp)
> > + sh s2, 0(sp)
> > + sh s2, 1(sp)
> > + sh s0, 32(sp)
> > +
> > +explicit_xw:
> > + wchqk.c.lbu s0, (s0)
> > + wchqk.c.lbu s0, 0(s0)
> > + wchqk.c.lbu s0, 1(s0)
> > + wchqk.c.lbu s0, 16(s0)
> > +
> > + wchqk.c.sb s0, (s0)
> > + wchqk.c.sb s0, 0(s0)
> > + wchqk.c.sb s0, 16(s0)
> > +
> > + wchqk.c.lhu s0, (s0)
> > + wchqk.c.lhu s0, 0(s0)
> > + wchqk.c.lhu s0, 32(s0)
> > +
> > + wchqk.c.sh s0, (s0)
> > + wchqk.c.sh s0, 0(s0)
> > + wchqk.c.sh s0, 32(s0)
> > +
> > + wchqk.c.lbusp s0, (sp)
> > + wchqk.c.lbusp s0, 0(sp)
> > + wchqk.c.lbusp s0, 8(sp)
> > +
> > + wchqk.c.sbsp s0, (sp)
> > + wchqk.c.sbsp s0, 0(sp)
> > + wchqk.c.sbsp s0, 8(sp)
> > +
> > + wchqk.c.lhusp s0, (sp)
> > + wchqk.c.lhusp s0, 0(sp)
> > + wchqk.c.lhusp s0, 16(sp)
> > +
> > + wchqk.c.shsp s0, (sp)
> > + wchqk.c.shsp s0, 0(sp)
> > + wchqk.c.shsp s0, 16(sp)
> > diff --git a/include/ChangeLog b/include/ChangeLog
> > index 6ef4b590930..e52dbe9e71f 100644
> > --- a/include/ChangeLog
> > +++ b/include/ChangeLog
> > @@ -1,3 +1,8 @@
> > +2025-11-23 Andy Lin <andylinpersonal@gmail.com>
> > +
> > + * opcode/riscv-opc.h: Add MATCH and MASK opcode macros for XW.
> > + * opcode/riscv.h (riscv_insn_class): Add INSN_CLASS_XWCH_QK.
> > +
> > 2025-07-13 Nick Clifton <nickc@redhat.com>
> >
> > * 2.45 Branch point.
> > diff --git a/include/opcode/riscv-opc.h b/include/opcode/riscv-opc.h
> > index bce59c7e6f7..8f54973ed26 100644
> > --- a/include/opcode/riscv-opc.h
> > +++ b/include/opcode/riscv-opc.h
> > @@ -3811,6 +3811,23 @@
> > /* Vendor-specific (SiFive) cease instruction. */
> > #define MATCH_SF_CEASE 0x30500073
> > #define MASK_SF_CEASE 0xffffffff
> > +/* Qinheng QingKe Xw instructions. */
> > +#define MATCH_WCH_QK_C_LBU 0x2000
> > +#define MASK_WCH_QK_C_LBU 0xe003
> > +#define MATCH_WCH_QK_C_LHU 0x2002
> > +#define MASK_WCH_QK_C_LHU 0xe003
> > +#define MATCH_WCH_QK_C_SB 0xa000
> > +#define MASK_WCH_QK_C_SB 0xe003
> > +#define MATCH_WCH_QK_C_SH 0xa002
> > +#define MASK_WCH_QK_C_SH 0xe003
> > +#define MATCH_WCH_QK_C_LBUSP 0x8000
> > +#define MASK_WCH_QK_C_LBUSP 0xf863
> > +#define MATCH_WCH_QK_C_LHUSP 0x8020
> > +#define MASK_WCH_QK_C_LHUSP 0xf863
> > +#define MATCH_WCH_QK_C_SBSP 0x8040
> > +#define MASK_WCH_QK_C_SBSP 0xf863
> > +#define MATCH_WCH_QK_C_SHSP 0x8060
> > +#define MASK_WCH_QK_C_SHSP 0xf863
> > /* SiFive custom int8 matrix-multiply instruction. */
> > #define MATCH_SFVQMACCU4X8X4 0xf200205b
> > #define MASK_SFVQMACCU4X8X4 0xfe00707f
> > @@ -5022,6 +5039,15 @@ DECLARE_INSN(mips_ehb, MATCH_MIPS_EHB, MASK_MIPS_EHB)
> > DECLARE_INSN(mips_ihb, MATCH_MIPS_IHB, MASK_MIPS_IHB)
> > DECLARE_INSN(mips_pause, MATCH_MIPS_PAUSE, MASK_MIPS_PAUSE)
> > DECLARE_INSN(mips_pref, MATCH_MIPS_PREF, MASK_MIPS_PREF)
> > +/* Vendor-specific (Qinheng QingKe Xw) instructions. */
> > +DECLARE_INSN(qk_c_lbu, MATCH_WCH_QK_C_LBU, MASK_WCH_QK_C_LBU)
> > +DECLARE_INSN(qk_c_lhu, MATCH_WCH_QK_C_LHU, MASK_WCH_QK_C_LHU)
> > +DECLARE_INSN(qk_c_sb, MATCH_WCH_QK_C_SB, MASK_WCH_QK_C_SB)
> > +DECLARE_INSN(qk_c_sh, MATCH_WCH_QK_C_SH, MASK_WCH_QK_C_SH)
> > +DECLARE_INSN(qk_c_lbusp, MATCH_WCH_QK_C_LBUSP, MASK_WCH_QK_C_LBUSP)
> > +DECLARE_INSN(qk_c_lhusp, MATCH_WCH_QK_C_LHUSP, MASK_WCH_QK_C_LHUSP)
> > +DECLARE_INSN(qk_c_sbsp, MATCH_WCH_QK_C_SBSP, MASK_WCH_QK_C_SBSP)
> > +DECLARE_INSN(qk_c_shsp, MATCH_WCH_QK_C_SHSP, MASK_WCH_QK_C_SHSP)
> > #endif /* DECLARE_INSN */
> > #ifdef DECLARE_CSR
> > /* Unprivileged Counter/Timers CSRs. */
> > diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
> > index 858fcce6871..e0b6033ca5e 100644
> > --- a/include/opcode/riscv.h
> > +++ b/include/opcode/riscv.h
> > @@ -141,6 +141,15 @@ static inline unsigned int riscv_insn_length (insn_t insn)
> > ((RV_X(x, 25, 2) << 5) | (RV_X(x, 9, 3) << 2))
> > #define EXTRACT_MIPS_SDP_IMM(x) \
> > ((RV_X(x, 25, 2) << 5) | (RV_X(x, 10, 2) << 3))
> > +/* Vendor-specific (Qinheng QingKe Xw) extract macros. */
> > +#define EXTRACT_WCH_QK_UIMM5(x) \
> > + ((RV_X(x, 12, 1)) | (RV_X(x, 10, 2) << 3) | (RV_X(x, 5, 2) << 1))
> > +#define EXTRACT_WCH_QK_UIMM6_LSB0(x) \
> > + ((RV_X(x, 10, 3) << 3) | (RV_X(x, 5, 2) << 1))
> > +#define EXTRACT_WCH_QK_UIMM4(x) \
> > + (RV_X(x, 7, 4))
> > +#define EXTRACT_WCH_QK_UIMM5_LSB0(x) \
> > + ((RV_X(x, 8, 3) << 1) | (RV_X(x, 7, 1) << 4))
> >
> > #define ENCODE_ITYPE_IMM(x) \
> > (RV_X(x, 0, 12) << 20)
> > @@ -218,6 +227,15 @@ static inline unsigned int riscv_insn_length (insn_t insn)
> > ((RV_X(x, 5, 2) << 25) | (RV_X(x, 2, 3) << 9))
> > #define ENCODE_MIPS_SDP_IMM(x) \
> > ((RV_X(x, 5, 2) << 25) | (RV_X(x, 3, 2) << 10))
> > +/* Vendor-specific (Qinheng QingKe Xw) encode macros. */
> > +#define ENCODE_WCH_QK_UIMM5(x) \
> > + ((RV_X(x, 0, 1) << 12) | (RV_X(x, 3, 2) << 10) | (RV_X(x, 1, 2) << 5))
> > +#define ENCODE_WCH_QK_UIMM6_LSB0(x) \
> > + ((RV_X(x, 5, 1) << 12) | (RV_X(x, 3, 2) << 10) | (RV_X(x, 1, 2) << 5))
> > +#define ENCODE_WCH_QK_UIMM4(x) \
> > + (RV_X(x, 0, 4) << 7)
> > +#define ENCODE_WCH_QK_UIMM5_LSB0(x) \
> > + ((RV_X(x, 1, 3) << 8) | (RV_X(x, 4, 1) << 7))
> >
> > #define VALID_ITYPE_IMM(x) (EXTRACT_ITYPE_IMM(ENCODE_ITYPE_IMM(x)) == (x))
> > #define VALID_STYPE_IMM(x) (EXTRACT_STYPE_IMM(ENCODE_STYPE_IMM(x)) == (x))
> > @@ -246,6 +264,11 @@ static inline unsigned int riscv_insn_length (insn_t insn)
> > #define VALID_ZCB_BYTE_UIMM(x) (EXTRACT_ZCB_BYTE_UIMM(ENCODE_ZCB_BYTE_UIMM(x)) == (x))
> > #define VALID_ZCB_HALFWORD_UIMM(x) (EXTRACT_ZCB_HALFWORD_UIMM(ENCODE_ZCB_HALFWORD_UIMM(x)) == (x))
> > #define VALID_ZCMP_SPIMM(x) (EXTRACT_ZCMP_SPIMM(ENCODE_ZCMP_SPIMM(x)) == (x))
> > +/* Vendor-specific (Qinheng QingKe Xw) validation macros. */
> > +#define VALID_WCH_QK_UIMM5(x) (EXTRACT_WCH_QK_UIMM5(ENCODE_WCH_QK_UIMM5(x)) == (x))
> > +#define VALID_WCH_QK_UIMM6_LSB0(x) (EXTRACT_WCH_QK_UIMM6_LSB0(ENCODE_WCH_QK_UIMM6_LSB0(x)) == (x))
> > +#define VALID_WCH_QK_UIMM4(x) (EXTRACT_WCH_QK_UIMM4(ENCODE_WCH_QK_UIMM4(x)) == (x))
> > +#define VALID_WCH_QK_UIMM5_LSB0(x) (EXTRACT_WCH_QK_UIMM5_LSB0(ENCODE_WCH_QK_UIMM5_LSB0(x)) == (x))
> >
> > #define RISCV_RTYPE(insn, rd, rs1, rs2) \
> > ((MATCH_ ## insn) | ((rd) << OP_SH_RD) | ((rs1) << OP_SH_RS1) | ((rs2) << OP_SH_RS2))
> > @@ -606,6 +629,7 @@ enum riscv_insn_class
> > INSN_CLASS_XMIPSCMOV,
> > INSN_CLASS_XMIPSEXECTL,
> > INSN_CLASS_XMIPSLSP,
> > + INSN_CLASS_XWCH_QK,
> > };
> >
> > /* This structure holds information for a particular instruction. */
> > diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
> > index 13659e317eb..dc5839b83d5 100644
> > --- a/opcodes/ChangeLog
> > +++ b/opcodes/ChangeLog
> > @@ -1,3 +1,8 @@
> > +2025-11-23 Andy Lin <andylinpersonal@gmail.com>
> > +
> > + * riscv-opc.c (riscv_opcodes): Add XW opcodes and aliases.
> > + * riscv-dis.c (print_insn_args): Add XW opcode to disassembler.
> > +
> > 2025-07-13 Nick Clifton <nickc@redhat.com>
> >
> > * 2.45 Branch point.
> > diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
> > index fa2d44af28f..4e92dcd41ac 100644
> > --- a/opcodes/riscv-dis.c
> > +++ b/opcodes/riscv-dis.c
> > @@ -917,6 +917,29 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
> > goto undefined_modifier;
> > }
> > break;
> > + case 'w': /* Vendor-specific (Qinghen QingKe Xw) operands. */
> > + switch (*++oparg)
> > + {
> > + case 'b':
> > + print (info->stream, dis_style_immediate, "%d",
> > + (unsigned)EXTRACT_WCH_QK_UIMM5 (l));
> > + break;
> > + case '6':
> > + print (info->stream, dis_style_immediate, "%d",
> > + (unsigned)EXTRACT_WCH_QK_UIMM6_LSB0 (l));
> > + break;
> > + case '4':
> > + print (info->stream, dis_style_immediate, "%d",
> > + (unsigned)EXTRACT_WCH_QK_UIMM4 (l));
> > + break;
> > + case '5':
> > + print (info->stream, dis_style_immediate, "%d",
> > + (unsigned)EXTRACT_WCH_QK_UIMM5_LSB0 (l));
> > + break;
> > + default:
> > + goto undefined_modifier;
> > + }
> > + break;
> > default:
> > goto undefined_modifier;
> > }
> > diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
> > index e6fe5e9afba..69fe23fd553 100644
> > --- a/opcodes/riscv-opc.c
> > +++ b/opcodes/riscv-opc.c
> > @@ -589,12 +589,16 @@ const struct riscv_opcode riscv_opcodes[] =
> > {"lb", 0, INSN_CLASS_I, "d,o(s)", MATCH_LB, MASK_LB, match_opcode, INSN_DREF|INSN_1_BYTE },
> > {"lb", 0, INSN_CLASS_I, "d,A", 0, (int) M_Lx, match_rd_nonzero, INSN_MACRO },
> > {"lbu", 0, INSN_CLASS_ZCB, "Ct,Wcb(Cs)", MATCH_C_LBU, MASK_C_LBU, match_opcode, INSN_ALIAS|INSN_DREF|INSN_1_BYTE },
> > +{"lbu", 32, INSN_CLASS_XWCH_QK, "Ct,Xw4(Cc)", MATCH_WCH_QK_C_LBUSP, MASK_WCH_QK_C_LBUSP, match_opcode, INSN_ALIAS|INSN_DREF|INSN_1_BYTE },
> > +{"lbu", 32, INSN_CLASS_XWCH_QK, "Ct,Xwb(Cs)", MATCH_WCH_QK_C_LBU, MASK_WCH_QK_C_LBU, match_opcode, INSN_ALIAS|INSN_DREF|INSN_1_BYTE },
> > {"lbu", 0, INSN_CLASS_I, "d,o(s)", MATCH_LBU, MASK_LBU, match_opcode, INSN_DREF|INSN_1_BYTE },
> > {"lbu", 0, INSN_CLASS_I, "d,A", 0, (int) M_Lx, match_rd_nonzero, INSN_MACRO },
> > {"lh", 0, INSN_CLASS_ZCB, "Ct,Wch(Cs)", MATCH_C_LH, MASK_C_LH, match_opcode, INSN_ALIAS|INSN_DREF|INSN_2_BYTE },
> > {"lh", 0, INSN_CLASS_I, "d,o(s)", MATCH_LH, MASK_LH, match_opcode, INSN_DREF|INSN_2_BYTE },
> > {"lh", 0, INSN_CLASS_I, "d,A", 0, (int) M_Lx, match_rd_nonzero, INSN_MACRO },
> > {"lhu", 0, INSN_CLASS_ZCB, "Ct,Wch(Cs)", MATCH_C_LHU, MASK_C_LHU, match_opcode, INSN_ALIAS|INSN_DREF|INSN_2_BYTE },
> > +{"lhu", 32, INSN_CLASS_XWCH_QK, "Ct,Xw5(Cc)", MATCH_WCH_QK_C_LHUSP, MASK_WCH_QK_C_LHUSP, match_opcode, INSN_ALIAS|INSN_DREF|INSN_2_BYTE },
> > +{"lhu", 32, INSN_CLASS_XWCH_QK, "Ct,Xw6(Cs)", MATCH_WCH_QK_C_LHU, MASK_WCH_QK_C_LHU, match_opcode, INSN_ALIAS|INSN_DREF|INSN_2_BYTE },
> > {"lhu", 0, INSN_CLASS_I, "d,o(s)", MATCH_LHU, MASK_LHU, match_opcode, INSN_DREF|INSN_2_BYTE },
> > {"lhu", 0, INSN_CLASS_I, "d,A", 0, (int) M_Lx, match_rd_nonzero, INSN_MACRO },
> > {"lw", 0, INSN_CLASS_ZCA, "d,Cm(Cc)", MATCH_C_LWSP, MASK_C_LWSP, match_rd_nonzero, INSN_ALIAS|INSN_DREF|INSN_4_BYTE },
> > @@ -626,9 +630,13 @@ const struct riscv_opcode riscv_opcodes[] =
> > {"sgt", 0, INSN_CLASS_I, "d,t,s", MATCH_SLT, MASK_SLT, match_opcode, INSN_ALIAS },
> > {"sgtu", 0, INSN_CLASS_I, "d,t,s", MATCH_SLTU, MASK_SLTU, match_opcode, INSN_ALIAS },
> > {"sb", 0, INSN_CLASS_ZCB, "Ct,Wcb(Cs)", MATCH_C_SB, MASK_C_SB, match_opcode, INSN_DREF|INSN_1_BYTE|INSN_ALIAS },
> > +{"sb", 32, INSN_CLASS_XWCH_QK, "Ct,Xw4(Cc)", MATCH_WCH_QK_C_SBSP, MASK_WCH_QK_C_SBSP, match_opcode, INSN_DREF|INSN_1_BYTE|INSN_ALIAS },
> > +{"sb", 32, INSN_CLASS_XWCH_QK, "Ct,Xwb(Cs)", MATCH_WCH_QK_C_SB, MASK_WCH_QK_C_SB, match_opcode, INSN_DREF|INSN_1_BYTE|INSN_ALIAS },
> > {"sb", 0, INSN_CLASS_I, "t,q(s)", MATCH_SB, MASK_SB, match_opcode, INSN_DREF|INSN_1_BYTE },
> > {"sb", 0, INSN_CLASS_I, "t,A,s", 0, (int) M_Sx_FSx, match_rs1_nonzero, INSN_MACRO },
> > {"sh", 0, INSN_CLASS_ZCB, "Ct,Wch(Cs)", MATCH_C_SH, MASK_C_SH, match_opcode, INSN_DREF|INSN_2_BYTE|INSN_ALIAS },
> > +{"sh", 32, INSN_CLASS_XWCH_QK, "Ct,Xw5(Cc)", MATCH_WCH_QK_C_SHSP, MASK_WCH_QK_C_SHSP, match_opcode, INSN_DREF|INSN_2_BYTE|INSN_ALIAS },
> > +{"sh", 32, INSN_CLASS_XWCH_QK, "Ct,Xw6(Cs)", MATCH_WCH_QK_C_SH, MASK_WCH_QK_C_SH, match_opcode, INSN_DREF|INSN_2_BYTE|INSN_ALIAS },
> > {"sh", 0, INSN_CLASS_I, "t,q(s)", MATCH_SH, MASK_SH, match_opcode, INSN_DREF|INSN_2_BYTE },
> > {"sh", 0, INSN_CLASS_I, "t,A,s", 0, (int) M_Sx_FSx, match_rs1_nonzero, INSN_MACRO },
> > {"sw", 0, INSN_CLASS_ZCA, "CV,CM(Cc)", MATCH_C_SWSP, MASK_C_SWSP, match_opcode, INSN_ALIAS|INSN_DREF|INSN_4_BYTE },
> > @@ -3579,6 +3587,16 @@ const struct riscv_opcode riscv_opcodes[] =
> > {"mips.sdp", 0, INSN_CLASS_XMIPSLSP, "t,r,Xm^(s)", MATCH_MIPS_SDP, MASK_MIPS_SDP, match_opcode, 0 },
> > {"mips.swp", 0, INSN_CLASS_XMIPSLSP, "t,r,Xm&(s)", MATCH_MIPS_SWP, MASK_MIPS_SWP, match_opcode, 0 },
> >
> > +/* Qinghen QingKe Xw instructions. */
> > +{"wchqk.c.lbu", 32, INSN_CLASS_XWCH_QK, "Ct,Xwb(Cs)", MATCH_WCH_QK_C_LBU, MASK_WCH_QK_C_LBU, match_opcode, INSN_DREF|INSN_1_BYTE },
> > +{"wchqk.c.lhu", 32, INSN_CLASS_XWCH_QK, "Ct,Xw6(Cs)", MATCH_WCH_QK_C_LHU, MASK_WCH_QK_C_LHU, match_opcode, INSN_DREF|INSN_2_BYTE },
> > +{"wchqk.c.sb", 32, INSN_CLASS_XWCH_QK, "Ct,Xwb(Cs)", MATCH_WCH_QK_C_SB, MASK_WCH_QK_C_SB, match_opcode, INSN_DREF|INSN_1_BYTE },
> > +{"wchqk.c.sh", 32, INSN_CLASS_XWCH_QK, "Ct,Xw6(Cs)", MATCH_WCH_QK_C_SH, MASK_WCH_QK_C_SH, match_opcode, INSN_DREF|INSN_2_BYTE },
> > +{"wchqk.c.lbusp", 32, INSN_CLASS_XWCH_QK, "Ct,Xw4(Cc)", MATCH_WCH_QK_C_LBUSP, MASK_WCH_QK_C_LBUSP, match_opcode, INSN_DREF|INSN_1_BYTE },
> > +{"wchqk.c.lhusp", 32, INSN_CLASS_XWCH_QK, "Ct,Xw5(Cc)", MATCH_WCH_QK_C_LHUSP, MASK_WCH_QK_C_LHUSP, match_opcode, INSN_DREF|INSN_2_BYTE },
> > +{"wchqk.c.sbsp", 32, INSN_CLASS_XWCH_QK, "Ct,Xw4(Cc)", MATCH_WCH_QK_C_SBSP, MASK_WCH_QK_C_SBSP, match_opcode, INSN_DREF|INSN_1_BYTE },
> > +{"wchqk.c.shsp", 32, INSN_CLASS_XWCH_QK, "Ct,Xw5(Cc)", MATCH_WCH_QK_C_SHSP, MASK_WCH_QK_C_SHSP, match_opcode, INSN_DREF|INSN_2_BYTE },
> > +
> > /* Terminate the list. */
> > {0, 0, INSN_CLASS_NONE, 0, 0, 0, 0, 0}
> > };
> > --
> > 2.43.0
> >
More information about the Binutils
mailing list