From fe12bd96b41985de974a98361b9ee0af7f9b66dc Mon Sep 17 00:00:00 2001 From: Francesco Conti Date: Fri, 4 Jul 2025 12:23:46 +0200 Subject: [PATCH 1/4] Squash of Luca Codeluppi's thesis - QoS modes part (RTL) initial commit multi-hwpe extension adjustment in write check corrected few errors push test QoS: bandwidth adjusted an error in read check few tests handled the scenario with 0 hwpe, core, ext, or dma waveform to check few modifies debug waveform correct the previous commit: debug this waveform PATH: corrected list of forbidden addresses, assign correct data during read transaction, create path if does't exist modified the makefile to automatically generate the stimuli corrected a small error in the python code small error in the upper bound (address generation) parametric number of HWPE_WIDTH added latency TEST QoS arbitration multi-hwpe: debug photo of waveforms for arbitration problem Enriched the makefile: setup targets updated python documentation corrected an error in tb_top: PRIORITY_CHECK and RANDOM_REQ macros adjusted QoS metrics example config modified hci_arbiter, added mode 1 cleaned the code eliminated task check_hwpe_read_task: redundant cleaned the code changed the description of the arbiter added another mode for the hci_arbiter changed description of the hci_arbiter removed unnecessary from tb_top.sv modified a name in the makefile removed nested generate in the arbiter propagate arbiter mode through the hci added TEST_RATIO: ratio between the number of transactions in the two branches debug corrected small error in tb_top Improved the makefile and changed the python script accordingly Eliminate few targets from makefile Eliminated the following targets: setup_bandwidth, setup_data_integ, setup_arbiter_stall, setup_arbiter_no_stall. Replaced with test_1.mk, test_2.mk, test_3.mk, test_4.mk in config folder forgot to add makefile to the staging area in the previous commit Clean makefile Fix MACRO_TB in the Makefile Eliminate unnecessary in tb_top.sv Change few messages in tb_top.sv Change name N_TEST in config files to N_TRANSACTION and add EXACT_OR_MAX_OFFSET Adapt python script to support EXACT_OR_MAX_OFFSET parameter Implement hci_inteconnect_wrap.sv and fix small error in hci_arbiter.sv Set default value for memory access pattern Eliminate WIDTH_OF_MEMORY and improve readability of sim_time metric Fix few comments Add module queue_stimuli.sv Add modules: queues_out and queues_rdata Add comments to write transaction checker Create verificaion_hci_package Define parameters, structs and tasks in the package Add arbiter_checker module Add macro in hci_package.sv and set ecc to 0 Add progress bar Modularize logic to compute QoS metrics Add end_simulation, progress_bar modules and fix bugs in hci_wrapper Add assignment modules between masters and hci Eliminate data_for_read_transaction method from python class stimuli_generator Fix output warning Add comments to tb_top for clarity Fix error in previous commit [Update] python documentation [Update] process_txt.py and class_stimuli_generator.py documentation [Clean] verification_hci_package.sv [Clean] the code [Clean] [FIX] small error in stimuli generation [Documentation] Update [FIX] README.md [Documentation] Update [Removed] unnecessary print --- rtl/common/hci_package.sv | 4 +- rtl/hci_interconnect.sv | 5 +- rtl/hci_interconnect_wrap.sv | 417 ++++++++++++++++++++++++++++++++ rtl/interco/hci_arbiter.sv | 186 +++++++++++--- rtl/interco/hci_arbiter_tree.sv | 7 +- 5 files changed, 574 insertions(+), 45 deletions(-) create mode 100644 rtl/hci_interconnect_wrap.sv diff --git a/rtl/common/hci_package.sv b/rtl/common/hci_package.sv index 1e3d1e1..76140c0 100644 --- a/rtl/common/hci_package.sv +++ b/rtl/common/hci_package.sv @@ -20,8 +20,8 @@ package hci_package; return (width != 32'd0) ? unsigned'(width - 1) : 32'd0; endfunction - parameter int unsigned DEFAULT_DW = 32; // Default Data Width - parameter int unsigned DEFAULT_AW = 32; // Default Address Width + parameter int unsigned DEFAULT_DW = `ifdef DATA_WIDTH `DATA_WIDTH `else 32 `endif; // Default Data Width + parameter int unsigned DEFAULT_AW = `ifdef TOT_MEM_SIZE $clog2(`TOT_MEM_SIZE*1024) `else 32 `endif; // Default Address Width parameter int unsigned DEFAULT_BW = 8; // Default Byte Width parameter int unsigned DEFAULT_UW = 1; // Default User Width parameter int unsigned DEFAULT_IW = 8; // Default ID Width diff --git a/rtl/hci_interconnect.sv b/rtl/hci_interconnect.sv index 9825891..56888c0 100644 --- a/rtl/hci_interconnect.sv +++ b/rtl/hci_interconnect.sv @@ -62,6 +62,7 @@ module hci_interconnect parameter int unsigned IW = N_HWPE+N_CORE+N_DMA+N_EXT, // ID Width parameter int unsigned EXPFIFO = 0 , // FIFO Depth for HWPE Interconnect parameter int unsigned SEL_LIC = 0 , // Log interconnect type selector + parameter int unsigned ARBITER_MODE = 0 , // Chosen mode for the arbiter parameter int unsigned FILTER_WRITE_R_VALID[0:N_HWPE-1] = '{default: 0}, parameter hci_size_parameter_t `HCI_SIZE_PARAM(cores) = '0, parameter hci_size_parameter_t `HCI_SIZE_PARAM(mems) = '0, @@ -257,6 +258,7 @@ module hci_interconnect hci_arbiter_tree #( .NB_REQUESTS(N_HWPE), .NB_CHAN ( N_MEM ), + .MODE( ARBITER_MODE ), .`HCI_SIZE_PARAM(out)(`HCI_SIZE_PARAM(hwpe_mem_muxed)) ) i_wide_port_arbiter_tree ( .clk_i ( clk_i ), @@ -268,7 +270,8 @@ module hci_interconnect ); hci_arbiter #( - .NB_CHAN ( N_MEM ) + .NB_CHAN ( N_MEM ), + .MODE( ARBITER_MODE ) ) i_wide_vs_narrow_arbiter ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), diff --git a/rtl/hci_interconnect_wrap.sv b/rtl/hci_interconnect_wrap.sv new file mode 100644 index 0000000..3b16c30 --- /dev/null +++ b/rtl/hci_interconnect_wrap.sv @@ -0,0 +1,417 @@ +/* + * hci_interconnect_wrap.sv + * + * Authors (hci_interconnect) + * -Francesco Conti + * -Tobias Riedener + * -Arpan Suravi Prasad + * + * + * Authors (hci_interconnect_wrap) + * -Luca Codeluppi + * + * Copyright (C) 2019-2020 ETH Zurich, 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. + */ +`include "hci_helpers.svh" + +module hci_interconnect_wrap + import hci_package::*; +#( + parameter int unsigned N_HWPE = 1 , // Number of HWPEs attached to the port + parameter int unsigned N_CORE = 8 , // Number of Core ports + parameter int unsigned N_DMA = 4 , // Number of DMA ports + parameter int unsigned N_EXT = 4 , // Number of External ports + parameter int unsigned N_MEM = 16 , // Number of Memory banks + parameter int unsigned TS_BIT = 21 , // TEST_SET_BIT (for Log Interconnect) + parameter int unsigned IW = N_HWPE+N_CORE+N_DMA+N_EXT , // ID Width + parameter int unsigned EXPFIFO = 0 , // FIFO Depth for HWPE Interconnect + parameter int unsigned SEL_LIC = 0 , // Log interconnect type selector + parameter int unsigned ARBITER_MODE = 0 , // Chosen mode for the arbiter + parameter int unsigned FILTER_WRITE_R_VALID[0:N_HWPE-1] = '{default: 0} , + + parameter int unsigned TOT_MEM_SIZE = 32 , // Total memory size (kB), this parameter is only used to define the default value for AW + parameter int unsigned HWPE_WIDTH = 4 , // Width of an HWPE wide-word (as a multiple of DW_cores), this parameter is only used to define the default value for DW_hwpe + + parameter int unsigned DW_cores = DEFAULT_DW , + parameter int unsigned AW_cores = DEFAULT_AW , + parameter int unsigned BW_cores = DEFAULT_BW , + parameter int unsigned UW_cores = DEFAULT_UW , + parameter int unsigned IW_cores = IW , + parameter int unsigned EW_cores = DEFAULT_EW , + parameter int unsigned EHW_cores = DEFAULT_EHW , + + parameter int unsigned DW_mems = DEFAULT_DW , + parameter int unsigned AW_mems = DEFAULT_AW - $clog2(N_MEM), + parameter int unsigned BW_mems = DEFAULT_BW , + parameter int unsigned UW_mems = DEFAULT_UW , + parameter int unsigned IW_mems = IW , + parameter int unsigned EW_mems = DEFAULT_EW , + parameter int unsigned EHW_mems = DEFAULT_EHW , + + parameter int unsigned DW_hwpe = HWPE_WIDTH*DEFAULT_DW , + parameter int unsigned AW_hwpe = DEFAULT_AW , + parameter int unsigned BW_hwpe = DEFAULT_BW , + parameter int unsigned UW_hwpe = DEFAULT_UW , + parameter int unsigned IW_hwpe = IW , + parameter int unsigned EW_hwpe = DEFAULT_EW , + parameter int unsigned EHW_hwpe = DEFAULT_EHW , + + parameter bit WAIVE_RQ3_ASSERT = 1'b0, + parameter bit WAIVE_RQ4_ASSERT = 1'b0, + parameter bit WAIVE_RSP3_ASSERT = 1'b0, + parameter bit WAIVE_RSP5_ASSERT = 1'b0 +) ( + input logic clk_i, + input logic rst_ni, + input logic clear_i, + + input logic [1:0] arb_policy, + input logic invert_prio, + input logic [7:0] low_prio_max_stall, + + input logic [N_CORE-1:0] req_cores, + output logic [N_CORE-1:0] gnt_cores, + input logic [N_CORE-1:0][AW_cores-1:0] add_cores, + input logic [N_CORE-1:0] wen_cores, + input logic [N_CORE-1:0][DW_cores-1:0] data_cores, + input logic [N_CORE-1:0][DW_cores/BW_cores-1:0] be_cores, + input logic [N_CORE-1:0] r_ready_cores, + input logic [N_CORE-1:0][UW_cores-1:0] user_cores, + input logic [N_CORE-1:0][IW_cores-1:0] id_cores, + output logic [N_CORE-1:0][DW_cores-1:0] r_data_cores, + output logic [N_CORE-1:0] r_valid_cores, + output logic [N_CORE-1:0][UW_cores-1:0] r_user_cores, + output logic [N_CORE-1:0][IW_cores-1:0] r_id_cores, + output logic [N_CORE-1:0] r_opc_cores, + input logic [N_CORE-1:0][EW_cores-1:0] ecc_cores, + output logic [N_CORE-1:0][EW_cores-1:0] r_ecc_cores, + input logic [N_CORE-1:0][EHW_cores-1:0] ereq_cores, + output logic [N_CORE-1:0][EHW_cores-1:0] egnt_cores, + output logic [N_CORE-1:0][EHW_cores-1:0] r_evalid_cores, + input logic [N_CORE-1:0][EHW_cores-1:0] r_eready_cores, + + input logic [N_DMA-1:0] req_dma, + output logic [N_DMA-1:0] gnt_dma, + input logic [N_DMA-1:0][AW_cores-1:0] add_dma, + input logic [N_DMA-1:0] wen_dma, + input logic [N_DMA-1:0][DW_cores-1:0] data_dma, + input logic [N_DMA-1:0][DW_cores/BW_cores-1:0] be_dma, + input logic [N_DMA-1:0] r_ready_dma, + input logic [N_DMA-1:0][UW_cores-1:0] user_dma, + input logic [N_DMA-1:0][IW_cores-1:0] id_dma, + output logic [N_DMA-1:0][DW_cores-1:0] r_data_dma, + output logic [N_DMA-1:0] r_valid_dma, + output logic [N_DMA-1:0][UW_cores-1:0] r_user_dma, + output logic [N_DMA-1:0][IW_cores-1:0] r_id_dma, + output logic [N_DMA-1:0] r_opc_dma, + input logic [N_DMA-1:0][EW_cores-1:0] ecc_dma, + output logic [N_DMA-1:0][EW_cores-1:0] r_ecc_dma, + input logic [N_DMA-1:0][EHW_cores-1:0] ereq_dma, + output logic [N_DMA-1:0][EHW_cores-1:0] egnt_dma, + output logic [N_DMA-1:0][EHW_cores-1:0] r_evalid_dma, + input logic [N_DMA-1:0][EHW_cores-1:0] r_eready_dma, + + input logic [N_EXT-1:0] req_ext, + output logic [N_EXT-1:0] gnt_ext, + input logic [N_EXT-1:0][AW_cores-1:0] add_ext, + input logic [N_EXT-1:0] wen_ext, + input logic [N_EXT-1:0][DW_cores-1:0] data_ext, + input logic [N_EXT-1:0][DW_cores/BW_cores-1:0] be_ext, + input logic [N_EXT-1:0] r_ready_ext, + input logic [N_EXT-1:0][UW_cores-1:0] user_ext, + input logic [N_EXT-1:0][IW_cores-1:0] id_ext, + output logic [N_EXT-1:0][DW_cores-1:0] r_data_ext, + output logic [N_EXT-1:0] r_valid_ext, + output logic [N_EXT-1:0][UW_cores-1:0] r_user_ext, + output logic [N_EXT-1:0][IW_cores-1:0] r_id_ext, + output logic [N_EXT-1:0] r_opc_ext, + input logic [N_EXT-1:0][EW_cores-1:0] ecc_ext, + output logic [N_EXT-1:0][EW_cores-1:0] r_ecc_ext, + input logic [N_EXT-1:0][EHW_cores-1:0] ereq_ext, + output logic [N_EXT-1:0][EHW_cores-1:0] egnt_ext, + output logic [N_EXT-1:0][EHW_cores-1:0] r_evalid_ext, + input logic [N_EXT-1:0][EHW_cores-1:0] r_eready_ext, + + input logic [N_HWPE-1:0] req_hwpe, + output logic [N_HWPE-1:0] gnt_hwpe, + input logic [N_HWPE-1:0][AW_hwpe-1:0] add_hwpe, + input logic [N_HWPE-1:0] wen_hwpe, + input logic [N_HWPE-1:0][DW_hwpe-1:0] data_hwpe, + input logic [N_HWPE-1:0][DW_hwpe/BW_hwpe-1:0] be_hwpe, + input logic [N_HWPE-1:0] r_ready_hwpe, + input logic [N_HWPE-1:0][UW_hwpe-1:0] user_hwpe, + input logic [N_HWPE-1:0][IW_hwpe-1:0] id_hwpe, + output logic [N_HWPE-1:0][DW_hwpe-1:0] r_data_hwpe, + output logic [N_HWPE-1:0] r_valid_hwpe, + output logic [N_HWPE-1:0][UW_hwpe-1:0] r_user_hwpe, + output logic [N_HWPE-1:0][IW_hwpe-1:0] r_id_hwpe, + output logic [N_HWPE-1:0] r_opc_hwpe, + input logic [N_HWPE-1:0][EW_hwpe-1:0] ecc_hwpe, + output logic [N_HWPE-1:0][EW_hwpe-1:0] r_ecc_hwpe, + input logic [N_HWPE-1:0][EHW_hwpe-1:0] ereq_hwpe, + output logic [N_HWPE-1:0][EHW_hwpe-1:0] egnt_hwpe, + output logic [N_HWPE-1:0][EHW_hwpe-1:0] r_evalid_hwpe, + input logic [N_HWPE-1:0][EHW_hwpe-1:0] r_eready_hwpe, + + output logic [N_MEM-1:0] req_mems, + input logic [N_MEM-1:0] gnt_mems, + output logic [N_MEM-1:0][AW_mems-1:0] add_mems, + output logic [N_MEM-1:0] wen_mems, + output logic [N_MEM-1:0][DW_mems-1:0] data_mems, + output logic [N_MEM-1:0][DW_mems/BW_mems-1:0] be_mems, + output logic [N_MEM-1:0] r_ready_mems, + output logic [N_MEM-1:0][UW_mems-1:0] user_mems, + output logic [N_MEM-1:0][IW_mems-1:0] id_mems, + input logic [N_MEM-1:0][DW_mems-1:0] r_data_mems, + input logic [N_MEM-1:0] r_valid_mems, + input logic [N_MEM-1:0][UW_mems-1:0] r_user_mems, + input logic [N_MEM-1:0][IW_mems-1:0] r_id_mems, + input logic [N_MEM-1:0] r_opc_mems, + output logic [N_MEM-1:0][EW_mems-1:0] ecc_mems, + input logic [N_MEM-1:0][EW_mems-1:0] r_ecc_mems, + output logic [N_MEM-1:0][EHW_mems-1:0] ereq_mems, + input logic [N_MEM-1:0][EHW_mems-1:0] egnt_mems, + input logic [N_MEM-1:0][EHW_mems-1:0] r_evalid_mems, + output logic [N_MEM-1:0][EHW_mems-1:0] r_eready_mems +); + // local parameters + localparam hci_package::hci_size_parameter_t `HCI_SIZE_PARAM(cores) = '{ // CORE + DMA + EXT parameters + DW : DW_cores, + AW : AW_cores, + BW : BW_cores, + UW : UW_cores, + IW : IW_cores, + EW : EW_cores, + EHW : EHW_cores + }; + + localparam hci_package::hci_size_parameter_t `HCI_SIZE_PARAM(mems) = '{ // Bank parameters + DW : DW_mems, + AW : AW_mems, + BW : BW_mems, + UW : UW_mems, + IW : IW_mems, + EW : EW_mems, + EHW : EHW_mems + }; + + localparam hci_package::hci_size_parameter_t `HCI_SIZE_PARAM(hwpe) = '{ // HWPE parameters + DW : DW_hwpe, + AW : AW_hwpe, + BW : BW_hwpe, + UW : UW_hwpe, + IW : IW_hwpe, + EW : EW_hwpe, + EHW : EHW_hwpe + }; + + // interfaces + hci_core_intf #( + .DW(HCI_SIZE_hwpe.DW), + .AW(HCI_SIZE_hwpe.AW), + .BW(HCI_SIZE_hwpe.BW), + .UW(HCI_SIZE_hwpe.UW), + .IW(HCI_SIZE_hwpe.IW), + .EW(HCI_SIZE_hwpe.EW), + .EHW(HCI_SIZE_hwpe.EHW) + ) hwpe_intc [0:N_HWPE-1] ( + .clk(clk_i) + ); + + hci_core_intf #( + .DW(HCI_SIZE_cores.DW), + .AW(HCI_SIZE_cores.AW), + .BW(HCI_SIZE_cores.BW), + .UW(HCI_SIZE_cores.UW), + .IW(HCI_SIZE_cores.IW), + .EW(HCI_SIZE_cores.EW), + .EHW(HCI_SIZE_cores.EHW) + ) all_except_hwpe [0:N_CORE+N_DMA+N_EXT-1] ( + .clk(clk_i) + ); + + hci_core_intf #( + .DW(HCI_SIZE_mems.DW), + .AW(HCI_SIZE_mems.AW), + .BW(HCI_SIZE_mems.BW), + .UW(HCI_SIZE_mems.UW), + .IW(HCI_SIZE_mems.IW), + .EW(HCI_SIZE_mems.EW), + .EHW(HCI_SIZE_mems.EHW) + ) intc_mem_wiring [0:N_MEM-1] ( + .clk(clk_i) + ); + + // bindings + generate + for(genvar ii=0; ii * Tobias Riedener + * Luca Codeluppi * * Copyright (C) 2019-2024 ETH Zurich, University of Bologna * Copyright and related rights are licensed under the Solderpad Hardware @@ -24,8 +25,18 @@ * The arbiter uses a starvation-free unbalanced-priority scheme where one of * the input channels has by default access to most of the bandwidth guaranteed * by the output channels. To prevent starvation effects, depending on the control - * settings, the other input channel is always granted after a given number - * of stall cycles. + * settings and on the arbiter mode, the other input channel is always granted after a + * certain number of cycles. + * Two possible arbitration mode are provided: + * + * - Mode 0 (default): the signal "low_prio_max_stall" sets the maximum number of consecutive cycles with at least one request in both + * the high and low priority channel. **NOTE** The name of the signal could be misleading, but it is kept as it is to maintain consistency with previous verions + * of the hci_arbiter, where there was no distinction between Mode 0 and Mode 1 and where this signal was actually used improperly, + * + * - Mode 1: the signal "low_prio_max_stall" sets the maximum number of consecutive stalls on low-priority channel. + * + * There is also a third hardware implementation (Mode 2), not yet tested, with the same theoretical behaviour of Mode 1, but with less logic gates. + * * For more details, see: * - https://ieeexplore.ieee.org/document/9903915, Sec. II-A (open-access); * - https://ieeexplore.ieee.org/document/10247945 , Sec. II-A, III-B, and III-C. @@ -44,20 +55,25 @@ * .. _hci_arbiter_ctrl: * .. table:: **hci_arbiter** input control signals. * - * +----------------------+------------------------+---------------------------------------------------------------+ - * | **Name** | **Type** | **Description** | - * +----------------------+------------------------+---------------------------------------------------------------+ - * | *invert_prio* | `logic` | When 1, invert priorities between `in_high` and `in_low`. | - * +----------------------+------------------------+---------------------------------------------------------------+ - * | *low_prio_max_stall* | `logic[7:0]` | Maximum number of consecutive stalls on low-priority channel. | - * +----------------------+------------------------+---------------------------------------------------------------+ + * +----------------------+------------------------+-------------------------------------------------------------------------------------------+ + * | **Name** | **Type** | **Description** | + * +----------------------+------------------------+-------------------------------------------------------------------------------------------+ + * | *invert_prio* | `logic` | When 1, invert priorities between `in_high` and `in_low`. | + * +----------------------+------------------------+-------------------------------------------------------------------------------------------+ + * | | | - Mode 0: Maximum number of consecutive cycles with at least one request in both | + * | | | the high and low priority channel. | + * | *low_prio_max_stall* | `logic[7:0]` | | + * | | | - Mode 1 & Mode 2: Maximum number of consecutive stalls on low-priority channel. | + * | | | | + * +----------------------+------------------------+-------------------------------------------------------------------------------------------+ * */ module hci_arbiter import hci_package::*; #( - parameter int unsigned NB_CHAN = 2 + parameter int unsigned NB_CHAN = 2, + parameter int unsigned MODE = 0 ) ( input logic clk_i, @@ -76,32 +92,13 @@ module hci_arbiter logic hs_req_d; logic ls_req_d; logic switch_channels_d; + logic invert_prio_one_cycle; + logic conflict; logic unsigned [7:0] ls_stall_ctr_d; - // priority_req is the OR of all requests coming out of the log interconnect. - // it should be simplified to simply an OR of all requests coming *into* the - // log interconnect directly within the synthesis tool. - always_comb - begin - hs_req_d = |hs_req_in; - ls_req_d = |ls_req_in; - if (ctrl_i.low_prio_max_stall > 0) //Set to 0 to disable this functionality - begin - if (ls_stall_ctr_d >= ctrl_i.low_prio_max_stall) - hs_req_d = 0; //Let low side through for once - end - end - - //Low side stall counter - always_ff @(posedge clk_i or negedge rst_ni) - begin - if (~rst_ni) - ls_stall_ctr_d <= 0; - else if (hs_req_d & ls_req_d) - ls_stall_ctr_d <= ls_stall_ctr_d + 1; - else - ls_stall_ctr_d <= 0; - end + //----------------------------------------------------------------------- + //- COMMON PART - + //----------------------------------------------------------------------- assign switch_channels_d = ctrl_i.invert_prio; @@ -126,12 +123,6 @@ module hci_arbiter end // req_mapping endgenerate - // Side select - generate - for(genvar ii=0; ii 0) //Set to 0 to disable this functionality + begin + if (ls_stall_ctr_d >= ctrl_i.low_prio_max_stall) + hs_req_d = 0; //Let low side through for once + end + end + + //Low side stall counter + always_ff @(posedge clk_i or negedge rst_ni) + begin + if (~rst_ni) + ls_stall_ctr_d <= 0; + else if (hs_req_d & ls_req_d) + ls_stall_ctr_d <= ls_stall_ctr_d + 1; + else + ls_stall_ctr_d <= 0; + end + // Side select + + for(genvar ii=0; ii 0) //Set to 0 to disable this functionality + begin + if (ls_stall_ctr_d >= ctrl_i.low_prio_max_stall) + hs_req_d = 0; //Let low side through for once + end + end + + //Low side stall counter + always_ff @(posedge clk_i or negedge rst_ni) + begin + if (~rst_ni) + ls_stall_ctr_d <= 0; + else if (conflict & hs_req_d) + ls_stall_ctr_d <= ls_stall_ctr_d + 1; + else + ls_stall_ctr_d <= 0; + end + + // Side select + + for(genvar ii=0; ii 0) //Set to 0 to disable this functionality + begin + if (ls_stall_ctr_d >= ctrl_i.low_prio_max_stall) + invert_prio_one_cycle = 1'b1; //Let low side through for once + end + end + + //Low side stall counter + always_ff @(posedge clk_i or negedge rst_ni) + begin + if (~rst_ni) + ls_stall_ctr_d <= 0; + else if (conflict & !invert_prio_one_cycle) + ls_stall_ctr_d <= ls_stall_ctr_d + 1; + else + ls_stall_ctr_d <= 0; + end + + // Side select + + for(genvar ii=0; ii