diff --git a/Bender.yml b/Bender.yml index 3da2575..18d4c8e 100644 --- a/Bender.yml +++ b/Bender.yml @@ -19,17 +19,17 @@ package: - "Alessandro Ottaviano" dependencies: - common_cells: { git: "https://github.com/pulp-platform/common_cells.git", version: 1.21.0 } - register_interface: { git: "https://github.com/pulp-platform/register_interface.git", version: 0.3.1 } + common_cells: { git: "https://github.com/pulp-platform/common_cells.git", version: 1.26.0 } + register_interface: { git: "https://github.com/pulp-platform/register_interface.git", version: 0.3.9 } sources: - # - src/gen/clic_reg_pkg.sv - # - src/gen/clic_reg_top.sv - # - src/gen/clic_reg_adapater.sv - - src/clic_reg_pkg.sv - - src/clic_reg_top.sv + - src/clicint_reg_pkg.sv + - src/clicint_reg_top.sv + - src/mclic_reg_pkg.sv + - src/mclic_reg_top.sv - src/clic_reg_adapter.sv - src/clic_gateway.sv - src/clic_target.sv + - src/clic_apb.sv - src/clic.sv diff --git a/src/clic.sv b/src/clic.sv index 00a845c..bbdd7ce 100644 --- a/src/clic.sv +++ b/src/clic.sv @@ -17,13 +17,15 @@ `include "common_cells/assertions.svh" -module clic import clic_reg_pkg::*; #( +module clic import mclic_reg_pkg::*; import clicint_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, // do not edit below, these are derived - localparam int SRC_W = $clog2(N_SOURCE) + localparam int SRC_W = $clog2(N_SOURCE) )( input logic clk_i, input logic rst_ni, @@ -36,19 +38,42 @@ module clic import clic_reg_pkg::*; #( input [N_SOURCE-1:0] intr_src_i, // Interrupt notification to core - output irq_valid_o, - input irq_ready_i, - output [SRC_W-1:0] irq_id_o, - output [7:0] irq_level_o, - output logic irq_shv_o + 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 irq_kill_req_o, + input logic irq_kill_ack_i ); - clic_reg2hw_t reg2hw; - clic_hw2reg_t hw2reg; + if (USCLIC) + $fatal(1, "usclic mode is not supported"); + + 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; + + mclic_reg2hw_t mclic_reg2hw; + + clicint_reg2hw_t [N_SOURCE-1:0] clicint_reg2hw; + clicint_hw2reg_t [N_SOURCE-1:0] clicint_hw2reg; logic [7:0] intctl [N_SOURCE]; logic [7:0] irq_max; + logic [1:0] intmode [N_SOURCE]; + logic [1:0] irq_mode; + logic [N_SOURCE-1:0] le; // 0: level-sensitive 1: edge-sensitive logic [N_SOURCE-1:0] ip; logic [N_SOURCE-1:0] ie; @@ -60,7 +85,7 @@ module clic import clic_reg_pkg::*; #( // handle incoming interrupts clic_gateway #( .N_SOURCE (N_SOURCE) - ) u_gateway ( + ) i_clic_gateway ( .clk_i, .rst_ni, @@ -76,8 +101,9 @@ module clic import clic_reg_pkg::*; #( // generate interrupt depending on ip, ie, level and priority clic_target #( .N_SOURCE (N_SOURCE), - .PrioWidth (INTCTLBITS) - ) u_target ( + .PrioWidth (INTCTLBITS), + .ModeWidth (2) + ) i_clic_target ( .clk_i, .rst_ni, @@ -86,60 +112,167 @@ module clic import clic_reg_pkg::*; #( .le_i (le), .prio_i (intctl), + .mode_i (intmode), .claim_o (claim), .irq_valid_o, .irq_ready_i, .irq_id_o, - .irq_max_o (irq_max) + .irq_max_o (irq_max), + .irq_mode_o (irq_mode), + + .irq_kill_req_o, + .irq_kill_ack_i ); - // registers - clic_reg_top #( + // configuration registers + // 0x0000 (machine mode) + reg_req_t reg_mclic_req; + reg_rsp_t reg_mclic_rsp; + + mclic_reg_top #( .reg_req_t (reg_req_t), .reg_rsp_t (reg_rsp_t) - ) u_reg ( + ) i_mclic_reg_top ( .clk_i, .rst_ni, - .reg_req_i, - .reg_rsp_o, + .reg_req_i (reg_mclic_req), + .reg_rsp_o (reg_mclic_rsp), - .reg2hw, - .hw2reg, + .reg2hw (mclic_reg2hw), .devmode_i (1'b1) ); + // interrupt control and status registers (per interrupt line) + // 0x1000 - 0x4fff (machine mode) + reg_req_t reg_all_int_req; + reg_rsp_t reg_all_int_rsp; + logic [15: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]; + + reg_int_req = '0; + reg_all_int_rsp = '0; + + reg_int_req[int_addr] = reg_all_int_req; + reg_all_int_rsp = reg_int_rsp[int_addr]; + end + + for (genvar i = 0; i < N_SOURCE; i++) begin : gen_clic_int + clicint_reg_top #( + .reg_req_t (reg_req_t), + .reg_rsp_t (reg_rsp_t) + ) i_clicint_reg_top ( + .clk_i, + .rst_ni, + + .reg_req_i (reg_int_req[i]), + .reg_rsp_o (reg_int_rsp[i]), + + .reg2hw (clicint_reg2hw[i]), + .hw2reg (clicint_hw2reg[i]), + + .devmode_i (1'b1) + ); + end + + // configuration registers + // 0x8000 (supervisor mode) + + // interrupt control and status register + // 0x9000 - 0xcfff (supervisor mode) + // mirror + + // top level address decoding and bus muxing + always_comb begin : clic_addr_decode + reg_mclic_req = '0; + reg_all_int_req = '0; + reg_rsp_o = '0; + + unique case(reg_req_i.addr[15:0]) inside + MCLICCFG_START: begin + reg_mclic_req = reg_req_i; + reg_rsp_o = reg_mclic_rsp; + end + [MCLICINT_START:MCLICINT_END]: begin + reg_all_int_req = reg_req_i; + reg_all_int_req.addr = reg_req_i.addr - MCLICINT_START; + reg_rsp_o = reg_all_int_rsp; + end + SCLICCFG_START: begin + if (SSCLIC) begin + reg_mclic_req = reg_req_i; + reg_rsp_o = reg_mclic_rsp; + end + 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[15: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 + // 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 + end + default: begin + // inaccesible (all zero) + reg_rsp_o.rdata = '0; + reg_rsp_o.error = '0; + reg_rsp_o.ready = 1'b1; + end + endcase // unique case (reg_req_i.addr) + end + + // adapter clic_reg_adapter #( .N_SOURCE (N_SOURCE), .INTCTLBITS (INTCTLBITS) - ) u_adapter ( + ) i_clic_reg_adapter ( .clk_i, .rst_ni, - .reg2hw, - .hw2reg, + .mclic_reg2hw, - .intctl_o (intctl), - .shv_o (shv), - .ip_sw_o (ip_sw), - .ie_o (ie), - .le_o (le), + .clicint_reg2hw, + .clicint_hw2reg, - .ip_i (ip) - ); + .intctl_o (intctl), + .intmode_o (intmode), + .shv_o (shv), + .ip_sw_o (ip_sw), + .ie_o (ie), + .le_o (le), + + .ip_i (ip) + ); // Create level and prio signals with dynamic indexing (#bits are read from // registers and stored in logic signals) - logic [3:0] nlbits; + logic [3:0] mnlbits; always_comb begin // Saturate nlbits if nlbits > clicintctlbits (nlbits > 0 && nlbits <= 8) - nlbits = ClicIntCtlBits; - if (nlbits <= ClicIntCtlBits) - nlbits = reg2hw.cliccfg.nlbits.q; + mnlbits = INTCTLBITS; + if (mnlbits <= INTCTLBITS) + mnlbits = mclic_reg2hw.mcliccfg.mnlbits.q; end // Extract SHV bit for the highest level, highest priority pending interrupt @@ -151,7 +284,7 @@ module clic import clic_reg_pkg::*; #( // Get level value of the highest level, highest priority interrupt from // clic_target (still in the form `L-P-1`) irq_level_tmp = 8'hff; - unique case (nlbits) + unique case (mnlbits) 4'h0: begin irq_level_tmp = 8'hff; end @@ -184,6 +317,45 @@ module clic import clic_reg_pkg::*; #( endcase end + logic [1:0] nmbits; + + always_comb begin + // m-mode only supported means no configuration + nmbits = 2'b0; + + if (SSCLIC || USCLIC) + nmbits[0] = mclic_reg2hw.mcliccfg.nmbits.q[0]; + + if (SSCLIC && USCLIC) + nmbits[1] = mclic_reg2hw.mcliccfg.nmbits.q[1]; + end + + logic [1:0] irq_mode_tmp; + + always_comb begin + // Get mode of the highest level, highest priority interrupt from + // clic_target (still in the form `L-P-1`) + irq_mode_tmp = M_MODE; + unique case (nmbits) + 4'h0: begin + irq_mode_tmp = M_MODE; + end + 4'h1: begin + irq_mode_tmp[1] = irq_mode[1]; + end + 4'h2: begin + irq_mode_tmp = irq_mode; + end + 4'h3: begin // this is reserved, not sure what to do + irq_mode_tmp = irq_mode; + end + default: + irq_mode_tmp = M_MODE; + endcase + end + + assign irq_level_o = irq_level_tmp; + assign irq_priv_o = irq_mode_tmp; endmodule // clic diff --git a/src/clic_apb.sv b/src/clic_apb.sv index 601c835..5e345c6 100644 --- a/src/clic_apb.sv +++ b/src/clic_apb.sv @@ -19,7 +19,7 @@ `include "register_interface/typedef.svh" `include "register_interface/assign.svh" -module clic_apb import clic_reg_pkg::*; #( +module clic_apb #( parameter int N_SOURCE = 256, parameter int INTCTLBITS = 8, // do not edit below, these are derived @@ -27,28 +27,32 @@ module clic_apb import clic_reg_pkg::*; #( localparam int unsigned REG_BUS_DATA_WIDTH = 32, localparam int SrcW = $clog2(N_SOURCE) )( - input logic clk_i, - input logic rst_ni, + input logic clk_i, + input logic rst_ni, // Bus Interface (device) - input logic penable_i, - input logic pwrite_i, - input logic [REG_BUS_ADDR_WIDTH-1:0] paddr_i, - input logic psel_i, - input logic [REG_BUS_DATA_WIDTH-1:0] pwdata_i, + input logic penable_i, + input logic pwrite_i, + input logic [REG_BUS_ADDR_WIDTH-1:0] paddr_i, + input logic psel_i, + input logic [REG_BUS_DATA_WIDTH-1:0] pwdata_i, output logic [REG_BUS_DATA_WIDTH-1:0] prdata_o, output logic pready_o, output logic pslverr_o, // Interrupt Sources - input [NumSrc-1:0] intr_src_i, + input [N_SOURCE-1:0] intr_src_i, // Interrupt notification to core - output irq_valid_o, - input irq_ready_i, - output [SrcW-1:0] irq_id_o, - output [7:0] irq_level_o, - output logic irq_shv_o + output irq_valid_o, + input irq_ready_i, + output [SrcW-1:0] irq_id_o, + output [7:0] irq_level_o, + output logic irq_shv_o, + output logic [1:0] irq_priv_o, + output logic irq_kill_req_o, + input logic irq_kill_ack_i + ); @@ -109,7 +113,10 @@ module clic_apb import clic_reg_pkg::*; #( .irq_ready_i, .irq_id_o, .irq_level_o, - .irq_shv_o + .irq_shv_o, + .irq_priv_o, + .irq_kill_req_o, + .irq_kill_ack_i ); endmodule // clic_apb diff --git a/src/clic_reg_adapter.sv b/src/clic_reg_adapter.sv index cdc2fd6..70008f4 100644 --- a/src/clic_reg_adapter.sv +++ b/src/clic_reg_adapter.sv @@ -14,17 +14,20 @@ // SPDX-License-Identifier: Apache-2.0 -module clic_reg_adapter import clic_reg_pkg::*; #( +module clic_reg_adapter import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( parameter int N_SOURCE = 32, parameter int INTCTLBITS = 8 )( input logic clk_i, input logic rst_ni, - input clic_reg_pkg::clic_reg2hw_t reg2hw, - output clic_reg_pkg::clic_hw2reg_t hw2reg, + input mclic_reg_pkg::mclic_reg2hw_t mclic_reg2hw, + + 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, output logic [7:0] intctl_o [N_SOURCE], + output logic [1:0] intmode_o [N_SOURCE], 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, @@ -33,23 +36,18 @@ module clic_reg_adapter import clic_reg_pkg::*; #( input logic [N_SOURCE-1:0] ip_i ); - if (N_SOURCE != clic_reg_pkg::NumSrc) - $fatal(1, "CLIC misconfigured: clic_reg_pkg::NumSrc needs to match N_SOURCE"); - - if (INTCTLBITS != clic_reg_pkg::ClicIntCtlBits) - $fatal(1, "CLIC misconfigured: clic_reg_pkg::ClicIntCtlBits needs to match INTCTLBITS"); - // We only support positive edge triggered and positive level triggered // interrupts atm. Either we hardware the trig.q[1] bit correctly or we // implement all modes - for (genvar i = 0; i < NumSrc; i++) begin : gen_reghw - assign intctl_o[i] = reg2hw.clicintctrl[i].q; - assign shv_o[i] = reg2hw.clicintattr[i].shv.q; - assign ip_sw_o[i] = reg2hw.clicintip[i].q; - assign ie_o[i] = reg2hw.clicintie[i].q; - assign hw2reg.clicintip[i].de = 1'b1; // Always write - assign hw2reg.clicintip[i].d = ip_i[i]; - assign le_o[i] = reg2hw.clicintattr[i].trig.q[0]; + 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 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; + assign clicint_hw2reg[i].clicint.ip.de = 1'b1; // Always write + assign clicint_hw2reg[i].clicint.ip.d = ip_i[i]; + assign le_o[i] = clicint_reg2hw[i].clicint.attr_trig.q[0]; end endmodule // clic_reg_adapter diff --git a/src/clic_reg_pkg.sv b/src/clic_reg_pkg.sv deleted file mode 100644 index ecbdb70..0000000 --- a/src/clic_reg_pkg.sv +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright lowRISC contributors. -// Copyright 2022 ETH Zurich -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the 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 - -package clic_reg_pkg; - - parameter int unsigned NumSrc = 256; - parameter int unsigned ClicIntCtlBits = 8; - - // Address widths within the block - parameter int BlockAw = 13; - - typedef struct packed { - struct packed { - logic q; - } nvbits; - struct packed { - logic [3:0] q; - } nlbits; - struct packed { - logic [1:0] q; - } nmbits; - } clic_reg2hw_cliccfg_reg_t; - - typedef struct packed { - struct packed { - logic [12:0] q; - } num_interrupt; - struct packed { - logic [7:0] q; - } version; - struct packed { - logic [3:0] q; - } clicintctlbits; - struct packed { - logic [5:0] q; - } num_trigger; - } clic_reg2hw_clicinfo_reg_t; - - typedef struct packed { - logic q; - } clic_reg2hw_clicintip_reg_t; - - typedef struct packed { - logic q; - } clic_reg2hw_clicintie_reg_t; - - typedef struct packed { - struct packed { - logic q; - } shv; - struct packed { - logic [1:0] q; - } trig; - struct packed { - logic [1:0] q; - } mode; - } clic_reg2hw_clicintattr_reg_t; - - typedef struct packed { - logic [7:0] q; - } clic_reg2hw_clicintctrl_reg_t; - - typedef struct packed { - logic d; - logic de; - } clic_hw2reg_clicintip_reg_t; - - // Register -> HW type - typedef struct packed { - clic_reg2hw_cliccfg_reg_t cliccfg; - clic_reg2hw_clicinfo_reg_t clicinfo; - clic_reg2hw_clicintip_reg_t [NumSrc-1:0] clicintip; - clic_reg2hw_clicintie_reg_t [NumSrc-1:0] clicintie; - clic_reg2hw_clicintattr_reg_t [NumSrc-1:0] clicintattr; - clic_reg2hw_clicintctrl_reg_t [NumSrc-1:0] clicintctrl; - } clic_reg2hw_t; - - // HW -> register type - typedef struct packed { - clic_hw2reg_clicintip_reg_t [NumSrc-1:0] clicintip; - } clic_hw2reg_t; - - - // Register offsets - parameter logic [BlockAw-1:0] CLIC_CLICCFG_OFFSET = 13'h 0; - parameter logic [BlockAw-1:0] CLIC_CLICINFO_OFFSET = 13'h 4; - parameter logic [BlockAw-1:0] CLIC_CLICINTIP_MASK = 13'b 1_????_????_00??; - parameter logic [BlockAw-1:0] CLIC_CLICINTIE_MASK = 13'b 1_????_????_01??; - parameter logic [BlockAw-1:0] CLIC_CLICINTATTR_MASK = 13'b 1_????_????_10??; - parameter logic [BlockAw-1:0] CLIC_CLICINTCTRL_MASK = 13'b 1_????_????_11??; - - // Register width information to check illegal writes - parameter logic [3:0] CLIC_PERMIT [6] = '{ - 4'b 0001, // index[ 0] CLIC_CLICCFG - 4'b 1111, // index[ 1] CLIC_CLICINFO - 4'b 0001, // index[ 2] CLIC_CLICINTIP - 4'b 0001, // index[ 3] CLIC_CLICINTIE - 4'b 0001, // index[ 4] CLIC_CLICINTATTR - 4'b 0001 // index[ 5] CLIC_CLICINTCTRL - }; - -endpackage diff --git a/src/clic_reg_top.sv b/src/clic_reg_top.sv deleted file mode 100644 index 08727b8..0000000 --- a/src/clic_reg_top.sv +++ /dev/null @@ -1,572 +0,0 @@ -// Copyright lowRISC contributors. -// Copyright 2022 ETH Zurich -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the 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 - -`include "common_cells/assertions.svh" - -module clic_reg_top #( - parameter type reg_req_t = logic, - parameter type reg_rsp_t = logic, - parameter int AW = 13 -) ( - input clk_i, - input rst_ni, - input reg_req_t reg_req_i, - output reg_rsp_t reg_rsp_o, - // To HW - output clic_reg_pkg::clic_reg2hw_t reg2hw, // Write - input clic_reg_pkg::clic_hw2reg_t hw2reg, // Read - - - // Config - input devmode_i // If 1, explicit error return for unmapped register access -); - - import clic_reg_pkg::* ; - - 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 [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 cliccfg_nvbits_qs; - logic cliccfg_nvbits_wd; - logic cliccfg_nvbits_we; - logic [3:0] cliccfg_nlbits_qs; - logic [3:0] cliccfg_nlbits_wd; - logic cliccfg_nlbits_we; - logic [1:0] cliccfg_nmbits_qs; - logic [1:0] cliccfg_nmbits_wd; - logic cliccfg_nmbits_we; - logic [12:0] clicinfo_num_interrupt_qs; - logic [7:0] clicinfo_version_qs; - logic [3:0] clicinfo_clicintctlbits_qs; - logic [5:0] clicinfo_num_trigger_qs; - logic [NumSrc-1:0] clicintip_qs; - logic [NumSrc-1:0] clicintip_wd; - logic [NumSrc-1:0] clicintip_we; - logic [NumSrc-1:0] clicintie_qs; - logic [NumSrc-1:0] clicintie_wd; - logic [NumSrc-1:0] clicintie_we; - logic [NumSrc-1:0] clicintattr_shv_qs; - logic [NumSrc-1:0] clicintattr_shv_wd; - logic [NumSrc-1:0] clicintattr_shv_we; - logic [NumSrc-1:0][1:0] clicintattr_trig_qs; - logic [NumSrc-1:0][1:0] clicintattr_trig_wd; - logic [NumSrc-1:0] clicintattr_trig_we; - logic [NumSrc-1:0][1:0] clicintattr_mode_qs; - logic [NumSrc-1:0][1:0] clicintattr_mode_wd; - logic [NumSrc-1:0] clicintattr_mode_we; - logic [NumSrc-1:0][7:0] clicintctrl_qs; - logic [NumSrc-1:0][7:0] clicintctrl_wd; - logic [NumSrc-1:0] clicintctrl_we; - - // Register instances - // R[cliccfg]: V(False) - - // F[nvbits]: 0:0 - prim_subreg #( - .DW (1), - .SWACCESS("RW"), - .RESVAL (1'h0) - ) u_cliccfg_nvbits ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (cliccfg_nvbits_we), - .wd (cliccfg_nvbits_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.cliccfg.nvbits.q ), - - // to register interface (read) - .qs (cliccfg_nvbits_qs) - ); - - - // F[nlbits]: 4:1 - prim_subreg #( - .DW (4), - .SWACCESS("RW"), - .RESVAL (4'h0) - ) u_cliccfg_nlbits ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (cliccfg_nlbits_we), - .wd (cliccfg_nlbits_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.cliccfg.nlbits.q ), - - // to register interface (read) - .qs (cliccfg_nlbits_qs) - ); - - - // F[nmbits]: 6:5 - prim_subreg #( - .DW (2), - .SWACCESS("RW"), - .RESVAL (2'h0) - ) u_cliccfg_nmbits ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (cliccfg_nmbits_we), - .wd (cliccfg_nmbits_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.cliccfg.nmbits.q ), - - // to register interface (read) - .qs (cliccfg_nmbits_qs) - ); - - - // R[clicinfo]: V(False) - - // F[num_interrupt]: 12:0 - prim_subreg #( - .DW (13), - .SWACCESS("RO"), - .RESVAL (13'h0) - ) u_clicinfo_num_interrupt ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - .we (1'b0), - .wd ('0 ), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicinfo.num_interrupt.q ), - - // to register interface (read) - .qs (clicinfo_num_interrupt_qs) - ); - - - // F[version]: 20:13 - prim_subreg #( - .DW (8), - .SWACCESS("RO"), - .RESVAL (8'h0) - ) u_clicinfo_version ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - .we (1'b0), - .wd ('0 ), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicinfo.version.q ), - - // to register interface (read) - .qs (clicinfo_version_qs) - ); - - - // F[clicintctlbits]: 24:21 - prim_subreg #( - .DW (4), - .SWACCESS("RO"), - .RESVAL (4'h0) - ) u_clicinfo_clicintctlbits ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - .we (1'b0), - .wd ('0 ), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicinfo.clicintctlbits.q ), - - // to register interface (read) - .qs (clicinfo_clicintctlbits_qs) - ); - - - // F[num_trigger]: 30:25 - prim_subreg #( - .DW (6), - .SWACCESS("RO"), - .RESVAL (6'h0) - ) u_clicinfo_num_trigger ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - .we (1'b0), - .wd ('0 ), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicinfo.num_trigger.q ), - - // to register interface (read) - .qs (clicinfo_num_trigger_qs) - ); - - - - for (genvar i = 0; i < NumSrc; i++) begin : gen_clicint - // R[clicintip0]: V(False) - - prim_subreg #( - .DW (1), - .SWACCESS("RW"), - .RESVAL (1'h0) - ) u_clicintip ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicintip_we[i]), - .wd (clicintip_wd[i]), - - // from internal hardware - .de (hw2reg.clicintip[i].de), - .d (hw2reg.clicintip[i].d ), - - // to internal hardware - .qe (), - .q (reg2hw.clicintip[i].q ), - - // to register interface (read) - .qs (clicintip_qs[i]) - ); - - // R[clicintie0]: V(False) - - prim_subreg #( - .DW (1), - .SWACCESS("RW"), - .RESVAL (1'h0) - ) u_clicintie ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicintie_we[i]), - .wd (clicintie_wd[i]), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicintie[i].q ), - - // to register interface (read) - .qs (clicintie_qs[i]) - ); - - // R[clicintattr0]: V(False) - - // F[shv]: 0:0 - prim_subreg #( - .DW (1), - .SWACCESS("RW"), - .RESVAL (1'h0) - ) u_clicintattr0_shv ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicintattr_shv_we[i]), - .wd (clicintattr_shv_wd[i]), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicintattr[i].shv.q ), - - // to register interface (read) - .qs (clicintattr_shv_qs[i]) - ); - - // F[trig]: 2:1 - prim_subreg #( - .DW (2), - .SWACCESS("RW"), - .RESVAL (2'h0) - ) u_clicintattr_trig ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicintattr_trig_we[i]), - .wd (clicintattr_trig_wd[i]), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicintattr[i].trig.q ), - - // to register interface (read) - .qs (clicintattr_trig_qs[i]) - ); - - // F[mode]: 7:6 - prim_subreg #( - .DW (2), - .SWACCESS("RW"), - .RESVAL (2'h0) - ) u_clicintattr_mode ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicintattr_mode_we[i]), - .wd (clicintattr_mode_wd[i]), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicintattr[i].mode.q ), - - // to register interface (read) - .qs (clicintattr_mode_qs[i]) - ); - - // R[clicintctrl0]: V(False) - - prim_subreg #( - .DW (8), - .SWACCESS("RW"), - .RESVAL (8'h0) - ) u_clicintctrl ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicintctrl_we[i]), - .wd (clicintctrl_wd[i]), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicintctrl[i].q ), - - // to register interface (read) - .qs (clicintctrl_qs[i]) - ); - - end - - - logic [1:0] addr_hit_cfg; - - always_comb begin - addr_hit_cfg = '0; - - // CLIC_CLICCFG - // CLIC_CLICINFO - addr_hit_cfg[0] = (reg_addr == CLIC_CLICCFG_OFFSET); - addr_hit_cfg[1] = (reg_addr == CLIC_CLICINFO_OFFSET); - end - - logic [4*NumSrc-1:0] addr_hit_int; - - always_comb begin - addr_hit_int = '0; - - // CLIC_CLICINTIP - // CLIC_CLICINTIE - // CLIC_CLICINTATTR - // CLIC_CLICINTCTRL - if (reg_addr[12] == 1'h1) - addr_hit_int[reg_addr[11:2]] = 1'b1; - end - - assign addrmiss = (reg_re || reg_we) ? ~|{addr_hit_cfg, addr_hit_int} : 1'b0 ; - assign wr_err = 1'b0; - // // // Check sub-word write is permitted - // always_comb begin - // wr_err = (reg_we & - // ((addr_hit[ 0] & (|(CLIC_PERMIT[ 0] & ~reg_be))) | - // (addr_hit[ 1] & (|(CLIC_PERMIT[ 1] & ~reg_be))))); - // end - - assign cliccfg_nvbits_we = addr_hit_cfg[0] & reg_we & !reg_error; - assign cliccfg_nvbits_wd = reg_wdata[0]; - - assign cliccfg_nlbits_we = addr_hit_cfg[0] & reg_we & !reg_error; - assign cliccfg_nlbits_wd = reg_wdata[4:1]; - - assign cliccfg_nmbits_we = addr_hit_cfg[0] & reg_we & !reg_error; - assign cliccfg_nmbits_wd = reg_wdata[6:5]; - - - for (genvar i = 0; i < NumSrc; i++) begin - assign clicintip_we[i] = addr_hit_int[0 + 4*i] & reg_we & !reg_error; - assign clicintip_wd[i] = reg_wdata[0]; - - assign clicintie_we[i] = addr_hit_int[1 + 4*i] & reg_we & !reg_error; - assign clicintie_wd[i] = reg_wdata[0]; - - assign clicintattr_shv_we[i] = addr_hit_int[2 + 4*i] & reg_we & !reg_error; - assign clicintattr_shv_wd[i] = reg_wdata[0]; - - assign clicintattr_trig_we[i] = addr_hit_int[2 + 4*i] & reg_we & !reg_error; - assign clicintattr_trig_wd[i] = reg_wdata[2:1]; - - assign clicintattr_mode_we[i] = addr_hit_int[2 + 4*i] & reg_we & !reg_error; - assign clicintattr_mode_wd[i] = reg_wdata[7:6]; - - assign clicintctrl_we[i] = addr_hit_int[3 + 4*i] & reg_we & !reg_error; - assign clicintctrl_wd[i] = reg_wdata[7:0]; - end - - // Read data return - always_comb begin - reg_rdata_next = '0; - unique case (reg_addr) inside - CLIC_CLICCFG_OFFSET: begin - reg_rdata_next[0] = cliccfg_nvbits_qs; - reg_rdata_next[4:1] = cliccfg_nlbits_qs; - reg_rdata_next[6:5] = cliccfg_nmbits_qs; - end - - CLIC_CLICINFO_OFFSET: begin - reg_rdata_next[12:0] = clicinfo_num_interrupt_qs; - reg_rdata_next[20:13] = clicinfo_version_qs; - reg_rdata_next[24:21] = clicinfo_clicintctlbits_qs; - reg_rdata_next[30:25] = clicinfo_num_trigger_qs; - end - - CLIC_CLICINTIP_MASK: begin - reg_rdata_next[0] = clicintip_qs[reg_addr[11:4]]; - end - - CLIC_CLICINTIE_MASK: begin - reg_rdata_next[0] = clicintie_qs[reg_addr[11:4]]; - end - - CLIC_CLICINTATTR_MASK: begin - reg_rdata_next[0] = clicintattr_shv_qs[reg_addr[11:4]]; - reg_rdata_next[2:1] = clicintattr_trig_qs[reg_addr[11:4]]; - reg_rdata_next[7:6] = clicintattr_mode_qs[reg_addr[11:4]]; - end - - CLIC_CLICINTCTRL_MASK: begin - reg_rdata_next[7:0] = clicintctrl_qs[reg_addr[11:4]]; - 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_cfg, addr_hit_int})) - -endmodule diff --git a/src/clic_target.sv b/src/clic_target.sv index 3da7127..e680049 100644 --- a/src/clic_target.sv +++ b/src/clic_target.sv @@ -31,6 +31,7 @@ module clic_target #( parameter int unsigned N_SOURCE = 256, parameter int unsigned PrioWidth = 8, + parameter int unsigned ModeWidth = 2, // derived parameters do not change this localparam int SrcWidth = $clog2(N_SOURCE) // derived parameter @@ -43,13 +44,18 @@ module clic_target #( input [N_SOURCE-1:0] le_i, input [PrioWidth-1:0] prio_i [N_SOURCE], + input [ModeWidth-1:0] mode_i [N_SOURCE], output logic [N_SOURCE-1:0] claim_o, output logic irq_valid_o, input logic irq_ready_i, output logic [SrcWidth-1:0] irq_id_o, - output logic [PrioWidth-1:0] irq_max_o + output logic [PrioWidth-1:0] irq_max_o, + output logic [ModeWidth-1:0] irq_mode_o, + + output logic irq_kill_req_o, + input logic irq_kill_ack_i ); // this only works with 2 or more sources @@ -61,6 +67,7 @@ module clic_target #( 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; for (genvar level = 0; level < NumLevels+1; level++) begin : gen_tree // @@ -89,10 +96,12 @@ 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]; end else begin : gen_tie_off - assign is_tree[Pa] = '0; - assign id_tree[Pa] = '0; - assign max_tree[Pa] = '0; + 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 @@ -114,28 +123,37 @@ 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'(max_tree[C1] > max_tree[C0])); + (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]))))))); // 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 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]); end end : gen_level end : gen_tree logic irq_valid_d, irq_valid_q; logic irq_root_valid; + 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; // 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; + // higher level interrupt is available than the one we are currently processing + // TODO: maybe add pipe? + assign higher_irq = irq_root_id != irq_id_q; + // handshake logic to send interrupt to core typedef enum logic [1:0] { IDLE, ACK, CLAIM @@ -146,9 +164,11 @@ module clic_target #( always_comb begin irq_id_d = '0; // default: No Interrupt irq_max_d = '0; + irq_mode_d = '0; claim_o = '0; irq_valid_d = 1'b0; + irq_kill_req_d = 1'b0; irq_state_d = irq_state_q; @@ -158,6 +178,7 @@ 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]; irq_valid_d = 1'b1; irq_state_d = ACK; end @@ -166,6 +187,7 @@ module clic_target #( irq_valid_d = 1'b1; irq_id_d = irq_id_q; irq_max_d = irq_max_q; + irq_mode_d = irq_mode_q; // 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 @@ -174,6 +196,15 @@ module clic_target #( end else if (irq_valid_o && irq_ready_i) begin irq_valid_d = 1'b0; irq_state_d = CLAIM; + end else if (higher_irq) begin + // we have a potentially higher level interrupt. Try to kill the + // current handshake (not irq!) and restart + irq_kill_req_d = 1'b1; + if (irq_kill_req_o && irq_kill_ack_i) begin + irq_kill_req_d = 1'b0; + irq_valid_d = 1'b0; + irq_state_d = IDLE; + end end end // generate interrupt claim pulse @@ -194,11 +225,15 @@ module clic_target #( irq_valid_q <= 1'b0; irq_id_q <= '0; irq_max_q <= '0; + irq_mode_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; + irq_kill_req_q <= irq_kill_req_d; irq_state_q <= irq_state_d; end end @@ -207,5 +242,8 @@ module clic_target #( assign irq_id_o = irq_id_q; assign irq_max_o = irq_max_q; + assign irq_mode_o = irq_mode_q; + + assign irq_kill_req_o = irq_kill_req_q; endmodule diff --git a/src/clicint_reg_pkg.sv b/src/clicint_reg_pkg.sv new file mode 100644 index 0000000..b88579b --- /dev/null +++ b/src/clicint_reg_pkg.sv @@ -0,0 +1,68 @@ +// 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 clicint_reg_pkg; + + // Address widths within the block + parameter int BlockAw = 2; + + //////////////////////////// + // Typedefs for registers // + //////////////////////////// + + typedef struct packed { + struct packed { + logic q; + } ip; + struct packed { + logic q; + } ie; + struct packed { + logic q; + } attr_shv; + struct packed { + logic [1:0] q; + } attr_trig; + struct packed { + logic [1:0] q; + } attr_mode; + struct packed { + logic [7:0] q; + } ctl; + } clicint_reg2hw_clicint_reg_t; + + typedef struct packed { + struct packed { + logic d; + logic de; + } ip; + } clicint_hw2reg_clicint_reg_t; + + // Register -> HW type + typedef struct packed { + clicint_reg2hw_clicint_reg_t clicint; // [14:0] + } clicint_reg2hw_t; + + // HW -> register type + typedef struct packed { + clicint_hw2reg_clicint_reg_t clicint; // [1:0] + } clicint_hw2reg_t; + + // Register offsets + parameter logic [BlockAw-1:0] CLICINT_CLICINT_OFFSET = 2'h 0; + + // Register index + typedef enum int { + CLICINT_CLICINT + } clicint_id_e; + + // Register width information to check illegal writes + parameter logic [3:0] CLICINT_PERMIT [1] = '{ + 4'b 1111 // index[0] CLICINT_CLICINT + }; + +endpackage + diff --git a/src/clicint_reg_top.sv b/src/clicint_reg_top.sv new file mode 100644 index 0000000..0ec8ae1 --- /dev/null +++ b/src/clicint_reg_top.sv @@ -0,0 +1,366 @@ +// 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 clicint_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 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 +); + + import clicint_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 clicint_ip_qs; + logic clicint_ip_wd; + logic clicint_ip_we; + logic clicint_ie_qs; + logic clicint_ie_wd; + logic clicint_ie_we; + logic clicint_attr_shv_qs; + logic clicint_attr_shv_wd; + logic clicint_attr_shv_we; + logic [1:0] clicint_attr_trig_qs; + logic [1:0] clicint_attr_trig_wd; + logic clicint_attr_trig_we; + logic [1:0] clicint_attr_mode_qs; + logic [1:0] clicint_attr_mode_wd; + logic clicint_attr_mode_we; + logic [7:0] clicint_ctl_qs; + logic [7:0] clicint_ctl_wd; + logic clicint_ctl_we; + + // Register instances + // R[clicint]: V(False) + + // F[ip]: 0:0 + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h0) + ) u_clicint_ip ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (clicint_ip_we), + .wd (clicint_ip_wd), + + // from internal hardware + .de (hw2reg.clicint.ip.de), + .d (hw2reg.clicint.ip.d ), + + // to internal hardware + .qe (), + .q (reg2hw.clicint.ip.q ), + + // to register interface (read) + .qs (clicint_ip_qs) + ); + + + // F[ie]: 7:7 + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h0) + ) u_clicint_ie ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (clicint_ie_we), + .wd (clicint_ie_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.clicint.ie.q ), + + // to register interface (read) + .qs (clicint_ie_qs) + ); + + + // F[attr_shv]: 16:16 + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h0) + ) u_clicint_attr_shv ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (clicint_attr_shv_we), + .wd (clicint_attr_shv_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.clicint.attr_shv.q ), + + // to register interface (read) + .qs (clicint_attr_shv_qs) + ); + + + // F[attr_trig]: 18:17 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_clicint_attr_trig ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (clicint_attr_trig_we), + .wd (clicint_attr_trig_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.clicint.attr_trig.q ), + + // to register interface (read) + .qs (clicint_attr_trig_qs) + ); + + + // F[attr_mode]: 23:22 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h3) + ) u_clicint_attr_mode ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (clicint_attr_mode_we), + .wd (clicint_attr_mode_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.clicint.attr_mode.q ), + + // to register interface (read) + .qs (clicint_attr_mode_qs) + ); + + + // F[ctl]: 31:24 + prim_subreg #( + .DW (8), + .SWACCESS("RW"), + .RESVAL (8'h0) + ) u_clicint_ctl ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (clicint_ctl_we), + .wd (clicint_ctl_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.clicint.ctl.q ), + + // to register interface (read) + .qs (clicint_ctl_qs) + ); + + + + + logic [0:0] addr_hit; + always_comb begin + addr_hit = '0; + addr_hit[0] = (reg_addr == CLICINT_CLICINT_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] & (|(CLICINT_PERMIT[0] & ~reg_be))))); + end + + assign clicint_ip_we = addr_hit[0] & reg_we & !reg_error; + assign clicint_ip_wd = reg_wdata[0]; + + assign clicint_ie_we = addr_hit[0] & reg_we & !reg_error; + assign clicint_ie_wd = reg_wdata[7]; + + assign clicint_attr_shv_we = addr_hit[0] & reg_we & !reg_error; + assign clicint_attr_shv_wd = reg_wdata[16]; + + assign clicint_attr_trig_we = addr_hit[0] & reg_we & !reg_error; + assign clicint_attr_trig_wd = reg_wdata[18:17]; + + assign clicint_attr_mode_we = addr_hit[0] & reg_we & !reg_error; + assign clicint_attr_mode_wd = reg_wdata[23:22]; + + assign clicint_ctl_we = addr_hit[0] & reg_we & !reg_error; + assign clicint_ctl_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[0] = clicint_ip_qs; + reg_rdata_next[7] = clicint_ie_qs; + reg_rdata_next[16] = clicint_attr_shv_qs; + reg_rdata_next[18:17] = clicint_attr_trig_qs; + reg_rdata_next[23:22] = clicint_attr_mode_qs; + reg_rdata_next[31:24] = clicint_ctl_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 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/gen/Makefile b/src/gen/Makefile index 2ab5d16..991694f 100644 --- a/src/gen/Makefile +++ b/src/gen/Makefile @@ -1,4 +1,4 @@ -# Copyright 2022 ETH Zurich +# Copyright 2023 ETH Zurich # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,34 +17,31 @@ # Generate C header and SystemVerilog files -ifndef $(REGTOOL) -REGTOOL=../../../register_interface/vendor/lowrisc_opentitan/util/regtool.py -endif -ifndef $(NUM_INTERRUPT) -NUM_INTERRUPT=256 -endif -ifndef $(CLICINTCTLBITSL) -CLICINTCTLBITS=8 -endif +REGTOOL = regtool.py -all: clic_reg_adapater.sv clic.hjson headers srcs +all: headers srcs -clic_reg_adapater.sv: clic_reg_adapter.sv.tpl - ./clic.py -s $(NUM_INTERRUPT) -c $(CLICINTCTLBITS) < $< > $@ +srcs: clicint_reg_pkg.sv clicint_reg_top.sv mclic_reg_pkg.sv mclic_reg_top.sv -srcs: clic_reg_pkg.sv clic_reg_top.sv +clicint_reg_pkg.sv clicint_reg_top.sv: clicint.hjson + $(REGTOOL) -r $< -t . -clic_reg_pkg.sv clic_reg_top.sv: clic.hjson - $(REGTOOL) -r clic.hjson -t . +mclic_reg_pkg.sv mclic_reg_top.sv: mclic.hjson + $(REGTOOL) -r $< -t . -clic.hjson: clic.hjson.tpl - ./clic.py < $< > $@ +headers: clic.h clicint.h -headers: clic.h +clic.h: mclic.hjson + $(REGTOOL) --cdefines mclic.hjson > $@ -clic.h: clic.hjson - $(REGTOOL) --cdefines clic.hjson > clic.h +clicint.h: clicint.hjson + $(REGTOOL) --cdefines clicint.hjson > $@ +.PHONY: install +install: + cp mclic_reg_pkg.sv mclic_reg_top.sv clicint_reg_pkg.sv clicint_reg_top.sv .. + +.PHONY: clean clean: - rm clic.h clic.hjson clic_reg_adapater.sv clic_reg_pkg.sv clic_reg_top.sv + rm clic.h mclic_reg_pkg.sv mclic_reg_top.sv clicint_reg_pkg.sv clicint_reg_top.sv diff --git a/src/gen/clic.hjson.tpl b/src/gen/clic.hjson.tpl deleted file mode 100644 index 3ca19c9..0000000 --- a/src/gen/clic.hjson.tpl +++ /dev/null @@ -1,111 +0,0 @@ -// 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 - -<% import math %>\ -# CLIC register template -# - src: Number of interrupt sources -{ - - name: "CLIC", - clock_primary: "clk_i", - bus_interfaces: [ - { protocol: "reg_iface", direction: "device" } - ], - - param_list: [ - { name: "NumSrc", - desc: "Number of interrupt sources", - type: "int", - default: "${src}", - local: "true" - }, - { name: "ClicIntCtlBits", - desc: "Number of interrupt control bits", - type: "int", - default: "${intctlbits}", - local: "true" - }, - ], - - regwidth: "32", - registers: [ - { name: "CLICCFG", - desc: "CLIC Configuration", - swaccess: "rw", - hwaccess: "hro", - fields: [ - //{ bits: "7", name: "reserved" }, - { bits: "6:5", name: "nmbits", desc: "number of privilege mode bits" }, - { bits: "4:1", name: "nlbits", desc: "number of interrupt level bits" }, - { bits: "0", name: "nvbits", - desc: "indicates whether selective hardware vectoring is supported" }, - ], - }, - { name: "CLICINFO", - desc: "CLIC Information", - swaccess: "ro", - hwaccess: "hro", - fields: [ - //{ bits: "31", name: "reserved" }, - { bits: "30:25", name: "num_trigger", - desc: "number of maximum interrupt triggers supported" }, - { bits: "24:21", name: "CLICINTCTLBITS", - desc: "number of bits implemented in clicintctl" }, - { bits: "20:13", name: "version", - desc: "archchitecture version [20:17] and implementation version [16:13]" }, - { bits: "12:0", name: "num_interrupt", - desc: "number of maximum interrupt inputs supported" }, - ], - }, - { skipto: "0x1000" } -% for i in range(src): - { name: "CLICINTIP${i}", - desc: "CLIC interrupt ${i} pending", - swaccess: "rw", - hwaccess: "hrw", - fields: [ - { bits: "0" } - ], - }, - { name: "CLICINTIE${i}", - desc: "CLIC interrupt ${i} enable", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "0" } - ], - }, - { name: "CLICINTATTR${i}", - desc: "CLIC interrupt ${i} attributes", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "7:6", name: "mode", - desc: "privilege mode of this interrupt" }, - //{ bits: "5:3", name: "reserved" }, - { bits: "2:1", name: "trig", - desc: "specify trigger type for this interrupt" }, - { bits: "0", name: "shv", - desc: "enable hardware vectoring for this interrupt" }, - ], - }, - { name: "CLICINTCTL${i}", - desc: "CLIC interrupt ${i} control", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "7:0" } - ], - }, -% endfor - ] -} diff --git a/src/gen/clic.py b/src/gen/clic.py index 5ff988c..04c115a 100755 --- a/src/gen/clic.py +++ b/src/gen/clic.py @@ -31,30 +31,13 @@ def main(): type=argparse.FileType('r'), default=sys.stdin, help='input template file') - parser.add_argument('--sources', - '-s', - type=int, - default=256, - help='Number of interrupt sources') - - parser.add_argument('--intctlbits', - '-c', - type=int, - default=8, - help='Number of interrupt control bits') args = parser.parse_args() - if args.intctlbits < 0 or args.intctlbits > 8: - print("ctlbits needs to be an integer n with 0 <= n <= 8", - file=sys.stderr) - exit(1) - out = StringIO() tpl = Template(args.input.read()) - out.write(tpl.render(src=args.sources, - intctlbits=args.intctlbits)) + out.write(tpl.render()) print(out.getvalue()) out.close() diff --git a/src/gen/clic_reg_adapter.sv.tpl b/src/gen/clic_reg_adapter.sv.tpl deleted file mode 100644 index 01c3998..0000000 --- a/src/gen/clic_reg_adapter.sv.tpl +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2022 ETH Zurich -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the 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 - -module clic_reg_adapter import clic_reg_pkg::*; #( - parameter int N_SOURCE = 32, - parameter int INTCTLBITS = 8 -)( - input logic clk_i, - input logic rst_ni, - - input clic_reg_pkg::clic_reg2hw_t reg2hw, - output clic_reg_pkg::clic_hw2reg_t hw2reg, - - output logic [7:0] intctl_o [N_SOURCE], - 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, - output logic [N_SOURCE-1:0] le_o, - - input logic [N_SOURCE-1:0] ip_i -); - - if (N_SOURCE != clic_reg_pkg::NumSrc) - $fatal(1, "CLIC misconfigured: clic_reg_pkg::NumSrc needs to match N_SOURCE"); - - if (INTCTLBITS != clic_reg_pkg::ClicIntCtlBits) - $fatal(1, "CLIC misconfigured: clic_reg_pkg::ClicIntCtlBits needs to match INTCTLBITS"); - - // We only support positive edge triggered and positive level triggered - // interrupts atm. Either we hardware the trig.q[1] bit correctly or we - // implement all modes -% for s in range(src): - assign intctl_o[${s}] = reg2hw.clicintctl${s}.q; - assign shv_o[${s}] = reg2hw.clicintattr${s}.shv.q; - assign ip_sw_o[${s}] = reg2hw.clicintip${s}.q; - assign ie_o[${s}] = reg2hw.clicintie${s}.q; - assign hw2reg.clicintip${s}.de = 1'b1; // Always write - assign hw2reg.clicintip${s}.d = ip_i[${s}]; - assign le_o[${s}] = reg2hw.clicintattr${s}.trig.q[0]; -% endfor - -endmodule // clic_reg_adapter diff --git a/src/gen/clicint.hjson b/src/gen/clicint.hjson new file mode 100644 index 0000000..f2fa0de --- /dev/null +++ b/src/gen/clicint.hjson @@ -0,0 +1,40 @@ +// 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 interrupt register +{ + name: "CLICINT", + clock_primary: "clk_i", + bus_interfaces: [ + { protocol: "reg_iface", direction: "device" } + ], + + regwidth: "32", + registers: [ + { name: "CLICINT", + desc: "CLIC interrupt pending, enable, attribute and control", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "31:24", name: "CTL", desc: "interrupt control for interrupt" }, + { bits: "23:22", name: "ATTR_MODE", desc: "privilege mode of this interrupt", resval: 3}, + //{ bits: "21:19", name: "reserved" }, + { bits: "18:17", name: "ATTR_TRIG", desc: "specify trigger type for this interrupt" }, + { bits: "16", name: "ATTR_SHV", desc: "enable hardware vectoring for this interrupt" }, + + { bits: "7", name: "IE", desc: "interrupt enable for interrupt" }, + + { bits: "0", name: "IP", desc: "interrupt pending for interrupt", hwaccess: "hrw" }, + ], + } + ] +} diff --git a/src/gen/mclic.hjson b/src/gen/mclic.hjson new file mode 100644 index 0000000..bd1b79a --- /dev/null +++ b/src/gen/mclic.hjson @@ -0,0 +1,39 @@ +// 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 m-mode registers +{ + name: "MCLIC", + clock_primary: "clk_i", + bus_interfaces: [ + { protocol: "reg_iface", direction: "device" } + ], + + regwidth: "32", + registers: [ + { name: "MCLICCFG", + desc: "CLIC configuration", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "31:28", name: "reserved", desc: "reserved", swaccess: "ro", hwaccess: "none" }, # workaround for full 32-bit access + { bits: "27:24", name: "unlbits", desc: "number of privilege mode bits in user mode" }, + //{ bits: "23:20", name: "reserved" }, + { bits: "19:16", name: "snlbits", desc: "number of privilege mode bits in supervisor mode" }, + //{ bits: "15:6", name: "reserved" }, + { bits: "5:4", name: "nmbits", desc: "number of privilege mode bits" }, + { bits: "3:0", name: "mnlbits", desc: "number of interrupt level bits in machine mode" }, + ], + }, + ] +} + diff --git a/src/mclic_reg_pkg.sv b/src/mclic_reg_pkg.sv new file mode 100644 index 0000000..a194e30 --- /dev/null +++ b/src/mclic_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 mclic_reg_pkg; + + // Address widths within the block + parameter int BlockAw = 2; + + //////////////////////////// + // Typedefs for registers // + //////////////////////////// + + typedef struct packed { + struct packed { + logic [3:0] q; + } mnlbits; + struct packed { + logic [1:0] q; + } nmbits; + struct packed { + logic [3:0] q; + } snlbits; + struct packed { + logic [3:0] q; + } unlbits; + } mclic_reg2hw_mcliccfg_reg_t; + + // Register -> HW type + typedef struct packed { + mclic_reg2hw_mcliccfg_reg_t mcliccfg; // [13:0] + } mclic_reg2hw_t; + + // Register offsets + parameter logic [BlockAw-1:0] MCLIC_MCLICCFG_OFFSET = 2'h 0; + + // Register index + typedef enum int { + MCLIC_MCLICCFG + } mclic_id_e; + + // Register width information to check illegal writes + parameter logic [3:0] MCLIC_PERMIT [1] = '{ + 4'b 1111 // index[0] MCLIC_MCLICCFG + }; + +endpackage + diff --git a/src/mclic_reg_top.sv b/src/mclic_reg_top.sv new file mode 100644 index 0000000..93560ed --- /dev/null +++ b/src/mclic_reg_top.sv @@ -0,0 +1,304 @@ +// 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 mclic_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 mclic_reg_pkg::mclic_reg2hw_t reg2hw, // Write + + + // Config + input devmode_i // If 1, explicit error return for unmapped register access +); + + import mclic_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 [3:0] mcliccfg_mnlbits_qs; + logic [3:0] mcliccfg_mnlbits_wd; + logic mcliccfg_mnlbits_we; + logic [1:0] mcliccfg_nmbits_qs; + logic [1:0] mcliccfg_nmbits_wd; + logic mcliccfg_nmbits_we; + logic [3:0] mcliccfg_snlbits_qs; + logic [3:0] mcliccfg_snlbits_wd; + logic mcliccfg_snlbits_we; + logic [3:0] mcliccfg_unlbits_qs; + logic [3:0] mcliccfg_unlbits_wd; + logic mcliccfg_unlbits_we; + logic [3:0] mcliccfg_reserved_qs; + + // Register instances + // R[mcliccfg]: V(False) + + // F[mnlbits]: 3:0 + prim_subreg #( + .DW (4), + .SWACCESS("RW"), + .RESVAL (4'h0) + ) u_mcliccfg_mnlbits ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (mcliccfg_mnlbits_we), + .wd (mcliccfg_mnlbits_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.mcliccfg.mnlbits.q ), + + // to register interface (read) + .qs (mcliccfg_mnlbits_qs) + ); + + + // F[nmbits]: 5:4 + prim_subreg #( + .DW (2), + .SWACCESS("RW"), + .RESVAL (2'h0) + ) u_mcliccfg_nmbits ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (mcliccfg_nmbits_we), + .wd (mcliccfg_nmbits_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.mcliccfg.nmbits.q ), + + // to register interface (read) + .qs (mcliccfg_nmbits_qs) + ); + + + // F[snlbits]: 19:16 + prim_subreg #( + .DW (4), + .SWACCESS("RW"), + .RESVAL (4'h0) + ) u_mcliccfg_snlbits ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (mcliccfg_snlbits_we), + .wd (mcliccfg_snlbits_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.mcliccfg.snlbits.q ), + + // to register interface (read) + .qs (mcliccfg_snlbits_qs) + ); + + + // F[unlbits]: 27:24 + prim_subreg #( + .DW (4), + .SWACCESS("RW"), + .RESVAL (4'h0) + ) u_mcliccfg_unlbits ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (mcliccfg_unlbits_we), + .wd (mcliccfg_unlbits_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.mcliccfg.unlbits.q ), + + // to register interface (read) + .qs (mcliccfg_unlbits_qs) + ); + + + // F[reserved]: 31:28 + // constant-only read + assign mcliccfg_reserved_qs = 4'h0; + + + + + logic [0:0] addr_hit; + always_comb begin + addr_hit = '0; + addr_hit[0] = (reg_addr == MCLIC_MCLICCFG_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] & (|(MCLIC_PERMIT[0] & ~reg_be))))); + end + + assign mcliccfg_mnlbits_we = addr_hit[0] & reg_we & !reg_error; + assign mcliccfg_mnlbits_wd = reg_wdata[3:0]; + + assign mcliccfg_nmbits_we = addr_hit[0] & reg_we & !reg_error; + assign mcliccfg_nmbits_wd = reg_wdata[5:4]; + + assign mcliccfg_snlbits_we = addr_hit[0] & reg_we & !reg_error; + assign mcliccfg_snlbits_wd = reg_wdata[19:16]; + + assign mcliccfg_unlbits_we = addr_hit[0] & reg_we & !reg_error; + assign mcliccfg_unlbits_wd = reg_wdata[27:24]; + + // Read data return + always_comb begin + reg_rdata_next = '0; + unique case (1'b1) + addr_hit[0]: begin + reg_rdata_next[3:0] = mcliccfg_mnlbits_qs; + reg_rdata_next[5:4] = mcliccfg_nmbits_qs; + reg_rdata_next[19:16] = mcliccfg_snlbits_qs; + reg_rdata_next[27:24] = mcliccfg_unlbits_qs; + reg_rdata_next[31:28] = mcliccfg_reserved_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 mclic_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 mclic_reg_pkg::mclic_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) + + + + mclic_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_files.yml b/src_files.yml index 136b35b..2bb5a92 100644 --- a/src_files.yml +++ b/src_files.yml @@ -16,11 +16,10 @@ clic: incdirs: - ../common_cells/include files: - # - src/gen/clic_reg_pkg.sv - # - src/gen/clic_reg_top.sv - # - src/gen/clic_reg_adapater.sv - - src/clic_reg_pkg.sv - - src/clic_reg_top.sv + - src/clicint_reg_pkg.sv + - src/clicint_reg_top.sv + - src/mclic_reg_pkg.sv + - src/mclic_reg_top.sv - src/clic_reg_adapter.sv - src/clic_gateway.sv - src/clic_target.sv