From 512a5d0a216ef16fd8f08ada1a7e123883bc2495 Mon Sep 17 00:00:00 2001
From: Enrico Zelioli <ezelioli@iis.ee.ethz.ch>
Date: Wed, 3 Jul 2024 10:09:12 +0200
Subject: [PATCH] Add vCLIC support

---
 core/csr_regfile.sv                           | 146 +++++++++++++++---
 core/cva6.sv                                  |  10 ++
 core/cva6_clic_controller.sv                  |  68 +++++++-
 core/include/ariane_pkg.sv                    |   6 +-
 core/include/config_pkg.sv                    |   3 +
 core/include/cv32a60x_config_pkg.sv           |   2 +
 core/include/cv32a65x_config_pkg.sv           |   4 +
 core/include/cv32a6_embedded_config_pkg.sv    |   2 +
 .../cv32a6_ima_sv32_fpga_config_pkg.sv        |   2 +
 core/include/cv32a6_imac_sv0_config_pkg.sv    |   2 +
 core/include/cv32a6_imac_sv32_config_pkg.sv   |   2 +
 core/include/cv32a6_imafc_sv32_config_pkg.sv  |   2 +
 .../cv64a6_imadfcv_sv39_polara_config_pkg.sv  |   2 +
 core/include/cv64a6_imafdc_sv39_config_pkg.sv |   2 +
 .../cv64a6_imafdc_sv39_hpdcache_config_pkg.sv |   2 +
 ...cv64a6_imafdc_sv39_openpiton_config_pkg.sv |   2 +
 .../cv64a6_imafdc_sv39_wb_config_pkg.sv       |   2 +
 .../include/cv64a6_imafdch_sv39_config_pkg.sv |   2 +
 .../cv64a6_imafdch_sv39_wb_config_pkg.sv      |   2 +
 .../cv64a6_imafdcsclic_sv39_config_pkg.sv     |   2 +
 .../include/cv64a6_imafdcv_sv39_config_pkg.sv |   2 +
 core/include/riscv_pkg.sv                     |   4 +-
 22 files changed, 240 insertions(+), 31 deletions(-)

diff --git a/core/csr_regfile.sv b/core/csr_regfile.sv
index e87a7b654b..ac3b60de12 100644
--- a/core/csr_regfile.sv
+++ b/core/csr_regfile.sv
@@ -124,6 +124,8 @@ module csr_regfile
     output logic [VmidWidth-1:0] vmid_o,
     // external interrupt in - SUBSYSTEM
     input logic [1:0] irq_i,
+    // interrupt request bit - CLIC
+    input logic clic_irq_req_i,
     // selective hardware vectoring bit - CLIC
     input logic clic_irq_shv_i,
     // inter processor interrupt -> connected to machine mode sw - SUBSYSTEM
@@ -151,6 +153,8 @@ module csr_regfile
     // TO_BE_COMPLETED - CLIC_CTRL
     output logic [7:0] sintthresh_o,
     // TO_BE_COMPLETED - CLIC_CTRL
+    output logic [7:0] vsintthresh_o,
+    // TO_BE_COMPLETED - CLIC_CTRL
     output logic clic_irq_ready_o,
     // we are in single-step mode - COMMIT_STAGE
     output logic single_step_o,
@@ -254,10 +258,12 @@ module csr_regfile
   riscv::xlen_t htinst_q, htinst_d;
 
   riscv::xlen_t vstvec_q, vstvec_d;
+  logic [riscv::XLEN-9:0] vstvt_q, vstvt_d;  // 64-byte aligned
   riscv::xlen_t vsscratch_q, vsscratch_d;
   riscv::xlen_t vsepc_q, vsepc_d;
   riscv::xlen_t vscause_q, vscause_d;
   riscv::xlen_t vstval_q, vstval_d;
+  riscv::intthresh_rv_t vsintthresh_q, vsintthresh_d;
 
   riscv::xlen_t dcache_q, dcache_d;
   riscv::xlen_t icache_q, icache_d;
@@ -330,6 +336,12 @@ module csr_regfile
     assign clic_irq_ready_o = 1'b0;
   end
 
+  if (CVA6Cfg.RVVCLIC) begin : gen_clic_vsintthresh_signal
+    assign vsintthresh_o = vsintthresh_q.th;
+  end else begin : gen_dummy_clic_vsintthresh_signal
+    assign vsintthresh_o = '0;
+  end
+
   always_comb begin : csr_read_process
     // a read access exception can only occur if we attempt to read a CSR which does not exist
     read_access_exception = 1'b0;
@@ -391,14 +403,22 @@ module csr_regfile
         if (CVA6Cfg.RVH) csr_rdata = vsstatus_extended;
         else read_access_exception = 1'b1;
         riscv::CSR_VSIE:
-        if (CVA6Cfg.RVH) csr_rdata = (mie_q & VS_DELEG_INTERRUPTS & hideleg_q) >> 1;
+        if (CVA6Cfg.RVH) csr_rdata = (CVA6Cfg.RVVCLIC && clic_mode_o) ? '0 : ((mie_q & VS_DELEG_INTERRUPTS & hideleg_q) >> 1);
         else read_access_exception = 1'b1;
         riscv::CSR_VSIP:
-        if (CVA6Cfg.RVH) csr_rdata = (mip_q & VS_DELEG_INTERRUPTS & hideleg_q) >> 1;
+        if (CVA6Cfg.RVH) csr_rdata = (CVA6Cfg.RVVCLIC && clic_mode_o) ? '0 :((mip_q & VS_DELEG_INTERRUPTS & hideleg_q) >> 1);
         else read_access_exception = 1'b1;
         riscv::CSR_VSTVEC:
         if (CVA6Cfg.RVH) csr_rdata = vstvec_q;
         else read_access_exception = 1'b1;
