From 41a09c23a82ab1ad7ce9563188df373dc07294d9 Mon Sep 17 00:00:00 2001 From: Enrico Zelioli Date: Tue, 23 May 2023 14:47:32 +0200 Subject: [PATCH 01/17] [ADD] ignore temp files --- .gitignore | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.gitignore b/.gitignore index 8b13789..f2baf14 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,10 @@ +**/work/ +.bender/ +Bender.lock +modelsim.ini +transcript +vsim.wlf +memories/ +traces/ +sim/tcl/compile.tcl From 3d1d9c8ef9ce8cadef3719a826e04af877635312 Mon Sep 17 00:00:00 2001 From: Enrico Zelioli Date: Fri, 26 May 2023 10:00:36 +0200 Subject: [PATCH 02/17] [FIX] Register generation --- src/gen/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gen/Makefile b/src/gen/Makefile index 991694f..94e6c2d 100644 --- a/src/gen/Makefile +++ b/src/gen/Makefile @@ -43,5 +43,5 @@ install: .PHONY: clean clean: - rm clic.h mclic_reg_pkg.sv mclic_reg_top.sv clicint_reg_pkg.sv clicint_reg_top.sv + rm clic.h clicint.h mclic_reg_pkg.sv mclic_reg_top.sv clicint_reg_pkg.sv clicint_reg_top.sv From e6d80a7c081ea9c6e429bcb5e5e5c1381e5144d2 Mon Sep 17 00:00:00 2001 From: Enrico Zelioli Date: Mon, 5 Jun 2023 18:09:49 +0200 Subject: [PATCH 03/17] [ADD] Interrupt virtualization support --- src/clic.sv | 189 ++++++++++++++++++++++++++++++++++++---- src/clic_reg_adapter.sv | 9 +- src/clic_target.sv | 14 ++- src/clicintv_reg_pkg.sv | 44 ++++++++++ src/clicintv_reg_top.sv | 181 ++++++++++++++++++++++++++++++++++++++ src/gen/Makefile | 14 ++- src/gen/clicintv.hjson | 34 ++++++++ 7 files changed, 463 insertions(+), 22 deletions(-) create mode 100644 src/clicintv_reg_pkg.sv create mode 100644 src/clicintv_reg_top.sv create mode 100644 src/gen/clicintv.hjson diff --git a/src/clic.sv b/src/clic.sv index 044da34..f83cfe9 100644 --- a/src/clic.sv +++ b/src/clic.sv @@ -17,15 +17,20 @@ `include "common_cells/assertions.svh" -module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( +module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_reg_pkg::*; #( parameter type reg_req_t = logic, parameter type reg_rsp_t = logic, parameter int N_SOURCE = 256, parameter int INTCTLBITS = 8, parameter bit SSCLIC = 0, parameter bit USCLIC = 0, + parameter bit VSCLIC = 0, // vCLIC enable + parameter int unsigned N_VSCTXTS = 0, // Number of Virtual Contexts supported. + // This implementation assumes CLIC is mapped to an address + // range that allows up to 64 contexts (at least 512KiB) // do not edit below, these are derived - localparam int SRC_W = $clog2(N_SOURCE) + localparam int SRC_W = $clog2(N_SOURCE), + localparam int MAX_VSCTXTS = 64 )( input logic clk_i, input logic rst_ni, @@ -44,6 +49,8 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( output logic [7:0] irq_level_o, output logic irq_shv_o, output logic [1:0] irq_priv_o, + output logic [5:0] irq_vsid_o, // up to 64 VS contexts + output logic irq_v_o, output logic irq_kill_req_o, input logic irq_kill_ack_i ); @@ -51,29 +58,52 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( if (USCLIC) $fatal(1, "usclic mode is not supported"); + if (N_VSCTXTS > MAX_VSCTXTS) + $fatal(1, "vsclic extension supports up to 64 virtual contexts"); + + // CLIC internal address size + localparam int unsigned ADDR_W = $clog2(MAX_VSCTXTS * 8 * 1024); // 19 + localparam logic [1:0] U_MODE = 2'b00; localparam logic [1:0] S_MODE = 2'b01; localparam logic [1:0] M_MODE = 2'b11; - localparam logic [15:0] MCLICCFG_START = 16'h0000; - localparam logic [15:0] MCLICINT_START = 16'h1000; - localparam logic [15:0] MCLICINT_END = 16'h4fff; - - localparam logic [15:0] SCLICCFG_START = 16'h8000; - localparam logic [15:0] SCLICINT_START = 16'h9000; - localparam logic [15:0] SCLICINT_END = 16'hcfff; + // Each privilege mode address space is aligned to a 8KiB physical memory region + localparam logic [ADDR_W-1:0] MCLICCFG_START = 'h00000; + localparam logic [ADDR_W-1:0] MCLICINT_START = 'h01000; + localparam logic [ADDR_W-1:0] MCLICINT_END = 'h04fff; + localparam logic [ADDR_W-1:0] MCLICINTV_START = 'h05000; + localparam logic [ADDR_W-1:0] MCLICINTV_END = 'h05fff; + + localparam logic [ADDR_W-1:0] SCLICCFG_START = 'h08000; + localparam logic [ADDR_W-1:0] SCLICINT_START = 'h09000; + localparam logic [ADDR_W-1:0] SCLICINT_END = 'h0cfff; + localparam logic [ADDR_W-1:0] SCLICINTV_START = 'h0d000; + localparam logic [ADDR_W-1:0] SCLICINTV_END = 'h0dfff; + + `define VSCLICCFG_START(i) ('h08000 * (i + 2)) + `define VSCLICINT_START(i) ('h08000 * (i + 2) + 'h01000) + `define VSCLICINT_END(i) ('h08000 * (i + 2) + 'h04fff) + `define VSCLICINTV_START(i) ('h08000 * (i + 2) + 'h05000) + `define VSCLICINTV_END(i) ('h08000 * (i + 2) + 'h05fff) mclic_reg2hw_t mclic_reg2hw; clicint_reg2hw_t [N_SOURCE-1:0] clicint_reg2hw; clicint_hw2reg_t [N_SOURCE-1:0] clicint_hw2reg; + clicintv_reg2hw_t [N_SOURCE-1:0] clicintv_reg2hw; + // clicintv_hw2reg_t [N_SOURCE-1:0] clicintv_hw2reg; + logic [7:0] intctl [N_SOURCE]; logic [7:0] irq_max; logic [1:0] intmode [N_SOURCE]; logic [1:0] irq_mode; + logic [5:0] vsid [N_SOURCE]; // Per-IRQ Virtual Supervisor (VS) ID + logic intv [N_SOURCE]; // Per-IRQ virtualization bit + logic [N_SOURCE-1:0] le; // 0: level-sensitive 1: edge-sensitive logic [N_SOURCE-1:0] ip; logic [N_SOURCE-1:0] ie; @@ -113,6 +143,7 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( .prio_i (intctl), .mode_i (intmode), + .intv_i (intv), .claim_o (claim), @@ -150,14 +181,14 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( // 0x1000 - 0x4fff (machine mode) reg_req_t reg_all_int_req; reg_rsp_t reg_all_int_rsp; - logic [15:0] int_addr; + logic [ADDR_W-1:0] int_addr; reg_req_t [N_SOURCE-1:0] reg_int_req; reg_rsp_t [N_SOURCE-1:0] reg_int_rsp; // TODO: improve decoding by only deasserting valid always_comb begin - int_addr = reg_all_int_req.addr[15:2]; + int_addr = reg_all_int_req.addr[ADDR_W-1:2]; reg_int_req = '0; reg_all_int_rsp = '0; @@ -184,6 +215,51 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( ); end + // interrupt control and status registers (per interrupt line) + // 0x???? - 0x???? (machine mode) + reg_req_t reg_all_v_req; + reg_rsp_t reg_all_v_rsp; + logic [ADDR_W-1:0] v_addr; + + reg_req_t [N_SOURCE-1:0] reg_v_req; + reg_rsp_t [N_SOURCE-1:0] reg_v_rsp; + + if (VSCLIC) begin + + always_comb begin + reg_v_req = '0; + reg_all_v_rsp = '0; + + v_addr = reg_all_v_req.addr[ADDR_W-1:2]; + + reg_v_req[v_addr] = reg_all_v_req; + reg_all_v_rsp = reg_v_rsp[v_addr]; + end + + for (genvar i = 0; i < N_SOURCE; i++) begin : gen_clic_intv + clicintv_reg_top #( + .reg_req_t (reg_req_t), + .reg_rsp_t (reg_rsp_t) + ) i_clicintv_reg_top ( + .clk_i, + .rst_ni, + + .reg_req_i (reg_v_req[i]), + .reg_rsp_o (reg_v_rsp[i]), + + .reg2hw (clicintv_reg2hw[i]), + // .hw2reg (clicintv_hw2reg[i]), + + .devmode_i (1'b1) + ); + end + end else begin + assign clicintv_reg2hw = '0; + // assign clicintv_hw2reg = '0; + assign v_addr = '0; + assign reg_all_v_rsp = '0; + end + // configuration registers // 0x8000 (supervisor mode) @@ -195,9 +271,10 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( always_comb begin : clic_addr_decode reg_mclic_req = '0; reg_all_int_req = '0; + reg_all_v_req = '0; reg_rsp_o = '0; - unique case(reg_req_i.addr[15:0]) inside + unique case(reg_req_i.addr[ADDR_W-1:0]) inside MCLICCFG_START: begin reg_mclic_req = reg_req_i; reg_rsp_o = reg_mclic_rsp; @@ -207,6 +284,18 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( reg_all_int_req.addr = reg_req_i.addr - MCLICINT_START; reg_rsp_o = reg_all_int_rsp; end + [MCLICINTV_START:MCLICINTV_END]: begin + if (VSCLIC) begin + reg_all_v_req = reg_req_i; + reg_all_v_req.addr = reg_req_i.addr - MCLICINTV_START; + reg_rsp_o = reg_all_v_rsp; + end else begin + // VSCLIC disabled + reg_rsp_o.rdata = '0; + reg_rsp_o.error = '0; + reg_rsp_o.ready = 1'b1; + end + end SCLICCFG_START: begin if (SSCLIC) begin reg_mclic_req = reg_req_i; @@ -216,7 +305,7 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( [SCLICINT_START:SCLICINT_END]: begin if (SSCLIC) begin reg_all_int_req.addr = reg_req_i.addr - SCLICINT_START; - if (intmode[reg_all_int_req.addr[15:2]] <= S_MODE) begin + if (intmode[reg_all_int_req.addr[ADDR_W-1:2]] <= S_MODE) begin // check whether the irq we want to access is s-mode or lower reg_all_int_req = reg_req_i; // Prevent setting interrupt mode to m-mode . This is currently a @@ -232,6 +321,26 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( end end end + [SCLICINTV_START:SCLICINTV_END]: begin + if (VSCLIC) begin + reg_all_v_req.addr = reg_req_i.addr - SCLICINTV_START; + if (intmode[reg_all_v_req.addr[ADDR_W-1:2]] <= S_MODE) begin + // check whether the irq we want to access is s-mode or lower + reg_all_v_req = reg_req_i; + reg_rsp_o = reg_all_v_rsp; + end else begin + // inaccesible (all zero) + reg_rsp_o.rdata = '0; + reg_rsp_o.error = '0; + reg_rsp_o.ready = 1'b1; + end + end else begin + // VSCLIC disabled + reg_rsp_o.rdata = '0; + reg_rsp_o.error = '0; + reg_rsp_o.ready = 1'b1; + end + end default: begin // inaccesible (all zero) reg_rsp_o.rdata = '0; @@ -239,6 +348,47 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( reg_rsp_o.ready = 1'b1; end endcase // unique case (reg_req_i.addr) + + // Match VS address space + if (VSCLIC) begin + for (int i = 0; i < N_VSCTXTS; i++) begin + case(reg_req_i.addr[ADDR_W-1:0]) inside + // TODO: whether / how to grant access to MCLICCFG register + `VSCLICCFG_START(i): begin + // inaccesible (all zero) + reg_rsp_o.rdata = '0; + reg_rsp_o.error = '0; + reg_rsp_o.ready = 1'b1; + end + [`VSCLICINT_START(i):`VSCLICINT_END(i)]: begin + reg_all_int_req.addr = reg_req_i.addr - `VSCLICINT_START(i); + if ((intmode[reg_all_int_req.addr[ADDR_W-1:2]] == S_MODE) && + (intv[reg_all_int_req.addr[ADDR_W-1:2]]) && + (vsid[reg_all_int_req.addr[ADDR_W-1:2]] == i)) begin + // check whether the irq we want to access is s-mode and its v bit is set and the VSID corresponds + reg_all_int_req = reg_req_i; + // Prevent setting interrupt mode to m-mode . This is currently a + // bit ugly but will be nicer once we do away with auto generated + // clicint registers + reg_all_int_req.wdata[23] = 1'b0; + reg_rsp_o = reg_all_int_rsp; + end else begin + // inaccesible (all zero) + reg_rsp_o.rdata = '0; + reg_rsp_o.error = '0; + reg_rsp_o.ready = 1'b1; + end + end + // TODO: whether / how to grant access to CLICINTV registers + [`VSCLICINTV_START(i):`VSCLICINTV_END(i)]: begin + // inaccesible (all zero) + reg_rsp_o.rdata = '0; + reg_rsp_o.error = '0; + reg_rsp_o.ready = 1'b1; + end + endcase // case (reg_req_i.addr) + end + end end // adapter @@ -254,9 +404,14 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( .clicint_reg2hw, .clicint_hw2reg, + .clicintv_reg2hw, + // .clicintv_hw2reg, + .intctl_o (intctl), .intmode_o (intmode), .shv_o (shv), + .vsid_o (vsid), + .intv_o (intv), .ip_sw_o (ip_sw), .ie_o (ie), .le_o (le), @@ -277,6 +432,10 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( // Extract SHV bit for the highest level, highest priority pending interrupt assign irq_shv_o = shv[irq_id_o]; + + // Extract Virtual Supervisor ID for the highest level, highest priority pending interrupt + assign irq_vsid_o = (VSCLIC && (irq_priv_o == S_MODE)) ? vsid[irq_id_o] : '0; + assign irq_v_o = (VSCLIC && (irq_priv_o == S_MODE)) ? intv[irq_id_o] : '0; logic [7:0] irq_level_tmp; @@ -323,10 +482,10 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( // m-mode only supported means no configuration nmbits = 2'b0; - if (SSCLIC || USCLIC) + if (VSCLIC || SSCLIC || USCLIC) nmbits[0] = mclic_reg2hw.mcliccfg.nmbits.q[0]; - if (SSCLIC && USCLIC) + if ((VSCLIC || SSCLIC) && USCLIC) nmbits[1] = mclic_reg2hw.mcliccfg.nmbits.q[1]; end diff --git a/src/clic_reg_adapter.sv b/src/clic_reg_adapter.sv index 70008f4..1f0f6f7 100644 --- a/src/clic_reg_adapter.sv +++ b/src/clic_reg_adapter.sv @@ -14,7 +14,7 @@ // SPDX-License-Identifier: Apache-2.0 -module clic_reg_adapter import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( +module clic_reg_adapter import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_reg_pkg::*; #( parameter int N_SOURCE = 32, parameter int INTCTLBITS = 8 )( @@ -26,8 +26,13 @@ module clic_reg_adapter import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( input clicint_reg_pkg::clicint_reg2hw_t [N_SOURCE-1:0] clicint_reg2hw, output clicint_reg_pkg::clicint_hw2reg_t [N_SOURCE-1:0] clicint_hw2reg, + input clicintv_reg_pkg::clicintv_reg2hw_t [N_SOURCE-1:0] clicintv_reg2hw, + // output clicintv_reg_pkg::clicintv_hw2reg_t [N_SOURCE-1:0] clicintv_hw2reg, + output logic [7:0] intctl_o [N_SOURCE], output logic [1:0] intmode_o [N_SOURCE], + output logic [5:0] vsid_o [N_SOURCE], // interrupt VS id + output logic intv_o [N_SOURCE], // interrupt virtualization output logic [N_SOURCE-1:0] shv_o, output logic [N_SOURCE-1:0] ip_sw_o, output logic [N_SOURCE-1:0] ie_o, @@ -42,6 +47,8 @@ module clic_reg_adapter import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( for (genvar i = 0; i < N_SOURCE; i++) begin : gen_reghw assign intctl_o[i] = clicint_reg2hw[i].clicint.ctl.q; assign intmode_o[i] = clicint_reg2hw[i].clicint.attr_mode.q; + assign vsid_o[i] = clicintv_reg2hw[i].clicintv.vsid.q; + assign intv_o[i] = clicintv_reg2hw[i].clicintv.v.q; assign shv_o[i] = clicint_reg2hw[i].clicint.attr_shv.q; assign ip_sw_o[i] = clicint_reg2hw[i].clicint.ip.q; assign ie_o[i] = clicint_reg2hw[i].clicint.ie.q; diff --git a/src/clic_target.sv b/src/clic_target.sv index e680049..d0a303f 100644 --- a/src/clic_target.sv +++ b/src/clic_target.sv @@ -45,6 +45,7 @@ module clic_target #( input [PrioWidth-1:0] prio_i [N_SOURCE], input [ModeWidth-1:0] mode_i [N_SOURCE], + input logic intv_i [N_SOURCE], output logic [N_SOURCE-1:0] claim_o, @@ -61,6 +62,10 @@ module clic_target #( // this only works with 2 or more sources `ASSERT_INIT(NumSources_A, N_SOURCE >= 2) + localparam logic [1:0] U_MODE = 2'b00; + localparam logic [1:0] S_MODE = 2'b01; + localparam logic [1:0] M_MODE = 2'b11; + // align to powers of 2 for simplicity // a full binary tree with N levels has 2**N + 2**N-1 nodes localparam int NumLevels = $clog2(N_SOURCE); @@ -96,7 +101,11 @@ module clic_target #( assign is_tree[Pa] = ip_i[offset] & ie_i[offset]; assign id_tree[Pa] = offset; assign max_tree[Pa] = prio_i[offset]; - assign mode_tree[Pa] = mode_i[offset]; + // NOTE: save space by encoding the Virtualization bit in the privilege mode tree fields. + // This is done by temporarily elevating the privilege level of hypervisor IRQs (mode=S_MODE, intv=0) + // to the reserved value 2'b10 so that they have higher priority than virtualized IRQs (S_MODE == 1'b01) + // but still lower priority than M_MODE IRQs (M_MODE == 2'b11). + assign mode_tree[Pa] = ((mode_i[offset] == S_MODE) && ~intv_i[offset]) ? 2'b10 : mode_i[offset]; end else begin : gen_tie_off assign is_tree[Pa] = '0; assign id_tree[Pa] = '0; @@ -178,7 +187,8 @@ module clic_target #( if (irq_root_valid) begin irq_id_d = irq_root_id; irq_max_d = max_tree[0]; - irq_mode_d = mode_tree[0]; + // NOTE: If the interrupt priority was modified (see note above), restore nominal privilege + irq_mode_d = (mode_tree[0] == 2'b10) ? S_MODE : mode_tree[0]; irq_valid_d = 1'b1; irq_state_d = ACK; end diff --git a/src/clicintv_reg_pkg.sv b/src/clicintv_reg_pkg.sv new file mode 100644 index 0000000..c8d6afe --- /dev/null +++ b/src/clicintv_reg_pkg.sv @@ -0,0 +1,44 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Package auto-generated by `reggen` containing data structure + +package clicintv_reg_pkg; + + // Address widths within the block + parameter int BlockAw = 0; + + //////////////////////////// + // Typedefs for registers // + //////////////////////////// + + typedef struct packed { + struct packed { + logic q; + } v; + struct packed { + logic [5:0] q; + } vsid; + } clicintv_reg2hw_clicintv_reg_t; + + // Register -> HW type + typedef struct packed { + clicintv_reg2hw_clicintv_reg_t clicintv; // [6:0] + } clicintv_reg2hw_t; + + // Register offsets + parameter logic [BlockAw-1:0] CLICINTV_CLICINTV_OFFSET = 0'h 0; + + // Register index + typedef enum int { + CLICINTV_CLICINTV + } clicintv_id_e; + + // Register width information to check illegal writes + parameter logic [3:0] CLICINTV_PERMIT [1] = '{ + 4'b 0001 // index[0] CLICINTV_CLICINTV + }; + +endpackage + diff --git a/src/clicintv_reg_top.sv b/src/clicintv_reg_top.sv new file mode 100644 index 0000000..9f69bba --- /dev/null +++ b/src/clicintv_reg_top.sv @@ -0,0 +1,181 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Top module auto-generated by `reggen` + + +`include "common_cells/assertions.svh" + +module clicintv_reg_top #( + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic, + parameter int AW = 0 +) ( + input clk_i, + input rst_ni, + input reg_req_t reg_req_i, + output reg_rsp_t reg_rsp_o, + // To HW + output clicintv_reg_pkg::clicintv_reg2hw_t reg2hw, // Write + + + // Config + input devmode_i // If 1, explicit error return for unmapped register access +); + + import clicintv_reg_pkg::* ; + + localparam int DW = 8; + localparam int DBW = DW/8; // Byte Width + + // register signals + logic reg_we; + logic reg_re; + logic [AW-1:0] reg_addr; + logic [DW-1:0] reg_wdata; + logic [DBW-1:0] reg_be; + logic [DW-1:0] reg_rdata; + logic reg_error; + + logic addrmiss, wr_err; + + logic [DW-1:0] reg_rdata_next; + + // Below register interface can be changed + reg_req_t reg_intf_req; + reg_rsp_t reg_intf_rsp; + + + assign reg_intf_req = reg_req_i; + assign reg_rsp_o = reg_intf_rsp; + + + assign reg_we = reg_intf_req.valid & reg_intf_req.write; + assign reg_re = reg_intf_req.valid & ~reg_intf_req.write; + assign reg_addr = reg_intf_req.addr; + assign reg_wdata = reg_intf_req.wdata; + assign reg_be = reg_intf_req.wstrb; + assign reg_intf_rsp.rdata = reg_rdata; + assign reg_intf_rsp.error = reg_error; + assign reg_intf_rsp.ready = 1'b1; + + assign reg_rdata = reg_rdata_next ; + assign reg_error = (devmode_i & addrmiss) | wr_err; + + + // Define SW related signals + // Format: __{wd|we|qs} + // or _{wd|we|qs} if field == 1 or 0 + logic clicintv_v_qs; + logic clicintv_v_wd; + logic clicintv_v_we; + logic [5:0] clicintv_vsid_qs; + logic [5:0] clicintv_vsid_wd; + logic clicintv_vsid_we; + + // Register instances + // R[clicintv]: V(False) + + // F[v]: 0:0 + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h0) + ) u_clicintv_v ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (clicintv_v_we), + .wd (clicintv_v_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.clicintv.v.q ), + + // to register interface (read) + .qs (clicintv_v_qs) + ); + + + // F[vsid]: 7:2 + prim_subreg #( + .DW (6), + .SWACCESS("RW"), + .RESVAL (6'h0) + ) u_clicintv_vsid ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (clicintv_vsid_we), + .wd (clicintv_vsid_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.clicintv.vsid.q ), + + // to register interface (read) + .qs (clicintv_vsid_qs) + ); + + + + + logic [0:0] addr_hit; + always_comb begin + addr_hit = '0; + addr_hit[0] = (reg_addr == CLICINTV_CLICINTV_OFFSET); + end + + assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ; + + // Check sub-word write is permitted + always_comb begin + wr_err = (reg_we & + ((addr_hit[0] & (|(CLICINTV_PERMIT[0] & ~reg_be))))); + end + + assign clicintv_v_we = addr_hit[0] & reg_we & !reg_error; + assign clicintv_v_wd = reg_wdata[0]; + + assign clicintv_vsid_we = addr_hit[0] & reg_we & !reg_error; + assign clicintv_vsid_wd = reg_wdata[7:2]; + + // Read data return + always_comb begin + reg_rdata_next = '0; + unique case (1'b1) + addr_hit[0]: begin + reg_rdata_next[0] = clicintv_v_qs; + reg_rdata_next[7:2] = clicintv_vsid_qs; + end + + default: begin + reg_rdata_next = '1; + end + endcase + end + + // Unused signal tieoff + + // wdata / byte enable are not always fully used + // add a blanket unused statement to handle lint waivers + logic unused_wdata; + logic unused_be; + assign unused_wdata = ^reg_wdata; + assign unused_be = ^reg_be; + + // Assertions for Register Interface + `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit)) + +endmodule diff --git a/src/gen/Makefile b/src/gen/Makefile index 94e6c2d..47d0da4 100644 --- a/src/gen/Makefile +++ b/src/gen/Makefile @@ -21,7 +21,10 @@ REGTOOL = regtool.py all: headers srcs -srcs: clicint_reg_pkg.sv clicint_reg_top.sv mclic_reg_pkg.sv mclic_reg_top.sv +srcs: clicintv_reg_pkg.sv clicintv_reg_top.sv clicint_reg_pkg.sv clicint_reg_top.sv mclic_reg_pkg.sv mclic_reg_top.sv + +clicintv_reg_pkg.sv clicintv_reg_top.sv: clicintv.hjson + $(REGTOOL) -r $< -t . clicint_reg_pkg.sv clicint_reg_top.sv: clicint.hjson $(REGTOOL) -r $< -t . @@ -29,7 +32,7 @@ clicint_reg_pkg.sv clicint_reg_top.sv: clicint.hjson mclic_reg_pkg.sv mclic_reg_top.sv: mclic.hjson $(REGTOOL) -r $< -t . -headers: clic.h clicint.h +headers: clic.h clicint.h clicintv.h clic.h: mclic.hjson $(REGTOOL) --cdefines mclic.hjson > $@ @@ -37,11 +40,14 @@ clic.h: mclic.hjson clicint.h: clicint.hjson $(REGTOOL) --cdefines clicint.hjson > $@ +clicintv.h: clicintv.hjson + $(REGTOOL) --cdefines clicintv.hjson > $@ + .PHONY: install install: - cp mclic_reg_pkg.sv mclic_reg_top.sv clicint_reg_pkg.sv clicint_reg_top.sv .. + cp mclic_reg_pkg.sv mclic_reg_top.sv clicint_reg_pkg.sv clicint_reg_top.sv clicintv_reg_pkg.sv clicintv_reg_top.sv .. .PHONY: clean clean: - rm clic.h clicint.h mclic_reg_pkg.sv mclic_reg_top.sv clicint_reg_pkg.sv clicint_reg_top.sv + rm clic.h clicint.h clicintv.h mclic_reg_pkg.sv mclic_reg_top.sv clicint_reg_pkg.sv clicint_reg_top.sv clicintv_reg_pkg.sv clicintv_reg_top.sv diff --git a/src/gen/clicintv.hjson b/src/gen/clicintv.hjson new file mode 100644 index 0000000..daaf5fd --- /dev/null +++ b/src/gen/clicintv.hjson @@ -0,0 +1,34 @@ +// Copyright 2022 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// SPDX-License-Identifier: Apache-2.0 + +// CLIC virtual supervisor interrupt register +{ + name: "CLICINTV", + clock_primary: "clk_i", + bus_interfaces: [ + { protocol: "reg_iface", direction: "device" } + ], + + regwidth: "8", + registers: [ + { name: "CLICINTV", + desc: "CLIC interrupt virtualization", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "7:2", name: "VSID", desc: "interrupt VS id" }, + // { bits: "1", name: "reserved", desc: "reserved for future use"}, + { bits: "0", name: "V", desc: "interrupt delegated to VS-mode"}, + ], + } + ] +} From 33ce377964707df8e46acd672e38898cc4483a2a Mon Sep 17 00:00:00 2001 From: Enrico Zelioli Date: Tue, 4 Jul 2023 10:33:27 +0200 Subject: [PATCH 04/17] [FIX] Config register access from S/VS mode --- src/clic.sv | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/clic.sv b/src/clic.sv index f83cfe9..837a9fd 100644 --- a/src/clic.sv +++ b/src/clic.sv @@ -268,12 +268,18 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ // mirror // top level address decoding and bus muxing + + // Helper signal used to store intermediate address + logic [ADDR_W-1:0] addr_tmp; + always_comb begin : clic_addr_decode reg_mclic_req = '0; reg_all_int_req = '0; reg_all_v_req = '0; reg_rsp_o = '0; + addr_tmp = '0; + unique case(reg_req_i.addr[ADDR_W-1:0]) inside MCLICCFG_START: begin reg_mclic_req = reg_req_i; @@ -304,10 +310,11 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ end [SCLICINT_START:SCLICINT_END]: begin if (SSCLIC) begin - reg_all_int_req.addr = reg_req_i.addr - SCLICINT_START; - if (intmode[reg_all_int_req.addr[ADDR_W-1:2]] <= S_MODE) begin + addr_tmp = reg_req_i.addr[ADDR_W-1:0] - SCLICINT_START; + if (intmode[addr_tmp[ADDR_W-1:2]] <= S_MODE) begin // check whether the irq we want to access is s-mode or lower reg_all_int_req = reg_req_i; + reg_all_int_req.addr = addr_tmp; // Prevent setting interrupt mode to m-mode . This is currently a // bit ugly but will be nicer once we do away with auto generated // clicint registers @@ -323,10 +330,11 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ end [SCLICINTV_START:SCLICINTV_END]: begin if (VSCLIC) begin - reg_all_v_req.addr = reg_req_i.addr - SCLICINTV_START; - if (intmode[reg_all_v_req.addr[ADDR_W-1:2]] <= S_MODE) begin + addr_tmp = reg_req_i.addr[ADDR_W-1:0] - SCLICINTV_START; + if (intmode[addr_tmp[ADDR_W-1:2]] <= S_MODE) begin // check whether the irq we want to access is s-mode or lower reg_all_v_req = reg_req_i; + reg_all_v_req.addr = addr_tmp; reg_rsp_o = reg_all_v_rsp; end else begin // inaccesible (all zero) @@ -361,12 +369,13 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ reg_rsp_o.ready = 1'b1; end [`VSCLICINT_START(i):`VSCLICINT_END(i)]: begin - reg_all_int_req.addr = reg_req_i.addr - `VSCLICINT_START(i); - if ((intmode[reg_all_int_req.addr[ADDR_W-1:2]] == S_MODE) && - (intv[reg_all_int_req.addr[ADDR_W-1:2]]) && - (vsid[reg_all_int_req.addr[ADDR_W-1:2]] == i)) begin + addr_tmp = reg_req_i.addr[ADDR_W-1:0] - `VSCLICINT_START(i); + if ((intmode[addr_tmp[ADDR_W-1:2]] == S_MODE) && + (intv[addr_tmp[ADDR_W-1:2]]) && + (vsid[addr_tmp[ADDR_W-1:2]] == i)) begin // check whether the irq we want to access is s-mode and its v bit is set and the VSID corresponds reg_all_int_req = reg_req_i; + reg_all_int_req.addr = addr_tmp; // Prevent setting interrupt mode to m-mode . This is currently a // bit ugly but will be nicer once we do away with auto generated // clicint registers From 3816956693363f4017f92cce2d9350d171ca9b08 Mon Sep 17 00:00:00 2001 From: Enrico Zelioli Date: Thu, 10 Aug 2023 13:13:20 +0200 Subject: [PATCH 05/17] [FIX] Update clicint register layout --- src/clicint_reg_top.sv | 66 +++++------------------------------------- 1 file changed, 7 insertions(+), 59 deletions(-) diff --git a/src/clicint_reg_top.sv b/src/clicint_reg_top.sv index 6552ea0..e85f663 100644 --- a/src/clicint_reg_top.sv +++ b/src/clicint_reg_top.sv @@ -8,12 +8,12 @@ `include "common_cells/assertions.svh" module clicint_reg_top #( - parameter type reg_req_t = logic, - parameter type reg_rsp_t = logic, - parameter int AW = 2 + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic, + parameter int AW = 2 ) ( - input logic clk_i, - input logic rst_ni, + input clk_i, + input rst_ni, input reg_req_t reg_req_i, output reg_rsp_t reg_rsp_o, // To HW @@ -33,7 +33,7 @@ module clicint_reg_top #( // register signals logic reg_we; logic reg_re; - logic [BlockAw-1:0] reg_addr; + logic [AW-1:0] reg_addr; logic [DW-1:0] reg_wdata; logic [DBW-1:0] reg_be; logic [DW-1:0] reg_rdata; @@ -54,7 +54,7 @@ module clicint_reg_top #( assign reg_we = reg_intf_req.valid & reg_intf_req.write; assign reg_re = reg_intf_req.valid & ~reg_intf_req.write; - assign reg_addr = reg_intf_req.addr[BlockAw-1:0]; + assign reg_addr = reg_intf_req.addr; assign reg_wdata = reg_intf_req.wdata; assign reg_be = reg_intf_req.wstrb; assign reg_intf_rsp.rdata = reg_rdata; @@ -312,55 +312,3 @@ module clicint_reg_top #( `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit)) endmodule - -module clicint_reg_top_intf -#( - parameter int AW = 2, - localparam int DW = 32 -) ( - input logic clk_i, - input logic rst_ni, - REG_BUS.in regbus_slave, - // To HW - output clicint_reg_pkg::clicint_reg2hw_t reg2hw, // Write - input clicint_reg_pkg::clicint_hw2reg_t hw2reg, // Read - // Config - input devmode_i // If 1, explicit error return for unmapped register access -); - localparam int unsigned STRB_WIDTH = DW/8; - -`include "register_interface/typedef.svh" -`include "register_interface/assign.svh" - - // Define structs for reg_bus - typedef logic [AW-1:0] addr_t; - typedef logic [DW-1:0] data_t; - typedef logic [STRB_WIDTH-1:0] strb_t; - `REG_BUS_TYPEDEF_ALL(reg_bus, addr_t, data_t, strb_t) - - reg_bus_req_t s_reg_req; - reg_bus_rsp_t s_reg_rsp; - - // Assign SV interface to structs - `REG_BUS_ASSIGN_TO_REQ(s_reg_req, regbus_slave) - `REG_BUS_ASSIGN_FROM_RSP(regbus_slave, s_reg_rsp) - - - - clicint_reg_top #( - .reg_req_t(reg_bus_req_t), - .reg_rsp_t(reg_bus_rsp_t), - .AW(AW) - ) i_regs ( - .clk_i, - .rst_ni, - .reg_req_i(s_reg_req), - .reg_rsp_o(s_reg_rsp), - .reg2hw, // Write - .hw2reg, // Read - .devmode_i - ); - -endmodule - - From f7bb4d3f7527ab269132014f85a3977ea96b24c8 Mon Sep 17 00:00:00 2001 From: Enrico Zelioli Date: Thu, 10 Aug 2023 13:36:39 +0200 Subject: [PATCH 06/17] [FIX] CLICINTV register layout update --- Bender.yml | 2 + src/clic.sv | 71 +++++------ src/clic_reg_adapter.sv | 16 ++- src/clicintv_reg_pkg.sv | 30 ++++- src/clicintv_reg_top.sv | 262 +++++++++++++++++++++++++++++++++++----- src/gen/clicintv.hjson | 13 +- src_files.yml | 2 + 7 files changed, 308 insertions(+), 88 deletions(-) diff --git a/Bender.yml b/Bender.yml index 18d4c8e..04e624e 100644 --- a/Bender.yml +++ b/Bender.yml @@ -25,6 +25,8 @@ dependencies: sources: - src/clicint_reg_pkg.sv - src/clicint_reg_top.sv + - src/clicintv_reg_pkg.sv + - src/clicintv_reg_top.sv - src/mclic_reg_pkg.sv - src/mclic_reg_top.sv - src/clic_reg_adapter.sv diff --git a/src/clic.sv b/src/clic.sv index 837a9fd..480f5f9 100644 --- a/src/clic.sv +++ b/src/clic.sv @@ -72,8 +72,6 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ localparam logic [ADDR_W-1:0] MCLICCFG_START = 'h00000; localparam logic [ADDR_W-1:0] MCLICINT_START = 'h01000; localparam logic [ADDR_W-1:0] MCLICINT_END = 'h04fff; - localparam logic [ADDR_W-1:0] MCLICINTV_START = 'h05000; - localparam logic [ADDR_W-1:0] MCLICINTV_END = 'h05fff; localparam logic [ADDR_W-1:0] SCLICCFG_START = 'h08000; localparam logic [ADDR_W-1:0] SCLICINT_START = 'h09000; @@ -81,19 +79,18 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ localparam logic [ADDR_W-1:0] SCLICINTV_START = 'h0d000; localparam logic [ADDR_W-1:0] SCLICINTV_END = 'h0dfff; - `define VSCLICCFG_START(i) ('h08000 * (i + 2)) - `define VSCLICINT_START(i) ('h08000 * (i + 2) + 'h01000) - `define VSCLICINT_END(i) ('h08000 * (i + 2) + 'h04fff) - `define VSCLICINTV_START(i) ('h08000 * (i + 2) + 'h05000) - `define VSCLICINTV_END(i) ('h08000 * (i + 2) + 'h05fff) + // VS `i` (1 <= i <= 64) will be mapped to VSCLIC*(i) address space + `define VSCLICCFG_START(i) ('h08000 * (i + 1)) + `define VSCLICINT_START(i) ('h08000 * (i + 1) + 'h01000) + `define VSCLICINT_END(i) ('h08000 * (i + 1) + 'h04fff) mclic_reg2hw_t mclic_reg2hw; clicint_reg2hw_t [N_SOURCE-1:0] clicint_reg2hw; clicint_hw2reg_t [N_SOURCE-1:0] clicint_hw2reg; - clicintv_reg2hw_t [N_SOURCE-1:0] clicintv_reg2hw; - // clicintv_hw2reg_t [N_SOURCE-1:0] clicintv_hw2reg; + clicintv_reg2hw_t [(N_SOURCE/4)-1:0] clicintv_reg2hw; + // clicintv_hw2reg_t [(N_SOURCE/4)-1:0] clicintv_hw2reg; // Not needed logic [7:0] intctl [N_SOURCE]; logic [7:0] irq_max; @@ -221,8 +218,8 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ reg_rsp_t reg_all_v_rsp; logic [ADDR_W-1:0] v_addr; - reg_req_t [N_SOURCE-1:0] reg_v_req; - reg_rsp_t [N_SOURCE-1:0] reg_v_rsp; + reg_req_t [(N_SOURCE/4)-1:0] reg_v_req; + reg_rsp_t [(N_SOURCE/4)-1:0] reg_v_rsp; if (VSCLIC) begin @@ -236,7 +233,7 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ reg_all_v_rsp = reg_v_rsp[v_addr]; end - for (genvar i = 0; i < N_SOURCE; i++) begin : gen_clic_intv + for (genvar i = 0; i < (N_SOURCE/4); i++) begin : gen_clic_intv clicintv_reg_top #( .reg_req_t (reg_req_t), .reg_rsp_t (reg_rsp_t) @@ -290,18 +287,6 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ reg_all_int_req.addr = reg_req_i.addr - MCLICINT_START; reg_rsp_o = reg_all_int_rsp; end - [MCLICINTV_START:MCLICINTV_END]: begin - if (VSCLIC) begin - reg_all_v_req = reg_req_i; - reg_all_v_req.addr = reg_req_i.addr - MCLICINTV_START; - reg_rsp_o = reg_all_v_rsp; - end else begin - // VSCLIC disabled - reg_rsp_o.rdata = '0; - reg_rsp_o.error = '0; - reg_rsp_o.ready = 1'b1; - end - end SCLICCFG_START: begin if (SSCLIC) begin reg_mclic_req = reg_req_i; @@ -331,16 +316,25 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ [SCLICINTV_START:SCLICINTV_END]: begin if (VSCLIC) begin addr_tmp = reg_req_i.addr[ADDR_W-1:0] - SCLICINTV_START; - if (intmode[addr_tmp[ADDR_W-1:2]] <= S_MODE) begin - // check whether the irq we want to access is s-mode or lower - reg_all_v_req = reg_req_i; - reg_all_v_req.addr = addr_tmp; - reg_rsp_o = reg_all_v_rsp; - end else begin - // inaccesible (all zero) - reg_rsp_o.rdata = '0; - reg_rsp_o.error = '0; - reg_rsp_o.ready = 1'b1; + reg_all_v_req = reg_req_i; + reg_all_v_req.addr = addr_tmp; + addr_tmp = {addr_tmp[ADDR_W-1:2], 2'b0}; + reg_rsp_o = reg_all_v_rsp; + if(intmode[addr_tmp + 0] > S_MODE) begin + reg_all_v_req.wdata[7:0] = 8'b0; + reg_rsp_o.rdata[7:0] = 8'b0; + end + if(intmode[addr_tmp + 1] > S_MODE) begin + reg_all_v_req.wdata[15:8] = 8'b0; + reg_rsp_o.rdata[15:8] = 8'b0; + end + if(intmode[addr_tmp + 2] > S_MODE) begin + reg_all_v_req.wdata[23:16] = 8'b0; + reg_rsp_o.rdata[23:16] = 8'b0; + end + if(intmode[addr_tmp + 3] > S_MODE) begin + reg_all_v_req.wdata[31:24] = 8'b0; + reg_rsp_o.rdata[31:24] = 8'b0; end end else begin // VSCLIC disabled @@ -359,7 +353,7 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ // Match VS address space if (VSCLIC) begin - for (int i = 0; i < N_VSCTXTS; i++) begin + for (int i = 1; i <= N_VSCTXTS; i++) begin case(reg_req_i.addr[ADDR_W-1:0]) inside // TODO: whether / how to grant access to MCLICCFG register `VSCLICCFG_START(i): begin @@ -388,13 +382,6 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ reg_rsp_o.ready = 1'b1; end end - // TODO: whether / how to grant access to CLICINTV registers - [`VSCLICINTV_START(i):`VSCLICINTV_END(i)]: begin - // inaccesible (all zero) - reg_rsp_o.rdata = '0; - reg_rsp_o.error = '0; - reg_rsp_o.ready = 1'b1; - end endcase // case (reg_req_i.addr) end end diff --git a/src/clic_reg_adapter.sv b/src/clic_reg_adapter.sv index 1f0f6f7..ae0f803 100644 --- a/src/clic_reg_adapter.sv +++ b/src/clic_reg_adapter.sv @@ -26,8 +26,8 @@ module clic_reg_adapter import mclic_reg_pkg::*; import clicint_reg_pkg::*; impo input clicint_reg_pkg::clicint_reg2hw_t [N_SOURCE-1:0] clicint_reg2hw, output clicint_reg_pkg::clicint_hw2reg_t [N_SOURCE-1:0] clicint_hw2reg, - input clicintv_reg_pkg::clicintv_reg2hw_t [N_SOURCE-1:0] clicintv_reg2hw, - // output clicintv_reg_pkg::clicintv_hw2reg_t [N_SOURCE-1:0] clicintv_hw2reg, + input clicintv_reg_pkg::clicintv_reg2hw_t [(N_SOURCE/4)-1:0] clicintv_reg2hw, + // output clicintv_reg_pkg::clicintv_hw2reg_t [(N_SOURCE/4)-1:0] clicintv_hw2reg, output logic [7:0] intctl_o [N_SOURCE], output logic [1:0] intmode_o [N_SOURCE], @@ -47,8 +47,6 @@ module clic_reg_adapter import mclic_reg_pkg::*; import clicint_reg_pkg::*; impo for (genvar i = 0; i < N_SOURCE; i++) begin : gen_reghw assign intctl_o[i] = clicint_reg2hw[i].clicint.ctl.q; assign intmode_o[i] = clicint_reg2hw[i].clicint.attr_mode.q; - assign vsid_o[i] = clicintv_reg2hw[i].clicintv.vsid.q; - assign intv_o[i] = clicintv_reg2hw[i].clicintv.v.q; assign shv_o[i] = clicint_reg2hw[i].clicint.attr_shv.q; assign ip_sw_o[i] = clicint_reg2hw[i].clicint.ip.q; assign ie_o[i] = clicint_reg2hw[i].clicint.ie.q; @@ -57,4 +55,14 @@ module clic_reg_adapter import mclic_reg_pkg::*; import clicint_reg_pkg::*; impo assign le_o[i] = clicint_reg2hw[i].clicint.attr_trig.q[0]; end + for (genvar i = 0; i < N_SOURCE; i = i + 4) begin : gen_reghw_v + assign vsid_o[i+0] = clicintv_reg2hw[i/4].clicintv.vsid0.q; + assign intv_o[i+0] = clicintv_reg2hw[i/4].clicintv.v0.q; + assign vsid_o[i+1] = clicintv_reg2hw[i/4].clicintv.vsid1.q; + assign intv_o[i+1] = clicintv_reg2hw[i/4].clicintv.v1.q; + assign vsid_o[i+2] = clicintv_reg2hw[i/4].clicintv.vsid2.q; + assign intv_o[i+2] = clicintv_reg2hw[i/4].clicintv.v2.q; + assign vsid_o[i+3] = clicintv_reg2hw[i/4].clicintv.vsid3.q; + assign intv_o[i+3] = clicintv_reg2hw[i/4].clicintv.v3.q; + end endmodule // clic_reg_adapter diff --git a/src/clicintv_reg_pkg.sv b/src/clicintv_reg_pkg.sv index c8d6afe..e59878e 100644 --- a/src/clicintv_reg_pkg.sv +++ b/src/clicintv_reg_pkg.sv @@ -7,7 +7,7 @@ package clicintv_reg_pkg; // Address widths within the block - parameter int BlockAw = 0; + parameter int BlockAw = 2; //////////////////////////// // Typedefs for registers // @@ -16,19 +16,37 @@ package clicintv_reg_pkg; typedef struct packed { struct packed { logic q; - } v; + } v0; struct packed { logic [5:0] q; - } vsid; + } vsid0; + struct packed { + logic q; + } v1; + struct packed { + logic [5:0] q; + } vsid1; + struct packed { + logic q; + } v2; + struct packed { + logic [5:0] q; + } vsid2; + struct packed { + logic q; + } v3; + struct packed { + logic [5:0] q; + } vsid3; } clicintv_reg2hw_clicintv_reg_t; // Register -> HW type typedef struct packed { - clicintv_reg2hw_clicintv_reg_t clicintv; // [6:0] + clicintv_reg2hw_clicintv_reg_t clicintv; // [27:0] } clicintv_reg2hw_t; // Register offsets - parameter logic [BlockAw-1:0] CLICINTV_CLICINTV_OFFSET = 0'h 0; + parameter logic [BlockAw-1:0] CLICINTV_CLICINTV_OFFSET = 2'h 0; // Register index typedef enum int { @@ -37,7 +55,7 @@ package clicintv_reg_pkg; // Register width information to check illegal writes parameter logic [3:0] CLICINTV_PERMIT [1] = '{ - 4'b 0001 // index[0] CLICINTV_CLICINTV + 4'b 1111 // index[0] CLICINTV_CLICINTV }; endpackage diff --git a/src/clicintv_reg_top.sv b/src/clicintv_reg_top.sv index 9f69bba..0534036 100644 --- a/src/clicintv_reg_top.sv +++ b/src/clicintv_reg_top.sv @@ -8,12 +8,12 @@ `include "common_cells/assertions.svh" module clicintv_reg_top #( - parameter type reg_req_t = logic, - parameter type reg_rsp_t = logic, - parameter int AW = 0 + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic, + parameter int AW = 2 ) ( - input clk_i, - input rst_ni, + input logic clk_i, + input logic rst_ni, input reg_req_t reg_req_i, output reg_rsp_t reg_rsp_o, // To HW @@ -26,13 +26,13 @@ module clicintv_reg_top #( import clicintv_reg_pkg::* ; - localparam int DW = 8; + localparam int DW = 32; localparam int DBW = DW/8; // Byte Width // register signals logic reg_we; logic reg_re; - logic [AW-1:0] reg_addr; + logic [BlockAw-1:0] reg_addr; logic [DW-1:0] reg_wdata; logic [DBW-1:0] reg_be; logic [DW-1:0] reg_rdata; @@ -53,7 +53,7 @@ module clicintv_reg_top #( assign reg_we = reg_intf_req.valid & reg_intf_req.write; assign reg_re = reg_intf_req.valid & ~reg_intf_req.write; - assign reg_addr = reg_intf_req.addr; + assign reg_addr = reg_intf_req.addr[BlockAw-1:0]; assign reg_wdata = reg_intf_req.wdata; assign reg_be = reg_intf_req.wstrb; assign reg_intf_rsp.rdata = reg_rdata; @@ -67,28 +67,46 @@ module clicintv_reg_top #( // Define SW related signals // Format: __{wd|we|qs} // or _{wd|we|qs} if field == 1 or 0 - logic clicintv_v_qs; - logic clicintv_v_wd; - logic clicintv_v_we; - logic [5:0] clicintv_vsid_qs; - logic [5:0] clicintv_vsid_wd; - logic clicintv_vsid_we; + logic clicintv_v0_qs; + logic clicintv_v0_wd; + logic clicintv_v0_we; + logic [5:0] clicintv_vsid0_qs; + logic [5:0] clicintv_vsid0_wd; + logic clicintv_vsid0_we; + logic clicintv_v1_qs; + logic clicintv_v1_wd; + logic clicintv_v1_we; + logic [5:0] clicintv_vsid1_qs; + logic [5:0] clicintv_vsid1_wd; + logic clicintv_vsid1_we; + logic clicintv_v2_qs; + logic clicintv_v2_wd; + logic clicintv_v2_we; + logic [5:0] clicintv_vsid2_qs; + logic [5:0] clicintv_vsid2_wd; + logic clicintv_vsid2_we; + logic clicintv_v3_qs; + logic clicintv_v3_wd; + logic clicintv_v3_we; + logic [5:0] clicintv_vsid3_qs; + logic [5:0] clicintv_vsid3_wd; + logic clicintv_vsid3_we; // Register instances // R[clicintv]: V(False) - // F[v]: 0:0 + // F[v0]: 0:0 prim_subreg #( .DW (1), .SWACCESS("RW"), .RESVAL (1'h0) - ) u_clicintv_v ( + ) u_clicintv_v0 ( .clk_i (clk_i ), .rst_ni (rst_ni ), // from register interface - .we (clicintv_v_we), - .wd (clicintv_v_wd), + .we (clicintv_v0_we), + .wd (clicintv_v0_wd), // from internal hardware .de (1'b0), @@ -96,25 +114,25 @@ module clicintv_reg_top #( // to internal hardware .qe (), - .q (reg2hw.clicintv.v.q ), + .q (reg2hw.clicintv.v0.q ), // to register interface (read) - .qs (clicintv_v_qs) + .qs (clicintv_v0_qs) ); - // F[vsid]: 7:2 + // F[vsid0]: 7:2 prim_subreg #( .DW (6), .SWACCESS("RW"), .RESVAL (6'h0) - ) u_clicintv_vsid ( + ) u_clicintv_vsid0 ( .clk_i (clk_i ), .rst_ni (rst_ni ), // from register interface - .we (clicintv_vsid_we), - .wd (clicintv_vsid_wd), + .we (clicintv_vsid0_we), + .wd (clicintv_vsid0_wd), // from internal hardware .de (1'b0), @@ -122,10 +140,166 @@ module clicintv_reg_top #( // to internal hardware .qe (), - .q (reg2hw.clicintv.vsid.q ), + .q (reg2hw.clicintv.vsid0.q ), // to register interface (read) - .qs (clicintv_vsid_qs) + .qs (clicintv_vsid0_qs) + ); + + + // F[v1]: 8:8 + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h0) + ) u_clicintv_v1 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (clicintv_v1_we), + .wd (clicintv_v1_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.clicintv.v1.q ), + + // to register interface (read) + .qs (clicintv_v1_qs) + ); + + + // F[vsid1]: 15:10 + prim_subreg #( + .DW (6), + .SWACCESS("RW"), + .RESVAL (6'h0) + ) u_clicintv_vsid1 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (clicintv_vsid1_we), + .wd (clicintv_vsid1_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.clicintv.vsid1.q ), + + // to register interface (read) + .qs (clicintv_vsid1_qs) + ); + + + // F[v2]: 16:16 + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h0) + ) u_clicintv_v2 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (clicintv_v2_we), + .wd (clicintv_v2_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.clicintv.v2.q ), + + // to register interface (read) + .qs (clicintv_v2_qs) + ); + + + // F[vsid2]: 23:18 + prim_subreg #( + .DW (6), + .SWACCESS("RW"), + .RESVAL (6'h0) + ) u_clicintv_vsid2 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (clicintv_vsid2_we), + .wd (clicintv_vsid2_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.clicintv.vsid2.q ), + + // to register interface (read) + .qs (clicintv_vsid2_qs) + ); + + + // F[v3]: 24:24 + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h0) + ) u_clicintv_v3 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (clicintv_v3_we), + .wd (clicintv_v3_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.clicintv.v3.q ), + + // to register interface (read) + .qs (clicintv_v3_qs) + ); + + + // F[vsid3]: 31:26 + prim_subreg #( + .DW (6), + .SWACCESS("RW"), + .RESVAL (6'h0) + ) u_clicintv_vsid3 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (clicintv_vsid3_we), + .wd (clicintv_vsid3_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.clicintv.vsid3.q ), + + // to register interface (read) + .qs (clicintv_vsid3_qs) ); @@ -145,19 +319,43 @@ module clicintv_reg_top #( ((addr_hit[0] & (|(CLICINTV_PERMIT[0] & ~reg_be))))); end - assign clicintv_v_we = addr_hit[0] & reg_we & !reg_error; - assign clicintv_v_wd = reg_wdata[0]; + assign clicintv_v0_we = addr_hit[0] & reg_we & !reg_error; + assign clicintv_v0_wd = reg_wdata[0]; + + assign clicintv_vsid0_we = addr_hit[0] & reg_we & !reg_error; + assign clicintv_vsid0_wd = reg_wdata[7:2]; + + assign clicintv_v1_we = addr_hit[0] & reg_we & !reg_error; + assign clicintv_v1_wd = reg_wdata[8]; + + assign clicintv_vsid1_we = addr_hit[0] & reg_we & !reg_error; + assign clicintv_vsid1_wd = reg_wdata[15:10]; + + assign clicintv_v2_we = addr_hit[0] & reg_we & !reg_error; + assign clicintv_v2_wd = reg_wdata[16]; + + assign clicintv_vsid2_we = addr_hit[0] & reg_we & !reg_error; + assign clicintv_vsid2_wd = reg_wdata[23:18]; + + assign clicintv_v3_we = addr_hit[0] & reg_we & !reg_error; + assign clicintv_v3_wd = reg_wdata[24]; - assign clicintv_vsid_we = addr_hit[0] & reg_we & !reg_error; - assign clicintv_vsid_wd = reg_wdata[7:2]; + assign clicintv_vsid3_we = addr_hit[0] & reg_we & !reg_error; + assign clicintv_vsid3_wd = reg_wdata[31:26]; // Read data return always_comb begin reg_rdata_next = '0; unique case (1'b1) addr_hit[0]: begin - reg_rdata_next[0] = clicintv_v_qs; - reg_rdata_next[7:2] = clicintv_vsid_qs; + reg_rdata_next[0] = clicintv_v0_qs; + reg_rdata_next[7:2] = clicintv_vsid0_qs; + reg_rdata_next[8] = clicintv_v1_qs; + reg_rdata_next[15:10] = clicintv_vsid1_qs; + reg_rdata_next[16] = clicintv_v2_qs; + reg_rdata_next[23:18] = clicintv_vsid2_qs; + reg_rdata_next[24] = clicintv_v3_qs; + reg_rdata_next[31:26] = clicintv_vsid3_qs; end default: begin diff --git a/src/gen/clicintv.hjson b/src/gen/clicintv.hjson index daaf5fd..f31c500 100644 --- a/src/gen/clicintv.hjson +++ b/src/gen/clicintv.hjson @@ -18,16 +18,21 @@ { protocol: "reg_iface", direction: "device" } ], - regwidth: "8", + regwidth: "32", registers: [ { name: "CLICINTV", desc: "CLIC interrupt virtualization", swaccess: "rw", hwaccess: "hro", fields: [ - { bits: "7:2", name: "VSID", desc: "interrupt VS id" }, - // { bits: "1", name: "reserved", desc: "reserved for future use"}, - { bits: "0", name: "V", desc: "interrupt delegated to VS-mode"}, + { bits: "31:26", name: "VSID3", desc: "interrupt VS id" }, + { bits: "24", name: "V3", desc: "interrupt delegated to VS-mode"}, + { bits: "23:18", name: "VSID2", desc: "interrupt VS id" }, + { bits: "16", name: "V2", desc: "interrupt delegated to VS-mode"}, + { bits: "15:10", name: "VSID1", desc: "interrupt VS id" }, + { bits: "8", name: "V1", desc: "interrupt delegated to VS-mode"}, + { bits: "7:2", name: "VSID0", desc: "interrupt VS id" }, + { bits: "0", name: "V0", desc: "interrupt delegated to VS-mode"}, ], } ] diff --git a/src_files.yml b/src_files.yml index 2bb5a92..add4613 100644 --- a/src_files.yml +++ b/src_files.yml @@ -18,6 +18,8 @@ clic: files: - src/clicint_reg_pkg.sv - src/clicint_reg_top.sv + - src/clicintv_reg_pkg.sv + - src/clicintv_reg_top.sv - src/mclic_reg_pkg.sv - src/mclic_reg_top.sv - src/clic_reg_adapter.sv From b425cdfc15825bc4be16af2d8cd01cfdd0b7e2aa Mon Sep 17 00:00:00 2001 From: Enrico Zelioli Date: Thu, 10 Aug 2023 13:37:47 +0200 Subject: [PATCH 07/17] [ADD] VS prioritization --- Bender.yml | 2 + src/clic.sv | 206 +++++++++++++++++++++------- src/clic_reg_adapter.sv | 19 ++- src/clic_target.sv | 73 ++++++---- src/clicvs_reg_pkg.sv | 50 +++++++ src/clicvs_reg_top.sv | 297 ++++++++++++++++++++++++++++++++++++++++ src/gen/Makefile | 17 ++- src/gen/clicvs.hjson | 35 +++++ src_files.yml | 2 + 9 files changed, 618 insertions(+), 83 deletions(-) create mode 100644 src/clicvs_reg_pkg.sv create mode 100644 src/clicvs_reg_top.sv create mode 100644 src/gen/clicvs.hjson diff --git a/Bender.yml b/Bender.yml index 04e624e..18ca59c 100644 --- a/Bender.yml +++ b/Bender.yml @@ -27,6 +27,8 @@ sources: - src/clicint_reg_top.sv - src/clicintv_reg_pkg.sv - src/clicintv_reg_top.sv + - src/clicvs_reg_pkg.sv + - src/clicvs_reg_top.sv - src/mclic_reg_pkg.sv - src/mclic_reg_top.sv - src/clic_reg_adapter.sv diff --git a/src/clic.sv b/src/clic.sv index 480f5f9..8d69207 100644 --- a/src/clic.sv +++ b/src/clic.sv @@ -17,20 +17,25 @@ `include "common_cells/assertions.svh" -module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_reg_pkg::*; #( +module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_reg_pkg::*; import clicvs_reg_pkg::*; #( parameter type reg_req_t = logic, parameter type reg_rsp_t = logic, parameter int N_SOURCE = 256, parameter int INTCTLBITS = 8, parameter bit SSCLIC = 0, parameter bit USCLIC = 0, - parameter bit VSCLIC = 0, // vCLIC enable + parameter bit VSCLIC = 0, // enable vCLIC (requires SSCLIC) + + // vCLIC dependent parameters parameter int unsigned N_VSCTXTS = 0, // Number of Virtual Contexts supported. - // This implementation assumes CLIC is mapped to an address - // range that allows up to 64 contexts (at least 512KiB) + // This implementation assumes CLIC is mapped to an address + // range that allows up to 64 contexts (at least 512KiB) + parameter bit VSPRIO = 0, // enable VS prioritization (requires VSCLIC) + // do not edit below, these are derived localparam int SRC_W = $clog2(N_SOURCE), - localparam int MAX_VSCTXTS = 64 + localparam int unsigned MAX_VSCTXTS = 64, // up to 64 VS contexts + localparam int unsigned VSID_W = $clog2(MAX_VSCTXTS) )( input logic clk_i, input logic rst_ni, @@ -43,32 +48,55 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ input [N_SOURCE-1:0] intr_src_i, // Interrupt notification to core - output logic irq_valid_o, - input logic irq_ready_i, - output logic [SRC_W-1:0] irq_id_o, - output logic [7:0] irq_level_o, - output logic irq_shv_o, - output logic [1:0] irq_priv_o, - output logic [5:0] irq_vsid_o, // up to 64 VS contexts - output logic irq_v_o, - output logic irq_kill_req_o, - input logic irq_kill_ack_i + output logic irq_valid_o, + input logic irq_ready_i, + output logic [SRC_W-1:0] irq_id_o, + output logic [7:0] irq_level_o, + output logic irq_shv_o, + output logic [1:0] irq_priv_o, + output logic [VSID_W-1:0] irq_vsid_o, + output logic irq_v_o, + output logic irq_kill_req_o, + input logic irq_kill_ack_i ); if (USCLIC) $fatal(1, "usclic mode is not supported"); - if (N_VSCTXTS > MAX_VSCTXTS) - $fatal(1, "vsclic extension supports up to 64 virtual contexts"); - - // CLIC internal address size - localparam int unsigned ADDR_W = $clog2(MAX_VSCTXTS * 8 * 1024); // 19 + if (VSCLIC) begin + if (N_VSCTXTS <= 0 || N_VSCTXTS > MAX_VSCTXTS) + $fatal(1, "vsclic extension requires N_VSCTXTS in [1, 64]"); + if (!SSCLIC) + $fatal(1, "vsclic extension requires ssclic"); + end else begin + if(VSPRIO) + $fatal(1, "vsprio extension requires vsclic"); + end localparam logic [1:0] U_MODE = 2'b00; localparam logic [1:0] S_MODE = 2'b01; localparam logic [1:0] M_MODE = 2'b11; - // Each privilege mode address space is aligned to a 8KiB physical memory region + /////////////////////////////////////////////////// + // CLIC internal addressing // + /////////////////////////////////////////////////// + // + // The address range is divided into blocks of 32KB. + // There is one block each for S-mode and M-mode, + // and there are up to MAX_VSCTXTS extra blocks, + // one per guest VS. + // + // M_MODE : [0x000000 - 0x007fff] + // S_MODE : [0x008000 - 0x00ffff] + // VS_1 : [0x010000 - 0x017fff] + // VS_2 : [0x018000 - 0x01ffff] + // : + // VS_64 : [0x208000 - 0x20ffff] + + // Some value between 16 (VSCLIC = 0) and 22 (64 VS contexts) + localparam int unsigned ADDR_W = $clog2((N_VSCTXTS + 2) * 32 * 1024); + + // Each privilege mode address space is aligned to a 32KiB physical memory region localparam logic [ADDR_W-1:0] MCLICCFG_START = 'h00000; localparam logic [ADDR_W-1:0] MCLICINT_START = 'h01000; localparam logic [ADDR_W-1:0] MCLICINT_END = 'h04fff; @@ -79,11 +107,18 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ localparam logic [ADDR_W-1:0] SCLICINTV_START = 'h0d000; localparam logic [ADDR_W-1:0] SCLICINTV_END = 'h0dfff; + localparam logic [ADDR_W-1:0] VSCLICPRIO_START = 'h0e000; + localparam logic [ADDR_W-1:0] VSCLICPRIO_END = 'h0efff; + // VS `i` (1 <= i <= 64) will be mapped to VSCLIC*(i) address space `define VSCLICCFG_START(i) ('h08000 * (i + 1)) `define VSCLICINT_START(i) ('h08000 * (i + 1) + 'h01000) `define VSCLICINT_END(i) ('h08000 * (i + 1) + 'h04fff) + // Reduce area by setting wire width to 0 + // if VSPRIO extension is not enabled. + localparam VsprioWidth = 8; // VSPRIO ? 8 : 1; + mclic_reg2hw_t mclic_reg2hw; clicint_reg2hw_t [N_SOURCE-1:0] clicint_reg2hw; @@ -92,14 +127,19 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ clicintv_reg2hw_t [(N_SOURCE/4)-1:0] clicintv_reg2hw; // clicintv_hw2reg_t [(N_SOURCE/4)-1:0] clicintv_hw2reg; // Not needed + clicvs_reg2hw_t [(MAX_VSCTXTS/4)-1:0] clicvs_reg2hw; + // clicvs_hw2reg_t [(MAX_VSCTXTS/4)-1:0] clicvs_hw2reg; // Not needed + logic [7:0] intctl [N_SOURCE]; logic [7:0] irq_max; logic [1:0] intmode [N_SOURCE]; logic [1:0] irq_mode; - logic [5:0] vsid [N_SOURCE]; // Per-IRQ Virtual Supervisor (VS) ID - logic intv [N_SOURCE]; // Per-IRQ virtualization bit + logic [VSID_W-1:0] vsid [N_SOURCE]; // Per-IRQ Virtual Supervisor (VS) ID + logic intv [N_SOURCE]; // Per-IRQ virtualization bit + + logic [VsprioWidth-1:0] vsprio [MAX_VSCTXTS]; logic [N_SOURCE-1:0] le; // 0: level-sensitive 1: edge-sensitive logic [N_SOURCE-1:0] ip; @@ -127,9 +167,12 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ // generate interrupt depending on ip, ie, level and priority clic_target #( - .N_SOURCE (N_SOURCE), - .PrioWidth (INTCTLBITS), - .ModeWidth (2) + .N_SOURCE (N_SOURCE), + .MAX_VSCTXTS (MAX_VSCTXTS), + .PrioWidth (INTCTLBITS), + .ModeWidth (2), + .VsidWidth (VSID_W), + .VsprioWidth (VsprioWidth) ) i_clic_target ( .clk_i, .rst_ni, @@ -137,10 +180,14 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ .ip_i (ip), .ie_i (ie), .le_i (le), + .shv_i (shv), .prio_i (intctl), .mode_i (intmode), .intv_i (intv), + .vsid_i (vsid), + + .vsprio_i (vsprio), .claim_o (claim), @@ -149,6 +196,9 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ .irq_id_o, .irq_max_o (irq_max), .irq_mode_o (irq_mode), + .irq_v_o, + .irq_vsid_o, + .irq_shv_o, .irq_kill_req_o, .irq_kill_ack_i @@ -221,6 +271,14 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ reg_req_t [(N_SOURCE/4)-1:0] reg_v_req; reg_rsp_t [(N_SOURCE/4)-1:0] reg_v_rsp; + // VSPRIO register interface signals + reg_req_t reg_all_vs_req; + reg_rsp_t reg_all_vs_rsp; + logic [ADDR_W-1:0] vs_addr; + + reg_req_t [(MAX_VSCTXTS/4)-1:0] reg_vs_req; + reg_rsp_t [(MAX_VSCTXTS/4)-1:0] reg_vs_rsp; + if (VSCLIC) begin always_comb begin @@ -250,32 +308,70 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ .devmode_i (1'b1) ); end + + if (VSPRIO) begin + + always_comb begin + reg_vs_req = '0; + reg_all_vs_rsp = '0; + + vs_addr = reg_all_vs_req.addr[ADDR_W-1:2]; + + reg_vs_req[vs_addr] = reg_all_vs_req; + reg_all_vs_rsp = reg_vs_rsp[vs_addr]; + end + + for(genvar i = 0; i < (MAX_VSCTXTS/4); i++) begin : gen_clic_vs + + clicvs_reg_top #( + .reg_req_t (reg_req_t), + .reg_rsp_t (reg_rsp_t) + ) i_clicvs_reg_top ( + .clk_i, + .rst_ni, + + .reg_req_i (reg_vs_req[i]), + .reg_rsp_o (reg_vs_rsp[i]), + + .reg2hw (clicvs_reg2hw[i]), + // .hw2reg (clicvs_hw2reg[i]), + + .devmode_i (1'b1) + ); + + end + + end else begin + assign clicvs_reg2hw = '0; + // assign clicvs_hw2reg = '0; + assign reg_vs_req = '0; + assign reg_vs_rsp = '0; + assign vs_addr = '0; + assign reg_all_vs_rsp = '0; + end + end else begin - assign clicintv_reg2hw = '0; + assign clicintv_reg2hw = '0; // assign clicintv_hw2reg = '0; - assign v_addr = '0; - assign reg_all_v_rsp = '0; + assign reg_v_req = '0; + assign reg_v_rsp = '0; + assign v_addr = '0; + assign reg_all_v_rsp = '0; end - // configuration registers - // 0x8000 (supervisor mode) - - // interrupt control and status register - // 0x9000 - 0xcfff (supervisor mode) - // mirror - // top level address decoding and bus muxing // Helper signal used to store intermediate address logic [ADDR_W-1:0] addr_tmp; always_comb begin : clic_addr_decode - reg_mclic_req = '0; + reg_mclic_req = '0; reg_all_int_req = '0; - reg_all_v_req = '0; - reg_rsp_o = '0; + reg_all_v_req = '0; + reg_all_vs_req = '0; + reg_rsp_o = '0; - addr_tmp = '0; + addr_tmp = '0; unique case(reg_req_i.addr[ADDR_W-1:0]) inside MCLICCFG_START: begin @@ -343,6 +439,18 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ reg_rsp_o.ready = 1'b1; end end + [VSCLICPRIO_START:VSCLICPRIO_END]: begin + if(VSCLIC && VSPRIO) begin + addr_tmp = reg_req_i.addr[ADDR_W-1:0] - VSCLICPRIO_START; + reg_all_vs_req = reg_req_i; + reg_all_vs_req.addr = addr_tmp; + reg_rsp_o = reg_all_vs_rsp; + end else begin + reg_rsp_o.rdata = '0; + reg_rsp_o.error = '0; + reg_rsp_o.ready = 1'b1; + end + end default: begin // inaccesible (all zero) reg_rsp_o.rdata = '0; @@ -389,8 +497,11 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ // adapter clic_reg_adapter #( - .N_SOURCE (N_SOURCE), - .INTCTLBITS (INTCTLBITS) + .N_SOURCE (N_SOURCE), + .INTCTLBITS (INTCTLBITS), + .MAX_VSCTXTS (MAX_VSCTXTS), + .VsidWidth (VSID_W), + .VsprioWidth (VsprioWidth) ) i_clic_reg_adapter ( .clk_i, .rst_ni, @@ -403,11 +514,15 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ .clicintv_reg2hw, // .clicintv_hw2reg, + .clicvs_reg2hw, + // .clicvs_hw2reg, + .intctl_o (intctl), .intmode_o (intmode), .shv_o (shv), .vsid_o (vsid), .intv_o (intv), + .vsprio_o (vsprio), .ip_sw_o (ip_sw), .ie_o (ie), .le_o (le), @@ -426,13 +541,6 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ mnlbits = mclic_reg2hw.mcliccfg.mnlbits.q; end - // Extract SHV bit for the highest level, highest priority pending interrupt - assign irq_shv_o = shv[irq_id_o]; - - // Extract Virtual Supervisor ID for the highest level, highest priority pending interrupt - assign irq_vsid_o = (VSCLIC && (irq_priv_o == S_MODE)) ? vsid[irq_id_o] : '0; - assign irq_v_o = (VSCLIC && (irq_priv_o == S_MODE)) ? intv[irq_id_o] : '0; - logic [7:0] irq_level_tmp; always_comb begin diff --git a/src/clic_reg_adapter.sv b/src/clic_reg_adapter.sv index ae0f803..34a1a16 100644 --- a/src/clic_reg_adapter.sv +++ b/src/clic_reg_adapter.sv @@ -14,9 +14,12 @@ // SPDX-License-Identifier: Apache-2.0 -module clic_reg_adapter import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_reg_pkg::*; #( +module clic_reg_adapter import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_reg_pkg::*; import clicvs_reg_pkg::*; #( parameter int N_SOURCE = 32, - parameter int INTCTLBITS = 8 + parameter int INTCTLBITS = 8, + parameter int unsigned MAX_VSCTXTS = 64, + parameter int unsigned VsidWidth = 6, + parameter int unsigned VsprioWidth = 8 )( input logic clk_i, input logic rst_ni, @@ -29,10 +32,14 @@ module clic_reg_adapter import mclic_reg_pkg::*; import clicint_reg_pkg::*; impo input clicintv_reg_pkg::clicintv_reg2hw_t [(N_SOURCE/4)-1:0] clicintv_reg2hw, // output clicintv_reg_pkg::clicintv_hw2reg_t [(N_SOURCE/4)-1:0] clicintv_hw2reg, - output logic [7:0] intctl_o [N_SOURCE], - output logic [1:0] intmode_o [N_SOURCE], - output logic [5:0] vsid_o [N_SOURCE], // interrupt VS id - output logic intv_o [N_SOURCE], // interrupt virtualization + input clicvs_reg_pkg::clicvs_reg2hw_t [(MAX_VSCTXTS/4)-1:0] clicvs_reg2hw, + // output clicvs_reg_pkg::clicvs_hw2reg_t [(MAX_VSCTXTS/4)-1:0] clicvs_hw2reg, + + output logic [7:0] intctl_o [N_SOURCE], + output logic [1:0] intmode_o [N_SOURCE], + output logic [VsidWidth-1:0] vsid_o [N_SOURCE], // interrupt VS id + output logic intv_o [N_SOURCE], // interrupt virtualization + output logic [VsprioWidth-1:0] vsprio_o [MAX_VSCTXTS], // VS priority output logic [N_SOURCE-1:0] shv_o, output logic [N_SOURCE-1:0] ip_sw_o, output logic [N_SOURCE-1:0] ie_o, diff --git a/src/clic_target.sv b/src/clic_target.sv index d0a303f..381b8cf 100644 --- a/src/clic_target.sv +++ b/src/clic_target.sv @@ -29,9 +29,12 @@ `include "common_cells/assertions.svh" module clic_target #( - parameter int unsigned N_SOURCE = 256, - parameter int unsigned PrioWidth = 8, - parameter int unsigned ModeWidth = 2, + parameter int unsigned N_SOURCE = 256, + parameter int unsigned MAX_VSCTXTS = 64, + parameter int unsigned PrioWidth = 8, + parameter int unsigned ModeWidth = 2, + parameter int unsigned VsidWidth = 6, + parameter int unsigned VsprioWidth = 8, // derived parameters do not change this localparam int SrcWidth = $clog2(N_SOURCE) // derived parameter @@ -42,10 +45,14 @@ module clic_target #( input [N_SOURCE-1:0] ip_i, input [N_SOURCE-1:0] ie_i, input [N_SOURCE-1:0] le_i, + input [N_SOURCE-1:0] shv_i, input [PrioWidth-1:0] prio_i [N_SOURCE], input [ModeWidth-1:0] mode_i [N_SOURCE], input logic intv_i [N_SOURCE], + input [VsidWidth-1:0] vsid_i [N_SOURCE], + + input [VsprioWidth-1:0] vsprio_i [MAX_VSCTXTS], output logic [N_SOURCE-1:0] claim_o, @@ -54,6 +61,9 @@ module clic_target #( output logic [SrcWidth-1:0] irq_id_o, output logic [PrioWidth-1:0] irq_max_o, output logic [ModeWidth-1:0] irq_mode_o, + output logic [VsidWidth-1:0] irq_vsid_o, + output logic irq_v_o, + output logic irq_shv_o, output logic irq_kill_req_o, input logic irq_kill_ack_i @@ -62,6 +72,12 @@ module clic_target #( // this only works with 2 or more sources `ASSERT_INIT(NumSources_A, N_SOURCE >= 2) + typedef struct packed { + logic [ModeWidth-1:0] mode; + logic [VsprioWidth-1:0] vsprio; + logic [PrioWidth-1:0] prio; + } prio_t; + localparam logic [1:0] U_MODE = 2'b00; localparam logic [1:0] S_MODE = 2'b01; localparam logic [1:0] M_MODE = 2'b11; @@ -69,10 +85,9 @@ module clic_target #( // align to powers of 2 for simplicity // a full binary tree with N levels has 2**N + 2**N-1 nodes localparam int NumLevels = $clog2(N_SOURCE); - logic [2**(NumLevels+1)-2:0] is_tree; - logic [2**(NumLevels+1)-2:0][SrcWidth-1:0] id_tree; - logic [2**(NumLevels+1)-2:0][PrioWidth-1:0] max_tree; - logic [2**(NumLevels+1)-2:0][ModeWidth-1:0] mode_tree; + logic [2**(NumLevels+1)-2:0] is_tree; + logic [2**(NumLevels+1)-2:0][SrcWidth-1:0] id_tree; + prio_t [2**(NumLevels+1)-2:0] max_tree; for (genvar level = 0; level < NumLevels+1; level++) begin : gen_tree // @@ -100,17 +115,17 @@ module clic_target #( if (offset < N_SOURCE) begin : gen_assign assign is_tree[Pa] = ip_i[offset] & ie_i[offset]; assign id_tree[Pa] = offset; - assign max_tree[Pa] = prio_i[offset]; // NOTE: save space by encoding the Virtualization bit in the privilege mode tree fields. // This is done by temporarily elevating the privilege level of hypervisor IRQs (mode=S_MODE, intv=0) // to the reserved value 2'b10 so that they have higher priority than virtualized IRQs (S_MODE == 1'b01) // but still lower priority than M_MODE IRQs (M_MODE == 2'b11). - assign mode_tree[Pa] = ((mode_i[offset] == S_MODE) && ~intv_i[offset]) ? 2'b10 : mode_i[offset]; + assign max_tree[Pa].mode = ((mode_i[offset] == S_MODE) && ~intv_i[offset]) ? 2'b10 : mode_i[offset]; + assign max_tree[Pa].vsprio = ((mode_i[offset] == S_MODE) && intv_i[offset]) ? vsprio_i[vsid_i[offset]] : '0; + assign max_tree[Pa].prio = prio_i[offset]; end else begin : gen_tie_off assign is_tree[Pa] = '0; assign id_tree[Pa] = '0; assign max_tree[Pa] = '0; - assign mode_tree[Pa] = '0; end // this creates the node assignments end else begin : gen_nodes @@ -132,16 +147,18 @@ module clic_target #( // in case only one of the parent has a pending irq_o, forward that one // in case both irqs are pending, forward the one with higher priority assign sel = (~is_tree[C0] & is_tree[C1]) | - (is_tree[C0] & is_tree[C1] & ((logic'(mode_tree[C1] > mode_tree[C0]) | ((logic'(mode_tree[C1] == mode_tree[C0]) & (logic'(max_tree[C1] > max_tree[C0]))))))); + (is_tree[C0] & is_tree[C1] & logic'(max_tree[C1] > max_tree[C0])); // forwarding muxes assign is_tree[Pa] = (sel & is_tree[C1]) | ((~sel) & is_tree[C0]); assign id_tree[Pa] = ({SrcWidth{sel}} & id_tree[C1]) | ({SrcWidth{~sel}} & id_tree[C0]); - assign max_tree[Pa] = ({PrioWidth{sel}} & max_tree[C1]) | - ({PrioWidth{~sel}} & max_tree[C0]); - assign mode_tree[Pa] = ({ModeWidth{sel}} & mode_tree[C1]) | - ({ModeWidth{~sel}} & mode_tree[C0]); + assign max_tree[Pa].mode = ({ModeWidth{sel}} & max_tree[C1].mode) | + ({ModeWidth{~sel}} & max_tree[C0].mode); + assign max_tree[Pa].vsprio = ({VsprioWidth{sel}} & max_tree[C1].vsprio) | + ({VsprioWidth{~sel}} & max_tree[C0].vsprio); + assign max_tree[Pa].prio = ({PrioWidth{sel}} & max_tree[C1].prio) | + ({PrioWidth{~sel}} & max_tree[C0].prio); end end : gen_level end : gen_tree @@ -151,8 +168,9 @@ module clic_target #( logic irq_kill_req_d, irq_kill_req_q; logic higher_irq; logic [SrcWidth-1:0] irq_root_id, irq_id_d, irq_id_q; - logic [PrioWidth-1:0] irq_max_d, irq_max_q; - logic [ModeWidth-1:0] irq_mode_d, irq_mode_q; + prio_t irq_max_d, irq_max_q; + logic [VsidWidth-1:0] vsid_max_d, vsid_max_q; + logic shv_max_d, shv_max_q; // the results can be found at the tree root // TODO: remove useless inequality comparison @@ -173,7 +191,8 @@ module clic_target #( always_comb begin irq_id_d = '0; // default: No Interrupt irq_max_d = '0; - irq_mode_d = '0; + vsid_max_d = '0; + shv_max_d = '0; claim_o = '0; irq_valid_d = 1'b0; @@ -187,8 +206,8 @@ module clic_target #( if (irq_root_valid) begin irq_id_d = irq_root_id; irq_max_d = max_tree[0]; - // NOTE: If the interrupt priority was modified (see note above), restore nominal privilege - irq_mode_d = (mode_tree[0] == 2'b10) ? S_MODE : mode_tree[0]; + vsid_max_d = vsid_i[irq_root_id]; + shv_max_d = shv_i[irq_root_id]; irq_valid_d = 1'b1; irq_state_d = ACK; end @@ -235,14 +254,16 @@ module clic_target #( irq_valid_q <= 1'b0; irq_id_q <= '0; irq_max_q <= '0; - irq_mode_q <= '0; + vsid_max_q <= '0; + shv_max_q <= '0; irq_kill_req_q <= 1'b0; irq_state_q <= IDLE; end else begin irq_valid_q <= irq_valid_d; irq_id_q <= irq_id_d; irq_max_q <= irq_max_d; - irq_mode_q <= irq_mode_d; + vsid_max_q <= vsid_max_d; + shv_max_q <= shv_max_d; irq_kill_req_q <= irq_kill_req_d; irq_state_q <= irq_state_d; end @@ -251,8 +272,12 @@ module clic_target #( assign irq_valid_o = irq_valid_q; assign irq_id_o = irq_id_q; - assign irq_max_o = irq_max_q; - assign irq_mode_o = irq_mode_q; + assign irq_max_o = irq_max_q.prio; + // NOTE: If the interrupt priority was modified (see note above), restore nominal privilege + assign irq_mode_o = (irq_max_q.mode == 2'b10) ? S_MODE : irq_max_q.mode; + assign irq_vsid_o = vsid_max_q; + assign irq_v_o = logic'(irq_max_q.mode == S_MODE); + assign irq_shv_o = shv_max_q; assign irq_kill_req_o = irq_kill_req_q; diff --git a/src/clicvs_reg_pkg.sv b/src/clicvs_reg_pkg.sv new file mode 100644 index 0000000..5ac8fb4 --- /dev/null +++ b/src/clicvs_reg_pkg.sv @@ -0,0 +1,50 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Package auto-generated by `reggen` containing data structure + +package clicvs_reg_pkg; + + // Address widths within the block + parameter int BlockAw = 2; + + //////////////////////////// + // Typedefs for registers // + //////////////////////////// + + typedef struct packed { + struct packed { + logic [7:0] q; + } prio0; + struct packed { + logic [7:0] q; + } prio1; + struct packed { + logic [7:0] q; + } prio2; + struct packed { + logic [7:0] q; + } prio3; + } clicvs_reg2hw_vsprio_reg_t; + + // Register -> HW type + typedef struct packed { + clicvs_reg2hw_vsprio_reg_t vsprio; // [31:0] + } clicvs_reg2hw_t; + + // Register offsets + parameter logic [BlockAw-1:0] CLICVS_VSPRIO_OFFSET = 2'h 0; + + // Register index + typedef enum int { + CLICVS_VSPRIO + } clicvs_id_e; + + // Register width information to check illegal writes + parameter logic [3:0] CLICVS_PERMIT [1] = '{ + 4'b 1111 // index[0] CLICVS_VSPRIO + }; + +endpackage + diff --git a/src/clicvs_reg_top.sv b/src/clicvs_reg_top.sv new file mode 100644 index 0000000..63bc26e --- /dev/null +++ b/src/clicvs_reg_top.sv @@ -0,0 +1,297 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Top module auto-generated by `reggen` + + +`include "common_cells/assertions.svh" + +module clicvs_reg_top #( + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic, + parameter int AW = 2 +) ( + input logic clk_i, + input logic rst_ni, + input reg_req_t reg_req_i, + output reg_rsp_t reg_rsp_o, + // To HW + output clicvs_reg_pkg::clicvs_reg2hw_t reg2hw, // Write + + + // Config + input devmode_i // If 1, explicit error return for unmapped register access +); + + import clicvs_reg_pkg::* ; + + localparam int DW = 32; + localparam int DBW = DW/8; // Byte Width + + // register signals + logic reg_we; + logic reg_re; + logic [BlockAw-1:0] reg_addr; + logic [DW-1:0] reg_wdata; + logic [DBW-1:0] reg_be; + logic [DW-1:0] reg_rdata; + logic reg_error; + + logic addrmiss, wr_err; + + logic [DW-1:0] reg_rdata_next; + + // Below register interface can be changed + reg_req_t reg_intf_req; + reg_rsp_t reg_intf_rsp; + + + assign reg_intf_req = reg_req_i; + assign reg_rsp_o = reg_intf_rsp; + + + assign reg_we = reg_intf_req.valid & reg_intf_req.write; + assign reg_re = reg_intf_req.valid & ~reg_intf_req.write; + assign reg_addr = reg_intf_req.addr[BlockAw-1:0]; + assign reg_wdata = reg_intf_req.wdata; + assign reg_be = reg_intf_req.wstrb; + assign reg_intf_rsp.rdata = reg_rdata; + assign reg_intf_rsp.error = reg_error; + assign reg_intf_rsp.ready = 1'b1; + + assign reg_rdata = reg_rdata_next ; + assign reg_error = (devmode_i & addrmiss) | wr_err; + + + // Define SW related signals + // Format: __{wd|we|qs} + // or _{wd|we|qs} if field == 1 or 0 + logic [7:0] vsprio_prio0_qs; + logic [7:0] vsprio_prio0_wd; + logic vsprio_prio0_we; + logic [7:0] vsprio_prio1_qs; + logic [7:0] vsprio_prio1_wd; + logic vsprio_prio1_we; + logic [7:0] vsprio_prio2_qs; + logic [7:0] vsprio_prio2_wd; + logic vsprio_prio2_we; + logic [7:0] vsprio_prio3_qs; + logic [7:0] vsprio_prio3_wd; + logic vsprio_prio3_we; + + // Register instances + // R[vsprio]: V(False) + + // F[prio0]: 7:0 + prim_subreg #( + .DW (8), + .SWACCESS("RW"), + .RESVAL (8'h0) + ) u_vsprio_prio0 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (vsprio_prio0_we), + .wd (vsprio_prio0_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.vsprio.prio0.q ), + + // to register interface (read) + .qs (vsprio_prio0_qs) + ); + + + // F[prio1]: 15:8 + prim_subreg #( + .DW (8), + .SWACCESS("RW"), + .RESVAL (8'h0) + ) u_vsprio_prio1 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (vsprio_prio1_we), + .wd (vsprio_prio1_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.vsprio.prio1.q ), + + // to register interface (read) + .qs (vsprio_prio1_qs) + ); + + + // F[prio2]: 23:16 + prim_subreg #( + .DW (8), + .SWACCESS("RW"), + .RESVAL (8'h0) + ) u_vsprio_prio2 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (vsprio_prio2_we), + .wd (vsprio_prio2_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.vsprio.prio2.q ), + + // to register interface (read) + .qs (vsprio_prio2_qs) + ); + + + // F[prio3]: 31:24 + prim_subreg #( + .DW (8), + .SWACCESS("RW"), + .RESVAL (8'h0) + ) u_vsprio_prio3 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (vsprio_prio3_we), + .wd (vsprio_prio3_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.vsprio.prio3.q ), + + // to register interface (read) + .qs (vsprio_prio3_qs) + ); + + + + + logic [0:0] addr_hit; + always_comb begin + addr_hit = '0; + addr_hit[0] = (reg_addr == CLICVS_VSPRIO_OFFSET); + end + + assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ; + + // Check sub-word write is permitted + always_comb begin + wr_err = (reg_we & + ((addr_hit[0] & (|(CLICVS_PERMIT[0] & ~reg_be))))); + end + + assign vsprio_prio0_we = addr_hit[0] & reg_we & !reg_error; + assign vsprio_prio0_wd = reg_wdata[7:0]; + + assign vsprio_prio1_we = addr_hit[0] & reg_we & !reg_error; + assign vsprio_prio1_wd = reg_wdata[15:8]; + + assign vsprio_prio2_we = addr_hit[0] & reg_we & !reg_error; + assign vsprio_prio2_wd = reg_wdata[23:16]; + + assign vsprio_prio3_we = addr_hit[0] & reg_we & !reg_error; + assign vsprio_prio3_wd = reg_wdata[31:24]; + + // Read data return + always_comb begin + reg_rdata_next = '0; + unique case (1'b1) + addr_hit[0]: begin + reg_rdata_next[7:0] = vsprio_prio0_qs; + reg_rdata_next[15:8] = vsprio_prio1_qs; + reg_rdata_next[23:16] = vsprio_prio2_qs; + reg_rdata_next[31:24] = vsprio_prio3_qs; + end + + default: begin + reg_rdata_next = '1; + end + endcase + end + + // Unused signal tieoff + + // wdata / byte enable are not always fully used + // add a blanket unused statement to handle lint waivers + logic unused_wdata; + logic unused_be; + assign unused_wdata = ^reg_wdata; + assign unused_be = ^reg_be; + + // Assertions for Register Interface + `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit)) + +endmodule + +module clicvs_reg_top_intf +#( + parameter int AW = 2, + localparam int DW = 32 +) ( + input logic clk_i, + input logic rst_ni, + REG_BUS.in regbus_slave, + // To HW + output clicvs_reg_pkg::clicvs_reg2hw_t reg2hw, // Write + // Config + input devmode_i // If 1, explicit error return for unmapped register access +); + localparam int unsigned STRB_WIDTH = DW/8; + +`include "register_interface/typedef.svh" +`include "register_interface/assign.svh" + + // Define structs for reg_bus + typedef logic [AW-1:0] addr_t; + typedef logic [DW-1:0] data_t; + typedef logic [STRB_WIDTH-1:0] strb_t; + `REG_BUS_TYPEDEF_ALL(reg_bus, addr_t, data_t, strb_t) + + reg_bus_req_t s_reg_req; + reg_bus_rsp_t s_reg_rsp; + + // Assign SV interface to structs + `REG_BUS_ASSIGN_TO_REQ(s_reg_req, regbus_slave) + `REG_BUS_ASSIGN_FROM_RSP(regbus_slave, s_reg_rsp) + + + + clicvs_reg_top #( + .reg_req_t(reg_bus_req_t), + .reg_rsp_t(reg_bus_rsp_t), + .AW(AW) + ) i_regs ( + .clk_i, + .rst_ni, + .reg_req_i(s_reg_req), + .reg_rsp_o(s_reg_rsp), + .reg2hw, // Write + .devmode_i + ); + +endmodule + + diff --git a/src/gen/Makefile b/src/gen/Makefile index 47d0da4..a12ee74 100644 --- a/src/gen/Makefile +++ b/src/gen/Makefile @@ -19,9 +19,15 @@ REGTOOL = regtool.py +SRCS = clicvs_reg_pkg.sv clicvs_reg_top.sv clicintv_reg_pkg.sv clicintv_reg_top.sv clicint_reg_pkg.sv clicint_reg_top.sv mclic_reg_pkg.sv mclic_reg_top.sv +HDRS = clic.h clicint.h clicintv.h clicvs.h + all: headers srcs -srcs: clicintv_reg_pkg.sv clicintv_reg_top.sv clicint_reg_pkg.sv clicint_reg_top.sv mclic_reg_pkg.sv mclic_reg_top.sv +srcs: $(SRCS) + +clicvs_reg_pkg.sv clicvs_reg_top.sv: clicvs.hjson + $(REGTOOL) -r $< -t . clicintv_reg_pkg.sv clicintv_reg_top.sv: clicintv.hjson $(REGTOOL) -r $< -t . @@ -32,7 +38,7 @@ clicint_reg_pkg.sv clicint_reg_top.sv: clicint.hjson mclic_reg_pkg.sv mclic_reg_top.sv: mclic.hjson $(REGTOOL) -r $< -t . -headers: clic.h clicint.h clicintv.h +headers: $(HDRS) clic.h: mclic.hjson $(REGTOOL) --cdefines mclic.hjson > $@ @@ -43,11 +49,14 @@ clicint.h: clicint.hjson clicintv.h: clicintv.hjson $(REGTOOL) --cdefines clicintv.hjson > $@ +clicvs.h: clicvs.hjson + $(REGTOOL) --cdefines clicvs.hjson > $@ + .PHONY: install install: - cp mclic_reg_pkg.sv mclic_reg_top.sv clicint_reg_pkg.sv clicint_reg_top.sv clicintv_reg_pkg.sv clicintv_reg_top.sv .. + cp $(SRCS) .. .PHONY: clean clean: - rm clic.h clicint.h clicintv.h mclic_reg_pkg.sv mclic_reg_top.sv clicint_reg_pkg.sv clicint_reg_top.sv clicintv_reg_pkg.sv clicintv_reg_top.sv + rm $(HDRS) $(SRCS) diff --git a/src/gen/clicvs.hjson b/src/gen/clicvs.hjson new file mode 100644 index 0000000..284c3cb --- /dev/null +++ b/src/gen/clicvs.hjson @@ -0,0 +1,35 @@ +// Copyright 2022 ETH Zurich and University of Bologna. +// Copyright and related rights are licensed under the Solderpad Hardware +// License, Version 0.51 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law +// or agreed to in writing, software, hardware and materials distributed under +// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +// SPDX-License-Identifier: Apache-2.0 + +// CLIC virtual supervisor configuration register +{ + name: "CLICVS", + clock_primary: "clk_i", + bus_interfaces: [ + { protocol: "reg_iface", direction: "device" } + ], + + regwidth: "32", + registers: [ + { name: "vsprio", + desc: "CLIC virtual supervisor priority", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "31:24", name: "prio3", desc: "VS3 priority" }, + { bits: "23:16", name: "prio2", desc: "VS2 priority" }, + { bits: "15:8", name: "prio1", desc: "VS1 priority" }, + { bits: "7:0", name: "prio0", desc: "VS0 priority" }, + ], + } + ] +} diff --git a/src_files.yml b/src_files.yml index add4613..690f9d5 100644 --- a/src_files.yml +++ b/src_files.yml @@ -20,6 +20,8 @@ clic: - src/clicint_reg_top.sv - src/clicintv_reg_pkg.sv - src/clicintv_reg_top.sv + - src/clicvs_reg_pkg.sv + - src/clicvs_reg_top.sv - src/mclic_reg_pkg.sv - src/mclic_reg_top.sv - src/clic_reg_adapter.sv From f8de4db83d78c5d4083b306d618abe02f526d78b Mon Sep 17 00:00:00 2001 From: Enrico Zelioli Date: Mon, 11 Sep 2023 10:56:23 +0200 Subject: [PATCH 08/17] [MOD] Set VSprio width to 1bit --- src/clic.sv | 10 +++----- src/clicvs_reg_pkg.sv | 10 ++++---- src/clicvs_reg_top.sv | 56 +++++++++++++++++++++---------------------- src/gen/clicvs.hjson | 8 +++---- 4 files changed, 40 insertions(+), 44 deletions(-) diff --git a/src/clic.sv b/src/clic.sv index 8d69207..a462249 100644 --- a/src/clic.sv +++ b/src/clic.sv @@ -30,7 +30,8 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ parameter int unsigned N_VSCTXTS = 0, // Number of Virtual Contexts supported. // This implementation assumes CLIC is mapped to an address // range that allows up to 64 contexts (at least 512KiB) - parameter bit VSPRIO = 0, // enable VS prioritization (requires VSCLIC) + parameter bit VSPRIO = 0, // Enable VS prioritization (requires VSCLIC) + parameter int VsprioWidth = 1, // N of VS priority bits (must be set accordingly to the `clicvs` register width) // do not edit below, these are derived localparam int SRC_W = $clog2(N_SOURCE), @@ -115,10 +116,6 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ `define VSCLICINT_START(i) ('h08000 * (i + 1) + 'h01000) `define VSCLICINT_END(i) ('h08000 * (i + 1) + 'h04fff) - // Reduce area by setting wire width to 0 - // if VSPRIO extension is not enabled. - localparam VsprioWidth = 8; // VSPRIO ? 8 : 1; - mclic_reg2hw_t mclic_reg2hw; clicint_reg2hw_t [N_SOURCE-1:0] clicint_reg2hw; @@ -139,7 +136,7 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ logic [VSID_W-1:0] vsid [N_SOURCE]; // Per-IRQ Virtual Supervisor (VS) ID logic intv [N_SOURCE]; // Per-IRQ virtualization bit - logic [VsprioWidth-1:0] vsprio [MAX_VSCTXTS]; + logic [VsprioWidth-1:0] vsprio [MAX_VSCTXTS]; // Per-VS priority logic [N_SOURCE-1:0] le; // 0: level-sensitive 1: edge-sensitive logic [N_SOURCE-1:0] ip; @@ -463,7 +460,6 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ if (VSCLIC) begin for (int i = 1; i <= N_VSCTXTS; i++) begin case(reg_req_i.addr[ADDR_W-1:0]) inside - // TODO: whether / how to grant access to MCLICCFG register `VSCLICCFG_START(i): begin // inaccesible (all zero) reg_rsp_o.rdata = '0; diff --git a/src/clicvs_reg_pkg.sv b/src/clicvs_reg_pkg.sv index 5ac8fb4..ea3f6e7 100644 --- a/src/clicvs_reg_pkg.sv +++ b/src/clicvs_reg_pkg.sv @@ -15,22 +15,22 @@ package clicvs_reg_pkg; typedef struct packed { struct packed { - logic [7:0] q; + logic q; } prio0; struct packed { - logic [7:0] q; + logic q; } prio1; struct packed { - logic [7:0] q; + logic q; } prio2; struct packed { - logic [7:0] q; + logic q; } prio3; } clicvs_reg2hw_vsprio_reg_t; // Register -> HW type typedef struct packed { - clicvs_reg2hw_vsprio_reg_t vsprio; // [31:0] + clicvs_reg2hw_vsprio_reg_t vsprio; // [3:0] } clicvs_reg2hw_t; // Register offsets diff --git a/src/clicvs_reg_top.sv b/src/clicvs_reg_top.sv index 63bc26e..f836899 100644 --- a/src/clicvs_reg_top.sv +++ b/src/clicvs_reg_top.sv @@ -67,27 +67,27 @@ module clicvs_reg_top #( // Define SW related signals // Format: __{wd|we|qs} // or _{wd|we|qs} if field == 1 or 0 - logic [7:0] vsprio_prio0_qs; - logic [7:0] vsprio_prio0_wd; + logic vsprio_prio0_qs; + logic vsprio_prio0_wd; logic vsprio_prio0_we; - logic [7:0] vsprio_prio1_qs; - logic [7:0] vsprio_prio1_wd; + logic vsprio_prio1_qs; + logic vsprio_prio1_wd; logic vsprio_prio1_we; - logic [7:0] vsprio_prio2_qs; - logic [7:0] vsprio_prio2_wd; + logic vsprio_prio2_qs; + logic vsprio_prio2_wd; logic vsprio_prio2_we; - logic [7:0] vsprio_prio3_qs; - logic [7:0] vsprio_prio3_wd; + logic vsprio_prio3_qs; + logic vsprio_prio3_wd; logic vsprio_prio3_we; // Register instances // R[vsprio]: V(False) - // F[prio0]: 7:0 + // F[prio0]: 0:0 prim_subreg #( - .DW (8), + .DW (1), .SWACCESS("RW"), - .RESVAL (8'h0) + .RESVAL (1'h0) ) u_vsprio_prio0 ( .clk_i (clk_i ), .rst_ni (rst_ni ), @@ -109,11 +109,11 @@ module clicvs_reg_top #( ); - // F[prio1]: 15:8 + // F[prio1]: 8:8 prim_subreg #( - .DW (8), + .DW (1), .SWACCESS("RW"), - .RESVAL (8'h0) + .RESVAL (1'h0) ) u_vsprio_prio1 ( .clk_i (clk_i ), .rst_ni (rst_ni ), @@ -135,11 +135,11 @@ module clicvs_reg_top #( ); - // F[prio2]: 23:16 + // F[prio2]: 16:16 prim_subreg #( - .DW (8), + .DW (1), .SWACCESS("RW"), - .RESVAL (8'h0) + .RESVAL (1'h0) ) u_vsprio_prio2 ( .clk_i (clk_i ), .rst_ni (rst_ni ), @@ -161,11 +161,11 @@ module clicvs_reg_top #( ); - // F[prio3]: 31:24 + // F[prio3]: 24:24 prim_subreg #( - .DW (8), + .DW (1), .SWACCESS("RW"), - .RESVAL (8'h0) + .RESVAL (1'h0) ) u_vsprio_prio3 ( .clk_i (clk_i ), .rst_ni (rst_ni ), @@ -204,26 +204,26 @@ module clicvs_reg_top #( end assign vsprio_prio0_we = addr_hit[0] & reg_we & !reg_error; - assign vsprio_prio0_wd = reg_wdata[7:0]; + assign vsprio_prio0_wd = reg_wdata[0]; assign vsprio_prio1_we = addr_hit[0] & reg_we & !reg_error; - assign vsprio_prio1_wd = reg_wdata[15:8]; + assign vsprio_prio1_wd = reg_wdata[8]; assign vsprio_prio2_we = addr_hit[0] & reg_we & !reg_error; - assign vsprio_prio2_wd = reg_wdata[23:16]; + assign vsprio_prio2_wd = reg_wdata[16]; assign vsprio_prio3_we = addr_hit[0] & reg_we & !reg_error; - assign vsprio_prio3_wd = reg_wdata[31:24]; + assign vsprio_prio3_wd = reg_wdata[24]; // Read data return always_comb begin reg_rdata_next = '0; unique case (1'b1) addr_hit[0]: begin - reg_rdata_next[7:0] = vsprio_prio0_qs; - reg_rdata_next[15:8] = vsprio_prio1_qs; - reg_rdata_next[23:16] = vsprio_prio2_qs; - reg_rdata_next[31:24] = vsprio_prio3_qs; + reg_rdata_next[0] = vsprio_prio0_qs; + reg_rdata_next[8] = vsprio_prio1_qs; + reg_rdata_next[16] = vsprio_prio2_qs; + reg_rdata_next[24] = vsprio_prio3_qs; end default: begin diff --git a/src/gen/clicvs.hjson b/src/gen/clicvs.hjson index 284c3cb..fccc122 100644 --- a/src/gen/clicvs.hjson +++ b/src/gen/clicvs.hjson @@ -25,10 +25,10 @@ swaccess: "rw", hwaccess: "hro", fields: [ - { bits: "31:24", name: "prio3", desc: "VS3 priority" }, - { bits: "23:16", name: "prio2", desc: "VS2 priority" }, - { bits: "15:8", name: "prio1", desc: "VS1 priority" }, - { bits: "7:0", name: "prio0", desc: "VS0 priority" }, + { bits: "24", name: "prio3", desc: "VS3 priority" }, + { bits: "16", name: "prio2", desc: "VS2 priority" }, + { bits: "8", name: "prio1", desc: "VS1 priority" }, + { bits: "0", name: "prio0", desc: "VS0 priority" }, ], } ] From 4d7a1b7a70befd45ce564be7b27e161785137518 Mon Sep 17 00:00:00 2001 From: aottaviano Date: Tue, 4 Apr 2023 19:31:29 +0200 Subject: [PATCH 09/17] src/gen: Add mnxti config register --- src/clic.sv | 13 ++++++++---- src/clic_reg_adapter.sv | 13 +++++++++++- src/clic_target.sv | 20 ++++++++++++++---- src/gen/mclic.hjson | 8 +++++++ src/mclic_reg_pkg.sv | 20 ++++++++++++------ src/mclic_reg_top.sv | 47 +++++++++++++++++++++++++++++++++++++---- 6 files changed, 102 insertions(+), 19 deletions(-) diff --git a/src/clic.sv b/src/clic.sv index a462249..13f169a 100644 --- a/src/clic.sv +++ b/src/clic.sv @@ -99,6 +99,7 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ // Each privilege mode address space is aligned to a 32KiB physical memory region localparam logic [ADDR_W-1:0] MCLICCFG_START = 'h00000; + localparam logic [ADDR_W-1:0] MCLICCFG_END = 'h00800; localparam logic [ADDR_W-1:0] MCLICINT_START = 'h01000; localparam logic [ADDR_W-1:0] MCLICINT_END = 'h04fff; @@ -145,6 +146,7 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ logic [N_SOURCE-1:0] shv; // Handle per-irq SHV bits logic [N_SOURCE-1:0] claim; + logic mnxti_cfg; // handle incoming interrupts clic_gateway #( @@ -198,7 +200,9 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ .irq_shv_o, .irq_kill_req_o, - .irq_kill_ack_i + .irq_kill_ack_i, + + .mnxti_cfg_i (mnxti_cfg) ); // configuration registers @@ -370,8 +374,8 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ addr_tmp = '0; - unique case(reg_req_i.addr[ADDR_W-1:0]) inside - MCLICCFG_START: begin + unique case(reg_req_i.addr[ADDR_W:0]) inside + [MCLICCFG_START:MCLICCFG_END]: begin reg_mclic_req = reg_req_i; reg_rsp_o = reg_mclic_rsp; end @@ -523,7 +527,8 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ .ie_o (ie), .le_o (le), - .ip_i (ip) + .ip_i (ip), + .mnxti_cfg_o(mnxti_cfg) ); // Create level and prio signals with dynamic indexing (#bits are read from diff --git a/src/clic_reg_adapter.sv b/src/clic_reg_adapter.sv index 34a1a16..6acc1a1 100644 --- a/src/clic_reg_adapter.sv +++ b/src/clic_reg_adapter.sv @@ -45,7 +45,8 @@ module clic_reg_adapter import mclic_reg_pkg::*; import clicint_reg_pkg::*; impo output logic [N_SOURCE-1:0] ie_o, output logic [N_SOURCE-1:0] le_o, - input logic [N_SOURCE-1:0] ip_i + input logic [N_SOURCE-1:0] ip_i, + output logic mnxti_cfg_o ); // We only support positive edge triggered and positive level triggered @@ -72,4 +73,14 @@ module clic_reg_adapter import mclic_reg_pkg::*; import clicint_reg_pkg::*; impo assign vsid_o[i+3] = clicintv_reg2hw[i/4].clicintv.vsid3.q; assign intv_o[i+3] = clicintv_reg2hw[i/4].clicintv.v3.q; end + + for (genvar i = 0; i < MAX_VSCTXTS; i = i + 4) begin : gen_reghw_vs + assign vsprio_o[i+0] = clicvs_reg2hw[i/4].vsprio.prio0.q; + assign vsprio_o[i+1] = clicvs_reg2hw[i/4].vsprio.prio1.q; + assign vsprio_o[i+2] = clicvs_reg2hw[i/4].vsprio.prio2.q; + assign vsprio_o[i+3] = clicvs_reg2hw[i/4].vsprio.prio3.q; + end + + assign mnxti_cfg_o = mclic_reg2hw.clicmnxticonf.q; + endmodule // clic_reg_adapter diff --git a/src/clic_target.sv b/src/clic_target.sv index 381b8cf..ecc08a1 100644 --- a/src/clic_target.sv +++ b/src/clic_target.sv @@ -66,7 +66,8 @@ module clic_target #( output logic irq_shv_o, output logic irq_kill_req_o, - input logic irq_kill_ack_i + input logic irq_kill_ack_i, + input logic mnxti_cfg_i ); // this only works with 2 or more sources @@ -214,9 +215,20 @@ module clic_target #( // wait for handshake ACK: begin irq_valid_d = 1'b1; - irq_id_d = irq_id_q; - irq_max_d = irq_max_q; - irq_mode_d = irq_mode_q; + if (!mnxti_cfg_i) begin + irq_id_d = irq_id_q; + irq_max_d = irq_max_q; + vsid_max_d = vsid_max_q; + shv_max_d = shv_max_q; + end else begin + if (irq_root_valid) begin + irq_id_d = irq_root_id; // give irq_id_d the most updated value + irq_max_d = max_tree[0]; // give irq_max_d the most updated value + end else begin + irq_id_d = '0; + irq_max_d = '0; + end + end // level sensitive interrupts (le_i == 1'b0) can be cleared (ip_i goes // to 1'b0) and shouldn't fire anymore so we should get unstuck here if (!le_i[irq_id_q] && !ip_i[irq_id_q]) begin diff --git a/src/gen/mclic.hjson b/src/gen/mclic.hjson index bd1b79a..c6bde00 100644 --- a/src/gen/mclic.hjson +++ b/src/gen/mclic.hjson @@ -34,6 +34,14 @@ { bits: "3:0", name: "mnlbits", desc: "number of interrupt level bits in machine mode" }, ], }, + { name: "CLICMNXTICONF", + desc: "CLIC enable mnxti irq forwarding logic", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "0" } + ], + }, ] } diff --git a/src/mclic_reg_pkg.sv b/src/mclic_reg_pkg.sv index a194e30..f987079 100644 --- a/src/mclic_reg_pkg.sv +++ b/src/mclic_reg_pkg.sv @@ -7,7 +7,7 @@ package mclic_reg_pkg; // Address widths within the block - parameter int BlockAw = 2; + parameter int BlockAw = 3; //////////////////////////// // Typedefs for registers // @@ -28,22 +28,30 @@ package mclic_reg_pkg; } unlbits; } mclic_reg2hw_mcliccfg_reg_t; + typedef struct packed { + logic q; + } mclic_reg2hw_clicmnxticonf_reg_t; + // Register -> HW type typedef struct packed { - mclic_reg2hw_mcliccfg_reg_t mcliccfg; // [13:0] + mclic_reg2hw_mcliccfg_reg_t mcliccfg; // [14:1] + mclic_reg2hw_clicmnxticonf_reg_t clicmnxticonf; // [0:0] } mclic_reg2hw_t; // Register offsets - parameter logic [BlockAw-1:0] MCLIC_MCLICCFG_OFFSET = 2'h 0; + parameter logic [BlockAw-1:0] MCLIC_MCLICCFG_OFFSET = 3'h 0; + parameter logic [BlockAw-1:0] MCLIC_CLICMNXTICONF_OFFSET = 3'h 4; // Register index typedef enum int { - MCLIC_MCLICCFG + MCLIC_MCLICCFG, + MCLIC_CLICMNXTICONF } mclic_id_e; // Register width information to check illegal writes - parameter logic [3:0] MCLIC_PERMIT [1] = '{ - 4'b 1111 // index[0] MCLIC_MCLICCFG + parameter logic [3:0] MCLIC_PERMIT [2] = '{ + 4'b 1111, // index[0] MCLIC_MCLICCFG + 4'b 0001 // index[1] MCLIC_CLICMNXTICONF }; endpackage diff --git a/src/mclic_reg_top.sv b/src/mclic_reg_top.sv index 93560ed..d52cdf7 100644 --- a/src/mclic_reg_top.sv +++ b/src/mclic_reg_top.sv @@ -10,7 +10,7 @@ module mclic_reg_top #( parameter type reg_req_t = logic, parameter type reg_rsp_t = logic, - parameter int AW = 2 + parameter int AW = 3 ) ( input logic clk_i, input logic rst_ni, @@ -80,6 +80,9 @@ module mclic_reg_top #( logic [3:0] mcliccfg_unlbits_wd; logic mcliccfg_unlbits_we; logic [3:0] mcliccfg_reserved_qs; + logic clicmnxticonf_qs; + logic clicmnxticonf_wd; + logic clicmnxticonf_we; // Register instances // R[mcliccfg]: V(False) @@ -193,12 +196,40 @@ module mclic_reg_top #( assign mcliccfg_reserved_qs = 4'h0; + // R[clicmnxticonf]: V(False) + + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h0) + ) u_clicmnxticonf ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (clicmnxticonf_we), + .wd (clicmnxticonf_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.clicmnxticonf.q ), + + // to register interface (read) + .qs (clicmnxticonf_qs) + ); - logic [0:0] addr_hit; + + + logic [1:0] addr_hit; always_comb begin addr_hit = '0; addr_hit[0] = (reg_addr == MCLIC_MCLICCFG_OFFSET); + addr_hit[1] = (reg_addr == MCLIC_CLICMNXTICONF_OFFSET); end assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ; @@ -206,7 +237,8 @@ module mclic_reg_top #( // Check sub-word write is permitted always_comb begin wr_err = (reg_we & - ((addr_hit[0] & (|(MCLIC_PERMIT[0] & ~reg_be))))); + ((addr_hit[0] & (|(MCLIC_PERMIT[0] & ~reg_be))) | + (addr_hit[1] & (|(MCLIC_PERMIT[1] & ~reg_be))))); end assign mcliccfg_mnlbits_we = addr_hit[0] & reg_we & !reg_error; @@ -221,6 +253,9 @@ module mclic_reg_top #( assign mcliccfg_unlbits_we = addr_hit[0] & reg_we & !reg_error; assign mcliccfg_unlbits_wd = reg_wdata[27:24]; + assign clicmnxticonf_we = addr_hit[1] & reg_we & !reg_error; + assign clicmnxticonf_wd = reg_wdata[0]; + // Read data return always_comb begin reg_rdata_next = '0; @@ -233,6 +268,10 @@ module mclic_reg_top #( reg_rdata_next[31:28] = mcliccfg_reserved_qs; end + addr_hit[1]: begin + reg_rdata_next[0] = clicmnxticonf_qs; + end + default: begin reg_rdata_next = '1; end @@ -255,7 +294,7 @@ endmodule module mclic_reg_top_intf #( - parameter int AW = 2, + parameter int AW = 3, localparam int DW = 32 ) ( input logic clk_i, From 94e2a77143053f1a2a72c88989616c89e05854fc Mon Sep 17 00:00:00 2001 From: aottaviano Date: Tue, 26 Sep 2023 14:08:21 +0200 Subject: [PATCH 10/17] src: Regenerate registers --- src/clicint_reg_top.sv | 66 ++++++++++++++++++++++++++++++++++++----- src/clicintv_reg_top.sv | 50 +++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 7 deletions(-) diff --git a/src/clicint_reg_top.sv b/src/clicint_reg_top.sv index e85f663..6552ea0 100644 --- a/src/clicint_reg_top.sv +++ b/src/clicint_reg_top.sv @@ -8,12 +8,12 @@ `include "common_cells/assertions.svh" module clicint_reg_top #( - parameter type reg_req_t = logic, - parameter type reg_rsp_t = logic, - parameter int AW = 2 + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic, + parameter int AW = 2 ) ( - input clk_i, - input rst_ni, + input logic clk_i, + input logic rst_ni, input reg_req_t reg_req_i, output reg_rsp_t reg_rsp_o, // To HW @@ -33,7 +33,7 @@ module clicint_reg_top #( // register signals logic reg_we; logic reg_re; - logic [AW-1:0] reg_addr; + logic [BlockAw-1:0] reg_addr; logic [DW-1:0] reg_wdata; logic [DBW-1:0] reg_be; logic [DW-1:0] reg_rdata; @@ -54,7 +54,7 @@ module clicint_reg_top #( assign reg_we = reg_intf_req.valid & reg_intf_req.write; assign reg_re = reg_intf_req.valid & ~reg_intf_req.write; - assign reg_addr = reg_intf_req.addr; + assign reg_addr = reg_intf_req.addr[BlockAw-1:0]; assign reg_wdata = reg_intf_req.wdata; assign reg_be = reg_intf_req.wstrb; assign reg_intf_rsp.rdata = reg_rdata; @@ -312,3 +312,55 @@ module clicint_reg_top #( `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit)) endmodule + +module clicint_reg_top_intf +#( + parameter int AW = 2, + localparam int DW = 32 +) ( + input logic clk_i, + input logic rst_ni, + REG_BUS.in regbus_slave, + // To HW + output clicint_reg_pkg::clicint_reg2hw_t reg2hw, // Write + input clicint_reg_pkg::clicint_hw2reg_t hw2reg, // Read + // Config + input devmode_i // If 1, explicit error return for unmapped register access +); + localparam int unsigned STRB_WIDTH = DW/8; + +`include "register_interface/typedef.svh" +`include "register_interface/assign.svh" + + // Define structs for reg_bus + typedef logic [AW-1:0] addr_t; + typedef logic [DW-1:0] data_t; + typedef logic [STRB_WIDTH-1:0] strb_t; + `REG_BUS_TYPEDEF_ALL(reg_bus, addr_t, data_t, strb_t) + + reg_bus_req_t s_reg_req; + reg_bus_rsp_t s_reg_rsp; + + // Assign SV interface to structs + `REG_BUS_ASSIGN_TO_REQ(s_reg_req, regbus_slave) + `REG_BUS_ASSIGN_FROM_RSP(regbus_slave, s_reg_rsp) + + + + clicint_reg_top #( + .reg_req_t(reg_bus_req_t), + .reg_rsp_t(reg_bus_rsp_t), + .AW(AW) + ) i_regs ( + .clk_i, + .rst_ni, + .reg_req_i(s_reg_req), + .reg_rsp_o(s_reg_rsp), + .reg2hw, // Write + .hw2reg, // Read + .devmode_i + ); + +endmodule + + diff --git a/src/clicintv_reg_top.sv b/src/clicintv_reg_top.sv index 0534036..3d2e599 100644 --- a/src/clicintv_reg_top.sv +++ b/src/clicintv_reg_top.sv @@ -377,3 +377,53 @@ module clicintv_reg_top #( `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit)) endmodule + +module clicintv_reg_top_intf +#( + parameter int AW = 2, + localparam int DW = 32 +) ( + input logic clk_i, + input logic rst_ni, + REG_BUS.in regbus_slave, + // To HW + output clicintv_reg_pkg::clicintv_reg2hw_t reg2hw, // Write + // Config + input devmode_i // If 1, explicit error return for unmapped register access +); + localparam int unsigned STRB_WIDTH = DW/8; + +`include "register_interface/typedef.svh" +`include "register_interface/assign.svh" + + // Define structs for reg_bus + typedef logic [AW-1:0] addr_t; + typedef logic [DW-1:0] data_t; + typedef logic [STRB_WIDTH-1:0] strb_t; + `REG_BUS_TYPEDEF_ALL(reg_bus, addr_t, data_t, strb_t) + + reg_bus_req_t s_reg_req; + reg_bus_rsp_t s_reg_rsp; + + // Assign SV interface to structs + `REG_BUS_ASSIGN_TO_REQ(s_reg_req, regbus_slave) + `REG_BUS_ASSIGN_FROM_RSP(regbus_slave, s_reg_rsp) + + + + clicintv_reg_top #( + .reg_req_t(reg_bus_req_t), + .reg_rsp_t(reg_bus_rsp_t), + .AW(AW) + ) i_regs ( + .clk_i, + .rst_ni, + .reg_req_i(s_reg_req), + .reg_rsp_o(s_reg_rsp), + .reg2hw, // Write + .devmode_i + ); + +endmodule + + From a4155d8aabaa9667cfd75e8575cc1bad90a80494 Mon Sep 17 00:00:00 2001 From: aottaviano Date: Tue, 26 Sep 2023 19:50:43 +0200 Subject: [PATCH 11/17] src: Tie both VS and VSprio signals to 0 when both disabled --- src/clic.sv | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/clic.sv b/src/clic.sv index 13f169a..ef455ff 100644 --- a/src/clic.sv +++ b/src/clic.sv @@ -352,19 +352,26 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ end end else begin + // If both V and Vprio are not enabled, tie all to 0' + // V assign clicintv_reg2hw = '0; - // assign clicintv_hw2reg = '0; assign reg_v_req = '0; assign reg_v_rsp = '0; assign v_addr = '0; assign reg_all_v_rsp = '0; + // VS + assign clicvs_reg2hw = '0; + assign reg_vs_req = '0; + assign reg_vs_rsp = '0; + assign vs_addr = '0; + assign reg_all_vs_rsp = '0; end // top level address decoding and bus muxing // Helper signal used to store intermediate address logic [ADDR_W-1:0] addr_tmp; - + always_comb begin : clic_addr_decode reg_mclic_req = '0; reg_all_int_req = '0; From c1ccd77d6b617dce4dc6ae5efdb0c1636f77ff43 Mon Sep 17 00:00:00 2001 From: aottaviano Date: Tue, 26 Sep 2023 19:51:40 +0200 Subject: [PATCH 12/17] src: Remove trailing whitespaces --- src/clic.sv | 32 ++++++++++++++++---------------- src/clic_target.sv | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/clic.sv b/src/clic.sv index ef455ff..7af03e7 100644 --- a/src/clic.sv +++ b/src/clic.sv @@ -27,12 +27,12 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ parameter bit VSCLIC = 0, // enable vCLIC (requires SSCLIC) // vCLIC dependent parameters - parameter int unsigned N_VSCTXTS = 0, // Number of Virtual Contexts supported. - // This implementation assumes CLIC is mapped to an address + parameter int unsigned N_VSCTXTS = 0, // Number of Virtual Contexts supported. + // This implementation assumes CLIC is mapped to an address // range that allows up to 64 contexts (at least 512KiB) parameter bit VSPRIO = 0, // Enable VS prioritization (requires VSCLIC) parameter int VsprioWidth = 1, // N of VS priority bits (must be set accordingly to the `clicvs` register width) - + // do not edit below, these are derived localparam int SRC_W = $clog2(N_SOURCE), localparam int unsigned MAX_VSCTXTS = 64, // up to 64 VS contexts @@ -83,8 +83,8 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ /////////////////////////////////////////////////// // // The address range is divided into blocks of 32KB. - // There is one block each for S-mode and M-mode, - // and there are up to MAX_VSCTXTS extra blocks, + // There is one block each for S-mode and M-mode, + // and there are up to MAX_VSCTXTS extra blocks, // one per guest VS. // // M_MODE : [0x000000 - 0x007fff] @@ -95,7 +95,7 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ // VS_64 : [0x208000 - 0x20ffff] // Some value between 16 (VSCLIC = 0) and 22 (64 VS contexts) - localparam int unsigned ADDR_W = $clog2((N_VSCTXTS + 2) * 32 * 1024); + localparam int unsigned ADDR_W = $clog2((N_VSCTXTS + 2) * 32 * 1024); // Each privilege mode address space is aligned to a 32KiB physical memory region localparam logic [ADDR_W-1:0] MCLICCFG_START = 'h00000; @@ -281,11 +281,11 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ reg_rsp_t [(MAX_VSCTXTS/4)-1:0] reg_vs_rsp; if (VSCLIC) begin - + always_comb begin reg_v_req = '0; reg_all_v_rsp = '0; - + v_addr = reg_all_v_req.addr[ADDR_W-1:2]; reg_v_req[v_addr] = reg_all_v_req; @@ -309,21 +309,21 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ .devmode_i (1'b1) ); end - + if (VSPRIO) begin always_comb begin reg_vs_req = '0; reg_all_vs_rsp = '0; - + vs_addr = reg_all_vs_req.addr[ADDR_W-1:2]; reg_vs_req[vs_addr] = reg_all_vs_req; reg_all_vs_rsp = reg_vs_rsp[vs_addr]; end - + for(genvar i = 0; i < (MAX_VSCTXTS/4); i++) begin : gen_clic_vs - + clicvs_reg_top #( .reg_req_t (reg_req_t), .reg_rsp_t (reg_rsp_t) @@ -353,13 +353,13 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ end else begin // If both V and Vprio are not enabled, tie all to 0' - // V + // VS assign clicintv_reg2hw = '0; assign reg_v_req = '0; assign reg_v_rsp = '0; assign v_addr = '0; assign reg_all_v_rsp = '0; - // VS + // VSprio assign clicvs_reg2hw = '0; assign reg_vs_req = '0; assign reg_vs_rsp = '0; @@ -479,8 +479,8 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ end [`VSCLICINT_START(i):`VSCLICINT_END(i)]: begin addr_tmp = reg_req_i.addr[ADDR_W-1:0] - `VSCLICINT_START(i); - if ((intmode[addr_tmp[ADDR_W-1:2]] == S_MODE) && - (intv[addr_tmp[ADDR_W-1:2]]) && + if ((intmode[addr_tmp[ADDR_W-1:2]] == S_MODE) && + (intv[addr_tmp[ADDR_W-1:2]]) && (vsid[addr_tmp[ADDR_W-1:2]] == i)) begin // check whether the irq we want to access is s-mode and its v bit is set and the VSID corresponds reg_all_int_req = reg_req_i; diff --git a/src/clic_target.sv b/src/clic_target.sv index ecc08a1..2612574 100644 --- a/src/clic_target.sv +++ b/src/clic_target.sv @@ -117,9 +117,9 @@ module clic_target #( assign is_tree[Pa] = ip_i[offset] & ie_i[offset]; assign id_tree[Pa] = offset; // NOTE: save space by encoding the Virtualization bit in the privilege mode tree fields. - // This is done by temporarily elevating the privilege level of hypervisor IRQs (mode=S_MODE, intv=0) + // This is done by temporarily elevating the privilege level of hypervisor IRQs (mode=S_MODE, intv=0) // to the reserved value 2'b10 so that they have higher priority than virtualized IRQs (S_MODE == 1'b01) - // but still lower priority than M_MODE IRQs (M_MODE == 2'b11). + // but still lower priority than M_MODE IRQs (M_MODE == 2'b11). assign max_tree[Pa].mode = ((mode_i[offset] == S_MODE) && ~intv_i[offset]) ? 2'b10 : mode_i[offset]; assign max_tree[Pa].vsprio = ((mode_i[offset] == S_MODE) && intv_i[offset]) ? vsprio_i[vsid_i[offset]] : '0; assign max_tree[Pa].prio = prio_i[offset]; From c9ae93916ace009f62d3a9bc2c05ba32ff07e0f3 Mon Sep 17 00:00:00 2001 From: bluew Date: Fri, 29 Sep 2023 19:29:30 +0200 Subject: [PATCH 13/17] src: Fix address decoding too wide --- src/clic.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clic.sv b/src/clic.sv index 7af03e7..949d7d7 100644 --- a/src/clic.sv +++ b/src/clic.sv @@ -381,7 +381,7 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ addr_tmp = '0; - unique case(reg_req_i.addr[ADDR_W:0]) inside + unique case(reg_req_i.addr[ADDR_W-1:0]) inside [MCLICCFG_START:MCLICCFG_END]: begin reg_mclic_req = reg_req_i; reg_rsp_o = reg_mclic_rsp; From 3aa6f06eb03e6c74b6fead5b1d42318f49a3cf32 Mon Sep 17 00:00:00 2001 From: bluew Date: Mon, 2 Oct 2023 20:54:49 +0200 Subject: [PATCH 14/17] src: Preserve shv state when using mnxti mode --- src/clic_target.sv | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/clic_target.sv b/src/clic_target.sv index 2612574..3260e5a 100644 --- a/src/clic_target.sv +++ b/src/clic_target.sv @@ -224,9 +224,11 @@ module clic_target #( if (irq_root_valid) begin irq_id_d = irq_root_id; // give irq_id_d the most updated value irq_max_d = max_tree[0]; // give irq_max_d the most updated value + shv_max_d = shv_i[irq_root_id]; end else begin irq_id_d = '0; irq_max_d = '0; + shv_max_d = shv_max_q; end end // level sensitive interrupts (le_i == 1'b0) can be cleared (ip_i goes From 9f3ead92e9ce4c867af7eae6fc64d1f5cd065ddf Mon Sep 17 00:00:00 2001 From: bluew Date: Tue, 3 Oct 2023 18:23:22 +0200 Subject: [PATCH 15/17] src: Turn case inside into if for synth compat Since this is priority logic it might yield slightly less efficient hardware but have to look into that yet. --- src/clic.sv | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/clic.sv b/src/clic.sv index 949d7d7..31999b3 100644 --- a/src/clic.sv +++ b/src/clic.sv @@ -470,34 +470,32 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ // Match VS address space if (VSCLIC) begin for (int i = 1; i <= N_VSCTXTS; i++) begin - case(reg_req_i.addr[ADDR_W-1:0]) inside - `VSCLICCFG_START(i): begin + if (reg_req_i.addr[ADDR_W-1:0] == `VSCLICCFG_START(i)) begin + // inaccesible (all zero) + reg_rsp_o.rdata = '0; + reg_rsp_o.error = '0; + reg_rsp_o.ready = 1'b1; + end else if (`VSCLICINT_START(i) >= reg_req_i.addr[ADDR_W-1:0] && + reg_req_i.addr[ADDR_W-1:0] <= `VSCLICINT_END(i)) begin + addr_tmp = reg_req_i.addr[ADDR_W-1:0] - `VSCLICINT_START(i); + if ((intmode[addr_tmp[ADDR_W-1:2]] == S_MODE) && + (intv[addr_tmp[ADDR_W-1:2]]) && + (vsid[addr_tmp[ADDR_W-1:2]] == i)) begin + // check whether the irq we want to access is s-mode and its v bit is set and the VSID corresponds + reg_all_int_req = reg_req_i; + reg_all_int_req.addr = addr_tmp; + // Prevent setting interrupt mode to m-mode . This is currently a + // bit ugly but will be nicer once we do away with auto generated + // clicint registers + reg_all_int_req.wdata[23] = 1'b0; + reg_rsp_o = reg_all_int_rsp; + end else begin // inaccesible (all zero) reg_rsp_o.rdata = '0; reg_rsp_o.error = '0; reg_rsp_o.ready = 1'b1; end - [`VSCLICINT_START(i):`VSCLICINT_END(i)]: begin - addr_tmp = reg_req_i.addr[ADDR_W-1:0] - `VSCLICINT_START(i); - if ((intmode[addr_tmp[ADDR_W-1:2]] == S_MODE) && - (intv[addr_tmp[ADDR_W-1:2]]) && - (vsid[addr_tmp[ADDR_W-1:2]] == i)) begin - // check whether the irq we want to access is s-mode and its v bit is set and the VSID corresponds - reg_all_int_req = reg_req_i; - reg_all_int_req.addr = addr_tmp; - // Prevent setting interrupt mode to m-mode . This is currently a - // bit ugly but will be nicer once we do away with auto generated - // clicint registers - reg_all_int_req.wdata[23] = 1'b0; - reg_rsp_o = reg_all_int_rsp; - end else begin - // inaccesible (all zero) - reg_rsp_o.rdata = '0; - reg_rsp_o.error = '0; - reg_rsp_o.ready = 1'b1; - end - end - endcase // case (reg_req_i.addr) + end end end end From 0ff9f07e0a492bff046dfe24399b1e1e82d557b7 Mon Sep 17 00:00:00 2001 From: bluew Date: Tue, 14 Nov 2023 00:54:50 +0100 Subject: [PATCH 16/17] src: Fix broken address range comparison in virt mode --- src/clic.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clic.sv b/src/clic.sv index 31999b3..39915a1 100644 --- a/src/clic.sv +++ b/src/clic.sv @@ -475,7 +475,7 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ reg_rsp_o.rdata = '0; reg_rsp_o.error = '0; reg_rsp_o.ready = 1'b1; - end else if (`VSCLICINT_START(i) >= reg_req_i.addr[ADDR_W-1:0] && + end else if (`VSCLICINT_START(i) <= reg_req_i.addr[ADDR_W-1:0] && reg_req_i.addr[ADDR_W-1:0] <= `VSCLICINT_END(i)) begin addr_tmp = reg_req_i.addr[ADDR_W-1:0] - `VSCLICINT_START(i); if ((intmode[addr_tmp[ADDR_W-1:2]] == S_MODE) && From 40ae266dab5768f63ca8dabe70e7474feb403bab Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Wed, 24 Jan 2024 12:37:45 +0100 Subject: [PATCH 17/17] Attempt to solve critical path. --- src/clic.sv | 2 ++ src/clic_target.sv | 35 ++++++++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/clic.sv b/src/clic.sv index 39915a1..20e7ea5 100644 --- a/src/clic.sv +++ b/src/clic.sv @@ -21,6 +21,7 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ parameter type reg_req_t = logic, parameter type reg_rsp_t = logic, parameter int N_SOURCE = 256, + parameter int N_PIPE = 1, parameter int INTCTLBITS = 8, parameter bit SSCLIC = 0, parameter bit USCLIC = 0, @@ -167,6 +168,7 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_ // generate interrupt depending on ip, ie, level and priority clic_target #( .N_SOURCE (N_SOURCE), + .N_PIPE (N_PIPE), .MAX_VSCTXTS (MAX_VSCTXTS), .PrioWidth (INTCTLBITS), .ModeWidth (2), diff --git a/src/clic_target.sv b/src/clic_target.sv index 3260e5a..03d7cc5 100644 --- a/src/clic_target.sv +++ b/src/clic_target.sv @@ -30,6 +30,7 @@ module clic_target #( parameter int unsigned N_SOURCE = 256, + parameter int unsigned N_PIPE = 1, parameter int unsigned MAX_VSCTXTS = 64, parameter int unsigned PrioWidth = 8, parameter int unsigned ModeWidth = 2, @@ -86,9 +87,9 @@ module clic_target #( // align to powers of 2 for simplicity // a full binary tree with N levels has 2**N + 2**N-1 nodes localparam int NumLevels = $clog2(N_SOURCE); - logic [2**(NumLevels+1)-2:0] is_tree; - logic [2**(NumLevels+1)-2:0][SrcWidth-1:0] id_tree; - prio_t [2**(NumLevels+1)-2:0] max_tree; + logic [2**(NumLevels+1)-2:0] is_tree, is_tree_q; + logic [2**(NumLevels+1)-2:0][SrcWidth-1:0] id_tree, id_tree_q; + prio_t [2**(NumLevels+1)-2:0] max_tree, max_tree_q; for (genvar level = 0; level < NumLevels+1; level++) begin : gen_tree // @@ -173,10 +174,26 @@ module clic_target #( logic [VsidWidth-1:0] vsid_max_d, vsid_max_q; logic shv_max_d, shv_max_q; - // the results can be found at the tree root - // TODO: remove useless inequality comparison - assign irq_root_valid = (max_tree[0] > '0) ? is_tree[0] : 1'b0; - assign irq_root_id = (is_tree[0]) ? id_tree[0] : '0; + if (N_PIPE == 0) begin : gen_no_pipe + assign max_tree_q = max_tree; + assign is_tree_q = is_tree; + assign id_tree_q = id_tree; + end else begin: gen_pipe + always_ff @(posedge clk_i or negedge rst_ni) begin + if (~rst_ni) begin + max_tree_q <= '0; + is_tree_q <= '0; + id_tree_q <= '0; + end else begin + max_tree_q <= max_tree; + is_tree_q <= is_tree; + id_tree_q <= id_tree; + end + end + end + + assign irq_root_valid = (max_tree_q[0] > '0) ? is_tree_q[0] : 1'b0; + assign irq_root_id = (is_tree_q[0]) ? id_tree_q[0] : '0; // higher level interrupt is available than the one we are currently processing // TODO: maybe add pipe? @@ -206,7 +223,7 @@ module clic_target #( IDLE: if (irq_root_valid) begin irq_id_d = irq_root_id; - irq_max_d = max_tree[0]; + irq_max_d = max_tree_q[0]; vsid_max_d = vsid_i[irq_root_id]; shv_max_d = shv_i[irq_root_id]; irq_valid_d = 1'b1; @@ -223,7 +240,7 @@ module clic_target #( end else begin if (irq_root_valid) begin irq_id_d = irq_root_id; // give irq_id_d the most updated value - irq_max_d = max_tree[0]; // give irq_max_d the most updated value + irq_max_d = max_tree_q[0]; // give irq_max_d the most updated value shv_max_d = shv_i[irq_root_id]; end else begin irq_id_d = '0;