From dbd2e53aa9262083d30753822d98a258e98bb4a1 Mon Sep 17 00:00:00 2001 From: "Paul A. Clarke" Date: Thu, 6 Nov 2025 09:06:58 -0600 Subject: [PATCH 1/6] feat(data): add Zcmt instructions with IDL Signed-off-by: Paul A. Clarke --- spec/std/isa/inst/Zcmt/cm.jalt.yaml | 67 +++++++++++++++++++++++++++++ spec/std/isa/inst/Zcmt/cm.jt.yaml | 61 ++++++++++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100644 spec/std/isa/inst/Zcmt/cm.jalt.yaml create mode 100644 spec/std/isa/inst/Zcmt/cm.jt.yaml diff --git a/spec/std/isa/inst/Zcmt/cm.jalt.yaml b/spec/std/isa/inst/Zcmt/cm.jalt.yaml new file mode 100644 index 000000000..e37411f51 --- /dev/null +++ b/spec/std/isa/inst/Zcmt/cm.jalt.yaml @@ -0,0 +1,67 @@ +# Copyright (c) Ventana Micro Systems +# SPDX-License-Identifier: BSD-3-Clause-Clear + +# yaml-language-server: $schema=../../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: cm.jalt +long_name: Jump Via Table with Optional Link +description: | + Read an address from the Jump Vector Table and jump to it, linking to `ra`. +definedBy: Zcmt +assembly: index +encoding: + match: 101000--------10 + variables: + - name: index + location: 9-2 + # prettier-ignore + not: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 ] +access: + s: always + u: always + vs: always + vu: always +operation(): | + # Ensure JVT readable + XReg jvt = csr_sw_read(0x017); + + if (CSR[jvt].MODE != 0) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + # Skip over _this_ 16-bit instruction + XReg return_addr = $pc + 2; + X[1] = return_addr; + + XReg jump_table_base = { CSR[jvt].BASE, 6'b000000 }; + XReg virtual_address = jump_table_base + index * (xlen() / 8); + XReg addr; + + # TODO + # For a table jump instruction, the table entry that the instruction selects + # is considered an extension of the instruction itself. Hence, the execution + # of a table jump instruction involves two instruction fetches, the first to + # read the instruction (cm.jt/cm.jalt) and the second to read from the jump + # vector table (JVT). Both instruction fetches are implicit reads, and both + # require execute permission; read permission is irrelevant. It is + # recommended that the second fetch be ignored for hardware triggers and breakpoints. + # + # If an exception occurs on either instruction fetch, xEPC is set to the PC + # of the table jump instruction, xCAUSE is set as expected for the type of + # fault and xTVAL (if not set to zero) contains the fetch address which + # caused the fault. + + if (xlen() == 32) { + addr = read_memory<32>(virtual_address, $encoding); + } else { + addr = read_memory<64>(virtual_address, $encoding); + } + + # Ensure low-order bit is clear + addr = addr & $signed(2'b10); + + jump(addr); + +sail(): | diff --git a/spec/std/isa/inst/Zcmt/cm.jt.yaml b/spec/std/isa/inst/Zcmt/cm.jt.yaml new file mode 100644 index 000000000..f843683a2 --- /dev/null +++ b/spec/std/isa/inst/Zcmt/cm.jt.yaml @@ -0,0 +1,61 @@ +# Copyright (c) Ventana Micro Systems +# SPDX-License-Identifier: BSD-3-Clause-Clear + +# yaml-language-server: $schema=../../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: cm.jt +long_name: Jump Via Table +description: | + Read an address from the Jump Vector Table and jump to it. +definedBy: Zcmt +assembly: index +encoding: + match: 101000000-----10 + variables: + - name: index + location: 6-2 +access: + s: always + u: always + vs: always + vu: always +operation(): | + # Ensure JVT readable + XReg jvt = csr_sw_read(0x017); + + if (CSR[jvt].MODE != 0) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + XReg jump_table_base = { CSR[jvt].BASE, 6'b000000 }; + XReg virtual_address = jump_table_base + index `* (xlen() / 8); + XReg addr; + + # TODO + # For a table jump instruction, the table entry that the instruction selects + # is considered an extension of the instruction itself. Hence, the execution + # of a table jump instruction involves two instruction fetches, the first to + # read the instruction (cm.jt/cm.jalt) and the second to read from the jump + # vector table (JVT). Both instruction fetches are implicit reads, and both + # require execute permission; read permission is irrelevant. It is + # recommended that the second fetch be ignored for hardware triggers and breakpoints. + # + # If an exception occurs on either instruction fetch, xEPC is set to the PC + # of the table jump instruction, xCAUSE is set as expected for the type of + # fault and xTVAL (if not set to zero) contains the fetch address which + # caused the fault. + + if (xlen() == 32) { + addr = read_memory<32>(virtual_address, $encoding); + } else { + addr = read_memory<64>(virtual_address, $encoding); + } + + # Ensure low-order bit is clear + addr = addr & $signed(2'b10); + + jump(addr); + +sail(): | From 57b3b75b86fd6ca3ac02fbe6802c9e66a797b03b Mon Sep 17 00:00:00 2001 From: "Paul A. Clarke" Date: Thu, 6 Nov 2025 13:37:27 -0600 Subject: [PATCH 2/6] fix: update golden instruction appendix --- .../all_instructions.golden.adoc | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/backends/instructions_appendix/all_instructions.golden.adoc b/backends/instructions_appendix/all_instructions.golden.adoc index 8aab83aa5..7357633dd 100644 --- a/backends/instructions_appendix/all_instructions.golden.adoc +++ b/backends/instructions_appendix/all_instructions.golden.adoc @@ -11513,6 +11513,78 @@ Included in:: |=== +[#udb:doc:inst:cm_jalt] +== cm.jalt + +Synopsis:: +Jump Via Table with Optional Link + +Assembly:: +cm.jalt index + +Encoding:: +[wavedrom, ,svg,subs='attributes',width="100%"] +.... +{"reg":[{"bits":2,"name": 0x2,"type":2},{"bits":8,"name": "index != {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31}","type":4},{"bits":6,"name": 0x28,"type":2}]} +.... + +Description:: +Read an address from the Jump Vector Table and jump to it, linking to `ra`. + + +Decode Variables:: +[width="100%", cols="1,2", options="header"] +|=== +|Variable Name |Location +|index |$encoding[9:2] +|=== + +Included in:: +[options="autowrap,autowidth"] +|=== +| Extension | Version + +| *Zcmt* | ~> 1.0.0 + +|=== + + +[#udb:doc:inst:cm_jt] +== cm.jt + +Synopsis:: +Jump Via Table + +Assembly:: +cm.jt index + +Encoding:: +[wavedrom, ,svg,subs='attributes',width="100%"] +.... +{"reg":[{"bits":2,"name": 0x2,"type":2},{"bits":5,"name": "index","type":4},{"bits":9,"name": 0x140,"type":2}]} +.... + +Description:: +Read an address from the Jump Vector Table and jump to it. + + +Decode Variables:: +[width="100%", cols="1,2", options="header"] +|=== +|Variable Name |Location +|index |$encoding[6:2] +|=== + +Included in:: +[options="autowrap,autowidth"] +|=== +| Extension | Version + +| *Zcmt* | ~> 1.0.0 + +|=== + + [#udb:doc:inst:cm_mva01s] == cm.mva01s From 0597854db253e161cc56a036afba2ebc9a3de244 Mon Sep 17 00:00:00 2001 From: "Paul A. Clarke" Date: Thu, 6 Nov 2025 14:25:23 -0600 Subject: [PATCH 3/6] fix: use csr_handles --- spec/std/isa/inst/Zcmt/cm.jalt.yaml | 3 ++- spec/std/isa/inst/Zcmt/cm.jt.yaml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/std/isa/inst/Zcmt/cm.jalt.yaml b/spec/std/isa/inst/Zcmt/cm.jalt.yaml index e37411f51..701078c08 100644 --- a/spec/std/isa/inst/Zcmt/cm.jalt.yaml +++ b/spec/std/isa/inst/Zcmt/cm.jalt.yaml @@ -25,7 +25,8 @@ access: vu: always operation(): | # Ensure JVT readable - XReg jvt = csr_sw_read(0x017); + Csr csr_handle = direct_csr_lookup(0x017); + XReg jvt = csr_sw_read(csr_handle); if (CSR[jvt].MODE != 0) { raise(ExceptionCode::IllegalInstruction, mode(), $encoding); diff --git a/spec/std/isa/inst/Zcmt/cm.jt.yaml b/spec/std/isa/inst/Zcmt/cm.jt.yaml index f843683a2..7a751061d 100644 --- a/spec/std/isa/inst/Zcmt/cm.jt.yaml +++ b/spec/std/isa/inst/Zcmt/cm.jt.yaml @@ -23,7 +23,8 @@ access: vu: always operation(): | # Ensure JVT readable - XReg jvt = csr_sw_read(0x017); + Csr csr_handle = direct_csr_lookup(0x017); + XReg jvt = csr_sw_read(csr_handle); if (CSR[jvt].MODE != 0) { raise(ExceptionCode::IllegalInstruction, mode(), $encoding); From 42119649add47d3fca2a1b44e8857c37d59c726c Mon Sep 17 00:00:00 2001 From: "Paul A. Clarke" Date: Fri, 7 Nov 2025 11:47:33 -0600 Subject: [PATCH 4/6] fix: updates per review --- spec/std/isa/inst/Zcmt/cm.jalt.yaml | 34 +++++++++++++---------------- spec/std/isa/inst/Zcmt/cm.jt.yaml | 29 +++++++++++------------- 2 files changed, 28 insertions(+), 35 deletions(-) diff --git a/spec/std/isa/inst/Zcmt/cm.jalt.yaml b/spec/std/isa/inst/Zcmt/cm.jalt.yaml index 701078c08..1d48f3823 100644 --- a/spec/std/isa/inst/Zcmt/cm.jalt.yaml +++ b/spec/std/isa/inst/Zcmt/cm.jalt.yaml @@ -25,7 +25,7 @@ access: vu: always operation(): | # Ensure JVT readable - Csr csr_handle = direct_csr_lookup(0x017); + Csr csr_handle = direct_csr_lookup(CSR[jvt].address()); XReg jvt = csr_sw_read(csr_handle); if (CSR[jvt].MODE != 0) { @@ -37,30 +37,26 @@ operation(): | X[1] = return_addr; XReg jump_table_base = { CSR[jvt].BASE, 6'b000000 }; - XReg virtual_address = jump_table_base + index * (xlen() / 8); + XReg virtual_address = jump_table_base + index `* (xlen() / 8); XReg addr; + TranslationResult result; - # TODO - # For a table jump instruction, the table entry that the instruction selects - # is considered an extension of the instruction itself. Hence, the execution - # of a table jump instruction involves two instruction fetches, the first to - # read the instruction (cm.jt/cm.jalt) and the second to read from the jump - # vector table (JVT). Both instruction fetches are implicit reads, and both - # require execute permission; read permission is irrelevant. It is - # recommended that the second fetch be ignored for hardware triggers and breakpoints. - # - # If an exception occurs on either instruction fetch, xEPC is set to the PC - # of the table jump instruction, xCAUSE is set as expected for the type of - # fault and xTVAL (if not set to zero) contains the fetch address which - # caused the fault. + # TODO: Correct this check when we figure out what MISA can do + if (CSR[misa].S == 1) { + result = translate(virtual_address, MemoryOperation::Fetch, mode(), $encoding); + } else { + result.paddr = virtual_address; + } + + # may raise an exception + access_check(result.paddr, xlen(), $pc, MemoryOperation::Fetch, ExceptionCode::InstructionAccessFault, mode()); if (xlen() == 32) { - addr = read_memory<32>(virtual_address, $encoding); + addr = read_physical_memory<32>(result.paddr); } else { - addr = read_memory<64>(virtual_address, $encoding); - } + addr = read_physical_memory<64>(result.paddr); + } # Ensure low-order bit is clear - # Ensure low-order bit is clear addr = addr & $signed(2'b10); jump(addr); diff --git a/spec/std/isa/inst/Zcmt/cm.jt.yaml b/spec/std/isa/inst/Zcmt/cm.jt.yaml index 7a751061d..2ff6d9cf3 100644 --- a/spec/std/isa/inst/Zcmt/cm.jt.yaml +++ b/spec/std/isa/inst/Zcmt/cm.jt.yaml @@ -23,7 +23,7 @@ access: vu: always operation(): | # Ensure JVT readable - Csr csr_handle = direct_csr_lookup(0x017); + Csr csr_handle = direct_csr_lookup(CSR[jvt].address()); XReg jvt = csr_sw_read(csr_handle); if (CSR[jvt].MODE != 0) { @@ -33,25 +33,22 @@ operation(): | XReg jump_table_base = { CSR[jvt].BASE, 6'b000000 }; XReg virtual_address = jump_table_base + index `* (xlen() / 8); XReg addr; + TranslationResult result; - # TODO - # For a table jump instruction, the table entry that the instruction selects - # is considered an extension of the instruction itself. Hence, the execution - # of a table jump instruction involves two instruction fetches, the first to - # read the instruction (cm.jt/cm.jalt) and the second to read from the jump - # vector table (JVT). Both instruction fetches are implicit reads, and both - # require execute permission; read permission is irrelevant. It is - # recommended that the second fetch be ignored for hardware triggers and breakpoints. - # - # If an exception occurs on either instruction fetch, xEPC is set to the PC - # of the table jump instruction, xCAUSE is set as expected for the type of - # fault and xTVAL (if not set to zero) contains the fetch address which - # caused the fault. + # TODO: Correct this check when we figure out what MISA can do + if (CSR[misa].S == 1) { + result = translate(virtual_address, MemoryOperation::Fetch, mode(), $encoding); + } else { + result.paddr = virtual_address; + } + + # may raise an exception + access_check(result.paddr, xlen(), $pc, MemoryOperation::Fetch, ExceptionCode::InstructionAccessFault, mode()); if (xlen() == 32) { - addr = read_memory<32>(virtual_address, $encoding); + addr = read_physical_memory<32>(result.paddr); } else { - addr = read_memory<64>(virtual_address, $encoding); + addr = read_physical_memory<64>(result.paddr); } # Ensure low-order bit is clear From 9a0d89e07b5acade92cb349246e150cc229848d5 Mon Sep 17 00:00:00 2001 From: "Paul A. Clarke" Date: Fri, 7 Nov 2025 14:24:08 -0600 Subject: [PATCH 5/6] fix: wip --- spec/std/isa/inst/Zcmt/cm.jalt.yaml | 3 ++- spec/std/isa/inst/Zcmt/cm.jt.yaml | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/spec/std/isa/inst/Zcmt/cm.jalt.yaml b/spec/std/isa/inst/Zcmt/cm.jalt.yaml index 1d48f3823..023c25257 100644 --- a/spec/std/isa/inst/Zcmt/cm.jalt.yaml +++ b/spec/std/isa/inst/Zcmt/cm.jalt.yaml @@ -25,7 +25,8 @@ access: vu: always operation(): | # Ensure JVT readable - Csr csr_handle = direct_csr_lookup(CSR[jvt].address()); + Bits<12> csr_addr = $bits(CSR[jvt].address()); + Csr csr_handle = direct_csr_lookup(csr_addr); XReg jvt = csr_sw_read(csr_handle); if (CSR[jvt].MODE != 0) { diff --git a/spec/std/isa/inst/Zcmt/cm.jt.yaml b/spec/std/isa/inst/Zcmt/cm.jt.yaml index 2ff6d9cf3..7ad1de99d 100644 --- a/spec/std/isa/inst/Zcmt/cm.jt.yaml +++ b/spec/std/isa/inst/Zcmt/cm.jt.yaml @@ -23,8 +23,8 @@ access: vu: always operation(): | # Ensure JVT readable - Csr csr_handle = direct_csr_lookup(CSR[jvt].address()); - XReg jvt = csr_sw_read(csr_handle); + #Csr csr_handle = direct_csr_lookup(CSR[jvt].address()); + #XReg jvt = csr_sw_read(csr_handle); if (CSR[jvt].MODE != 0) { raise(ExceptionCode::IllegalInstruction, mode(), $encoding); From 5ee650784251cc3268664f4b33b1c65526bfc9b3 Mon Sep 17 00:00:00 2001 From: "Paul A. Clarke" Date: Wed, 12 Nov 2025 05:40:45 -0600 Subject: [PATCH 6/6] fix(data): fix and refactor check for Zcmt enabled --- spec/std/isa/csr/jvt.yaml | 58 +++++++---------------------- spec/std/isa/inst/Zcmt/cm.jalt.yaml | 4 +- spec/std/isa/inst/Zcmt/cm.jt.yaml | 3 +- spec/std/isa/isa/globals.isa | 30 +++++++++++++++ 4 files changed, 46 insertions(+), 49 deletions(-) diff --git a/spec/std/isa/csr/jvt.yaml b/spec/std/isa/csr/jvt.yaml index 890bdfc06..fbbc7c0c6 100644 --- a/spec/std/isa/csr/jvt.yaml +++ b/spec/std/isa/csr/jvt.yaml @@ -46,25 +46,19 @@ fields: } reset_value: UNDEFINED_LEGAL sw_write(csr_value): | - if ((mode() != PrivilegeMode::M) && implemented?(ExtensionName::Smstateen)) { - if (CSR[mstateen0].JVT == 1'b0) { - unimplemented_csr($encoding); - } - } - else if ((mode() == PrivilegeMode::U) && implemented?(ExtensionName::Ssstateen)) { - if (CSR[sstateen0].JVT == 1'b0) { - unimplemented_csr($encoding); - } - } - else if ((mode() == PrivilegeMode::VS) && implemented?(ExtensionName::Ssstateen)) { - if (CSR[hstateen0].JVT == 1'b0) { - unimplemented_csr($encoding); - } - } - else if ((mode() == PrivilegeMode::VU) && implemented?(ExtensionName::Ssstateen)) { - if ((CSR[sstateen0].JVT == 1'b0) || (CSR[hstateen0].JVT == 1'b0)) { - unimplemented_csr($encoding); - } + if (( mode() != PrivilegeMode::M && implemented?(ExtensionName::Smstateen) + && CSR[mstateen0].JVT == 1'b0 ) + || + ( mode() == PrivilegeMode::U && implemented?(ExtensionName::Ssstateen) + && CSR[sstateen0].JVT == 1'b0 ) + || + ( mode() == PrivilegeMode::VS && implemented?(ExtensionName::Ssstateen) + && CSR[hstateen0].JVT == 1'b0 ) + || + ( mode() == PrivilegeMode::VU && implemented?(ExtensionName::Ssstateen) + && (CSR[sstateen0].JVT == 1'b0 || CSR[hstateen0].JVT == 1'b0) )) { + + unimplemented_csr($encoding); } else { if (JVT_BASE_TYPE == "custom") { @@ -94,28 +88,4 @@ fields: } return 0; sw_read(): | - # If the Smstateen extension is implemented, then bit 2 in `mstateen0`, `sstateen0`, and `hstateen0` is - # implemented. If bit 2 of a controlling `stateen0` CSR is zero, then access to the `jvt` CSR and execution - # of a `cm.jalt` or `cm.jt` instruction by a lower privilege level results in an illegal-instruction trap (or, if - # appropriate, a virtual-instruction trap). - - if ((mode() != PrivilegeMode::M) && implemented?(ExtensionName::Smstateen)) { - if (CSR[mstateen0].JVT == 1'b0) { - raise(ExceptionCode::VirtualInstruction, mode(), $encoding); - } - } - else if ((mode() == PrivilegeMode::U) && implemented?(ExtensionName::Ssstateen)) { - if (CSR[sstateen0].JVT == 1'b0) { - raise(ExceptionCode::IllegalInstruction, mode(), $encoding); - } - } - else if ((mode() == PrivilegeMode::VS) && implemented?(ExtensionName::Ssstateen)) { - if (CSR[hstateen0].JVT == 1'b0) { - raise(ExceptionCode::VirtualInstruction, mode(), $encoding); - } - } - else if ((mode() == PrivilegeMode::VU) && implemented?(ExtensionName::Ssstateen)) { - if ((CSR[sstateen0].JVT == 1'b0) || (CSR[hstateen0].JVT == 1'b0)) { - raise(ExceptionCode::VirtualInstruction, mode(), $encoding); - } - } + check_zcmt_enabled($encoding); diff --git a/spec/std/isa/inst/Zcmt/cm.jalt.yaml b/spec/std/isa/inst/Zcmt/cm.jalt.yaml index 023c25257..770901013 100644 --- a/spec/std/isa/inst/Zcmt/cm.jalt.yaml +++ b/spec/std/isa/inst/Zcmt/cm.jalt.yaml @@ -25,9 +25,7 @@ access: vu: always operation(): | # Ensure JVT readable - Bits<12> csr_addr = $bits(CSR[jvt].address()); - Csr csr_handle = direct_csr_lookup(csr_addr); - XReg jvt = csr_sw_read(csr_handle); + check_zcmt_enabled($encoding); if (CSR[jvt].MODE != 0) { raise(ExceptionCode::IllegalInstruction, mode(), $encoding); diff --git a/spec/std/isa/inst/Zcmt/cm.jt.yaml b/spec/std/isa/inst/Zcmt/cm.jt.yaml index 7ad1de99d..4fb59de7e 100644 --- a/spec/std/isa/inst/Zcmt/cm.jt.yaml +++ b/spec/std/isa/inst/Zcmt/cm.jt.yaml @@ -23,8 +23,7 @@ access: vu: always operation(): | # Ensure JVT readable - #Csr csr_handle = direct_csr_lookup(CSR[jvt].address()); - #XReg jvt = csr_sw_read(csr_handle); + check_zcmt_enabled($encoding); if (CSR[jvt].MODE != 0) { raise(ExceptionCode::IllegalInstruction, mode(), $encoding); diff --git a/spec/std/isa/isa/globals.isa b/spec/std/isa/isa/globals.isa index 9afd483a5..e08e1cd1a 100644 --- a/spec/std/isa/isa/globals.isa +++ b/spec/std/isa/isa/globals.isa @@ -3062,3 +3062,33 @@ function mstatus_sd_reset_value return ((fs_value == 3) || (vs_value == 3)) ? 1 : 0; } } + +function check_zcmt_enabled { + arguments + Bits encoding + description { + If the Smstateen extension is implemented, then bit 2 in `mstateen0`, `sstateen0`, and `hstateen0` is + implemented. If bit 2 of a controlling `stateen0` CSR is zero, then access to the `jvt` CSR and execution + of a `cm.jalt` or `cm.jt` instruction by a lower privilege level results in an illegal-instruction trap (or, if + appropriate, a virtual-instruction trap). + } + body { + if (( mode() != PrivilegeMode::M && implemented?(ExtensionName::Smstateen) + && CSR[mstateen0].JVT == 1'b0 ) + || + ( mode() == PrivilegeMode::U && implemented?(ExtensionName::Ssstateen) + && CSR[sstateen0].JVT == 1'b0 )) { + + raise(ExceptionCode::IllegalInstruction, mode(), encoding); + } + else + if (( mode() == PrivilegeMode::VS && implemented?(ExtensionName::Ssstateen) + && CSR[hstateen0].JVT == 1'b0 ) + || + ( mode() == PrivilegeMode::VU && implemented?(ExtensionName::Ssstateen) + && (CSR[sstateen0].JVT == 1'b0 || CSR[hstateen0].JVT == 1'b0) )) { + + raise(ExceptionCode::VirtualInstruction, mode(), encoding); + } + } +}