+        riscv::CSR_VSTVT: begin
+          if (CVA6Cfg.RVVCLIC) begin
+            // vstvt reads 0 from CLINT mode
+            csr_rdata = clic_mode_o ? {vstvt_q, 8'b0} : '0;
+          end else begin
+            read_access_exception = 1'b1;
+          end
+        end
         riscv::CSR_VSSCRATCH:
         if (CVA6Cfg.RVH) csr_rdata = vsscratch_q;
         else read_access_exception = 1'b1;
@@ -420,6 +440,14 @@ module csr_regfile
         end else begin
           read_access_exception = 1'b1;
         end
+        riscv::CSR_VSINTTHRESH: begin
+          if (CVA6Cfg.RVVCLIC) begin
+            // vsintthresh reads 0 from CLINT mode
+            csr_rdata = clic_mode_o ? {{riscv::XLEN - 8{1'b0}}, vsintthresh_q} : '0;
+          end else begin
+            read_access_exception = 1'b1;
+          end
+        end
         // supervisor registers
         riscv::CSR_SSTATUS: begin
           if (CVA6Cfg.RVS)
@@ -513,13 +541,13 @@ module csr_regfile
         if (CVA6Cfg.RVH) csr_rdata = hideleg_q;
         else read_access_exception = 1'b1;
         riscv::CSR_HIE:
-        if (CVA6Cfg.RVH) csr_rdata = mie_q & HS_DELEG_INTERRUPTS;
+        if (CVA6Cfg.RVH) csr_rdata = (CVA6Cfg.RVVCLIC && clic_mode_o) ? mie_q & riscv::MIP_SGEIP : mie_q & HS_DELEG_INTERRUPTS;
         else read_access_exception = 1'b1;
         riscv::CSR_HIP:
-        if (CVA6Cfg.RVH) csr_rdata = mip_q & HS_DELEG_INTERRUPTS;
+        if (CVA6Cfg.RVH) csr_rdata = (CVA6Cfg.RVVCLIC && clic_mode_o) ? '0 : mip_q & HS_DELEG_INTERRUPTS;
         else read_access_exception = 1'b1;
         riscv::CSR_HVIP:
-        if (CVA6Cfg.RVH) csr_rdata = mip_q & VS_DELEG_INTERRUPTS;
+        if (CVA6Cfg.RVH) csr_rdata = (CVA6Cfg.RVVCLIC && clic_mode_o) ? '0 : mip_q & VS_DELEG_INTERRUPTS;
         else read_access_exception = 1'b1;
         riscv::CSR_HCOUNTEREN:
         if (CVA6Cfg.RVH) csr_rdata = hcounteren_q;
@@ -531,7 +559,7 @@ module csr_regfile
         if (CVA6Cfg.RVH) csr_rdata = htinst_q;
         else read_access_exception = 1'b1;
         riscv::CSR_HGEIE:
-        if (CVA6Cfg.RVH) csr_rdata = '0;
+        if (CVA6Cfg.RVH) csr_rdata = {hgeie_q[riscv::XLEN-1:1], 1'b0};
         else read_access_exception = 1'b1;
         riscv::CSR_HGEIP:
         if (CVA6Cfg.RVH) csr_rdata = '0;
@@ -943,11 +971,13 @@ module csr_regfile
 
     vsstatus_d = vsstatus_q;
     vstvec_d = vstvec_q;
+    vstvt_d = vstvt_q;
     vsscratch_d = vsscratch_q;
     vsepc_d = vsepc_q;
     vscause_d = vscause_q;
     vstval_d = vstval_q;
     vsatp_d = vsatp_q;
+    vsintthresh_d = vsintthresh_q;
 
     sepc_d = sepc_q;
     scause_d = scause_q;
@@ -1062,13 +1092,22 @@ module csr_regfile
           end
         end
         riscv::CSR_VSIE:
-        if (CVA6Cfg.RVH) mie_d = (mie_q & ~hideleg_q) | ((csr_wdata << 1) & hideleg_q);
-        else update_access_exception = 1'b1;
+        if (CVA6Cfg.RVH) begin
+          // Writes are legal but ignored in CLIC mode
+          if (!(CVA6Cfg.RVVCLIC && clic_mode_o)) begin
+            mie_d = (mie_q & ~hideleg_q) | ((csr_wdata << 1) & hideleg_q);
+          end
+        end else begin
+          update_access_exception = 1'b1;
+        end
         riscv::CSR_VSIP: begin
           if (CVA6Cfg.RVH) begin
-            // only the virtual supervisor software interrupt is write-able, iff delegated
-            mask  = riscv::MIP_VSSIP & hideleg_q;
-            mip_d = (mip_q & ~mask) | ((csr_wdata << 1) & mask);
+            // Writes are legal but ignored in CLIC mode
+            if (!(CVA6Cfg.RVVCLIC && clic_mode_o)) begin
+              // only the virtual supervisor software interrupt is write-able, iff delegated
+              mask  = riscv::MIP_VSSIP & hideleg_q;
+              mip_d = (mip_q & ~mask) | ((csr_wdata << 1) & mask);
+            end
           end else begin
             update_access_exception = 1'b1;
           end
@@ -1080,6 +1119,16 @@ module csr_regfile
             update_access_exception = 1'b1;
           end
         end
+        riscv::CSR_VSTVT: begin
+          if (CVA6Cfg.RVVCLIC) begin
+            // Writes are legal but ignored in CLINT mode
+            if (clic_mode_o) begin
+              vstvt_d = csr_wdata[riscv::XLEN-1:8];
+            end
+          end else begin
+            update_access_exception = 1'b1;
+          end
+        end
         riscv::CSR_VSSCRATCH:
         if (CVA6Cfg.RVH) vsscratch_d = csr_wdata;
         else update_access_exception = 1'b1;
@@ -1113,6 +1162,16 @@ module csr_regfile
             update_access_exception = 1'b1;
           end
         end
+        riscv::CSR_VSINTTHRESH: begin
+          if (CVA6Cfg.RVVCLIC) begin
+            // Writes are legal but ignored in CLINT mode
+            if (clic_mode_o) begin
+              vsintthresh_d.th = csr_wdata[7:0];
+            end
+          end else begin
+            update_access_exception = 1'b1;
+          end
+        end
         // sstatus is a subset of mstatus - mask it accordingly
         riscv::CSR_SSTATUS: begin
           if (CVA6Cfg.RVS) begin
@@ -1260,7 +1319,12 @@ module csr_regfile
         end
         riscv::CSR_HIE: begin
           if (CVA6Cfg.RVH) begin
-            mask  = HS_DELEG_INTERRUPTS;
+            // In CLIC mode only SGEIE bit is writable
+            if (CVA6Cfg.RVVCLIC && clic_mode_o) begin
+              mask  = riscv::MIP_SGEIP;
+            end else begin
+              mask  = HS_DELEG_INTERRUPTS;
+            end
             mie_d = (mie_q & ~mask) | (csr_wdata & mask);
           end else begin
             update_access_exception = 1'b1;
@@ -1268,16 +1332,22 @@ module csr_regfile
         end
         riscv::CSR_HIP: begin
           if (CVA6Cfg.RVH) begin
-            mask  = riscv::MIP_VSSIP;
-            mip_d = (mip_q & ~mask) | (csr_wdata & mask);
+            // Writes are legal but ignored in CLIC mode
+            if (!(CVA6Cfg.RVVCLIC && clic_mode_o)) begin
+              mask  = riscv::MIP_VSSIP;
+              mip_d = (mip_q & ~mask) | (csr_wdata & mask);
+            end
           end else begin
             update_access_exception = 1'b1;
           end
         end
         riscv::CSR_HVIP: begin
           if (CVA6Cfg.RVH) begin
-            mask  = VS_DELEG_INTERRUPTS;
-            mip_d = (mip_q & ~mask) | (csr_wdata & mask);
+            // Writes are legal but ignored in CLIC mode
+            if (!(CVA6Cfg.RVVCLIC && clic_mode_o)) begin
+              mask  = VS_DELEG_INTERRUPTS;
+              mip_d = (mip_q & ~mask) | (csr_wdata & mask);
+            end
           end else begin
             update_access_exception = 1'b1;
           end
@@ -1303,9 +1373,10 @@ module csr_regfile
             update_access_exception = 1'b1;
           end
         end
-        //TODO Hyp: implement hgeie write
         riscv::CSR_HGEIE: begin
-          if (!CVA6Cfg.RVH) begin
+          if (CVA6Cfg.RVH) begin
+            hgeie_d = {csr_wdata[riscv::XLEN-1:1], 1'b0};
+          end else begin
             update_access_exception = 1'b1;
           end
         end
@@ -1740,6 +1811,11 @@ module csr_regfile
           trap_to_priv_lvl = (priv_lvl_o == riscv::PRIV_LVL_M) ? riscv::PRIV_LVL_M : riscv::PRIV_LVL_S;
           // trap to VS only if it is  the currently active mode
           trap_to_v = v_q;
+        end else if (ex_i.cause[riscv::XLEN-1] && clic_mode_o) begin
+          trap_to_priv_lvl = riscv::priv_lvl_t'(ex_i.cause[25:24]);
+          if (CVA6Cfg.RVVCLIC) begin
+            trap_to_v = ex_i.cause[26];
+          end
         end
       end else begin
         if (CVA6Cfg.RVS && (ex_i.cause[riscv::XLEN-1] && mideleg_q[ex_i.cause[$clog2(
@@ -1750,6 +1826,8 @@ module csr_regfile
           // traps never transition from a more-privileged mode to a less privileged mode
           // so if we are already in M mode, stay there
           trap_to_priv_lvl = (priv_lvl_o == riscv::PRIV_LVL_M) ? riscv::PRIV_LVL_M : riscv::PRIV_LVL_S;
+        end else if (ex_i.cause[riscv::XLEN-1] && clic_mode_o) begin
+          trap_to_priv_lvl = riscv::priv_lvl_t'(ex_i.cause[25:24]);
         end
       end
 
@@ -1762,7 +1840,12 @@ module csr_regfile
           // this can either be user or supervisor mode
           vsstatus_d.spp = priv_lvl_q[0];
           // set cause
-          vscause_d = ex_i.cause[riscv::XLEN-1] ? {ex_i.cause[riscv::XLEN-1:2], 2'b01} : ex_i.cause;
+          vscause_d = (~clic_mode_o & ex_i.cause[riscv::XLEN-1]) ? {ex_i.cause[riscv::XLEN-1:2], 2'b01} : ex_i.cause;
+          // update the current and previous interrupt level
+          if (CVA6Cfg.RVVCLIC && clic_mode_o && ex_i.cause[riscv::XLEN-1]) begin
+            mintstatus_d.vsil = ex_i.cause[23:16];
+            vscause_d[23:16]  = mintstatus_q.vsil;
+          end
           // set epc
           vsepc_d = {{riscv::XLEN - riscv::VLEN{pc_i[riscv::VLEN-1]}}, pc_i};
           // set vstval
@@ -2078,6 +2161,9 @@ module csr_regfile
       vsstatus_d.spp  = 1'b0;
       // set spie to 1
       vsstatus_d.spie = 1'b1;
+      // restore sintstatus
+      if (CVA6Cfg.RVVCLIC && clic_mode_o && vscause_q[riscv::XLEN-1])
+        mintstatus_d.vsil = vscause_q[23:16];
     end
 
     // return from debug mode
@@ -2146,6 +2232,8 @@ module csr_regfile
   assign irq_ctrl_o.sie = (CVA6Cfg.RVH && v_q) ? vsstatus_q.sie : mstatus_q.sie;
   assign irq_ctrl_o.mideleg = mideleg_q;
   assign irq_ctrl_o.hideleg = (CVA6Cfg.RVH) ? hideleg_q : '0;
+  assign irq_ctrl_o.hgeie = (CVA6Cfg.RVH) ? hgeie_q : '0;
+  assign irq_ctrl_o.vgein = (CVA6Cfg.RVH) ? hstatus_q.vgein : '0;
   assign irq_ctrl_o.global_enable = (~debug_mode_q)
       // interrupts are enabled during single step or we are not stepping
       // No need to check interrupts during single step if we don't support DEBUG mode
@@ -2267,7 +2355,7 @@ module csr_regfile
     wfi_d = wfi_q;
     // if there is any (enabled) interrupt pending un-stall the core
     // also un-stall if we want to enter debug mode
-    if ((CVA6Cfg.DebugEn && debug_req_i) || (!clic_mode_o && (|(mip_q & mie_q) || irq_i[1])) || clic_irq_ready_o) begin
+    if ((CVA6Cfg.DebugEn && debug_req_i) || (!clic_mode_o && (|(mip_q & mie_q) || irq_i[1])) || clic_irq_req_i) begin
       wfi_d = 1'b0;
       // or alternatively if there is no exception pending and we are not in debug mode wait here
       // for the interrupt
@@ -2281,7 +2369,9 @@ module csr_regfile
     trap_vector_base_o = (CVA6Cfg.RVSCLIC && clic_mode_o && clic_irq_shv_i && ex_i.cause[riscv::XLEN-1]) ? {mtvt_q[riscv::VLEN-1:8], 8'b0} : {mtvec_q[riscv::VLEN-1:2], 2'b0};
     // output user mode stvec
     if (CVA6Cfg.RVS && trap_to_priv_lvl == riscv::PRIV_LVL_S) begin
-      if (CVA6Cfg.RVSCLIC && clic_mode_o && clic_irq_shv_i && ex_i.cause[riscv::XLEN-1]) begin
+      if (CVA6Cfg.RVVCLIC && clic_mode_o && clic_irq_shv_i && ex_i.cause[riscv::XLEN-1] && trap_to_v) begin
+        trap_vector_base_o = {vstvt_q, 8'b0};
+      end else if (CVA6Cfg.RVSCLIC && clic_mode_o && clic_irq_shv_i && ex_i.cause[riscv::XLEN-1]) begin
         trap_vector_base_o = {stvt_q[riscv::VLEN-1:8], 8'b0};
       end else if (CVA6Cfg.RVH && trap_to_v) begin
         trap_vector_base_o = {vstvec_q[riscv::VLEN-1:2], 2'b0};
@@ -2305,13 +2395,13 @@ module csr_regfile
     // significant benefit, we conciously diverge from the spec here by jumping to
     // trap_vector_base instead.
     if (ex_i.cause[riscv::XLEN-1] &&
-                ((((CVA6Cfg.RVS || CVA6Cfg.RVU) && trap_to_priv_lvl == riscv::PRIV_LVL_M && mtvec_q[0]) || (!CVA6Cfg.RVS && !CVA6Cfg.RVU && mtvec_q[0]))
-               || (CVA6Cfg.RVS && trap_to_priv_lvl == riscv::PRIV_LVL_S && !trap_to_v && stvec_q[0])
+                ((((CVA6Cfg.RVS || CVA6Cfg.RVU) && trap_to_priv_lvl == riscv::PRIV_LVL_M && mtvec_q[0] && !clic_mode_o) || (!CVA6Cfg.RVS && !CVA6Cfg.RVU && mtvec_q[0] && !clic_mode_o))
+               || (CVA6Cfg.RVS && trap_to_priv_lvl == riscv::PRIV_LVL_S && !trap_to_v && stvec_q[0] && !clic_mode_o)
                || (CVA6Cfg.RVSCLIC && clic_mode_o && clic_irq_shv_i))) begin
       trap_vector_base_o[7:2] = ex_i.cause[5:0];
     end
     if (ex_i.cause[riscv::XLEN-1] &&
-                (CVA6Cfg.RVH && trap_to_priv_lvl == riscv::PRIV_LVL_S && trap_to_v && vstvec_q[0])) begin
+                (CVA6Cfg.RVH && trap_to_priv_lvl == riscv::PRIV_LVL_S && trap_to_v && vstvec_q[0] && !clic_mode_o)) begin
       trap_vector_base_o[7:2] = {ex_i.cause[5:2], 2'b01};
     end
 
@@ -2455,6 +2545,8 @@ module csr_regfile
         sscratch_q   <= {riscv::XLEN{1'b0}};
         stval_q      <= {riscv::XLEN{1'b0}};
         satp_q       <= {riscv::XLEN{1'b0}};
+        stvt_q       <= {riscv::XLEN{1'b0}};
+        sintthresh_q <= 8'b0;
       end
 
       if (CVA6Cfg.RVH) begin
@@ -2474,9 +2566,11 @@ module csr_regfile
         vsepc_q                  <= {riscv::XLEN{1'b0}};
         vscause_q                <= {riscv::XLEN{1'b0}};
         vstvec_q                 <= {riscv::XLEN{1'b0}};
+        vstvt_q                  <= {(riscv::XLEN-9){1'b0}};
         vsscratch_q              <= {riscv::XLEN{1'b0}};
         vstval_q                 <= {riscv::XLEN{1'b0}};
         vsatp_q                  <= {riscv::XLEN{1'b0}};
+        vsintthresh_q            <= 8'b0;
         en_ld_st_g_translation_q <= 1'b0;
       end
       // timer and counters
@@ -2540,6 +2634,8 @@ module csr_regfile
         sscratch_q   <= sscratch_d;
         if (CVA6Cfg.TvalEn) stval_q <= stval_d;
         satp_q <= satp_d;
+        stvt_q       <= stvt_d;
+        sintthresh_q <= sintthresh_d;
       end
       if (CVA6Cfg.RVH) begin
         v_q                      <= v_d;
@@ -2559,9 +2655,11 @@ module csr_regfile
         vsepc_q                  <= vsepc_d;
         vscause_q                <= vscause_d;
         vstvec_q                 <= vstvec_d;
+        vstvt_q                  <= vstvt_d;
         vsscratch_q              <= vsscratch_d;
         vstval_q                 <= vstval_d;
         vsatp_q                  <= vsatp_d;
+        vsintthresh_q            <= vsintthresh_d;
         en_ld_st_g_translation_q <= en_ld_st_g_translation_d;
       end
       // timer and counters
diff --git a/core/cva6.sv b/core/cva6.sv
index 42285e1b02..4acd6f3444 100644
--- a/core/cva6.sv
+++ b/core/cva6.sv
@@ -136,6 +136,8 @@ module cva6
     input logic [$clog2(CVA6Cfg.CLICNumInterruptSrc)-1:0] clic_irq_id_i,  // interrupt source ID
     input logic [7:0] clic_irq_level_i,  // interrupt level is 8-bit from CLIC spec
     input riscv::priv_lvl_t clic_irq_priv_i,  // CLIC interrupt privilege level
+    input logic clic_irq_v_i,  // CLIC interrupt virtualization bit (only for vCLIC)
+    input logic [5:0] clic_irq_vsid_i,  // CLIC interrupt Virtual Supervisor ID (only for vCLIC)
     input logic clic_irq_shv_i,  // selective hardware vectoring bit
     output logic clic_irq_ready_o,  // core side interrupt hanshake (ready)
     input logic clic_kill_req_i,  // kill request
@@ -202,6 +204,7 @@ module cva6
     CVA6Cfg.CvxifEn,
     CVA6Cfg.ZiCondExtEn,
     CVA6Cfg.RVSCLIC,
+    CVA6Cfg.RVVCLIC,
     // Extended
     bit'(RVF),
     bit'(RVD),
@@ -427,6 +430,7 @@ module cva6
   riscv::intstatus_rv_t mintstatus_csr;
   logic [7:0] mintthresh_csr;
   logic [7:0] sintthresh_csr;
+  logic [7:0] vsintthresh_csr;
   logic dcache_en_csr_nbdcache;
   logic csr_write_fflags_commit_cs;
   logic icache_en_csr;
@@ -954,6 +958,8 @@ module cva6
       .mintstatus_o            (mintstatus_csr),
       .mintthresh_o            (mintthresh_csr),
       .sintthresh_o            (sintthresh_csr),
+      .vsintthresh_o           (vsintthresh_csr),
+      .clic_irq_req_i          (clic_irq_req_id),
       .clic_irq_shv_i          (clic_irq_shv_i),
       .clic_irq_ready_o        (clic_irq_ready_o),
       .ld_st_priv_lvl_o        (ld_st_priv_lvl_csr_ex),
@@ -1361,9 +1367,11 @@ module cva6
         .rst_ni          (rst_ni),
         // from CSR file
         .priv_lvl_i      (priv_lvl),
+        .v_i             (v),
         .irq_ctrl_i      (irq_ctrl_csr_id),
         .mintthresh_i    (mintthresh_csr),
         .sintthresh_i    (sintthresh_csr),
+        .vsintthresh_i   (vsintthresh_csr),
         .mintstatus_i    (mintstatus_csr),
         // from/to CLIC
         .clic_irq_valid_i(clic_irq_valid_i),
@@ -1371,6 +1379,8 @@ module cva6
         .clic_irq_id_i   (clic_irq_id_i),
         .clic_irq_level_i(clic_irq_level_i),
         .clic_irq_priv_i (clic_irq_priv_i),
+        .clic_irq_v_i    (clic_irq_v_i),
+        .clic_irq_vsid_i (clic_irq_vsid_i),
         .clic_kill_req_i (clic_kill_req_i),
         .clic_kill_ack_o (clic_kill_ack_o),
         // to ID stage
diff --git a/core/cva6_clic_controller.sv b/core/cva6_clic_controller.sv
index 68c6947cec..23544442ec 100644
--- a/core/cva6_clic_controller.sv
+++ b/core/cva6_clic_controller.sv
@@ -11,9 +11,11 @@ module cva6_clic_controller #(
     input logic rst_ni,
     // from CSR file
     input riscv::priv_lvl_t priv_lvl_i,  // current privilege level
+    input logic v_i,  // virtualization mode bit
     input ariane_pkg::irq_ctrl_t irq_ctrl_i,
     input logic [7:0] mintthresh_i,  // M-mode interrupt threshold
     input logic [7:0] sintthresh_i,  // S-mode interrupt threshold
+    input logic [7:0] vsintthresh_i,  // VS-mode interrupt threshold
     input riscv::intstatus_rv_t mintstatus_i,  // interrupt status
     // from/to CLIC
     input logic clic_irq_valid_i,  // interrupt is valid
@@ -21,6 +23,8 @@ module cva6_clic_controller #(
     input logic [$clog2(CVA6Cfg.CLICNumInterruptSrc)-1:0] clic_irq_id_i,  // interrupt ID
     input logic [7:0] clic_irq_level_i,  // interrupt level
     input riscv::priv_lvl_t clic_irq_priv_i,  // interrupt privilege level
+    input logic clic_irq_v_i,  // interrupt virtualization bit (only for vCLIC)
+    input logic [5:0] clic_irq_vsid_i,  // interrupt Virtual Supervisor ID (only for vCLIC)
     input logic clic_kill_req_i,  // kill request
     output logic clic_kill_ack_o,  // kill acknowledge
     // to ID stage
@@ -34,14 +38,22 @@ module cva6_clic_controller #(
   // irq threshold and global interrupt are enabled (otherwise it won't fire).
   // The effective interrupt threshold is the maximum of mintstatus.mil and
   // mintthresh, because interrupts with higher level have priority.
-  logic [7:0] max_mthresh, max_sthresh;
+  logic [7:0] max_mthresh, max_sthresh, max_vsthresh;
+
+  logic clic_irq_v;  // Interrupt target virtualization mode (only for vCLIC)
+
+  logic sgeie;  // Guest external interrupts at hypervisor level enable (HIE register)
 
   assign max_mthresh = mintthresh_i > mintstatus_i.mil ? mintthresh_i : mintstatus_i.mil;
   assign max_sthresh = sintthresh_i > mintstatus_i.sil ? sintthresh_i : mintstatus_i.sil;
+  assign max_vsthresh = vsintthresh_i > mintstatus_i.vsil ? vsintthresh_i : mintstatus_i.vsil;
+
+  assign sgeie = (CVA6Cfg.RVH) ? irq_ctrl_i.mie[riscv::IRQ_HS_EXT] : 1'b0;
 
   // Determine if CLIC interrupt shall be accepted
   always_comb begin : clic_irq_accept
     clic_irq_req_o = 1'b0;
+    clic_irq_v = 1'b0;
     unique case (priv_lvl_i)
       riscv::PRIV_LVL_M: begin
         // Take M-mode interrupts with higher level
@@ -55,12 +67,56 @@ module cva6_clic_controller #(
           clic_irq_req_o = clic_irq_valid_i;
           // Take S-mode interrupts with higher level
         end else if (clic_irq_priv_i == riscv::PRIV_LVL_S) begin
-          clic_irq_req_o = (clic_irq_level_i > max_sthresh) && (clic_irq_valid_i) && irq_ctrl_i.sie;
+          if (CVA6Cfg.RVH && v_i) begin // Hart currently in VS-mode
+            if (CVA6Cfg.RVVCLIC && clic_irq_v_i) begin // Virtual supervisor interrrupt
+              if (clic_irq_vsid_i == irq_ctrl_i.vgein) begin // VS-mode interrupt is for currently running VS
+                clic_irq_req_o = (clic_irq_level_i > max_vsthresh) && (clic_irq_valid_i) && irq_ctrl_i.sie;
+                clic_irq_v = 1'b1;
+              end else begin // Received interrupt is delegated to a differet VS
+                // Trap to HS-mode iff HIE.sgeie is set and HGEIE[vsid] is set
+                clic_irq_req_o = (clic_irq_valid_i) && sgeie && irq_ctrl_i.hgeie[clic_irq_vsid_i];
+              end
+            end else begin // Hypervisor interrupt
+              clic_irq_req_o = (clic_irq_level_i > max_sthresh) && (clic_irq_valid_i); // HS-mode sie is implicitly enabled in VS-mode
+            end
+          end else begin // Hart currently in (H)S-mode
+            if (CVA6Cfg.RVVCLIC && clic_irq_v_i) begin // Virtual supervisor interrrupt
+              // The current custom vCLIC implementation does not provide a way to the hypervisor to set interrupt levels 
+              // to interrupts delegated to VS-mode. The incoming interrupt level is therefore ignored if the hart is running
+              // in HS-mode and a VS-mode interrupt is taken iff both HIE.sgeie and HGEIE[vsid] bits are set (and interrupts 
+              // are globally enabled at supervisor level (i.e. MSTATUS.sie bit is set)
+              clic_irq_req_o = (clic_irq_valid_i) && sgeie && irq_ctrl_i.hgeie[clic_irq_vsid_i] && irq_ctrl_i.sie;
+            end else begin // (Host) Supervisor interrupt
+              clic_irq_req_o = (clic_irq_level_i > max_sthresh) && (clic_irq_valid_i) && irq_ctrl_i.sie;
+            end
+          end
         end
       end
       riscv::PRIV_LVL_U: begin
-        // Take all M-mode and S-mode interrupts
-        clic_irq_req_o = clic_irq_valid_i;
+        // Take all M-mode interrupts
+        if (clic_irq_priv_i == riscv::PRIV_LVL_M) begin
+          clic_irq_req_o = clic_irq_valid_i;
+        end else if (clic_irq_priv_i == riscv::PRIV_LVL_S) begin
+          if (CVA6Cfg.RVH && v_i) begin  // Hart currently in VU-mode
+            if (CVA6Cfg.RVVCLIC && clic_irq_v_i) begin  // Virtual supervisor interrrupt
+              if (clic_irq_vsid_i == irq_ctrl_i.vgein) begin // VS-mode interrupt is for currently running VS
+                clic_irq_req_o = clic_irq_valid_i;
+                clic_irq_v = 1'b1;
+              end else begin // Received interrupt is delegated to a differet VS
+                // Trap to HS-mode iff HIE.sgeie is set and HGEIE[vsid] is set
+                clic_irq_req_o = (clic_irq_valid_i) && sgeie && irq_ctrl_i.hgeie[clic_irq_vsid_i];
+              end
+            end else begin // Hypervisor interrupt
+              clic_irq_req_o = clic_irq_valid_i;  // MSTATUS.sie is implicitly enabled in VU-mode
+            end
+          end else begin  // Hart currently in U-mode
+            if (CVA6Cfg.RVVCLIC && clic_irq_v_i) begin // Virtual supervisor interrrupt
+              clic_irq_req_o = (clic_irq_valid_i) && sgeie && irq_ctrl_i.hgeie[clic_irq_vsid_i]; // MSTATUS.sie is implicitly enabled in U-mode
+            end else begin // (Host) Supervisor interrupt
+              clic_irq_req_o = clic_irq_valid_i;  // HS-mode sie is implicitly enabled in U-mode
+            end
+          end
+        end
       end
       default: ;
     endcase
@@ -72,7 +128,9 @@ module cva6_clic_controller #(
   // Pack interrupt cause to be inserted into the pipeline
   assign clic_irq_cause_o = {
     1'b1,  // This is an irq
-    {riscv::XLEN - 25{1'b0}},  // XLEN-2...24
+    {riscv::XLEN - 28{1'b0}},  // XLEN-2...27
+    clic_irq_v,  // 26: interrupt target virtualization mode
+    clic_irq_priv_i,  // 25..24: interrupt target privilege level
     clic_irq_level_i,  // to mintstatus.mil
     {16 - $clog2(CVA6Cfg.CLICNumInterruptSrc) {1'b0}},  // 15...IDWidth
     clic_irq_id_i
diff --git a/core/include/ariane_pkg.sv b/core/include/ariane_pkg.sv
index b7ae4e2337..4a53377200 100644
--- a/core/include/ariane_pkg.sv
+++ b/core/include/ariane_pkg.sv
@@ -149,6 +149,7 @@ package ariane_pkg;
                                                     | riscv::HSTATUS_SPV
                                                     | riscv::HSTATUS_SPVP
                                                     | riscv::HSTATUS_HU
+                                                    | riscv::HSTATUS_VGEIN
                                                     | riscv::HSTATUS_VTVM
                                                     | riscv::HSTATUS_VTW
                                                     | riscv::HSTATUS_VTSR;
@@ -156,7 +157,8 @@ package ariane_pkg;
   // hypervisor delegable interrupts
   localparam logic [riscv::XLEN-1:0] HS_DELEG_INTERRUPTS = riscv::MIP_VSSIP
                                                     | riscv::MIP_VSTIP
-                                                    | riscv::MIP_VSEIP;
+                                                    | riscv::MIP_VSEIP
+                                                    | riscv::MIP_SGEIP;
   // virtual supervisor delegable interrupts
   localparam logic [riscv::XLEN-1:0] VS_DELEG_INTERRUPTS = riscv::MIP_VSSIP
                                                     | riscv::MIP_VSTIP
@@ -288,6 +290,8 @@ package ariane_pkg;
     riscv::xlen_t mip;
     riscv::xlen_t mideleg;
     riscv::xlen_t hideleg;
+    riscv::xlen_t hgeie; // Hypervisor Guest External Interrupt Enable (HGEIE) register
+    logic [5:0]   vgein; // Virtual Guest external interrupt number (HSTATUS register)
     logic         sie;
     logic         global_enable;
   } irq_ctrl_t;
diff --git a/core/include/config_pkg.sv b/core/include/config_pkg.sv
index fb458ecb23..d98f205733 100644
--- a/core/include/config_pkg.sv
+++ b/core/include/config_pkg.sv
@@ -78,6 +78,8 @@ package config_pkg;
     bit                          ZiCondExtEn;
     // CLIC extension
     bit                          RVSCLIC;
+    // CLIC virtualization extension (vCLIC)
+    bit                          RVVCLIC;
     // Single precision FP RISC-V extension
     bit                          RVF;
     // Double precision FP RISC-V extension
@@ -178,6 +180,7 @@ package config_pkg;
     assert (Cfg.NrExecuteRegionRules <= NrMaxRules);
     assert (Cfg.NrCachedRegionRules <= NrMaxRules);
     assert (Cfg.NrPMPEntries <= 16);
+    assert (!(Cfg.RVVCLIC && (!Cfg.RVH || !Cfg.RVSCLIC)));
 `endif
     // pragma translate_on
   endfunction
diff --git a/core/include/cv32a60x_config_pkg.sv b/core/include/cv32a60x_config_pkg.sv
index e91dcc1987..3bf528ccae 100644
--- a/core/include/cv32a60x_config_pkg.sv
+++ b/core/include/cv32a60x_config_pkg.sv
@@ -28,6 +28,7 @@ package cva6_config_pkg;
   localparam CVA6ConfigVExtEn = 0;
   localparam CVA6ConfigZiCondExtEn = 1;
   localparam CVA6ConfigSclicExtEn = 0;
+  localparam CVA6ConfigVclicExtEn = 0;
 
   localparam CVA6ConfigAxiIdWidth = 4;
   localparam CVA6ConfigAxiAddrWidth = 64;
@@ -99,6 +100,7 @@ package cva6_config_pkg;
       CvxifEn: bit'(CVA6ConfigCvxifEn),
       ZiCondExtEn: bit'(CVA6ConfigZiCondExtEn),
       RVSCLIC: bit'(CVA6ConfigSclicExtEn),
+      RVVCLIC: bit'(CVA6ConfigVclicExtEn),
       // Extended
       RVF:
       bit'(
diff --git a/core/include/cv32a65x_config_pkg.sv b/core/include/cv32a65x_config_pkg.sv
index 1d33ae04ef..fd6c49796f 100644
--- a/core/include/cv32a65x_config_pkg.sv
+++ b/core/include/cv32a65x_config_pkg.sv
@@ -25,6 +25,8 @@ package cva6_config_pkg;
   localparam CVA6ConfigBExtEn = 1;
   localparam CVA6ConfigVExtEn = 0;
   localparam CVA6ConfigZiCondExtEn = 0;
+  localparam CVA6ConfigSclicExtEn = 0;
+  localparam CVA6ConfigVclicExtEn = 0;
 
   localparam CVA6ConfigAxiIdWidth = 4;
   localparam CVA6ConfigAxiAddrWidth = 64;
@@ -94,6 +96,8 @@ package cva6_config_pkg;
       XFVec: bit'(CVA6ConfigFVecEn),
       CvxifEn: bit'(CVA6ConfigCvxifEn),
       ZiCondExtEn: bit'(CVA6ConfigZiCondExtEn),
+      RVSCLIC: bit'(CVA6ConfigSclicExtEn),
+      RVVCLIC: bit'(CVA6ConfigVclicExtEn),
       RVF: bit'(0),
       RVD: bit'(0),
       FpPresent: bit'(0),
diff --git a/core/include/cv32a6_embedded_config_pkg.sv b/core/include/cv32a6_embedded_config_pkg.sv
index b08a8273d5..0e94fc4620 100644
--- a/core/include/cv32a6_embedded_config_pkg.sv
+++ b/core/include/cv32a6_embedded_config_pkg.sv
@@ -27,6 +27,7 @@ package cva6_config_pkg;
   localparam CVA6ConfigVExtEn = 0;
   localparam CVA6ConfigZiCondExtEn = 0;
   localparam CVA6ConfigSclicExtEn = 0;
+  localparam CVA6ConfigVclicExtEn = 0;
 
   localparam CVA6ConfigAxiIdWidth = 4;
   localparam CVA6ConfigAxiAddrWidth = 64;
@@ -98,6 +99,7 @@ package cva6_config_pkg;
       CvxifEn: bit'(CVA6ConfigCvxifEn),
       ZiCondExtEn: bit'(CVA6ConfigZiCondExtEn),
       RVSCLIC: bit'(CVA6ConfigSclicExtEn),
+      RVVCLIC: bit'(CVA6ConfigVclicExtEn),
       // Extended
       RVF:
       bit'(
diff --git a/core/include/cv32a6_ima_sv32_fpga_config_pkg.sv b/core/include/cv32a6_ima_sv32_fpga_config_pkg.sv
index acee7de1af..30292ad075 100644
--- a/core/include/cv32a6_ima_sv32_fpga_config_pkg.sv
+++ b/core/include/cv32a6_ima_sv32_fpga_config_pkg.sv
@@ -28,6 +28,7 @@ package cva6_config_pkg;
   localparam CVA6ConfigVExtEn = 0;
   localparam CVA6ConfigZiCondExtEn = 0;
   localparam CVA6ConfigSclicExtEn = 0;
+  localparam CVA6ConfigVclicExtEn = 0;
 
   localparam CVA6ConfigAxiIdWidth = 4;
   localparam CVA6ConfigAxiAddrWidth = 64;
@@ -99,6 +100,7 @@ package cva6_config_pkg;
       CvxifEn: bit'(CVA6ConfigCvxifEn),
       ZiCondExtEn: bit'(CVA6ConfigZiCondExtEn),
       RVSCLIC: bit'(CVA6ConfigSclicExtEn),
+      RVVCLIC: bit'(CVA6ConfigVclicExtEn),
       // Extended
       RVF:
       bit'(
diff --git a/core/include/cv32a6_imac_sv0_config_pkg.sv b/core/include/cv32a6_imac_sv0_config_pkg.sv
index 7f39e01c5f..83f8f2ed87 100644
--- a/core/include/cv32a6_imac_sv0_config_pkg.sv
+++ b/core/include/cv32a6_imac_sv0_config_pkg.sv
@@ -28,6 +28,7 @@ package cva6_config_pkg;
   localparam CVA6ConfigVExtEn = 0;
   localparam CVA6ConfigZiCondExtEn = 0;
   localparam CVA6ConfigSclicExtEn = 0;
+  localparam CVA6ConfigVclicExtEn = 0;
 
   localparam CVA6ConfigAxiIdWidth = 4;
   localparam CVA6ConfigAxiAddrWidth = 64;
@@ -99,6 +100,7 @@ package cva6_config_pkg;
       CvxifEn: bit'(CVA6ConfigCvxifEn),
       ZiCondExtEn: bit'(CVA6ConfigZiCondExtEn),
       RVSCLIC: bit'(CVA6ConfigSclicExtEn),
+      RVVCLIC: bit'(CVA6ConfigVclicExtEn),
       // Extended
       RVF:
       bit'(
diff --git a/core/include/cv32a6_imac_sv32_config_pkg.sv b/core/include/cv32a6_imac_sv32_config_pkg.sv
index 72b84e06dd..235613dbb7 100644
--- a/core/include/cv32a6_imac_sv32_config_pkg.sv
+++ b/core/include/cv32a6_imac_sv32_config_pkg.sv
@@ -28,6 +28,7 @@ package cva6_config_pkg;
   localparam CVA6ConfigVExtEn = 0;
   localparam CVA6ConfigZiCondExtEn = 0;
   localparam CVA6ConfigSclicExtEn = 0;
+  localparam CVA6ConfigVclicExtEn = 0;
 
   localparam CVA6ConfigAxiIdWidth = 4;
   localparam CVA6ConfigAxiAddrWidth = 64;
@@ -99,6 +100,7 @@ package cva6_config_pkg;
       CvxifEn: bit'(CVA6ConfigCvxifEn),
       ZiCondExtEn: bit'(CVA6ConfigZiCondExtEn),
       RVSCLIC: bit'(CVA6ConfigSclicExtEn),
+      RVVCLIC: bit'(CVA6ConfigVclicExtEn),
       // Extended
       RVF:
       bit'(
diff --git a/core/include/cv32a6_imafc_sv32_config_pkg.sv b/core/include/cv32a6_imafc_sv32_config_pkg.sv
index e9344dc74c..8b5a5f424f 100644
--- a/core/include/cv32a6_imafc_sv32_config_pkg.sv
+++ b/core/include/cv32a6_imafc_sv32_config_pkg.sv
@@ -28,6 +28,7 @@ package cva6_config_pkg;
   localparam CVA6ConfigVExtEn = 0;
   localparam CVA6ConfigZiCondExtEn = 0;
   localparam CVA6ConfigSclicExtEn = 0;
+  localparam CVA6ConfigVclicExtEn = 0;
 
   localparam CVA6ConfigAxiIdWidth = 4;
   localparam CVA6ConfigAxiAddrWidth = 64;
@@ -99,6 +100,7 @@ package cva6_config_pkg;
       CvxifEn: bit'(CVA6ConfigCvxifEn),
       ZiCondExtEn: bit'(CVA6ConfigZiCondExtEn),
       RVSCLIC: bit'(CVA6ConfigSclicExtEn),
+      RVVCLIC: bit'(CVA6ConfigVclicExtEn),
       // Extended
       RVF:
       bit'(
diff --git a/core/include/cv64a6_imadfcv_sv39_polara_config_pkg.sv b/core/include/cv64a6_imadfcv_sv39_polara_config_pkg.sv
index fe9c8e8345..7fd1776219 100644
--- a/core/include/cv64a6_imadfcv_sv39_polara_config_pkg.sv
+++ b/core/include/cv64a6_imadfcv_sv39_polara_config_pkg.sv
@@ -28,6 +28,7 @@ package cva6_config_pkg;
   localparam CVA6ConfigVExtEn = 1;
   localparam CVA6ConfigZiCondExtEn = 0;
   localparam CVA6ConfigSclicExtEn = 0;
+  localparam CVA6ConfigVclicExtEn = 0;
 
   localparam CVA6ConfigAxiIdWidth = 4;
   localparam CVA6ConfigAxiAddrWidth = 64;
@@ -99,6 +100,7 @@ package cva6_config_pkg;
       CvxifEn: bit'(CVA6ConfigCvxifEn),
       ZiCondExtEn: bit'(CVA6ConfigZiCondExtEn),
       RVSCLIC: bit'(CVA6ConfigSclicExtEn),
+      RVVCLIC: bit'(CVA6ConfigVclicExtEn),
       // Extended
       RVF:
       bit'(
diff --git a/core/include/cv64a6_imafdc_sv39_config_pkg.sv b/core/include/cv64a6_imafdc_sv39_config_pkg.sv
index 1d1b6a273b..0a8484378e 100644
--- a/core/include/cv64a6_imafdc_sv39_config_pkg.sv
+++ b/core/include/cv64a6_imafdc_sv39_config_pkg.sv
@@ -28,6 +28,7 @@ package cva6_config_pkg;
   localparam CVA6ConfigVExtEn = 0;
   localparam CVA6ConfigZiCondExtEn = 1;
   localparam CVA6ConfigSclicExtEn = 0;
+  localparam CVA6ConfigVclicExtEn = 0;
 
   localparam CVA6ConfigAxiIdWidth = 4;
   localparam CVA6ConfigAxiAddrWidth = 64;
@@ -99,6 +100,7 @@ package cva6_config_pkg;
       CvxifEn: bit'(CVA6ConfigCvxifEn),
       ZiCondExtEn: bit'(CVA6ConfigZiCondExtEn),
       RVSCLIC: bit'(CVA6ConfigSclicExtEn),
+      RVVCLIC: bit'(CVA6ConfigVclicExtEn),
       // Extended
       RVF:
       bit'(
diff --git a/core/include/cv64a6_imafdc_sv39_hpdcache_config_pkg.sv b/core/include/cv64a6_imafdc_sv39_hpdcache_config_pkg.sv
index df48a38f5b..bf35e74c17 100644
--- a/core/include/cv64a6_imafdc_sv39_hpdcache_config_pkg.sv
+++ b/core/include/cv64a6_imafdc_sv39_hpdcache_config_pkg.sv
@@ -35,6 +35,7 @@ package cva6_config_pkg;
   localparam CVA6ConfigHExtEn = 0;
   localparam CVA6ConfigZiCondExtEn = 1;
   localparam CVA6ConfigSclicExtEn = 0;
+  localparam CVA6ConfigVclicExtEn = 0;
 
   localparam CVA6ConfigAxiIdWidth = 4;
   localparam CVA6ConfigAxiAddrWidth = 64;
@@ -106,6 +107,7 @@ package cva6_config_pkg;
       CvxifEn: bit'(CVA6ConfigCvxifEn),
       ZiCondExtEn: bit'(CVA6ConfigZiCondExtEn),
       RVSCLIC: bit'(CVA6ConfigSclicExtEn),
+      RVVCLIC: bit'(CVA6ConfigVclicExtEn),
       // Extended
       RVF:
       bit'(
diff --git a/core/include/cv64a6_imafdc_sv39_openpiton_config_pkg.sv b/core/include/cv64a6_imafdc_sv39_openpiton_config_pkg.sv
index 78ec9eba46..e96e03c753 100644
--- a/core/include/cv64a6_imafdc_sv39_openpiton_config_pkg.sv
+++ b/core/include/cv64a6_imafdc_sv39_openpiton_config_pkg.sv
@@ -28,6 +28,7 @@ package cva6_config_pkg;
   localparam CVA6ConfigVExtEn = 0;
   localparam CVA6ConfigZiCondExtEn = 0;
   localparam CVA6ConfigSclicExtEn = 0;
+  localparam CVA6ConfigVclicExtEn = 0;
 
   localparam CVA6ConfigAxiIdWidth = 4;
   localparam CVA6ConfigAxiAddrWidth = 64;
@@ -99,6 +100,7 @@ package cva6_config_pkg;
       CvxifEn: bit'(CVA6ConfigCvxifEn),
       ZiCondExtEn: bit'(CVA6ConfigZiCondExtEn),
       RVSCLIC: bit'(CVA6ConfigSclicExtEn),
+      RVVCLIC: bit'(CVA6ConfigVclicExtEn),
       // Extended
       RVF:
       bit'(
diff --git a/core/include/cv64a6_imafdc_sv39_wb_config_pkg.sv b/core/include/cv64a6_imafdc_sv39_wb_config_pkg.sv
index 2d4f3730e8..d44d699250 100644
--- a/core/include/cv64a6_imafdc_sv39_wb_config_pkg.sv
+++ b/core/include/cv64a6_imafdc_sv39_wb_config_pkg.sv
@@ -28,6 +28,7 @@ package cva6_config_pkg;
   localparam CVA6ConfigHExtEn = 0;
   localparam CVA6ConfigZiCondExtEn = 1;
   localparam CVA6ConfigSclicExtEn = 0;
+  localparam CVA6ConfigVclicExtEn = 0;
 
   localparam CVA6ConfigAxiIdWidth = 4;
   localparam CVA6ConfigAxiAddrWidth = 64;
@@ -99,6 +100,7 @@ package cva6_config_pkg;
       CvxifEn: bit'(CVA6ConfigCvxifEn),
       ZiCondExtEn: bit'(CVA6ConfigZiCondExtEn),
       RVSCLIC: bit'(CVA6ConfigSclicExtEn),
+      RVVCLIC: bit'(CVA6ConfigVclicExtEn),
       // Extended
       RVF:
       bit'(
diff --git a/core/include/cv64a6_imafdch_sv39_config_pkg.sv b/core/include/cv64a6_imafdch_sv39_config_pkg.sv
index d3eb2cb192..9c4fa2a174 100644
--- a/core/include/cv64a6_imafdch_sv39_config_pkg.sv
+++ b/core/include/cv64a6_imafdch_sv39_config_pkg.sv
@@ -28,6 +28,7 @@ package cva6_config_pkg;
   localparam CVA6ConfigVExtEn = 0;
   localparam CVA6ConfigZiCondExtEn = 1;
   localparam CVA6ConfigSclicExtEn = 0;
+  localparam CVA6ConfigVclicExtEn = 0;
 
   localparam CVA6ConfigAxiIdWidth = 4;
   localparam CVA6ConfigAxiAddrWidth = 64;
@@ -99,6 +100,7 @@ package cva6_config_pkg;
       CvxifEn: bit'(CVA6ConfigCvxifEn),
       ZiCondExtEn: bit'(CVA6ConfigZiCondExtEn),
       RVSCLIC: bit'(CVA6ConfigSclicExtEn),
+      RVVCLIC: bit'(CVA6ConfigVclicExtEn),
       // Extended
       RVF:
       bit'(
diff --git a/core/include/cv64a6_imafdch_sv39_wb_config_pkg.sv b/core/include/cv64a6_imafdch_sv39_wb_config_pkg.sv
index 06e7e0fb5e..416a5f19e7 100644
--- a/core/include/cv64a6_imafdch_sv39_wb_config_pkg.sv
+++ b/core/include/cv64a6_imafdch_sv39_wb_config_pkg.sv
@@ -28,6 +28,7 @@ package cva6_config_pkg;
   localparam CVA6ConfigHExtEn = 1;
   localparam CVA6ConfigZiCondExtEn = 1;
   localparam CVA6ConfigSclicExtEn = 0;
+  localparam CVA6ConfigVclicExtEn = 0;
 
   localparam CVA6ConfigAxiIdWidth = 4;
   localparam CVA6ConfigAxiAddrWidth = 64;
@@ -99,6 +100,7 @@ package cva6_config_pkg;
       CvxifEn: bit'(CVA6ConfigCvxifEn),
       ZiCondExtEn: bit'(CVA6ConfigZiCondExtEn),
       RVSCLIC: bit'(CVA6ConfigSclicExtEn),
+      RVVCLIC: bit'(CVA6ConfigVclicExtEn),
       // Extended
       RVF:
       bit'(
diff --git a/core/include/cv64a6_imafdcsclic_sv39_config_pkg.sv b/core/include/cv64a6_imafdcsclic_sv39_config_pkg.sv
index cb3d53cabd..e18aee638f 100644
--- a/core/include/cv64a6_imafdcsclic_sv39_config_pkg.sv
+++ b/core/include/cv64a6_imafdcsclic_sv39_config_pkg.sv
@@ -28,6 +28,7 @@ package cva6_config_pkg;
   localparam CVA6ConfigHExtEn = 1;
   localparam CVA6ConfigZiCondExtEn = 1;
   localparam CVA6ConfigSclicExtEn = 1;
+  localparam CVA6ConfigVclicExtEn = 0;
 
   localparam CVA6ConfigAxiIdWidth = 4;
   localparam CVA6ConfigAxiAddrWidth = 64;
@@ -99,6 +100,7 @@ package cva6_config_pkg;
       CvxifEn: bit'(CVA6ConfigCvxifEn),
       ZiCondExtEn: bit'(CVA6ConfigZiCondExtEn),
       RVSCLIC: bit'(CVA6ConfigSclicExtEn),
+      RVVCLIC: bit'(CVA6ConfigVclicExtEn),
       // Extended
       RVF:
       bit'(
diff --git a/core/include/cv64a6_imafdcv_sv39_config_pkg.sv b/core/include/cv64a6_imafdcv_sv39_config_pkg.sv
index 770830a5d3..e7bba11d1a 100644
--- a/core/include/cv64a6_imafdcv_sv39_config_pkg.sv
+++ b/core/include/cv64a6_imafdcv_sv39_config_pkg.sv
@@ -28,6 +28,7 @@ package cva6_config_pkg;
   localparam CVA6ConfigVExtEn = 1;
   localparam CVA6ConfigZiCondExtEn = 0;
   localparam CVA6ConfigSclicExtEn = 0;
+  localparam CVA6ConfigVclicExtEn = 0;
 
   localparam CVA6ConfigAxiIdWidth = 4;
   localparam CVA6ConfigAxiAddrWidth = 64;
@@ -99,6 +100,7 @@ package cva6_config_pkg;
       CvxifEn: bit'(CVA6ConfigCvxifEn),
       ZiCondExtEn: bit'(CVA6ConfigZiCondExtEn),
       RVSCLIC: bit'(CVA6ConfigSclicExtEn),
+      RVVCLIC: bit'(CVA6ConfigVclicExtEn),
       // Extended
       RVF:
       bit'(
diff --git a/core/include/riscv_pkg.sv b/core/include/riscv_pkg.sv
index 3e3f70a3ee..9c0ac23cec 100644
--- a/core/include/riscv_pkg.sv
+++ b/core/include/riscv_pkg.sv
@@ -165,7 +165,7 @@ package riscv;
 
   typedef struct packed {
     logic [7:0] mil;
-    logic [7:0] wpri;
+    logic [7:0] vsil;
     logic [7:0] sil;
     logic [7:0] uil;
   } intstatus_rv_t;
@@ -463,11 +463,13 @@ package riscv;
     CSR_VSSTATUS         = 12'h200,
     CSR_VSIE             = 12'h204,
     CSR_VSTVEC           = 12'h205,
+    CSR_VSTVT            = 12'h207,
     CSR_VSSCRATCH        = 12'h240,
     CSR_VSEPC            = 12'h241,
     CSR_VSCAUSE          = 12'h242,
     CSR_VSTVAL           = 12'h243,
     CSR_VSIP             = 12'h244,
+    CSR_VSINTTHRESH      = 12'h247,
     CSR_VSATP            = 12'h280,
     // Supervisor Mode CSRs
     CSR_SSTATUS          = 12'h100,