diff --git a/hw/mem_interface/src/mem_wide_narrow_mux.sv b/hw/mem_interface/src/mem_wide_narrow_mux.sv index 716393c8d4..381b862f6d 100644 --- a/hw/mem_interface/src/mem_wide_narrow_mux.sv +++ b/hw/mem_interface/src/mem_wide_narrow_mux.sv @@ -7,11 +7,9 @@ `include "common_cells/assertions.svh" -/// This module multiplexes many narrow ports and one wide port onto many narrow -/// ports. The wide or narrow ports can be selected by using the `sel_wide_i` signal. -/// -/// `1` selects the wide port. -/// `0` selects the narrow port. +/// This module multiplexes many narrow ports, one wide port, and one external port onto many narrow +/// ports. Arbitration is done statically: the wide port has the highest priority, +/// followed by the external port, and finally the narrow ports. /// /// ## Constraint /// @@ -21,7 +19,7 @@ /// ## Caution /// /// As of now this module's request always need an immediate grant in case -/// `sel_wide_i` is high. Any delayed grant will break the module's behavior. +/// `in_wide_req_i.q_valid` is high. Any delayed grant will break the module's behavior. module mem_wide_narrow_mux #( /// Width of narrow data. parameter int unsigned NarrowDataWidth = 0, @@ -50,11 +48,12 @@ module mem_wide_narrow_mux #( /// Wide side. input mem_wide_req_t in_wide_req_i, output mem_wide_rsp_t in_wide_rsp_o, + /// External side. + input mem_wide_req_t in_ext_req_i, + output mem_wide_rsp_t in_ext_rsp_o, // Multiplexed output. output mem_narrow_req_t [NrPorts-1:0] out_req_o, - input mem_narrow_rsp_t [NrPorts-1:0] out_rsp_i, - /// `0`: Use narrow port, `1`: Use wide port - input logic sel_wide_i + input mem_narrow_rsp_t [NrPorts-1:0] out_rsp_i ); localparam int unsigned NarrowStrbWidth = NarrowDataWidth/8; @@ -67,6 +66,7 @@ module mem_wide_narrow_mux #( // Broadcast data from all banks. for (int i = 0; i < NrPorts; i++) begin in_wide_rsp_o.p[i*NarrowDataWidth+:NarrowDataWidth] = out_rsp_i[i].p.data; + in_ext_rsp_o.p[i*NarrowDataWidth+:NarrowDataWidth] = out_rsp_i[i].p.data; end // --------------- @@ -74,11 +74,12 @@ module mem_wide_narrow_mux #( // --------------- // By default feed through narrow requests. out_req_o = in_narrow_req_i; - // Tie-off wide by default. + // Tie-off wide and ext by default. in_wide_rsp_o.q_ready = 1'b0; + in_ext_rsp_o.q_ready = 1'b0; - // The wide port is selected. - if (sel_wide_i) begin + // The wide port has the highest priority + if (in_wide_req_i.q_valid) begin for (int i = 0; i < NrPorts; i++) begin out_req_o[i].q_valid = in_wide_req_i.q_valid; // Block access from narrow ports. @@ -92,9 +93,25 @@ module mem_wide_narrow_mux #( user: in_wide_req_i.q.user }; // The protocol requires that the response is always granted - // immediately (at least when `sel_wide_i` is high). + // immediately (at least when `in_wide_req_i.q_valid` is high). in_wide_rsp_o.q_ready = 1'b1; end + end else if (in_ext_req_i.q_valid) begin // The ext port has the second highest priority + for (int i = 0; i < NrPorts; i++) begin + out_req_o[i].q_valid = in_ext_req_i.q_valid; + // Block access from narrow ports. + in_narrow_rsp_o[i].q_ready = 1'b0; + out_req_o[i].q = '{ + addr: in_ext_req_i.q.addr, + write: in_ext_req_i.q.write, + amo: reqrsp_pkg::AMONone, + data: in_ext_req_i.q.data[i*NarrowDataWidth+:NarrowDataWidth], + strb: in_ext_req_i.q.strb[i*NarrowStrbWidth+:NarrowStrbWidth], + user: in_ext_req_i.q.user + }; + + in_ext_rsp_o.q_ready = 1'b1; + end end end @@ -108,21 +125,23 @@ module mem_wide_narrow_mux #( logic [NrPorts-1:0] q_valid_flat; logic [NrPorts-1:0][NarrowDataWidth-1:0] q_data; logic [NrPorts-1:0][NarrowStrbWidth-1:0] q_strb; + // verilog_lint: waive-start line-length `ASSERT(ImmediateGrantWide, in_wide_req_i.q_valid |-> in_wide_rsp_o.q_ready) for (genvar i = 0; i < NrPorts; i++) begin : gen_per_port assign q_valid_flat[i] = out_req_o[i].q_valid; assign q_data[i] = out_req_o[i].q.data; assign q_strb[i] = out_req_o[i].q.strb; - `ASSERT(ImmediateGrantOut, sel_wide_i & out_req_o[i].q_valid |-> out_rsp_i[i].q_ready) - `ASSERT(SilentNarrow, sel_wide_i |-> !in_narrow_rsp_o[i].q_ready) - `ASSERT(NarrowPassThrough, !sel_wide_i & in_narrow_req_i[i].q_valid |-> out_req_o[i].q_valid) + `ASSERT(ImmediateGrantOut, in_wide_req_i.q_valid & out_req_o[i].q_valid |-> out_rsp_i[i].q_ready) + `ASSERT(SilentNarrow, in_wide_req_i.q_valid |-> !in_narrow_rsp_o[i].q_ready) + `ASSERT(NarrowPassThrough, !in_wide_req_i.q_valid & in_narrow_req_i[i].q_valid |-> out_req_o[i].q_valid) end - `ASSERT(DmaSelected, sel_wide_i & in_wide_req_i.q_valid |-> &q_valid_flat) + `ASSERT(DmaSelected, in_wide_req_i.q_valid & in_wide_req_i.q_valid |-> &q_valid_flat) `ASSERT(DmaSelectedReadyWhenValid, - sel_wide_i & in_wide_req_i.q_valid |-> in_wide_rsp_o.q_ready) + in_wide_req_i.q_valid & in_wide_req_i.q_valid |-> in_wide_rsp_o.q_ready) `ASSERT(DMAWriteDataCorrect, in_wide_req_i.q_valid & in_wide_rsp_o.q_ready |-> (in_wide_req_i.q.data == q_data) && (in_wide_req_i.q.strb == q_strb)) + // verilog_lint: waive-stop line-length endmodule @@ -151,10 +170,9 @@ module mem_wide_narrow_mux_intf #( /// Narrow side. MEM_BUS in_narrow [NrPorts], MEM_BUS in_wide, + MEM_BUS in_ext, // Output - MEM_BUS out [NrPorts], - /// `0`: Use narrow port, `1`: Use wide port - input logic sel_wide_i + MEM_BUS out [NrPorts] ); typedef logic [AddrWidth-1:0] addr_t; @@ -170,6 +188,8 @@ module mem_wide_narrow_mux_intf #( mem_narrow_rsp_t [NrPorts-1:0] in_narrow_rsp; mem_wide_req_t in_wide_req; mem_wide_rsp_t in_wide_rsp; + mem_wide_req_t in_ext_req; + mem_wide_rsp_t in_ext_rsp; mem_narrow_req_t [NrPorts-1:0] out_req; mem_narrow_rsp_t [NrPorts-1:0] out_rsp; @@ -190,9 +210,10 @@ module mem_wide_narrow_mux_intf #( .in_narrow_rsp_o (in_narrow_rsp), .in_wide_req_i (in_wide_req), .in_wide_rsp_o (in_wide_rsp), + .in_ext_req_i (in_ext_req), + .in_ext_rsp_o (in_ext_rsp), .out_req_o (out_req), - .out_rsp_i (out_rsp), - .sel_wide_i (sel_wide_i) + .out_rsp_i (out_rsp) ); for (genvar i = 0; i < NrPorts; i++) begin : gen_interface_assign @@ -205,4 +226,7 @@ module mem_wide_narrow_mux_intf #( `MEM_ASSIGN_TO_REQ(in_wide_req, in_wide) `MEM_ASSIGN_FROM_RESP(in_wide, in_wide_rsp) + `MEM_ASSIGN_TO_REQ(in_ext_req, in_ext) + `MEM_ASSIGN_FROM_RESP(in_ext, in_ext_rsp) + endmodule diff --git a/hw/mem_interface/test/mem_wide_narrow_mux_tb.sv b/hw/mem_interface/test/mem_wide_narrow_mux_tb.sv index 54f5bccac1..9bb49d976e 100644 --- a/hw/mem_interface/test/mem_wide_narrow_mux_tb.sv +++ b/hw/mem_interface/test/mem_wide_narrow_mux_tb.sv @@ -46,6 +46,18 @@ module mem_wide_narrow_mux_tb #( .user_t (logic) ) master_wide_dv (clk); + MEM_BUS #( + .ADDR_WIDTH ( AW ), + .DATA_WIDTH ( DW_WIDE ), + .user_t (logic) + ) master_ext (); + + MEM_BUS_DV #( + .ADDR_WIDTH ( AW ), + .DATA_WIDTH ( DW_WIDE ), + .user_t (logic) + ) master_ext_dv (clk); + MEM_BUS #( .ADDR_WIDTH ( AW ), .DATA_WIDTH ( DW_NARROW ), @@ -69,8 +81,8 @@ module mem_wide_narrow_mux_tb #( .rst_ni (rst_n), .in_narrow (master_narrow), .in_wide (master_wide), - .out (slave), - .sel_wide_i (master_wide.q_valid) + .in_ext (master_ext), + .out (slave) ); @@ -79,6 +91,7 @@ module mem_wide_narrow_mux_tb #( `MEM_ASSIGN(master_narrow[i], master_narrow_dv[i]) end `MEM_ASSIGN(master_wide, master_wide_dv) + `MEM_ASSIGN(master_ext, master_ext_dv) // ---------------- // Clock generation @@ -132,6 +145,15 @@ module mem_wide_narrow_mux_tb #( $finish; end + mem_rand_master_wide_t rand_mem_master_ext = new (master_ext_dv); + initial begin + rand_mem_master_ext.reset(); + @(posedge rst_n); + rand_mem_master_ext.run(NrRandomTransactions); + repeat(1000) @(posedge clk); + $finish; + end + typedef mem_test::rand_mem_slave #( .AW ( AW ), .DW ( DW_NARROW ), diff --git a/hw/snitch/src/snitch.sv b/hw/snitch/src/snitch.sv index 2c35dd1cfe..adc24b29b2 100644 --- a/hw/snitch/src/snitch.sv +++ b/hw/snitch/src/snitch.sv @@ -127,7 +127,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( logic interrupt, ecall, ebreak; logic zero_lsb; - logic meip, mtip, msip, mcip; + logic meip, mtip, msip, mcip, mxip; logic seip, stip, ssip, scip; logic interrupts_enabled; logic any_interrupt_pending; @@ -268,6 +268,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( logic [1:0] tie_d, tie_q; logic [1:0] sie_d, sie_q; logic [1:0] cie_d, cie_q; + logic [1:0] xie_d, xie_q; logic seip_d, seip_q; logic stip_d, stip_q; logic ssip_d, ssip_q; @@ -301,6 +302,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( `FFAR(tie_q, tie_d, '0, clk_i, rst_i) `FFAR(sie_q, sie_d, '0, clk_i, rst_i) `FFAR(cie_q, cie_d, '0, clk_i, rst_i) + `FFAR(xie_q, xie_d, '0, clk_i, rst_i) `FFAR(seip_q, seip_d, '0, clk_i, rst_i) `FFAR(stip_q, stip_d, '0, clk_i, rst_i) `FFAR(ssip_q, ssip_d, '0, clk_i, rst_i) @@ -2309,6 +2311,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( assign mtip = irq_i.mtip & tie_q[M]; assign msip = irq_i.msip & sie_q[M]; assign mcip = irq_i.mcip & cie_q[M]; + assign mxip = irq_i.mxip & xie_q[M]; assign seip = seip_q & eie_q[S]; assign stip = stip_q & tie_q[S]; @@ -2316,7 +2319,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( assign scip = scip_q & cie_q[S]; assign interrupts_enabled = ((priv_lvl_q == PrivLvlM) & ie_q[M]) || (priv_lvl_q != PrivLvlM); - assign any_interrupt_pending = meip | mtip | msip | mcip | seip | stip | ssip | scip; + assign any_interrupt_pending = meip | mtip | msip | mcip | mxip | seip | stip | ssip | scip; assign interrupt = interrupts_enabled & any_interrupt_pending; // CSR logic @@ -2346,6 +2349,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( tie_d = tie_q; sie_d = sie_q; cie_d = cie_q; + xie_d = xie_q; seip_d = seip_q; stip_d = stip_q; ssip_d = ssip_q; @@ -2476,6 +2480,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( csr_rvalue[MTI] = irq_i.mtip; csr_rvalue[MSI] = irq_i.msip; csr_rvalue[MCI] = irq_i.mcip; + csr_rvalue[MXI] = irq_i.mxip; csr_rvalue[SEI] = seip_q; csr_rvalue[STI] = stip_q; csr_rvalue[SSI] = ssip_q; @@ -2492,6 +2497,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( csr_rvalue[MTI] = tie_q[M]; csr_rvalue[MSI] = sie_q[M]; csr_rvalue[MCI] = cie_q[M]; + csr_rvalue[MXI] = xie_q[M]; csr_rvalue[SEI] = eie_q[S]; csr_rvalue[STI] = tie_q[S]; csr_rvalue[SSI] = sie_q[S]; @@ -2501,6 +2507,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( tie_d[M] = alu_result[MTI]; sie_d[M] = alu_result[MSI]; cie_d[M] = alu_result[MCI]; + xie_d[M] = alu_result[MXI]; eie_d[S] = alu_result[SEI]; tie_d[S] = alu_result[STI]; sie_d[S] = alu_result[SSI]; @@ -2629,6 +2636,7 @@ module snitch import snitch_pkg::*; import riscv_instr::*; #( else if (mtip) cause_d[M] = MTI; else if (msip) cause_d[M] = MSI; else if (mcip) cause_d[M] = MCI; + else if (mxip) cause_d[M] = MXI; else if (seip) cause_d[M] = SEI; else if (stip) cause_d[M] = STI; else if (ssip) cause_d[M] = SSI; diff --git a/hw/snitch/src/snitch_pkg.sv b/hw/snitch/src/snitch_pkg.sv index 6918a0a773..2dc09fc232 100644 --- a/hw/snitch/src/snitch_pkg.sv +++ b/hw/snitch/src/snitch_pkg.sv @@ -28,6 +28,8 @@ package snitch_pkg; logic msip; /// Machine cluster-local interrupt pending logic mcip; + /// Machine external accelerator interrupt pending + logic mxip; } interrupts_t; typedef enum logic [31:0] { @@ -117,6 +119,7 @@ package snitch_pkg; localparam logic [3:0] MTI = 7; localparam logic [3:0] MEI = 11; localparam logic [4:0] MCI = 19; + localparam logic [4:0] MXI = 20; localparam logic [3:0] SSI = 1; localparam logic [3:0] STI = 5; localparam logic [3:0] SEI = 9; @@ -126,7 +129,8 @@ package snitch_pkg; typedef enum integer { TCDM = 0, ClusterPeripherals = 1, - SoC = 2 + SoC = 2, + ExtSlave = 3 } cluster_slave_e; typedef enum integer { diff --git a/hw/snitch_cluster/src/snitch_cluster.sv b/hw/snitch_cluster/src/snitch_cluster.sv index c90145d0c5..602d8cff57 100644 --- a/hw/snitch_cluster/src/snitch_cluster.sv +++ b/hw/snitch_cluster/src/snitch_cluster.sv @@ -51,6 +51,9 @@ module snitch_cluster parameter int unsigned TCDMDepth = 1024, /// Zero memory address region size (in kB). parameter int unsigned ZeroMemorySize = 64, + /// External memory address region size (in kB). This is the address region + /// mapped to the `narrow_ext` port. + parameter int unsigned ExtMemorySize = 1, /// Bootrom memory address region size (in kB). parameter int unsigned BootRomSize = 4, /// Cluster peripheral address region size (in kB). @@ -161,6 +164,8 @@ module snitch_cluster parameter bit RegisterExtWide = 1'b0, /// Decouple narrow external AXI plug parameter bit RegisterExtNarrow = 1'b0, + // Decouple narrow exposed internal AXI plug + parameter bit RegisterExpNarrow = 1'b0, /// Insert Pipeline register into the FPU data path (request) parameter bit RegisterFPUReq = 1'b0, /// Insert Pipeline registers after sequencer @@ -189,6 +194,9 @@ module snitch_cluster parameter type wide_out_resp_t = logic, parameter type wide_in_req_t = logic, parameter type wide_in_resp_t = logic, + // TCDM Ports + parameter type tcdm_dma_req_t = logic, + parameter type tcdm_dma_rsp_t = logic, // Memory configuration input types; these vary depending on implementation. parameter type sram_cfg_t = logic, parameter type sram_cfgs_t = logic, @@ -228,6 +236,8 @@ module snitch_cluster /// another core to facilitate inter-processor-interrupts. This signal is /// assumed to be _async_. input logic [NrCores-1:0] msip_i, + // External interrupt pending. + input logic [NrCores-1:0] mxip_i, /// First hartid of the cluster. Cores of a cluster are monotonically /// increasing without a gap, i.e., a cluster with 8 cores and a /// `hart_base_id_i` of 5 get the hartids 5 - 12. @@ -253,7 +263,18 @@ module snitch_cluster input wide_out_resp_t wide_out_resp_i, /// AXI DMA cluster in-port. input wide_in_req_t wide_in_req_i, - output wide_in_resp_t wide_in_resp_o + output wide_in_resp_t wide_in_resp_o, + // An additional AXI Core cluster out-port, used e.g. to connect + // to the configuration interface of an external accelerator. + // Compared to the `narrow_out` interface, the address space of + // this port extends the cluster address space. We refer to the prior + // as an external AXI plug, and to this as an externally-exposed + // internal AXI plug. + output narrow_out_req_t narrow_ext_req_o, + input narrow_out_resp_t narrow_ext_resp_i, + // External TCDM ports + input tcdm_dma_req_t tcdm_ext_req_i, + output tcdm_dma_rsp_t tcdm_ext_resp_o ); // --------- // Constants @@ -284,7 +305,7 @@ module snitch_cluster localparam int unsigned NrNarrowMasters = 3; localparam int unsigned NarrowIdWidthOut = $clog2(NrNarrowMasters) + NarrowIdWidthIn; - localparam int unsigned NrSlaves = 3; + localparam int unsigned NrSlaves = 4; localparam int unsigned NrRuleIdcs = NrSlaves - 1; localparam int unsigned NrRules = (1 + AliasRegionEnable) * NrRuleIdcs; @@ -405,7 +426,6 @@ module snitch_cluster `MEM_TYPEDEF_ALL(mem_dma, tcdm_mem_addr_t, data_dma_t, strb_dma_t, logic) `TCDM_TYPEDEF_ALL(tcdm, tcdm_addr_t, data_t, strb_t, tcdm_user_t) - `TCDM_TYPEDEF_ALL(tcdm_dma, tcdm_addr_t, data_dma_t, strb_dma_t, logic) `REG_BUS_TYPEDEF_REQ(reg_req_t, addr_t, data_t, strb_t) `REG_BUS_TYPEDEF_RSP(reg_rsp_t, data_t) @@ -508,6 +528,10 @@ module snitch_cluster assign zero_mem_start_address = cluster_periph_end_address; assign zero_mem_end_address = cluster_periph_end_address + ZeroMemorySize * 1024; + addr_t ext_mem_start_address, ext_mem_end_address; + assign ext_mem_start_address = zero_mem_end_address; + assign ext_mem_end_address = ext_mem_start_address + ExtMemorySize * 1024; + localparam addr_t TCDMAliasStart = AliasRegionBase & TCDMMask; localparam addr_t TCDMAliasEnd = (TCDMAliasStart + TCDMSize) & TCDMMask; @@ -520,6 +544,9 @@ module snitch_cluster localparam addr_t ZeroMemAliasStart = PeriphAliasEnd; localparam addr_t ZeroMemAliasEnd = PeriphAliasEnd + ZeroMemorySize * 1024; + localparam addr_t ExtAliasStart = ZeroMemAliasEnd; + localparam addr_t ExtAliasEnd = ExtAliasStart + ExtMemorySize * 1024; + // ---------------- // Wire Definitions // ---------------- @@ -543,6 +570,9 @@ module snitch_cluster mem_dma_req_t [NrSuperBanks-1:0] sb_dma_req; mem_dma_rsp_t [NrSuperBanks-1:0] sb_dma_rsp; + mem_dma_req_t [NrSuperBanks-1:0] sb_ext_req; + mem_dma_rsp_t [NrSuperBanks-1:0] sb_ext_rsp; + // 3. Memory Subsystem (Interconnect) tcdm_dma_req_t ext_dma_req; tcdm_dma_rsp_t ext_dma_rsp; @@ -779,6 +809,26 @@ module snitch_cluster .mem_rsp_i (sb_dma_rsp) ); + snitch_tcdm_interconnect #( + .NumInp (1), + .NumOut (NrSuperBanks), + .tcdm_req_t (tcdm_dma_req_t), + .tcdm_rsp_t (tcdm_dma_rsp_t), + .mem_req_t (mem_dma_req_t), + .mem_rsp_t (mem_dma_rsp_t), + .user_t (logic), + .MemAddrWidth (TCDMMemAddrWidth), + .DataWidth (WideDataWidth), + .MemoryResponseLatency (MemoryMacroLatency) + ) i_ext_interconnect ( + .clk_i, + .rst_ni, + .req_i (tcdm_ext_req_i), + .rsp_o (tcdm_ext_resp_o), + .mem_req_o (sb_ext_req), + .mem_rsp_i (sb_ext_rsp) + ); + // ---------------- // Memory Subsystem // ---------------- @@ -801,9 +851,10 @@ module snitch_cluster .in_narrow_rsp_o (ic_rsp [i]), .in_wide_req_i (sb_dma_req [i]), .in_wide_rsp_o (sb_dma_rsp [i]), + .in_ext_req_i (sb_ext_req [i]), + .in_ext_rsp_o (sb_ext_rsp [i]), .out_req_o (amo_req), - .out_rsp_i (amo_rsp), - .sel_wide_i (sb_dma_req[i].q_valid) + .out_rsp_i (amo_rsp) ); // generate banks of the superbank @@ -932,6 +983,7 @@ module snitch_cluster sync #(.STAGES (2)) i_sync_msip (.clk_i, .rst_ni, .serial_i (msip_i[i]), .serial_o (irq.msip)); assign irq.mcip = cl_interrupt[i]; + assign irq.mxip = mxip_i[i]; tcdm_req_t [TcdmPorts-1:0] tcdm_req_wo_user; @@ -1206,6 +1258,11 @@ module snitch_cluster idx: ClusterPeripherals, start_addr: cluster_periph_start_address, end_addr: cluster_periph_end_address + }, + '{ + idx: ExtSlave, + start_addr: ext_mem_start_address, + end_addr: ext_mem_end_address } }; if (AliasRegionEnable) begin : gen_cluster_xbar_alias @@ -1219,6 +1276,11 @@ module snitch_cluster idx: ClusterPeripherals, start_addr: PeriphAliasStart, end_addr: PeriphAliasEnd + }, + '{ + idx: ExtSlave, + start_addr: ExtAliasStart, + end_addr: ExtAliasEnd } }; end @@ -1384,7 +1446,26 @@ module snitch_cluster .icache_events_i (icache_events) ); - // Optionally decouple the external narrow AXI master ports. + // Optionally decouple the externally-exposed internal AXI plug. + axi_cut #( + .Bypass ( !RegisterExpNarrow ), + .aw_chan_t ( axi_slv_aw_chan_t ), + .w_chan_t ( axi_slv_w_chan_t ), + .b_chan_t ( axi_slv_b_chan_t ), + .ar_chan_t ( axi_slv_ar_chan_t ), + .r_chan_t ( axi_slv_r_chan_t ), + .axi_req_t ( axi_slv_req_t ), + .axi_resp_t ( axi_slv_resp_t ) + ) i_cut_exp_narrow_mst ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .slv_req_i ( narrow_axi_slv_req[ExtSlave] ), + .slv_resp_o ( narrow_axi_slv_rsp[ExtSlave] ), + .mst_req_o ( narrow_ext_req_o ), + .mst_resp_i ( narrow_ext_resp_i ) + ); + + // Optionally decouple the external AXI plug. axi_cut #( .Bypass ( !RegisterExtNarrow ), .aw_chan_t ( axi_slv_aw_chan_t ), diff --git a/hw/snitch_cluster/src/snitch_cluster_pkg.sv.tpl b/hw/snitch_cluster/src/snitch_cluster_pkg.sv.tpl index aa1773b5f3..597479ce22 100644 --- a/hw/snitch_cluster/src/snitch_cluster_pkg.sv.tpl +++ b/hw/snitch_cluster/src/snitch_cluster_pkg.sv.tpl @@ -32,6 +32,7 @@ ${',' if not loop.last else ''} \ `include "axi/typedef.svh" +`include "tcdm_interface/typedef.svh" // verilog_lint: waive-start package-filename package ${cfg['cluster']['name']}_pkg; @@ -43,6 +44,7 @@ package ${cfg['cluster']['name']}_pkg; localparam int unsigned BootromSize = 4; // Fixed size of 4kB localparam int unsigned ClusterPeriphSize = ${cfg['cluster']['cluster_periph_size']}; localparam int unsigned ZeroMemorySize = ${cfg['cluster']['zero_mem_size']}; + localparam int unsigned ExtMemorySize = ${cfg['cluster']['ext_mem_size']}; localparam int unsigned AddrWidth = ${cfg['cluster']['addr_width']}; localparam int unsigned NarrowDataWidth = ${cfg['cluster']['data_width']}; @@ -66,6 +68,8 @@ package ${cfg['cluster']['name']}_pkg; localparam int unsigned Hive [NrCores] = '{${core_cfg('hive')}}; + localparam int unsigned TcdmAddrWidth = $clog2(TcdmSize*1024); + typedef struct packed { % for field, width in cfg['cluster']['sram_cfg_fields'].items(): logic [${width-1}:0] ${field}; @@ -95,6 +99,10 @@ package ${cfg['cluster']['name']}_pkg; `AXI_TYPEDEF_ALL(wide_in, addr_t, wide_in_id_t, data_dma_t, strb_dma_t, user_dma_t) `AXI_TYPEDEF_ALL(wide_out, addr_t, wide_out_id_t, data_dma_t, strb_dma_t, user_dma_t) + typedef logic [TcdmAddrWidth-1:0] tcdm_addr_t; + + `TCDM_TYPEDEF_ALL(tcdm_dma, tcdm_addr_t, data_dma_t, strb_dma_t, logic) + function automatic snitch_pma_pkg::rule_t [snitch_pma_pkg::NrMaxRules-1:0] get_cached_regions(); automatic snitch_pma_pkg::rule_t [snitch_pma_pkg::NrMaxRules-1:0] cached_regions; cached_regions = '{default: '0}; diff --git a/hw/snitch_cluster/src/snitch_cluster_wrapper.sv.tpl b/hw/snitch_cluster/src/snitch_cluster_wrapper.sv.tpl index d2501fe87b..407c6ce406 100644 --- a/hw/snitch_cluster/src/snitch_cluster_wrapper.sv.tpl +++ b/hw/snitch_cluster/src/snitch_cluster_wrapper.sv.tpl @@ -35,6 +35,7 @@ module ${cfg['cluster']['name']}_wrapper ( input logic [${cfg['cluster']['name']}_pkg::NrCores-1:0] meip_i, input logic [${cfg['cluster']['name']}_pkg::NrCores-1:0] mtip_i, input logic [${cfg['cluster']['name']}_pkg::NrCores-1:0] msip_i, + input logic [${cfg['cluster']['name']}_pkg::NrCores-1:0] mxip_i, input logic [9:0] hart_base_id_i, input logic [${cfg['cluster']['addr_width']-1}:0] cluster_base_addr_i, input logic clk_d2_bypass_i, @@ -46,7 +47,11 @@ module ${cfg['cluster']['name']}_wrapper ( output ${cfg['cluster']['name']}_pkg::wide_out_req_t wide_out_req_o, input ${cfg['cluster']['name']}_pkg::wide_out_resp_t wide_out_resp_i, input ${cfg['cluster']['name']}_pkg::wide_in_req_t wide_in_req_i, - output ${cfg['cluster']['name']}_pkg::wide_in_resp_t wide_in_resp_o + output ${cfg['cluster']['name']}_pkg::wide_in_resp_t wide_in_resp_o, + output ${cfg['cluster']['name']}_pkg::narrow_out_req_t narrow_ext_req_o, + input ${cfg['cluster']['name']}_pkg::narrow_out_resp_t narrow_ext_resp_i, + input ${cfg['cluster']['name']}_pkg::tcdm_dma_req_t tcdm_ext_req_i, + output ${cfg['cluster']['name']}_pkg::tcdm_dma_rsp_t tcdm_ext_resp_o ); localparam int unsigned NumIntOutstandingLoads [${cfg['cluster']['nr_cores']}] = '{${core_cfg('num_int_outstanding_loads')}}; @@ -79,10 +84,13 @@ module ${cfg['cluster']['name']}_wrapper ( .wide_out_resp_t (${cfg['cluster']['name']}_pkg::wide_out_resp_t), .wide_in_req_t (${cfg['cluster']['name']}_pkg::wide_in_req_t), .wide_in_resp_t (${cfg['cluster']['name']}_pkg::wide_in_resp_t), + .tcdm_dma_req_t (${cfg['cluster']['name']}_pkg::tcdm_dma_req_t), + .tcdm_dma_rsp_t (${cfg['cluster']['name']}_pkg::tcdm_dma_rsp_t), .NrHives (${cfg['cluster']['nr_hives']}), .NrCores (${cfg['cluster']['nr_cores']}), .TCDMDepth (${cfg['cluster']['tcdm']['depth']}), .ZeroMemorySize (snitch_cluster_pkg::ZeroMemorySize), + .ExtMemorySize (snitch_cluster_pkg::ExtMemorySize), .BootRomSize (snitch_cluster_pkg::BootromSize), .ClusterPeriphSize (snitch_cluster_pkg::ClusterPeriphSize), .NrBanks (${cfg['cluster']['tcdm']['banks']}), @@ -134,6 +142,7 @@ module ${cfg['cluster']['name']}_wrapper ( .RegisterTCDMCuts (${int(cfg['cluster']['timing']['register_tcdm_cuts'])}), .RegisterExtWide (${int(cfg['cluster']['timing']['register_ext_wide'])}), .RegisterExtNarrow (${int(cfg['cluster']['timing']['register_ext_narrow'])}), + .RegisterExpNarrow (${int(cfg['cluster']['timing']['register_exp_narrow'])}), .RegisterFPUReq (${int(cfg['cluster']['timing']['register_fpu_req'])}), .RegisterFPUIn (${int(cfg['cluster']['timing']['register_fpu_in'])}), .RegisterFPUOut (${int(cfg['cluster']['timing']['register_fpu_out'])}), @@ -163,6 +172,11 @@ module ${cfg['cluster']['name']}_wrapper ( .meip_i, .mtip_i, .msip_i, +% if cfg['cluster']['enable_external_interrupts']: + .mxip_i, +% else: + .mxip_i ('0), +% endif % if cfg['cluster']['cluster_base_expose']: .hart_base_id_i, .cluster_base_addr_i, @@ -179,7 +193,21 @@ module ${cfg['cluster']['name']}_wrapper ( .sram_cfgs_i (sram_cfgs_i), % else: .sram_cfgs_i (${cfg['cluster']['name']}_pkg::sram_cfgs_t'('0)), -%endif +% endif +% if cfg['cluster']['narrow_axi_port_expose']: + .narrow_ext_req_o (narrow_ext_req_o), + .narrow_ext_resp_i (narrow_ext_resp_i), +% else: + .narrow_ext_req_o (narrow_ext_req_o), + .narrow_ext_resp_i (${cfg['cluster']['name']}_pkg::narrow_out_resp_t'('0)), +% endif +% if cfg['cluster']['wide_tcdm_port_expose']: + .tcdm_ext_req_i (tcdm_ext_req_i), + .tcdm_ext_resp_o (tcdm_ext_resp_o), +% else: + .tcdm_ext_req_i (${cfg['cluster']['name']}_pkg::tcdm_dma_req_t'('0)), + .tcdm_ext_resp_o (tcdm_ext_resp_o), +% endif .narrow_in_req_i, .narrow_in_resp_o, .narrow_out_req_o, diff --git a/sw/deps/riscv-opcodes b/sw/deps/riscv-opcodes index 65a6a06f2a..22ad1fc4b7 160000 --- a/sw/deps/riscv-opcodes +++ b/sw/deps/riscv-opcodes @@ -1 +1 @@ -Subproject commit 65a6a06f2a6ffc107d1236eeaea045cf20706f0b +Subproject commit 22ad1fc4b7526fb1486810ee84c98724f754b343 diff --git a/target/snitch_cluster/test/testharness.sv b/target/snitch_cluster/test/testharness.sv index 4a99c23a34..b4087fc765 100644 --- a/target/snitch_cluster/test/testharness.sv +++ b/target/snitch_cluster/test/testharness.sv @@ -20,7 +20,7 @@ module testharness; wide_out_resp_t wide_out_resp; wide_in_req_t wide_in_req; wide_in_resp_t wide_in_resp; - logic [snitch_cluster_pkg::NrCores-1:0] msip, meip, mtip; + logic [snitch_cluster_pkg::NrCores-1:0] msip, meip, mtip, mxip; snitch_cluster_wrapper i_snitch_cluster ( .clk_i (clk), @@ -29,6 +29,7 @@ module testharness; .meip_i (meip), .mtip_i (mtip), .msip_i (msip), + .mxip_i (mxip), .hart_base_id_i (CfgBaseHartId), .cluster_base_addr_i (CfgClusterBaseAddr), .clk_d2_bypass_i (1'b0), @@ -44,7 +45,11 @@ module testharness; .wide_out_req_o (wide_out_req), .wide_out_resp_i (wide_out_resp), .wide_in_req_i (wide_in_req), - .wide_in_resp_o (wide_in_resp) + .wide_in_resp_o (wide_in_resp), + .narrow_ext_req_o (), + .narrow_ext_resp_i ('0), + .tcdm_ext_req_i ('0), + .tcdm_ext_resp_o () ); /////////// @@ -53,7 +58,22 @@ module testharness; vip_snitch_cluster #( .ClkPeriod(1ns) - ) vip (.*); + ) vip ( + .clk, + .rst_n, + .msip, + .meip, + .mtip, + .mxip, + .narrow_in_req, + .narrow_in_resp, + .narrow_out_req, + .narrow_out_resp, + .wide_in_req, + .wide_in_resp, + .wide_out_req, + .wide_out_resp + ); initial begin // Wait for the reset diff --git a/target/snitch_cluster/test/vip_snitch_cluster.sv b/target/snitch_cluster/test/vip_snitch_cluster.sv index b061f3c73e..39ae285882 100644 --- a/target/snitch_cluster/test/vip_snitch_cluster.sv +++ b/target/snitch_cluster/test/vip_snitch_cluster.sv @@ -14,6 +14,7 @@ module vip_snitch_cluster output logic [NrCores-1:0] msip, output logic [NrCores-1:0] meip, output logic [NrCores-1:0] mtip, + output logic [NrCores-1:0] mxip, // AXI interfaces output narrow_in_req_t narrow_in_req, input narrow_in_resp_t narrow_in_resp, @@ -71,6 +72,7 @@ module vip_snitch_cluster // Tie-off unused input ports. assign mtip = '0; assign meip = '0; + assign mxip = '0; assign wide_in_req = '0; // Narrow port into simulation memory. diff --git a/util/clustergen/schema/snitch_cluster.schema.json b/util/clustergen/schema/snitch_cluster.schema.json index 75f2579851..e8c5776ea9 100644 --- a/util/clustergen/schema/snitch_cluster.schema.json +++ b/util/clustergen/schema/snitch_cluster.schema.json @@ -93,6 +93,15 @@ 64 ] }, + "ext_mem_size": { + "type": "number", + "description": "Address region size reserved for an external slave in KiByte.", + "default": 1, + "examples": [ + 2, + 4 + ] + }, "alias_region_enable": { "type": "boolean", "description": "Whether to provide a hardwired alias region for the TCDM (and cluster) address space.", @@ -213,6 +222,21 @@ "description": "Whether to expose memory cut configuration inputs for implementation", "default": false }, + "wide_tcdm_port_expose": { + "type": "boolean", + "description": "Whether to expose a wide port into the TCDM at the cluster interface. Used to provide external masters, such as accelerators, with wide access to the TCDM.", + "default": false + }, + "narrow_axi_port_expose": { + "type": "boolean", + "description": "Whether to expose a narrow AXI master port at the cluster interface. Used to provide a narrow interface to external slaves, e.g. to configure external accelerators.", + "default": false + }, + "enable_external_interrupts": { + "type": "boolean", + "description": "Whether to enable external interrupts", + "default": false + }, "sram_cfg_fields": { "type": "object", "description": "The names and widths of memory cut configuration inputs needed for implementation", @@ -308,6 +332,11 @@ "description": "Decouple narrow external AXI plug.", "default": false }, + "register_exp_narrow": { + "type": "boolean", + "description": "Decouple narrow exposed AXI plug.", + "default": false + }, "register_sequencer": { "type": "boolean", "description": "Insert Pipeline registers after sequencer.",