target/riscv: vxrm write preserves upper bits instead of zeroing vxrm[XLEN-1:2]
## Host environment - Operating system: Linux - OS/kernel version: Linux DESKTOP-PL0JDQL 6.6.87.2-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC Thu Jun 5 18:30:46 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux - Architecture: x86_64 - QEMU flavor: qemu-system-riscv64 - QEMU version: QEMU emulator version 10.2.50 (v10.2.0-2311-gfff352b9b6) ## Description of problem When writing a value with nonzero upper bits to the vxrm CSR on RV64, QEMU preserves the upper bits on readback instead of zeroing vxrm\[XLEN-1:2\]. The RISC-V vector specification says: > “The vector fixed-point rounding-mode register holds a two-bit read-write rounding-mode field in the least-significant bits (vxrm\[1:0\]). The upper bits, vxrm\[XLEN-1:2\], should be written as zeros.” With the test case below, writing -1 to vxrm and then reading it back produces 0xffffffffffffffff in QEMU. By contrast, Spike sanitizes the value and reads back 0x3. This looks like a model/spec-deviation issue in target/riscv/csr.c. The current write path stores the full value: `env->vxrm = val;` and does not mask it down to the low 2 bits. This does not appear to cause a trap or fault, but it creates non-portable behavior across emulators/implementations. ## Steps to reproduce 1. Build this bare-metal test case: `li a0, -1` `csrw vxrm, a0` `csrr a1, vxrm` `j .` 2. Build command used: `riscv64-unknown-elf-gcc -march=rv64imafdch_zicfiss_zicbom_zicboz_v_zicsr_zca_zimop_zcmop_zbb_zbs_zkne_zbkb_zabha_zacas_zawrs_zkr_smepmp_zcb_zicond_zba_zknd_zbc_zbkc_zfh_zfbfmin_zfhmin_zfa_zifencei_zvfbfmin_zbkx_zvksed_zvksh_zvknha_zvknhb_zvkg_zvfbfwma_zvbc_zvbb_zvkned_zksed_zksh_zknh_zvkb_zicbop_zicfilp_svinval_zve32f -mabi=lp64 -mcmodel=medany -nostdlib -nostartfiles -T linker.ld code.S machine_to_supervisor.S machine_to_user.S -o code.elf` 3. Run QEMU with: `qemu-system-riscv64 -machine virt -m 256M -bios none -kernel code.elf -serial null -display none -S -s -cpu rv64,v=on,smstateen=on,sscofpmf=on,smcsrind=on,sscsrind=on,smaia=on,ssaia=on,ssccfg=on,smcdeleg=on,zicfiss=on,zimop=on,zcmop=on,zaamo=on,zca=on,zbb=on,zbs=on,zkne=on,zbkb=on,zabha=on,zacas=on,zawrs=on,smdbltrp=on,zkr=on,smepmp=on,zcb=on,zicond=on,i=on,m=on,a=on,f=on,d=on,c=on,h=on,zicsr=on,zicbom=on,zicboz=on,zba=on,zknd=on,zbc=on,zbkc=on,zfh=on,zfbfmin=on,zfhmin=on,zfa=on,zifencei=on,zvfbfmin=on,zbkx=on,zvksed=on,zvksh=on,zvknha=on,zvknhb=on,zvkg=on,zvfbfwma=on,zvbc=on,zvbb=on,zvkned=on,zksed=on,zksh=on,zknh=on,zvkb=on,zicbop=on,zicfilp=on,svinval=on,zve32f=on` 4. Connect with GDB: `riscv64-unknown-elf-gdb code.elf` `set pagination off` `target remote :1234` `c` `Ctrl-C` `info registers a1` 5. Observe that QEMU reports: `a1 = 0xffffffffffffffff` Expected result: `a1 = 0x0000000000000003` ## Additional information Specification reference: > 30.3.8. Vector Fixed-Point Rounding Mode (vxrm) Register > > “The vector fixed-point rounding-mode register holds a two-bit read-write rounding-mode field in the least-significant bits (vxrm\[1:0\]). The upper bits, vxrm\[XLEN-1:2\], should be written as zeros.” Observed behavior: \- QEMU readback after writing -1 to vxrm: `0xffffffffffffffff` \- Spike readback after writing -1 to vxrm: `0x3` Suspected source location: \- `target/riscv/csr.c` \- `write_vxrm()` Current code stores the full written value: `env->vxrm = val;` A possible fix would be to mask the value to the low 2 bits: `env->vxrm = val & 0x3;` This appears to be a low-impact spec-deviation / portability issue rather than a crash or security issue. <!--The line below ensures that proper tags are added to the issue. Please do not remove it.-->
issue