mop.r / mop.rr preserve rd instead of trapping or zeroing it
Affected revision
RVVM staging snapshot used for this report, 2026-09-05, x86-64 host, RV64 guest user-mode execution.
Summary
In the SYSTEM instruction path (src/cpu/riscv_priv.c), the funct3 = 0b100 case contains:
case 0x04:
if ((insn & 0xB0000000UL) == 0x80000000UL) { // mop.r.{0,31}, mop.rr.{0,7} (Zimop)
return;
}
break;
For these code points RVVM returns without raising an illegal-instruction exception and without writing a value to rd. The RISC-V Zimop specification states that MOP.R.n and MOP.RR.n, unless redefined by another extension, write 0 to x[rd]. They are not pure no-ops.
Reproducer
Minimal Linux static guest:
#include <signal.h>
#include <setjmp.h>
#include <stdint.h>
#include <stdio.h>
static sigjmp_buf jb;
static volatile int trapped;
static void on_sigill(int sig, siginfo_t *si, void *ctx)
{
(void)sig; (void)si; (void)ctx;
trapped = 1;
siglongjmp(jb, 1);
}
int main(void)
{
struct sigaction sa = {0};
sa.sa_sigaction = on_sigill;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGILL, &sa, 0);
uint64_t a0 = 0x1122334455667788ULL;
if (sigsetjmp(jb, 1) == 0) {
asm volatile(".word 0x81c04573" : "+r"(a0)); // mop.r.0 a0, a0
}
printf("trap=%d out=0x%016" PRIx64 "\n", trapped, a0);
return 0;
}
The same raw words for mop.r.31, mop.rr.0, and mop.rr.7 reproduce the same behavior.
Environment
- Native RV64 reference: native RV64 hardware, RV64 Linux, direct execution.
- QEMU reference:
qemu-riscv64 user mode.
- RVVM: user-mode execution through the affected RVVM build.
Expected behavior
Either these code points should raise an illegal-instruction exception in a guest configuration that does not enable Zimop, or, if the default Zimop fallback is implemented, they should write 0 to rd.
Observed behavior
RVVM retires the instruction, preserves rd unchanged, and delivers no guest-visible trap:
trap=0 out=0x1122334455667788
On the native RV64 reference and on QEMU the same witness traps or writes zero:
native: trap=1
qemu: trap=0 out=0
Cause
The mop.r/mop.rr decode branch returns immediately. It neither traps nor applies the architectural rd = 0 writeback.
mop.r/mop.rrpreserverdinstead of trapping or zeroing itAffected revision
RVVM staging snapshot used for this report, 2026-09-05, x86-64 host, RV64 guest user-mode execution.
Summary
In the SYSTEM instruction path (
src/cpu/riscv_priv.c), thefunct3 = 0b100case contains:For these code points RVVM returns without raising an illegal-instruction exception and without writing a value to
rd. The RISC-VZimopspecification states thatMOP.R.nandMOP.RR.n, unless redefined by another extension, write0tox[rd]. They are not pure no-ops.Reproducer
Minimal Linux static guest:
The same raw words for
mop.r.31,mop.rr.0, andmop.rr.7reproduce the same behavior.Environment
qemu-riscv64user mode.Expected behavior
Either these code points should raise an illegal-instruction exception in a guest configuration that does not enable
Zimop, or, if the defaultZimopfallback is implemented, they should write0tord.Observed behavior
RVVM retires the instruction, preserves
rdunchanged, and delivers no guest-visible trap:On the native RV64 reference and on QEMU the same witness traps or writes zero:
Cause
The
mop.r/mop.rrdecode branch returns immediately. It neither traps nor applies the architecturalrd = 0writeback.