diff --git a/src/clic.sv b/src/clic.sv index 044da34..be98f3b 100644 --- a/src/clic.sv +++ b/src/clic.sv @@ -56,6 +56,7 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( localparam logic [1:0] M_MODE = 2'b11; localparam logic [15:0] MCLICCFG_START = 16'h0000; + localparam logic [15:0] MCLICCFG_END = 16'h0800; localparam logic [15:0] MCLICINT_START = 16'h1000; localparam logic [15:0] MCLICINT_END = 16'h4fff; @@ -81,6 +82,7 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( 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 #( @@ -123,7 +125,9 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( .irq_mode_o (irq_mode), .irq_kill_req_o, - .irq_kill_ack_i + .irq_kill_ack_i, + + .mnxti_cfg_i (mnxti_cfg) ); // configuration registers @@ -198,7 +202,7 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( reg_rsp_o = '0; unique case(reg_req_i.addr[15:0]) inside - MCLICCFG_START: begin + [MCLICCFG_START:MCLICCFG_END]: begin reg_mclic_req = reg_req_i; reg_rsp_o = reg_mclic_rsp; end @@ -261,7 +265,8 @@ module clic import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( .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 70008f4..5397b97 100644 --- a/src/clic_reg_adapter.sv +++ b/src/clic_reg_adapter.sv @@ -33,7 +33,8 @@ module clic_reg_adapter import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( 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 @@ -50,4 +51,6 @@ module clic_reg_adapter import mclic_reg_pkg::*; import clicint_reg_pkg::*; #( assign le_o[i] = clicint_reg2hw[i].clicint.attr_trig.q[0]; 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 e680049..ffb58b6 100644 --- a/src/clic_target.sv +++ b/src/clic_target.sv @@ -55,7 +55,8 @@ module clic_target #( output logic [ModeWidth-1:0] irq_mode_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 @@ -185,9 +186,19 @@ 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; + irq_mode_d = irq_mode_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,