diff --git a/Bender.yml b/Bender.yml index 9f0f6e86..c5b2e651 100644 --- a/Bender.yml +++ b/Bender.yml @@ -32,7 +32,7 @@ dependencies: idma : { git: "https://github.com/FondazioneChipsIT/iDMA.git" , rev: 26ac2cd1c535851b14c9c508762203a180961cad } # branch: cc/mcast_magia hwpe-stream : { git: "https://github.com/pulp-platform/hwpe-stream.git" , version: 1.6 } hwpe-ctrl : { git: "https://github.com/pulp-platform/hwpe-ctrl.git" , version: 3.1.1 } - hci : { git: "https://github.com/pulp-platform/hci.git" , version: 2.3.0 } + hci : { git: "https://github.com/pulp-platform/hci.git" , version: 2.6.1 } cluster_icache : { git: "https://github.com/pulp-platform/cluster_icache.git" , version: 0.2.0 } fpnew : { git: "https://github.com/pulp-platform/cvfpu.git" , rev: "pulp-v0.1.3" } fpu_ss : { git: "https://github.com/pulp-platform/fpu_ss.git" , rev: f31c77c7517c0a67f2c55a290fc8c6ff6019e362 } # branch: lb/cv32e40x_fpu @@ -81,13 +81,14 @@ sources: - hw/tile/magia_event_unit.sv - hw/tile/obi_demux_addr.sv - hw/tile/l1_spm.sv - - hw/tile/local_interconnect.sv + - hw/tile/magia_hci_interconnect.sv - hw/tile/idma_axi_obi_transfer_ch.sv - hw/tile/idma_obi_ctrl_decoder.sv - hw/tile/idma_ctrl_mm.sv - hw/tile/obi_slave_fsync.sv - hw/tile/obi_slave_ctrl_spatz.sv - hw/tile/obi_slave_ctrl_cluster.sv + - hw/tile/obi_slave_ctrl_hci.sv - hw/tile/spatz_bootrom.sv - hw/tile/spatz_cc_wrapper.sv - hw/tile/core_data_demux.sv diff --git a/README.md b/README.md index 6efd50a2..2bae4a2e 100644 --- a/README.md +++ b/README.md @@ -273,7 +273,8 @@ Private map: the same range in every tile, each tile maps it to its own copy: | *FractalSync CTRL*| `0x0000_0600-0x0000_06FF` | | *Ctrl-core Event Unit* | `0x0000_0700-0x0000_16FF` | | *Spatz CTRL* | `0x0000_1700-0x0000_173F` | -| *PULP CTRL* | `0x0000_1740-0x0000_17FF` | +| *PULP CTRL* | `0x0000_1740-0x0000_17BF` | +| *HCI CTRL* | `0x0000_17C0-0x0000_17FF` | | *Collective CTRL* | `0x0000_1800-0x0000_18FF` | | *Cluster Event Unit (direct)* | `0x0000_1900-0x0000_28FF` | | *Cluster Event Unit (SoC-side)* | `0x0000_2900-0x0000_38FF` | diff --git a/hw/mesh/magia_pkg.sv b/hw/mesh/magia_pkg.sv index d3dfdfc5..28540035 100644 --- a/hw/mesh/magia_pkg.sv +++ b/hw/mesh/magia_pkg.sv @@ -75,6 +75,7 @@ package magia_pkg; int unsigned Height; // Systolic array height int unsigned Width; // Systolic array width int unsigned NumPipeRegs; // Pipeline registers in the systolic array + bit MisalignedAccess; // TCDM accesses off the bank word, at the cost of one more bank on the HCI port } redmule_cfg_t; typedef struct packed { @@ -131,9 +132,10 @@ package magia_pkg; }; localparam redmule_cfg_t MagiaRedMuleDefaultCfg = '{ - Height: 8, - Width: 8, - NumPipeRegs: 1 + Height: 8, + Width: 8, + NumPipeRegs: 1, + MisalignedAccess: 1'b1 }; // Derived from the MAGIA Makefile (Reflects on spatz_pkg.sv in spatz_cluster dep) diff --git a/hw/tile/local_interconnect.sv b/hw/tile/local_interconnect.sv deleted file mode 100644 index 68a190ba..00000000 --- a/hw/tile/local_interconnect.sv +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (C) 2023-2024 ETH Zurich and University of Bologna - * - * 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 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: SHL-0.51 - * - * Authors: Victor Isachi - * - * MAGIA Tile Local Interconnect - */ - -`include "hci_helpers.svh" - -module local_interconnect - import hci_package::*; - import magia_tile_pkg::*; - import magia_pkg::*; -#( - parameter int unsigned N_HWPE = magia_tile_pkg::N_HWPE, - parameter int unsigned N_DMA = magia_tile_pkg::N_DMA, - parameter int unsigned N_CORE = magia_tile_pkg::N_CORE, - parameter int unsigned N_MEM = magia_pkg::N_MEM_BANKS, - parameter int unsigned EXPFIFO = magia_tile_pkg::EXPFIFO, - parameter int unsigned FILTER_WRITE_R_VALID[0:((N_HWPE > N_DMA ? N_HWPE : N_DMA) > N_CORE ? - (N_HWPE > N_DMA ? N_HWPE : N_DMA) : N_CORE)-1] = - '{default: 0}, - parameter int unsigned MEM_DATA_W = 0, - parameter int unsigned MEM_ADDR_W = 0, - parameter int unsigned MEM_BYTE_W = 0, - parameter int unsigned MEM_USER_W = 0, - parameter int unsigned MEM_ID_W = 0, - parameter hci_size_parameter_t `HCI_SIZE_PARAM(hwpe) = '0, - parameter hci_size_parameter_t `HCI_SIZE_PARAM(dma) = '0, - parameter hci_size_parameter_t `HCI_SIZE_PARAM(core) = '0, - parameter hci_size_parameter_t `HCI_SIZE_PARAM(mem) = '0 -) ( - input logic clk_i, - input logic rst_ni, - - input logic clear_i, - input hci_package::hci_interconnect_ctrl_t ctrl_i, - - hci_core_intf.target hwpe[N_HWPE], - hci_core_intf.target dma [N_DMA], - hci_core_intf.target core[N_CORE], - hci_core_intf.initiator mem [N_MEM] -); - -/*******************************************************/ -/** Parameter and Interface Definitions Beginning **/ -/*******************************************************/ - - localparam hci_size_parameter_t `HCI_SIZE_PARAM(hwpe_mem) = '{ - DW: MEM_DATA_W, - AW: MEM_ADDR_W, - BW: MEM_BYTE_W, - UW: MEM_USER_W, - IW: MEM_ID_W, - EW: hci_package::DEFAULT_EW, - EHW: hci_package::DEFAULT_EHW - }; - `HCI_INTF_ARRAY(hwpe_mem, clk_i, 0:N_HWPE*N_MEM-1); - - localparam hci_size_parameter_t `HCI_SIZE_PARAM(hwpe_mem_muxed) = '{ - DW: MEM_DATA_W, - AW: MEM_ADDR_W, - BW: MEM_BYTE_W, - UW: MEM_USER_W, - IW: MEM_ID_W, - EW: hci_package::DEFAULT_EW, - EHW: hci_package::DEFAULT_EHW - }; - `HCI_INTF_ARRAY(hwpe_mem_muxed, clk_i, 0:N_MEM-1); - - localparam hci_size_parameter_t `HCI_SIZE_PARAM(dma_mem) = '{ - DW: MEM_DATA_W, - AW: MEM_ADDR_W, - BW: MEM_BYTE_W, - UW: MEM_USER_W, - IW: MEM_ID_W, - EW: hci_package::DEFAULT_EW, - EHW: hci_package::DEFAULT_EHW - }; - `HCI_INTF_ARRAY(dma_mem, clk_i, 0:N_DMA*N_MEM-1); - - localparam hci_size_parameter_t `HCI_SIZE_PARAM(dma_mem_muxed) = '{ - DW: MEM_DATA_W, - AW: MEM_ADDR_W, - BW: MEM_BYTE_W, - UW: MEM_USER_W, - IW: MEM_ID_W, - EW: hci_package::DEFAULT_EW, - EHW: hci_package::DEFAULT_EHW - }; - `HCI_INTF_ARRAY(dma_mem_muxed, clk_i, 0:N_MEM-1); - - localparam hci_size_parameter_t `HCI_SIZE_PARAM(hwpe_dma_mem_muxed) = '{ - DW: MEM_DATA_W, - AW: MEM_ADDR_W, - BW: MEM_BYTE_W, - UW: MEM_USER_W, - IW: MEM_ID_W, - EW: hci_package::DEFAULT_EW, - EHW: hci_package::DEFAULT_EHW - }; - `HCI_INTF_ARRAY(hwpe_dma_mem_muxed, clk_i, 0:N_MEM-1); - - localparam hci_size_parameter_t `HCI_SIZE_PARAM(core_mem) = '{ - DW: MEM_DATA_W, - AW: MEM_ADDR_W, - BW: MEM_BYTE_W, - UW: MEM_USER_W, - IW: MEM_ID_W, - EW: hci_package::DEFAULT_EW, - EHW: hci_package::DEFAULT_EHW - }; - `HCI_INTF_ARRAY(core_mem, clk_i, 0:N_CORE*N_MEM-1); - - localparam hci_size_parameter_t `HCI_SIZE_PARAM(core_mem_muxed) = '{ - DW: MEM_DATA_W, - AW: MEM_ADDR_W, - BW: MEM_BYTE_W, - UW: MEM_USER_W, - IW: MEM_ID_W, - EW: hci_package::DEFAULT_EW, - EHW: hci_package::DEFAULT_EHW - }; - `HCI_INTF_ARRAY(core_mem_muxed, clk_i, 0:N_MEM-1); - -/*******************************************************/ -/** Parameter and Interface Definitions End **/ -/*******************************************************/ -/** HWPE Routing and Arbitration Beginning **/ -/*******************************************************/ - - for(genvar i = 0; i < N_HWPE; i++) begin : gen_hwpe_req2mem - hci_router #( - .FIFO_DEPTH ( EXPFIFO ), - .NB_OUT_CHAN ( N_MEM ), - .FILTER_WRITE_R_VALID ( FILTER_WRITE_R_VALID[i] ), - .`HCI_SIZE_PARAM(in) ( `HCI_SIZE_PARAM(hwpe) ), - .`HCI_SIZE_PARAM(out) ( `HCI_SIZE_PARAM(hwpe_mem) ) - ) i_hwpe_router ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clear_i ( clear_i ), - .in ( hwpe[i] ), - .out ( hwpe_mem[i*N_MEM:(i+1)*N_MEM-1] ) - ); - end - - // The trees' inner nodes re-arbitrate while not granted: internal signals, not protocol ports - hci_arbiter_tree #( - .NB_REQUESTS ( N_HWPE ), - .NB_CHAN ( N_MEM ), - .`HCI_SIZE_PARAM(out) ( `HCI_SIZE_PARAM(hwpe_mem_muxed) ), - .WAIVE_RQ3_ASSERT ( 1'b1 ), - .WAIVE_RQ4_ASSERT ( 1'b1 ) - ) i_hwpe_wide_port_arbiter_tree ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clear_i ( clear_i ), - .ctrl_i ( ctrl_i ), - .in ( hwpe_mem ), - .out ( hwpe_mem_muxed ) - ); - -/*******************************************************/ -/** HWPE Routing and Arbitration End **/ -/*******************************************************/ -/** DMA Routing and Arbitration Beginning **/ -/*******************************************************/ - - for(genvar i = 0; i < N_DMA; i++) begin : gen_dma_req2mem - hci_router #( - .FIFO_DEPTH ( EXPFIFO ), - .NB_OUT_CHAN ( N_MEM ), - .FILTER_WRITE_R_VALID ( FILTER_WRITE_R_VALID[i] ), - .`HCI_SIZE_PARAM(in) ( `HCI_SIZE_PARAM(dma) ), - .`HCI_SIZE_PARAM(out) ( `HCI_SIZE_PARAM(dma_mem) ) - ) i_dma_router ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clear_i ( clear_i ), - .in ( dma[i] ), - .out ( dma_mem[i*N_MEM:(i+1)*N_MEM-1] ) - ); - end - - hci_arbiter_tree #( - .NB_REQUESTS ( N_DMA ), - .NB_CHAN ( N_MEM ), - .`HCI_SIZE_PARAM(out) ( `HCI_SIZE_PARAM(dma_mem_muxed) ), - .WAIVE_RQ3_ASSERT ( 1'b1 ), - .WAIVE_RQ4_ASSERT ( 1'b1 ) - ) i_dma_wide_port_arbiter_tree ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clear_i ( clear_i ), - .ctrl_i ( ctrl_i ), - .in ( dma_mem ), - .out ( dma_mem_muxed ) - ); - -/*******************************************************/ -/** DMA Routing and Arbitration End **/ -/*******************************************************/ -/** HWPE and DMA Arbitration Beginning **/ -/*******************************************************/ - - hci_arbiter #( - .NB_CHAN ( N_MEM ) - ) i_hwpe_vs_dma_arbiter ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clear_i ( clear_i ), - .ctrl_i ( ctrl_i ), - .in_high ( hwpe_mem_muxed ), - .in_low ( dma_mem_muxed ), - .out ( hwpe_dma_mem_muxed ) - ); - -/*******************************************************/ -/** HWPE and DMA Arbitration End **/ -/*******************************************************/ -/** Core Routing and Arbitration Beginning **/ -/*******************************************************/ - - for(genvar i = 0; i < N_CORE; i++) begin : gen_core_req2mem - hci_router #( - .FIFO_DEPTH ( EXPFIFO ), - .NB_OUT_CHAN ( N_MEM ), - .FILTER_WRITE_R_VALID ( FILTER_WRITE_R_VALID[i] ), - .`HCI_SIZE_PARAM(in) ( `HCI_SIZE_PARAM(core) ), - .`HCI_SIZE_PARAM(out) ( `HCI_SIZE_PARAM(core_mem) ) - ) i_core_router ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clear_i ( clear_i ), - .in ( core[i] ), - .out ( core_mem[i*N_MEM:(i+1)*N_MEM-1] ) - ); - end - - hci_arbiter_tree #( - .NB_REQUESTS ( N_CORE ), - .NB_CHAN ( N_MEM ), - .`HCI_SIZE_PARAM(out) ( `HCI_SIZE_PARAM(core_mem_muxed) ), - .WAIVE_RQ3_ASSERT ( 1'b1 ), - .WAIVE_RQ4_ASSERT ( 1'b1 ) - ) i_core_wide_port_arbiter_tree ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clear_i ( clear_i ), - .ctrl_i ( ctrl_i ), - .in ( core_mem ), - .out ( core_mem_muxed ) - ); - -/*******************************************************/ -/** Core Routing and Arbitration End **/ -/*******************************************************/ -/** HWPE/DMA and Core Arbitration Beginning **/ -/*******************************************************/ - - hci_arbiter #( - .NB_CHAN ( N_MEM ) - ) i_wide_vs_narrow_arbiter ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clear_i ( clear_i ), - .ctrl_i ( ctrl_i ), - .in_high ( hwpe_dma_mem_muxed ), - .in_low ( core_mem_muxed ), - .out ( mem ) - ); - -/*******************************************************/ -/** HWPE/DMA and Core Arbitration End **/ -/*******************************************************/ - -endmodule: local_interconnect diff --git a/hw/tile/magia_hci_interconnect.sv b/hw/tile/magia_hci_interconnect.sv new file mode 100644 index 00000000..6b651349 --- /dev/null +++ b/hw/tile/magia_hci_interconnect.sv @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2023-2026 ETH Zurich, University of Bologna and Fondazione Chips-IT + * + * 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 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: SHL-0.51 + * + * Authors: Victor Isachi + * Luca Balboni, Fondazione Chips-IT + * + * MAGIA HCI interconnect: wide ports on an arbiter tree, narrow ports on the log interconnect + */ + +`include "hci_helpers.svh" + +module magia_hci_interconnect + import hci_package::*; +#( + parameter int unsigned NumHwpe = magia_tile_pkg::N_HWPE, + parameter int unsigned NumDma = magia_tile_pkg::N_DMA, + parameter int unsigned NumCore = magia_tile_pkg::N_CORE, + parameter int unsigned NumMem = magia_pkg::N_MEM_BANKS, + parameter int unsigned RouterFifoDepth = magia_tile_pkg::EXPFIFO, + parameter bit WaiveRq3Assert = 1'b0, + parameter bit WaiveRq4Assert = 1'b0, + parameter hci_size_parameter_t `HCI_SIZE_PARAM(hwpe) = '0, + parameter hci_size_parameter_t `HCI_SIZE_PARAM(dma) = '0, + parameter hci_size_parameter_t `HCI_SIZE_PARAM(core) = '0, + parameter hci_size_parameter_t `HCI_SIZE_PARAM(mem) = '0, + // Interface arrays cannot be zero-sized + localparam int unsigned NumHwpePort = (NumHwpe > 0) ? NumHwpe : 1 +) ( + input logic clk_i, + input logic rst_ni, + + input logic clear_i, + input hci_package::hci_interconnect_ctrl_t ctrl_i, + + hci_core_intf.target hwpe[NumHwpePort], + hci_core_intf.target dma [NumDma], + hci_core_intf.target core[NumCore], + hci_core_intf.initiator mem [NumMem] +); + +/*******************************************************/ +/** Parameter and Interface Definitions Beginning **/ +/*******************************************************/ + + localparam int unsigned NumWide = NumHwpe + NumDma; + + // Bank address width of the narrow LIC, in words + localparam int unsigned LicBankAddrW = `HCI_SIZE_GET_AW(mem) - + $clog2(`HCI_SIZE_GET_DW(mem) / `HCI_SIZE_GET_BW(mem)); + + localparam hci_size_parameter_t `HCI_SIZE_PARAM(wide_mem) = `HCI_SIZE_PARAM(mem); + + // hci_log_interconnect keeps the core address width on its bank side + localparam hci_size_parameter_t `HCI_SIZE_PARAM(lic_mem) = '{ + DW: `HCI_SIZE_GET_DW(mem), + AW: `HCI_SIZE_GET_AW(core), + BW: `HCI_SIZE_GET_BW(mem), + UW: `HCI_SIZE_GET_UW(mem), + IW: `HCI_SIZE_GET_IW(mem), + EW: `HCI_SIZE_GET_EW(mem), + EHW: `HCI_SIZE_GET_EHW(mem) + }; + + // The control core always sits on the narrow branch + if (NumCore == 0) begin : gen_no_core_error + $fatal(1, "magia_hci_interconnect: NumCore must be >= 1"); + end + + // LIC bank side: re-arbitrated while not granted, internal signals, not protocol ports + hci_core_intf #( + .DW ( `HCI_SIZE_GET_DW(lic_mem) ), + .AW ( `HCI_SIZE_GET_AW(lic_mem) ), + .BW ( `HCI_SIZE_GET_BW(lic_mem) ), + .UW ( `HCI_SIZE_GET_UW(lic_mem) ), + .IW ( `HCI_SIZE_GET_IW(lic_mem) ), + .EW ( `HCI_SIZE_GET_EW(lic_mem) ), + .EHW ( `HCI_SIZE_GET_EHW(lic_mem) ) +`ifndef SYNTHESIS + , + .WAIVE_RQ3_ASSERT ( WaiveRq3Assert ), + .WAIVE_RQ4_ASSERT ( WaiveRq4Assert ) +`endif + ) lic_mem [0:NumMem-1] ( + .clk ( clk_i ) + ); + + hci_core_intf #( + .DW ( `HCI_SIZE_GET_DW(mem) ), + .AW ( `HCI_SIZE_GET_AW(mem) ), + .BW ( `HCI_SIZE_GET_BW(mem) ), + .UW ( `HCI_SIZE_GET_UW(mem) ), + .IW ( `HCI_SIZE_GET_IW(mem) ), + .EW ( `HCI_SIZE_GET_EW(mem) ), + .EHW ( `HCI_SIZE_GET_EHW(mem) ) +`ifndef SYNTHESIS + , + .WAIVE_RQ3_ASSERT ( WaiveRq3Assert ), + .WAIVE_RQ4_ASSERT ( WaiveRq4Assert ) +`endif + ) core_mem_muxed [0:NumMem-1] ( + .clk ( clk_i ) + ); + +/*******************************************************/ +/** Parameter and Interface Definitions End **/ +/*******************************************************/ +/** Narrow Branch Beginning **/ +/*******************************************************/ + + // Per-bank round-robin among the narrow ports: hci_log_interconnect ignores ctrl_i + hci_log_interconnect #( + .N_CH0 ( NumCore ), + .N_CH1 ( 0 ), + .N_MEM ( NumMem ), + .AWC ( `HCI_SIZE_GET_AW(core) ), + .AWM ( LicBankAddrW ), + .DW ( `HCI_SIZE_GET_DW(core) ), + .BW ( `HCI_SIZE_GET_BW(core) ), + .TS_BIT ( magia_tile_pkg::TS_BIT ), + .IW ( NumCore ), + .UW ( `HCI_SIZE_GET_UW(core) ), + .EW ( `HCI_SIZE_GET_EW(core) ) + ) i_core_log_interconnect ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .ctrl_i ( '0 ), + .cores ( core ), + .mems ( lic_mem ) + ); + + // Left undriven by hci_log_interconnect: no error path, one outstanding request, no ECC + for (genvar i = 0; i < NumCore; i++) begin : gen_core_rsp_tieoff + assign core[i].r_id = '0; + assign core[i].r_opc = 1'b0; + assign core[i].egnt = '1; + assign core[i].r_evalid = '0; + end + + // Truncates the LIC bank address to the mem address width + for (genvar b = 0; b < NumMem; b++) begin : gen_lic_mem_bridge + hci_core_assign i_lic_mem_assign ( + .tcdm_target ( lic_mem[b] ), + .tcdm_initiator ( core_mem_muxed[b] ) + ); + end + +/*******************************************************/ +/** Narrow Branch End **/ +/*******************************************************/ +/** Wide Branch Beginning **/ +/*******************************************************/ + + // Without RedMulE no router drives the placeholder hwpe[0] port + if (NumHwpe == 0) begin : gen_hwpe_port_unused + assign hwpe[0].gnt = 1'b0; + assign hwpe[0].r_valid = 1'b0; + assign hwpe[0].r_data = '0; + assign hwpe[0].r_user = '0; + assign hwpe[0].r_id = '0; + assign hwpe[0].r_opc = 1'b0; + assign hwpe[0].egnt = '1; + assign hwpe[0].r_evalid = '0; + end + + if (NumWide > 0) begin : gen_wide_branch + // ARB_CTRL steers only the wide-vs-narrow arbiter: the tree nodes keep the default ratio + localparam hci_package::hci_interconnect_ctrl_t TreeCtrl = '{ + arb_policy: 2'b00, + invert_prio: 1'b0, + priority_cnt_numerator: 8'(magia_tile_pkg::HCI_QOS_NUM), + priority_cnt_denominator: 8'(magia_tile_pkg::HCI_QOS_DEN) + }; + + hci_package::hci_interconnect_ctrl_t ctrl; // Of the wide-vs-narrow arbiter + + // An unprogrammed ctrl_i (denominator 0) falls back to the default ratio + always_comb begin + ctrl = ctrl_i; + if (ctrl_i.priority_cnt_denominator == 8'd0) begin + ctrl.priority_cnt_numerator = 8'(magia_tile_pkg::HCI_QOS_NUM); + ctrl.priority_cnt_denominator = 8'(magia_tile_pkg::HCI_QOS_DEN); + end + end + + `HCI_INTF_ARRAY(wide_mem, clk_i, 0:NumWide*NumMem-1); + + // Output of the wide arbiter tree, which re-arbitrates while not granted + hci_core_intf #( + .DW ( `HCI_SIZE_GET_DW(mem) ), + .AW ( `HCI_SIZE_GET_AW(mem) ), + .BW ( `HCI_SIZE_GET_BW(mem) ), + .UW ( `HCI_SIZE_GET_UW(mem) ), + .IW ( `HCI_SIZE_GET_IW(mem) ), + .EW ( `HCI_SIZE_GET_EW(mem) ), + .EHW ( `HCI_SIZE_GET_EHW(mem) ) +`ifndef SYNTHESIS + , + .WAIVE_RQ3_ASSERT ( WaiveRq3Assert ), + .WAIVE_RQ4_ASSERT ( WaiveRq4Assert ) +`endif + ) wide_mem_muxed [0:NumMem-1] ( + .clk ( clk_i ) + ); + + // DMA channels take the first NumDma groups of wide_mem, RedMulE the following ones + for (genvar j = 0; j < NumDma; j++) begin : gen_dma_req2mem + hci_router #( + .FIFO_DEPTH ( RouterFifoDepth ), + .NB_OUT_CHAN ( NumMem ), + .`HCI_SIZE_PARAM(in) ( `HCI_SIZE_PARAM(dma) ), + .`HCI_SIZE_PARAM(out) ( `HCI_SIZE_PARAM(wide_mem) ) + ) i_dma_router ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .clear_i ( clear_i ), + .in ( dma[j] ), + .out ( wide_mem[j*NumMem:(j+1)*NumMem-1] ) + ); + end + + // Last leaf, so RedMulE alone faces the DMA pair at the tree root + for (genvar i = 0; i < NumHwpe; i++) begin : gen_hwpe_req2mem + hci_router #( + .FIFO_DEPTH ( RouterFifoDepth ), + .NB_OUT_CHAN ( NumMem ), + .`HCI_SIZE_PARAM(in) ( `HCI_SIZE_PARAM(hwpe) ), + .`HCI_SIZE_PARAM(out) ( `HCI_SIZE_PARAM(wide_mem) ) + ) i_hwpe_router ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .clear_i ( clear_i ), + .in ( hwpe[i] ), + .out ( wide_mem[(NumDma+i)*NumMem:(NumDma+i+1)*NumMem-1] ) + ); + end + + hci_arbiter_tree #( + .NB_REQUESTS ( NumWide ), + .NB_CHAN ( NumMem ), + .`HCI_SIZE_PARAM(out) ( `HCI_SIZE_PARAM(wide_mem) ), + .WAIVE_RQ3_ASSERT ( WaiveRq3Assert ), + .WAIVE_RQ4_ASSERT ( WaiveRq4Assert ) + ) i_wide_arbiter_tree ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .clear_i ( clear_i ), + .ctrl_i ( TreeCtrl ), + .in ( wide_mem ), + .out ( wide_mem_muxed ) + ); + + // Wide ports on in_high, the higher-priority side unless invert_prio is set + hci_arbiter #( + .NB_CHAN ( NumMem ) + ) i_wide_vs_narrow_arbiter ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .clear_i ( clear_i ), + .ctrl_i ( ctrl ), + .in_high ( wide_mem_muxed ), + .in_low ( core_mem_muxed ), + .out ( mem ) + ); + end else begin : gen_no_wide_branch + for (genvar b = 0; b < NumMem; b++) begin : gen_core_to_mem + hci_core_assign i_core_mem_assign ( + .tcdm_target ( core_mem_muxed[b] ), + .tcdm_initiator ( mem[b] ) + ); + end + end + +/*******************************************************/ +/** Wide Branch End **/ +/*******************************************************/ + +endmodule : magia_hci_interconnect diff --git a/hw/tile/magia_isle.sv b/hw/tile/magia_isle.sv index 73fa797f..68d09fc1 100644 --- a/hw/tile/magia_isle.sv +++ b/hw/tile/magia_isle.sv @@ -135,7 +135,7 @@ module magia_isle localparam int unsigned NumWordsBank = TileCfg.L1.NumWordsBank; localparam int unsigned L1BankAddrW = $clog2(NumWordsBank * magia_tile_pkg::DW_LIC / magia_tile_pkg::BW_LIC); // Byte address within a bank - localparam int unsigned NumHwpe = magia_tile_pkg::N_HWPE; // Stays 1 without RedMulE: local_interconnect is not 0-safe + localparam int unsigned NumHwpe = TileCfg.EnRedMule ? 1 : 0; // 0 drops the RedMulE leaf of the HCI interconnect localparam int unsigned NumDma = magia_tile_pkg::N_DMA; localparam int unsigned NumExt = magia_tile_pkg::N_EXT; localparam int unsigned TileIW = NumHwpe + NumHciCore + NumDma + NumExt; @@ -143,8 +143,10 @@ module magia_isle localparam int unsigned RedmuleFpW = 16; // FP16 localparam int unsigned RedmuleDataW = TileCfg.RedMule.Height * (TileCfg.RedMule.NumPipeRegs + 1) * RedmuleFpW; - `HCI_TYPEDEF_REQ_T(tile_redmule_data_req_t, logic[magia_tile_pkg::AWC-1:0], logic[RedmuleDataW-1:0], logic[RedmuleDataW/magia_tile_pkg::BWH-1:0], logic[magia_tile_pkg::UWH-1:0], logic[TileIW-1:0], logic[0:0], logic[0:0]) - `HCI_TYPEDEF_RSP_T(tile_redmule_data_rsp_t, logic[RedmuleDataW-1:0], logic[magia_tile_pkg::UWH-1:0], logic[TileIW-1:0], logic[0:0], logic[0:0]) + localparam int unsigned RedmuleHciW = RedmuleDataW + (TileCfg.RedMule.MisalignedAccess ? magia_tile_pkg::DW_LIC : 0); + + `HCI_TYPEDEF_REQ_T(tile_redmule_data_req_t, logic[magia_tile_pkg::AWC-1:0], logic[RedmuleHciW-1:0], logic[RedmuleHciW/magia_tile_pkg::BWH-1:0], logic[magia_tile_pkg::UWH-1:0], logic[TileIW-1:0], logic[0:0], logic[0:0]) + `HCI_TYPEDEF_RSP_T(tile_redmule_data_rsp_t, logic[RedmuleHciW-1:0], logic[magia_tile_pkg::UWH-1:0], logic[TileIW-1:0], logic[0:0], logic[0:0]) `HCI_TYPEDEF_REQ_T(tile_hci_data_req_t, logic[magia_tile_pkg::AWC-1:0], logic[magia_tile_pkg::DW_LIC-1:0], logic[magia_tile_pkg::SW_LIC-1:0], logic[magia_tile_pkg::UWH-1:0], logic[TileIW-1:0], logic[0:0], logic[0:0]) `HCI_TYPEDEF_RSP_T(tile_hci_data_rsp_t, logic[magia_tile_pkg::DW_LIC-1:0], logic[magia_tile_pkg::UWH-1:0], logic[TileIW-1:0], logic[0:0], logic[0:0]) @@ -1225,7 +1227,7 @@ module magia_isle `HCI_INTF_ARRAY(hci_core_if, sys_clk, 0:NumHciCore-1); localparam hci_package::hci_size_parameter_t `HCI_SIZE_PARAM(hci_redmule_if) = '{ - DW: RedmuleDataW, + DW: RedmuleHciW, AW: magia_tile_pkg::AWH, BW: hci_package::DEFAULT_BW, UW: magia_tile_pkg::REDMULE_UW, @@ -1233,7 +1235,8 @@ module magia_isle EW: hci_package::DEFAULT_EW, EHW: hci_package::DEFAULT_EHW }; - `HCI_INTF_ARRAY(hci_redmule_if, sys_clk, 0:NumHwpe-1); + // One element even without RedMulE: the tie-off drives it by name + `HCI_INTF_ARRAY(hci_redmule_if, sys_clk, 0:0); localparam hci_package::hci_size_parameter_t `HCI_SIZE_PARAM(hci_dma_if) = '{ DW: magia_tile_pkg::iDMA_DataWidth, @@ -1309,24 +1312,31 @@ module magia_isle hci_package::hci_interconnect_ctrl_t hci_ctrl; assign hci_clear = 1'b0; - assign hci_ctrl = '0; - - local_interconnect #( - .N_HWPE ( NumHwpe ), - .N_DMA ( NumDma ), - .N_CORE ( NumHciCore ), - .N_MEM ( NumMemBanks ), - .EXPFIFO ( magia_tile_pkg::EXPFIFO ), - .MEM_DATA_W ( magia_tile_pkg::DW_LIC ), - .MEM_ADDR_W ( L1BankAddrW ), - .MEM_BYTE_W ( magia_tile_pkg::BW_LIC ), - .MEM_USER_W ( magia_tile_pkg::UW_LIC ), - .MEM_ID_W ( TileIW ), - .HCI_SIZE_hwpe ( `HCI_SIZE_PARAM(hci_redmule_if) ), - .HCI_SIZE_dma ( `HCI_SIZE_PARAM(hci_dma_if) ), - .HCI_SIZE_core ( `HCI_SIZE_PARAM(hci_core_if) ), - .HCI_SIZE_mem ( `HCI_SIZE_PARAM(hci_tcdm_sram_if)) - ) i_local_interconnect ( + + // Wide-vs-narrow arbitration policy of the HCI, set by software + obi_slave_ctrl_hci #( + .BaseAddr ( magia_tile_pkg::HCI_CTRL_ADDR_START ) + ) i_hci_ctrl ( + .clk_i ( sys_clk ), + .rst_ni ( rst_ni ), + .obi_req_i ( ctrl_req[CtrlMap.hci] ), + .obi_rsp_o ( ctrl_rsp[CtrlMap.hci] ), + .ctrl_o ( hci_ctrl ) + ); + + magia_hci_interconnect #( + .NumHwpe ( NumHwpe ), + .NumDma ( NumDma ), + .NumCore ( NumHciCore ), + .NumMem ( NumMemBanks ), + .RouterFifoDepth ( magia_tile_pkg::EXPFIFO ), + .WaiveRq3Assert ( 1'b1 ), + .WaiveRq4Assert ( 1'b1 ), + .HCI_SIZE_hwpe ( `HCI_SIZE_PARAM(hci_redmule_if) ), + .HCI_SIZE_dma ( `HCI_SIZE_PARAM(hci_dma_if) ), + .HCI_SIZE_core ( `HCI_SIZE_PARAM(hci_core_if) ), + .HCI_SIZE_mem ( `HCI_SIZE_PARAM(hci_tcdm_sram_if) ) + ) i_magia_hci_interconnect ( .clk_i ( sys_clk ), .rst_ni ( rst_ni ), .clear_i ( hci_clear ), @@ -1654,14 +1664,15 @@ module magia_isle `HCI_ASSIGN_TO_INTF(hci_redmule_if[0], redmule_data_req, redmule_data_rsp) magia_redmule_wrap #( - .CtrlIntfConfig ( redmule_pkg::HWPE_TARGET ), - .DataW ( RedmuleDataW ), - .Height ( TileCfg.RedMule.Height ), - .Width ( TileCfg.RedMule.Width ), - .NumPipeRegs ( TileCfg.RedMule.NumPipeRegs ), - .redmule_data_req_t ( tile_redmule_data_req_t ), - .redmule_data_rsp_t ( tile_redmule_data_rsp_t ), - .`HCI_SIZE_PARAM(tcdm) ( `HCI_SIZE_PARAM(hci_redmule_if) ) + .CtrlIntfConfig ( redmule_pkg::HWPE_TARGET ), + .DataW ( RedmuleDataW ), + .MisalignedAccessSupport ( int'(TileCfg.RedMule.MisalignedAccess) ), + .Height ( TileCfg.RedMule.Height ), + .Width ( TileCfg.RedMule.Width ), + .NumPipeRegs ( TileCfg.RedMule.NumPipeRegs ), + .redmule_data_req_t ( tile_redmule_data_req_t ), + .redmule_data_rsp_t ( tile_redmule_data_rsp_t ), + .`HCI_SIZE_PARAM(tcdm) ( `HCI_SIZE_PARAM(hci_redmule_if) ) ) i_redmule_wrap ( .clk_i ( sys_clk ), .rst_ni ( rst_ni ), @@ -1693,7 +1704,7 @@ module magia_isle tile_redmule_data_req_t redmule_data_req_quiet; tile_redmule_data_rsp_t redmule_data_rsp_unused; - // The HWPE port stays: local_interconnect needs at least one + // The HCI interconnect keeps one HWPE port even when it has no RedMulE leaf assign redmule_data_req_quiet = '0; `HCI_ASSIGN_TO_INTF(hci_redmule_if[0], redmule_data_req_quiet, redmule_data_rsp_unused) diff --git a/hw/tile/magia_redmule_wrap.sv b/hw/tile/magia_redmule_wrap.sv index 9adbe999..96085e5c 100644 --- a/hw/tile/magia_redmule_wrap.sv +++ b/hw/tile/magia_redmule_wrap.sv @@ -33,33 +33,34 @@ module magia_redmule_wrap import magia_tile_pkg::*; import magia_pkg::*; #( - parameter int unsigned DataW = magia_tile_pkg::REDMULE_DW, - parameter fp_format_e FpFormat = FP16, - parameter int unsigned Height = 8, - parameter int unsigned Width = 8, - parameter int unsigned NumPipeRegs = 1, - parameter pipe_config_t PipeConfig = DISTRIBUTED, - parameter int unsigned EccChunkSize = 32, - parameter bit LatchBuffers = 0, - parameter fpnew_pkg::fmt_logic_t FpFmtConfig = 6'b001101, - parameter fpnew_pkg::ifmt_logic_t IntFmtConfig = 4'b1000, - parameter ctrl_intf_e CtrlIntfConfig = XIF, - parameter logic [6:0] McnfigOpCode = 7'b0001011, - parameter logic [6:0] MarithOpCode = 7'b0001011, - parameter logic [6:0] MopcntOpCode = 7'b0001011, - parameter logic [2:0] McnfigFunct3 = 3'b000, - parameter logic [2:0] MarithFunct3 = 3'b001, - parameter logic [2:0] MopcntFunct3 = 3'b010, - parameter logic [1:0] McnfigFunct2 = 2'b00, - parameter logic [1:0] MarithFunct2 = 2'b00, - parameter logic [1:0] MopcntFunct2 = 2'b00, - parameter int unsigned XifNumHarts = 1, - parameter int unsigned XifIdWidth = 1, - parameter int unsigned XifIssueRegisterSplit = 0, - parameter type redmule_data_req_t = magia_tile_pkg::redmule_data_req_t, - parameter type redmule_data_rsp_t = magia_tile_pkg::redmule_data_rsp_t, + parameter int unsigned DataW = magia_tile_pkg::REDMULE_DW, + parameter int unsigned MisalignedAccessSupport = 1, + parameter fp_format_e FpFormat = FP16, + parameter int unsigned Height = 8, + parameter int unsigned Width = 8, + parameter int unsigned NumPipeRegs = 1, + parameter pipe_config_t PipeConfig = DISTRIBUTED, + parameter int unsigned EccChunkSize = 32, + parameter bit LatchBuffers = 0, + parameter fpnew_pkg::fmt_logic_t FpFmtConfig = 6'b001101, + parameter fpnew_pkg::ifmt_logic_t IntFmtConfig = 4'b1000, + parameter ctrl_intf_e CtrlIntfConfig = XIF, + parameter logic [6:0] McnfigOpCode = 7'b0001011, + parameter logic [6:0] MarithOpCode = 7'b0001011, + parameter logic [6:0] MopcntOpCode = 7'b0001011, + parameter logic [2:0] McnfigFunct3 = 3'b000, + parameter logic [2:0] MarithFunct3 = 3'b001, + parameter logic [2:0] MopcntFunct3 = 3'b010, + parameter logic [1:0] McnfigFunct2 = 2'b00, + parameter logic [1:0] MarithFunct2 = 2'b00, + parameter logic [1:0] MopcntFunct2 = 2'b00, + parameter int unsigned XifNumHarts = 1, + parameter int unsigned XifIdWidth = 1, + parameter int unsigned XifIssueRegisterSplit = 0, + parameter type redmule_data_req_t = magia_tile_pkg::redmule_data_req_t, + parameter type redmule_data_rsp_t = magia_tile_pkg::redmule_data_rsp_t, parameter hci_size_parameter_t `HCI_SIZE_PARAM(tcdm) = '{ - DW: DataW, + DW: DataW + (MisalignedAccessSupport ? 32 : 0), AW: magia_pkg::ADDR_W, BW: hci_package::DEFAULT_BW, UW: magia_tile_pkg::REDMULE_UW, @@ -162,35 +163,36 @@ module magia_redmule_wrap // Instantiate redmule_top with interface-based ports redmule_top #( - .DataW ( DataW ), - .FpFormat ( FpFormat ), - .Height ( Height ), - .Width ( Width ), - .NumPipeRegs ( NumPipeRegs ), - .PipeConfig ( PipeConfig ), - .EccChunkSize ( EccChunkSize ), - .LatchBuffers ( LatchBuffers ), - .FpFmtConfig ( FpFmtConfig ), - .IntFmtConfig ( IntFmtConfig ), - .CtrlIntfConfig ( CtrlIntfConfig ), - .McnfigOpCode ( McnfigOpCode ), - .MarithOpCode ( MarithOpCode ), - .MopcntOpCode ( MopcntOpCode ), - .McnfigFunct3 ( McnfigFunct3 ), - .MarithFunct3 ( MarithFunct3 ), - .MopcntFunct3 ( MopcntFunct3 ), - .McnfigFunct2 ( McnfigFunct2 ), - .MarithFunct2 ( MarithFunct2 ), - .MopcntFunct2 ( MopcntFunct2 ), - .XifNumHarts ( XifNumHarts ), - .XifIdWidth ( XifIdWidth ), - .XifIssueRegisterSplit ( XifIssueRegisterSplit), - .x_issue_req_t ( logic ), - .x_issue_resp_t ( logic ), - .x_register_t ( logic ), - .x_commit_t ( logic ), - .x_result_t ( logic ), - .`HCI_SIZE_PARAM(tcdm) ( `HCI_SIZE_PARAM(tcdm)) + .DataW ( DataW ), + .MisalignedAccessSupport ( MisalignedAccessSupport ), + .FpFormat ( FpFormat ), + .Height ( Height ), + .Width ( Width ), + .NumPipeRegs ( NumPipeRegs ), + .PipeConfig ( PipeConfig ), + .EccChunkSize ( EccChunkSize ), + .LatchBuffers ( LatchBuffers ), + .FpFmtConfig ( FpFmtConfig ), + .IntFmtConfig ( IntFmtConfig ), + .CtrlIntfConfig ( CtrlIntfConfig ), + .McnfigOpCode ( McnfigOpCode ), + .MarithOpCode ( MarithOpCode ), + .MopcntOpCode ( MopcntOpCode ), + .McnfigFunct3 ( McnfigFunct3 ), + .MarithFunct3 ( MarithFunct3 ), + .MopcntFunct3 ( MopcntFunct3 ), + .McnfigFunct2 ( McnfigFunct2 ), + .MarithFunct2 ( MarithFunct2 ), + .MopcntFunct2 ( MopcntFunct2 ), + .XifNumHarts ( XifNumHarts ), + .XifIdWidth ( XifIdWidth ), + .XifIssueRegisterSplit ( XifIssueRegisterSplit ), + .x_issue_req_t ( logic ), + .x_issue_resp_t ( logic ), + .x_register_t ( logic ), + .x_commit_t ( logic ), + .x_result_t ( logic ), + .`HCI_SIZE_PARAM(tcdm) ( `HCI_SIZE_PARAM(tcdm) ) ) i_redmule_top ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), diff --git a/hw/tile/magia_tile_pkg.sv b/hw/tile/magia_tile_pkg.sv index 5435784b..4c3da9b2 100644 --- a/hw/tile/magia_tile_pkg.sv +++ b/hw/tile/magia_tile_pkg.sv @@ -75,9 +75,12 @@ package magia_tile_pkg; localparam logic [magia_pkg::ADDR_W-1:0] SPATZ_CTRL_SIZE = 32'h0000_0040; localparam logic [magia_pkg::ADDR_W-1:0] SPATZ_CTRL_ADDR_END = SPATZ_CTRL_ADDR_START + SPATZ_CTRL_SIZE; localparam logic [magia_pkg::ADDR_W-1:0] CLUSTER_CTRL_ADDR_START = SPATZ_CTRL_ADDR_END; - localparam logic [magia_pkg::ADDR_W-1:0] CLUSTER_CTRL_SIZE = 32'h0000_00C0; + localparam logic [magia_pkg::ADDR_W-1:0] CLUSTER_CTRL_SIZE = 32'h0000_0080; localparam logic [magia_pkg::ADDR_W-1:0] CLUSTER_CTRL_ADDR_END = CLUSTER_CTRL_ADDR_START + CLUSTER_CTRL_SIZE; - localparam logic [magia_pkg::ADDR_W-1:0] COLL_CTRL_ADDR_START = CLUSTER_CTRL_ADDR_END; + localparam logic [magia_pkg::ADDR_W-1:0] HCI_CTRL_ADDR_START = CLUSTER_CTRL_ADDR_END; + localparam logic [magia_pkg::ADDR_W-1:0] HCI_CTRL_SIZE = 32'h0000_0040; + localparam logic [magia_pkg::ADDR_W-1:0] HCI_CTRL_ADDR_END = HCI_CTRL_ADDR_START + HCI_CTRL_SIZE; + localparam logic [magia_pkg::ADDR_W-1:0] COLL_CTRL_ADDR_START = HCI_CTRL_ADDR_END; localparam logic [magia_pkg::ADDR_W-1:0] COLL_CTRL_SIZE = 32'h0000_0100; localparam logic [magia_pkg::ADDR_W-1:0] COLL_CTRL_ADDR_END = COLL_CTRL_ADDR_START + COLL_CTRL_SIZE; // Cluster-private Event Unit: direct link of the cluster cores, and memory-mapped view on the OBI crossbar @@ -253,6 +256,9 @@ package magia_tile_pkg; parameter int unsigned BW_LIC = magia_pkg::BYTE_W; // Byte Width for Log Interconnect parameter int unsigned UW_LIC = magia_pkg::USR_W; // User Width for Log Interconnect localparam int unsigned SW_LIC = DW_LIC/BW_LIC; // Strobe Width for Log Interconnect + parameter int unsigned TS_BIT = 21; // TEST_SET_BIT (for Log Interconnect) + parameter int unsigned HCI_QOS_NUM = 1; // Default HCI arbiter ratio, see obi_slave_ctrl_hci + parameter int unsigned HCI_QOS_DEN = 2; // Used while ARB_CTRL denominator is 0 parameter int unsigned IW = N_HWPE+N_CORE+N_DMA+N_EXT; // ID Width HCI parameter int unsigned EXPFIFO = 0; // FIFO Depth for HWPE Interconnect parameter int unsigned DWH = magia_pkg::MagiaRedMuleDefaultCfg.Height * @@ -357,7 +363,7 @@ package magia_tile_pkg; endfunction // Control units share one crossbar port through ctrl_demux; the EU keeps its own, its responses wait - localparam int unsigned CTRL_MAX_UNITS = 6; + localparam int unsigned CTRL_MAX_UNITS = 7; typedef struct packed { int unsigned num_units; // Number of units behind the control port (one address rule each) @@ -366,6 +372,7 @@ package magia_tile_pkg; int unsigned fsync; // FractalSync control (valid iff MAGIA_FSYNC) int unsigned spatz; // Spatz CC control (valid iff EnSpatzCC) int unsigned cluster; // PULP cluster control (valid iff EnCluster) + int unsigned hci; // HCI arbiter control int unsigned coll; // Collective control (valid iff EnCollective) } ctrl_map_t; @@ -392,6 +399,8 @@ package magia_tile_pkg; ret.cluster = idx; idx = idx + 1; end + ret.hci = idx; + idx = idx + 1; if (cfg.EnCollective) begin ret.coll = idx; idx = idx + 1; @@ -581,6 +590,7 @@ package magia_tile_pkg; if (cfg.EnCluster) begin ret[map.cluster] = '{idx: map.cluster, start_addr: CLUSTER_CTRL_ADDR_START, end_addr: CLUSTER_CTRL_ADDR_END}; end + ret[map.hci] = '{idx: map.hci, start_addr: HCI_CTRL_ADDR_START, end_addr: HCI_CTRL_ADDR_END}; if (cfg.EnCollective) begin ret[map.coll] = '{idx: map.coll, start_addr: COLL_CTRL_ADDR_START, end_addr: COLL_CTRL_ADDR_END}; end diff --git a/hw/tile/obi_slave_ctrl_hci.sv b/hw/tile/obi_slave_ctrl_hci.sv new file mode 100644 index 00000000..0ae48886 --- /dev/null +++ b/hw/tile/obi_slave_ctrl_hci.sv @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT + * + * 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 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: SHL-0.51 + * + * Author: Luca Balboni, Fondazione Chips-IT + * + * Control register of the HCI wide-vs-narrow arbiter, the last stage before the L1 banks + * + * ARB_CTRL (offset 0x00, RW, reset 0, byte enables honoured) + * [0] invert_prio - 0: wide ports on the higher side, 1: narrow ports + * [15:8] priority_cnt_numerator - conflict cycles the higher side wins per window, 0: strict + * [23:16] priority_cnt_denominator - conflict cycles per window, 0 selects the default ratio + * + * Any other offset of the window answers with an OBI error + */ + +module obi_slave_ctrl_hci + import magia_tile_pkg::*; +#( + parameter logic [31:0] BaseAddr = magia_tile_pkg::HCI_CTRL_ADDR_START +) ( + input logic clk_i, + input logic rst_ni, + + input core_obi_data_req_t obi_req_i, + output core_obi_data_rsp_t obi_rsp_o, + + output hci_package::hci_interconnect_ctrl_t ctrl_o // To magia_hci_interconnect +); + + logic arb_ctrl_sel; // Access to the ARB_CTRL word + logic arb_ctrl_we; + logic [31:0] arb_ctrl_d, arb_ctrl_q; + + logic rvalid_d, rvalid_q; + logic err_d, err_q; + logic [31:0] rdata_d, rdata_q; + + // Every request of the window is granted: a wrong offset faults instead of hanging + assign arb_ctrl_sel = (obi_req_i.a.addr[31:2] == BaseAddr[31:2]); + assign arb_ctrl_we = obi_req_i.req & obi_req_i.a.we & arb_ctrl_sel; + assign rvalid_d = obi_req_i.req; + assign err_d = obi_req_i.req & ~arb_ctrl_sel; + assign rdata_d = (obi_req_i.req & ~obi_req_i.a.we & arb_ctrl_sel) ? arb_ctrl_q : 32'h0; + + always_comb begin + arb_ctrl_d = arb_ctrl_q; + for (int unsigned b = 0; b < 4; b++) begin + if (obi_req_i.a.be[b]) begin + arb_ctrl_d[8*b +: 8] = obi_req_i.a.wdata[8*b +: 8]; + end + end + end + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + arb_ctrl_q <= 32'h0; // magia_hci_interconnect falls back to its default ratio + end else if (arb_ctrl_we) begin + arb_ctrl_q <= arb_ctrl_d; + end + end + + // Response, one cycle after the grant + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + rvalid_q <= 1'b0; + err_q <= 1'b0; + rdata_q <= 32'h0; + end else begin + rvalid_q <= rvalid_d; + err_q <= err_d; + rdata_q <= rdata_d; + end + end + + assign obi_rsp_o.gnt = rvalid_d; + assign obi_rsp_o.rvalid = rvalid_q; + assign obi_rsp_o.r.rdata = rdata_q; + assign obi_rsp_o.r.rid = '0; + assign obi_rsp_o.r.err = err_q; + assign obi_rsp_o.r.r_optional = '0; + + assign ctrl_o = '{ + arb_policy: 2'b00, + invert_prio: arb_ctrl_q[0], + priority_cnt_numerator: arb_ctrl_q[15:8], + priority_cnt_denominator: arb_ctrl_q[23:16] + }; + +endmodule : obi_slave_ctrl_hci diff --git a/sw/tests/cluster_tests/hci_arb_redmule_bench/main.c b/sw/tests/cluster_tests/hci_arb_redmule_bench/main.c new file mode 100644 index 00000000..716b632b --- /dev/null +++ b/sw/tests/cluster_tests/hci_arb_redmule_bench/main.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT + * + * 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 + * + * Author: Luca Balboni, Fondazione Chips-IT + * + * HCI Arbitration RedMulE Benchmark: control-core orchestrator + */ + +#include +#include "magia_tile_utils.h" +#include "magia_stats.h" +#include "cluster_utils.h" +#include "redmule_mm_utils.h" +#include "hci_arb_redmule_bench_pulp_task_bin.h" + +#include "x_input.h" +#include "w_input.h" + +#define M_SIZE (16) +#define N_SIZE (16) +#define K_SIZE (16) + +#define X_BASE (L1_BASE + 0x00012048) +#define W_BASE (L1_BASE + 0x00016048) +#define Y_BASE (L1_BASE + 0x0001A048) + +// Narrow branch on in_low: it wins (DEN - NUM) / DEN of the conflict cycles +#define HCI_ARB_NARROW75_NUM (1) +#define HCI_ARB_NARROW75_DEN (4) +#define HCI_ARB_WIDE75_NUM (3) +#define HCI_ARB_WIDE75_DEN (4) + +static uint32_t run_redmule_once(void) { + for (int i = 0; i < M_SIZE*K_SIZE; i++) + mmio16(Y_BASE + 2*i) = 0; + + hwpe_cg_enable(); + hwpe_soft_clear(); + + int offload_id_tmp; + while ((offload_id_tmp = hwpe_acquire_job()) < 0) + ; + + redmule_cfg((unsigned int)X_BASE, (unsigned int)W_BASE, (unsigned int)Y_BASE, + M_SIZE, N_SIZE, K_SIZE, (uint8_t)gemm_ops, (uint8_t)Float16, (uint8_t)Float16); + + uint32_t start = perf_csr_cycle(); + hwpe_trigger_job(); + hwpe_wait_for_completion(); + uint32_t cycles = perf_csr_cycle() - start; + + hwpe_cg_disable(); + + return cycles; +} + +// RedMulE cycles under the given arbitration, while the cluster stresses L1 +static uint32_t bench_arb(uint32_t arb_ctrl_value) { + mmio32(HCI_ARB_CTRL) = arb_ctrl_value; + + cluster_arm_done_event(); + cluster_dispatch_task(HCI_ARB_REDMULE_BENCH_TASK); + + uint32_t redmule_cycles = run_redmule_once(); + + cluster_wait_done_eu(); + + return redmule_cycles; +} + +int main(void) { + for (int i = 0; i < M_SIZE*N_SIZE; i++) + mmio16(X_BASE + 2*i) = x_inp[i]; + for (int i = 0; i < N_SIZE*K_SIZE; i++) + mmio16(W_BASE + 2*i) = w_inp[i]; + + ccount_en(); + + cluster_boot(PULP_BINARY_START); + + uint32_t cycles_narrow75 = bench_arb(HCI_ARB_PRIO_NUM(HCI_ARB_NARROW75_NUM) | HCI_ARB_PRIO_DEN(HCI_ARB_NARROW75_DEN)); + uint32_t cycles_wide75 = bench_arb(HCI_ARB_PRIO_NUM(HCI_ARB_WIDE75_NUM) | HCI_ARB_PRIO_DEN(HCI_ARB_WIDE75_DEN)); + + printf("RedMulE cycles, narrow 75%% / wide 25%% HCI arbitration: %u\n", (unsigned)cycles_narrow75); + printf("RedMulE cycles, narrow 25%% / wide 75%% HCI arbitration: %u\n", (unsigned)cycles_wide75); + + return 0; +} diff --git a/sw/tests/cluster_tests/hci_arb_redmule_bench/pulp_task/hci_arb_redmule_bench_task.c b/sw/tests/cluster_tests/hci_arb_redmule_bench/pulp_task/hci_arb_redmule_bench_task.c new file mode 100644 index 00000000..60921ecd --- /dev/null +++ b/sw/tests/cluster_tests/hci_arb_redmule_bench/pulp_task/hci_arb_redmule_bench_task.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2026 ETH Zurich, University of Bologna and Fondazione Chips-IT + * + * 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 + * + * Author: Luca Balboni, Fondazione Chips-IT + * + * HCI Arbitration RedMulE Benchmark: PULP cluster stress task + */ + +#include "magia_tile_utils.h" +#include "cluster_utils.h" + +#define HCI_STRESS_ITERS (4096) +#define HCI_STRESS_BASE (L1_BASE + 0x00060000) +#define HCI_STRESS_STRIDE (0x00000400) +#define HCI_STRESS_WORDS (HCI_STRESS_STRIDE / 4) + +// Each core loads and stores its own L1 slice, keeping the narrow branch busy +static void hci_stress_worker(void *arg) { + (void)arg; + volatile uint32_t *p = (volatile uint32_t *)(HCI_STRESS_BASE + pi_core_id() * HCI_STRESS_STRIDE); + for (uint32_t i = 0; i < HCI_STRESS_ITERS; i++) { + p[i % HCI_STRESS_WORDS] = i; + (void)p[i % HCI_STRESS_WORDS]; + } +} + +void hci_arb_redmule_bench_task(void *data) { + (void)data; + pi_cl_team_fork(PULP_CORE_COUNT, hci_stress_worker, 0); +} diff --git a/sw/tests/spatz_tests/matmul_compare_spatz_test.c b/sw/tests/spatz_tests/matmul_compare_spatz_test.c index cc3cbf2d..b7654c74 100644 --- a/sw/tests/spatz_tests/matmul_compare_spatz_test.c +++ b/sw/tests/spatz_tests/matmul_compare_spatz_test.c @@ -21,6 +21,7 @@ #include #include "magia_tile_utils.h" +#include "magia_stats.h" #include "magia_spatz_utils.h" #include "redmule_mm_utils.h" #include "event_unit_utils.h" @@ -107,7 +108,7 @@ int main(void) { printf("Starting RedMulE computation...\n"); - uint32_t redmule_start = get_cycle(); + uint32_t redmule_start = perf_csr_cycle(); // Trigger job hwpe_trigger_job(); @@ -115,7 +116,7 @@ int main(void) { // Wait for HWPE completion using the polling method hwpe_wait_for_completion(); - uint32_t redmule_cycles = get_cycle() - redmule_start; + uint32_t redmule_cycles = perf_csr_cycle() - redmule_start; printf("RedMule cycles: %u\n", redmule_cycles); printf("RedMule completed.\n\n"); @@ -147,13 +148,13 @@ int main(void) { printf("Starting Spatz computation...\n"); - uint32_t spatz_start = get_cycle(); + uint32_t spatz_start = perf_csr_cycle(); spatz_pass_params(MATMUL_PARAM_BASE); spatz_run_task(MATMUL16_TASK); eu_wait_spatz_polling(EU_SPATZ_DONE_MASK); - uint32_t spatz_cycles = get_cycle() - spatz_start; + uint32_t spatz_cycles = perf_csr_cycle() - spatz_start; printf("Spatz cycles: %u\n\n", spatz_cycles); diff --git a/sw/tests/tests.yml b/sw/tests/tests.yml index 1eeb0642..d5218d46 100644 --- a/sw/tests/tests.yml +++ b/sw/tests/tests.yml @@ -359,3 +359,8 @@ cluster_tests: cores: [CV32E40P, CV32E40X] sims: [questa, verilator] requires: [] + hci_arb_redmule_bench: + testbench: tile + cores: [CV32E40P, CV32E40X] + sims: [questa, verilator] + requires: [] diff --git a/sw/utils/magia_stats.h b/sw/utils/magia_stats.h new file mode 100644 index 00000000..bffbd70a --- /dev/null +++ b/sw/utils/magia_stats.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2023-2026 ETH Zurich, University of Bologna and Fondazione Chips-IT + * + * 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 + * + * Author: Luca Balboni, Fondazione Chips-IT + * + * MAGIA Stats / Performance Counters + */ + +#ifndef MAGIA_STATS_H +#define MAGIA_STATS_H + +#include + +static inline void ccount_en(void){ +#if defined(CV32E40X) || defined(CV32E40P) + asm volatile("csrrci zero, 0x320, 0x1" ::); +#else + asm volatile("csrw 0x7E0, %0" :: "r"(0x1)); + asm volatile("csrw 0x7E1, %0" :: "r"(0x1)); +#endif +} + +static inline void ccount_dis(void){ +#if defined(CV32E40X) || defined(CV32E40P) + asm volatile("csrrsi zero, 0x320, 0x1" ::); +#else + asm volatile("csrw 0x7E1, %0" :: "r"(0x0)); +#endif +} + +static inline uint32_t perf_csr_cycle(void){ + uint32_t v; + asm volatile("csrr %0, 0xB00" : "=r"(v)); + return v; +} + +static inline uint32_t perf_csr_instret(void){ + uint32_t v; + asm volatile("csrr %0, 0xB02" : "=r"(v)); + return v; +} + +#define EVT_LD_STALL (1u << 2) +#define EVT_JR_STALL (1u << 3) +#define EVT_IMISS (1u << 4) +#define EVT_LD (1u << 5) +#define EVT_ST (1u << 6) +#define EVT_JUMP (1u << 7) +#define EVT_BRANCH (1u << 8) +#define EVT_BTAKEN (1u << 9) +#define EVT_RVC (1u << 10) + +#define MHPMCTR_INHIBIT_MASK (0xFF8u) + +#if defined(CV32E40P) + +static inline void hpmcount_ext_en(void){ + uint32_t mask = MHPMCTR_INHIBIT_MASK; + asm volatile("csrrc zero, 0x320, %0" :: "r"(mask)); +} + +static inline void hpmcount_ext_dis(void){ + uint32_t mask = MHPMCTR_INHIBIT_MASK; + asm volatile("csrrs zero, 0x320, %0" :: "r"(mask)); +} + +#define DECL_MHPMCTR(NAME, EVENT_CSR, COUNTER_CSR, EVENT_MASK) \ + static inline void hpmevent_set_##NAME(void) { \ + asm volatile("csrw " #EVENT_CSR ", %0" :: "r"((uint32_t)(EVENT_MASK))); \ + } \ + static inline uint32_t hpmcounter_get_##NAME(void) { \ + uint32_t v; \ + asm volatile("csrr %0, " #COUNTER_CSR : "=r"(v)); \ + return v; \ + } \ + static inline void hpmcounter_reset_##NAME(void) { \ + asm volatile("csrw " #COUNTER_CSR ", zero"); \ + } + +#else + +static inline void hpmcount_ext_en(void){ } +static inline void hpmcount_ext_dis(void){ } + +#define DECL_MHPMCTR(NAME, EVENT_CSR, COUNTER_CSR, EVENT_MASK) \ + static inline void hpmevent_set_##NAME(void) { } \ + static inline uint32_t hpmcounter_get_##NAME(void) { return 0; } \ + static inline void hpmcounter_reset_##NAME(void) { } + +#endif + +DECL_MHPMCTR(ld_stall, 0x323, 0xB03, EVT_LD_STALL) +DECL_MHPMCTR(jr_stall, 0x324, 0xB04, EVT_JR_STALL) +DECL_MHPMCTR(imiss, 0x325, 0xB05, EVT_IMISS) +DECL_MHPMCTR(ld, 0x326, 0xB06, EVT_LD) +DECL_MHPMCTR(st, 0x327, 0xB07, EVT_ST) +DECL_MHPMCTR(jump, 0x328, 0xB08, EVT_JUMP) +DECL_MHPMCTR(branch, 0x329, 0xB09, EVT_BRANCH) +DECL_MHPMCTR(btaken, 0x32A, 0xB0A, EVT_BTAKEN) +DECL_MHPMCTR(rvc, 0x32B, 0xB0B, EVT_RVC) + +#undef DECL_MHPMCTR + +static inline void hpmevent_configure_all(void){ + hpmevent_set_ld_stall(); + hpmevent_set_jr_stall(); + hpmevent_set_imiss(); + hpmevent_set_ld(); + hpmevent_set_st(); + hpmevent_set_jump(); + hpmevent_set_branch(); + hpmevent_set_btaken(); + hpmevent_set_rvc(); +} + +static inline void hpmcounter_reset_all(void){ + hpmcounter_reset_ld_stall(); + hpmcounter_reset_jr_stall(); + hpmcounter_reset_imiss(); + hpmcounter_reset_ld(); + hpmcounter_reset_st(); + hpmcounter_reset_jump(); + hpmcounter_reset_branch(); + hpmcounter_reset_btaken(); + hpmcounter_reset_rvc(); +} + +#endif /*MAGIA_STATS_H*/ diff --git a/sw/utils/magia_tile_utils.h b/sw/utils/magia_tile_utils.h index 3e4ac2a7..7329c4c2 100644 --- a/sw/utils/magia_tile_utils.h +++ b/sw/utils/magia_tile_utils.h @@ -52,9 +52,17 @@ #define PULP_READY (PULP_CTRL_BASE + 0x18) /* R 1 once all cores booted, W each core posts 1 once armed */ #define PULP_RETURN (PULP_CTRL_BASE + 0x1C) /* R/W task exit code, written by core 0 before PULP_DONE */ #define PULP_RETURN_CRASHED_BIT (0x80000000u) /* Set when core 0 trapped instead of returning */ -#define PULP_CTRL_END (0x000017FF) +#define PULP_CTRL_END (0x000017BF) #define PULP_CORE_COUNT (8) -#define PULP_HARTID_BASE (32) /* 2 * NUM_CLUSTERS (16) */ +#define PULP_HARTID_BASE (32) +// HCI arbiter control register (tile_csr + 0xC0) +#define HCI_ARB_CTRL_BASE (0x000017C0) +#define HCI_ARB_CTRL (HCI_ARB_CTRL_BASE + 0x00) +#define HCI_ARB_CTRL_END (0x000017FF) +#define HCI_ARB_CTRL_DEFAULT (0x00000000u) /* Denominator 0: default ratio of magia_hci_interconnect */ +#define HCI_ARB_INVERT_PRIO (1u << 0) +#define HCI_ARB_PRIO_NUM(n) (((n) & 0xFFu) << 8) +#define HCI_ARB_PRIO_DEN(n) (((n) & 0xFFu) << 16) #define COLL_CTRL_BASE (0x00001800) #define COLL_CTRL_END (0x000018FF) #define CLUSTER_EU_DIRECT_BASE (0x00001900) @@ -75,16 +83,6 @@ #define PASS_EXIT_CODE (0xAAAA) #define FAIL_EXIT_CODE (0xFFFF) -// Individual IRQ indices unnecessary - Event Unit provides unified interrupt management -// Use Event Unit API (event_unit_utils.h) for event handling -#define IRQ_REDMULE_EVT_0 (31) -#define IRQ_REDMULE_EVT_1 (30) -#define IRQ_A2O_DONE (27) -#define IRQ_O2A_DONE (26) -#define IRQ_A2O_START (25) -#define IRQ_O2A_START (24) -#define IRQ_FSYNC_DONE (20) - #define mmio64(x) (*(volatile uint64_t *)(x)) #define mmio32(x) (*(volatile uint32_t *)(x)) #define mmio16(x) (*(volatile uint16_t *)(x)) @@ -139,72 +137,4 @@ static inline void sentinel_end(){ asm volatile("addi x0, x0, 0x5FF" ::); } -static inline void ccount_en(){ -#if defined(CV32E40X) || defined(CV32E40P) - asm volatile("csrrci zero, 0x320, 0x1" ::); -#else - asm volatile("csrw 0x7E0, %0" :: "r"(0x1)); - asm volatile("csrw 0x7E1, %0" :: "r"(0x1)); -#endif -} - -static inline void ccount_dis(){ -#if defined(CV32E40X) || defined(CV32E40P) - asm volatile("csrrsi zero, 0x320, 0x1" ::); -#else - asm volatile("csrw 0x7E1, %0" :: "r"(0x0)); -#endif -} - -static inline uint32_t get_cyclel(){ - uint32_t cyclel; -#if defined(CV32E40X) || defined(CV32E40P) - asm volatile("csrr %0, cycle" - :"=r"(cyclel):); -#else - asm volatile("csrr %0, 0x780" : "=r"(cyclel)); -#endif - return cyclel; -} - -static inline uint32_t get_cycleh(){ - uint32_t cycleh; - asm volatile("csrr %0, cycleh" - :"=r"(cycleh):); - return cycleh; -} - -uint32_t get_cycle(){ - uint32_t cyclel = get_cyclel(); - uint32_t cycleh = get_cycleh(); - if (cycleh) return 0; - return cyclel; -} - -static inline uint32_t get_timel(){ - uint32_t timel; -#ifdef CV32E40X - asm volatile("csrr %0, time" - :"=r"(timel):); -#else - asm volatile("csrr %0, 0x781" - :"=r"(timel):); -#endif - return timel; -} - -static inline uint32_t get_timeh(){ - uint32_t timeh; - asm volatile("csrr %0, timeh" - :"=r"(timeh):); - return timeh; -} - -uint32_t get_time(){ - uint32_t timel = get_timel(); - uint32_t timeh = get_timeh(); - if (timeh) return 0; - return timel; -} - #endif /*MAGIA_TILE_UTILS_H*/