From 59cc7ad6552a8dd579ed6f40371bca33505acd01 Mon Sep 17 00:00:00 2001 From: 124107157-KV <124107157@umail.ucc.ie> Date: Mon, 24 Aug 2026 21:11:47 +0100 Subject: [PATCH] Fix Zcmt table jump target LSB Clear bit 0 of the JVT-loaded target before converting it to the PC-relative offset used by the internal JAL expansion. Add RV32 directed regressions covering odd JVT targets for cm.jt and cm.jalt. --- core/zcmt_decoder.sv | 5 +- verif/regress/issue-tests.sh | 35 +++++++++ verif/tests/custom/zcmt/cm_jalt_target_lsb.S | 78 ++++++++++++++++++++ verif/tests/custom/zcmt/cm_jt_target_lsb.S | 68 +++++++++++++++++ verif/tests/testlist_issues.yaml | 26 +++++++ 5 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 verif/tests/custom/zcmt/cm_jalt_target_lsb.S create mode 100644 verif/tests/custom/zcmt/cm_jt_target_lsb.S diff --git a/core/zcmt_decoder.sv b/core/zcmt_decoder.sv index 64f651db325..e02f541aea1 100644 --- a/core/zcmt_decoder.sv +++ b/core/zcmt_decoder.sv @@ -97,8 +97,9 @@ module zcmt_decoder #( end TABLE_JUMP: begin if (req_port_i.data_rvalid) begin - // save the PC relative Xlen table jump address - jump_address_o = $unsigned($signed(req_port_i.data_rdata) - $signed(pc_i)); + // Clear bit 0 of the JVT target before converting it to a PC-relative offset. + jump_address_o = + $unsigned($signed({req_port_i.data_rdata[CVA6Cfg.XLEN-1:1], 1'b0}) - $signed(pc_i)); if (instr_i[9:2] < 32) begin // jal pc_offset, x0 for no return stack instr_o = { 20'h0, 5'h0, riscv::OpcodeJal diff --git a/verif/regress/issue-tests.sh b/verif/regress/issue-tests.sh index a722f0b73bf..37aaaf07fe0 100644 --- a/verif/regress/issue-tests.sh +++ b/verif/regress/issue-tests.sh @@ -51,4 +51,39 @@ if [ "$zcmt_status" -ne 0 ]; then return "$zcmt_status" 2>/dev/null || exit "$zcmt_status" fi + +# Check that cm.jt clears bit 0 of the loaded JVT target. +python3 cva6.py \ + --testlist=../tests/testlist_issues.yaml \ + --test zcmt-jt-target-lsb-rv32 \ + --iss_yaml cva6.yaml \ + --target hwconfig \ + --hwconfig_opts="cv32a60x *RVZCMT=1" \ + --iss=veri-testharness \ + --linker="../../config/gen_from_riscv_config/cv32a60x/linker/link.ld" + +zcmt_jt_lsb_status=$? +if [ "$zcmt_jt_lsb_status" -ne 0 ]; then + echo "Error: Zcmt cm.jt target LSB regression failed" + cd ../.. + return "$zcmt_jt_lsb_status" 2>/dev/null || exit "$zcmt_jt_lsb_status" +fi + +# Check that cm.jalt clears bit 0 of the loaded JVT target. +python3 cva6.py \ + --testlist=../tests/testlist_issues.yaml \ + --test zcmt-jalt-target-lsb-rv32 \ + --iss_yaml cva6.yaml \ + --target hwconfig \ + --hwconfig_opts="cv32a60x *RVZCMT=1" \ + --iss=veri-testharness \ + --linker="../../config/gen_from_riscv_config/cv32a60x/linker/link.ld" + +zcmt_jalt_lsb_status=$? +if [ "$zcmt_jalt_lsb_status" -ne 0 ]; then + echo "Error: Zcmt cm.jalt target LSB regression failed" + cd ../.. + return "$zcmt_jalt_lsb_status" 2>/dev/null || exit "$zcmt_jalt_lsb_status" +fi + cd - diff --git a/verif/tests/custom/zcmt/cm_jalt_target_lsb.S b/verif/tests/custom/zcmt/cm_jalt_target_lsb.S new file mode 100644 index 00000000000..ea507dff344 --- /dev/null +++ b/verif/tests/custom/zcmt/cm_jalt_target_lsb.S @@ -0,0 +1,78 @@ +.globl _start +_start: + la t0, trap_handler + csrw mtvec, t0 + + # Configure the Jump Vector Table. + la t0, __jvt_base$ + + # JVT CSR = 0x017. + # Use the numeric CSR address so this test does not depend on + # assembler support for the Zcmt CSR name. + csrw 0x017, t0 + + fence.i + + # JVT entry 64 contains cm_jalt_target + 1. cm.jalt must clear bit 0 + # before using the loaded value as the jump target. + # + # cm.jalt 64 encoding = 0xa102 + li s0, 0 + .2byte 0xa102 + +after_cm_jalt: + # The target must have executed and returned here. + beqz s0, fail + j pass + +.balign 2 +cm_jalt_target: + # Verify that the architectural PC has bit 0 cleared. + auipc t1, 0 + andi t1, t1, 1 + bnez t1, fail + + li s0, 1 + + # cm.jalt links to the instruction following the compressed jump. + ret + +.balign 4 +trap_handler: + j fail + +pass: + # RISC-V test convention: tohost = 1 means success. + li x1, 1 + j write_tohost + +fail: + # An odd value greater than one represents failure. + li x1, 3 + +write_tohost: + la t0, tohost + sw x1, 0(t0) + +1: + j 1b + +.section .riscv.jvt, "a", @progbits +.align 6 +__jvt_base$: + # Entries 0 through 63 are unused by this test. + .space 256 + + # Entry 64. + .word cm_jalt_target + 1 + +.section .data +.align 6 +.global tohost +tohost: + .dword 0 + +.align 6 +.global fromhost +fromhost: + .dword 0 diff --git a/verif/tests/custom/zcmt/cm_jt_target_lsb.S b/verif/tests/custom/zcmt/cm_jt_target_lsb.S new file mode 100644 index 00000000000..d1cfa898079 --- /dev/null +++ b/verif/tests/custom/zcmt/cm_jt_target_lsb.S @@ -0,0 +1,68 @@ +.globl _start +_start: + la t0, trap_handler + csrw mtvec, t0 + + # Configure the Jump Vector Table. + la t0, __jvt_base$ + + # JVT CSR = 0x017. + # Use the numeric CSR address so this test does not depend on + # assembler support for the Zcmt CSR name. + csrw 0x017, t0 + + fence.i + + # JVT entry 0 contains cm_jt_target + 1. cm.jt must clear bit 0 + # before using the loaded value as the jump target. + # + # cm.jt 0 encoding = 0xa002 + .2byte 0xa002 + + # cm.jt must not fall through. + j fail + +.balign 2 +cm_jt_target: + # Verify that the architectural PC has bit 0 cleared. + auipc t1, 0 + andi t1, t1, 1 + bnez t1, fail + + j pass + +.balign 4 +trap_handler: + j fail + +pass: + # RISC-V test convention: tohost = 1 means success. + li x1, 1 + j write_tohost + +fail: + # An odd value greater than one represents failure. + li x1, 3 + +write_tohost: + la t0, tohost + sw x1, 0(t0) + +1: + j 1b + +.section .riscv.jvt, "a", @progbits +.align 6 +__jvt_base$: + .word cm_jt_target + 1 + +.section .data +.align 6 +.global tohost +tohost: + .dword 0 + +.align 6 +.global fromhost +fromhost: + .dword 0 diff --git a/verif/tests/testlist_issues.yaml b/verif/tests/testlist_issues.yaml index 5d026533378..c8551b6bc82 100644 --- a/verif/tests/testlist_issues.yaml +++ b/verif/tests/testlist_issues.yaml @@ -62,3 +62,29 @@ testlist: -fvisibility=hidden -nostdlib -nostartfiles + + - test: zcmt-jt-target-lsb-rv32 + description: > + Check that cm.jt clears bit 0 of the loaded JVT target. + iterations: 1 + path_var: TESTS_PATH + asm_tests: /custom/zcmt/cm_jt_target_lsb.S + gcc_opts: >- + -static + -mcmodel=medany + -fvisibility=hidden + -nostdlib + -nostartfiles + + - test: zcmt-jalt-target-lsb-rv32 + description: > + Check that cm.jalt clears bit 0 of the loaded JVT target. + iterations: 1 + path_var: TESTS_PATH + asm_tests: /custom/zcmt/cm_jalt_target_lsb.S + gcc_opts: >- + -static + -mcmodel=medany + -fvisibility=hidden + -nostdlib + -nostartfiles