diff --git a/comp/base/pkg/type_pack.vhd b/comp/base/pkg/type_pack.vhd index d4d10a1dd..510aa64ae 100644 --- a/comp/base/pkg/type_pack.vhd +++ b/comp/base/pkg/type_pack.vhd @@ -42,6 +42,15 @@ package type_pack is -- This function returns a new array where each element is a sliced portion of the original array's elements. function slv_array_slice (arr: slv_array_t; hi, lo: natural) return slv_array_t; + -- Functions to concatenate either items of one array and a bit(s) of a vector or items of 2 arrays. + -- Standard concatenation order: bits of the TOP vector/array are placed on top of the bits of the BASE array. + -- Reversed concatenation order: bits of the BASE array are placed on top of the bits of the TOP vector/array. + -- Concatenation MODE: + -- - 0: concatenate one bit of the top vector/one Item of the top array to the base array. + -- - 1: concatenate the whole top vector/all items(serialized) of the top array to the base array. + function concat_arr(base: slv_array_t; top: std_logic_vector; reverse: boolean := false; mode: integer := 0) return slv_array_t; + function concat_arr(base: slv_array_t; top: slv_array_t; reverse: boolean := false; mode: integer := 0) return slv_array_t; + -- Array of std_array_t -- type slv_array_2d_t is array (natural range <>) of slv_array_t type slv_array_2d_t is array (natural range <>) of slv_array_t; @@ -295,6 +304,81 @@ package body type_pack is return ret; end function; + function concat_arr(base: slv_array_t; top: slv_array_t; reverse: boolean := false; mode: integer := 0) return slv_array_t is + variable arr_m0 : slv_array_t (base'length-1 downto 0)(base(0)'length+top(0)'length -1 downto 0); + variable arr_m1 : slv_array_t (base'length-1 downto 0)(base(0)'length+top(0)'length*top'length-1 downto 0); + variable top_ser : std_logic_vector( top(0)'length*top'length-1 downto 0); + begin + assert (top'length = base'length) or (mode = 1) + report "concat_arr: Arrays must have the same number of Items!" + severity Failure; + + if (reverse) then + -- Reverse mode does not really make sense here, though. + -- You could just switch the order of the arrays when sending them to the function. + if (mode = 0) then + for i in 0 to base'length-1 loop + arr_m0(i) := base(i) & top(i); + end loop; + return arr_m0; + else + top_ser := slv_array_ser(top); + for i in 0 to base'length-1 loop + arr_m1(i) := base(i) & top_ser; + end loop; + return arr_m1; + end if; + else + if (mode = 0) then + for i in 0 to base'length-1 loop + arr_m0(i) := top(i) & base(i); + end loop; + return arr_m0; + else + top_ser := slv_array_ser(top); + for i in 0 to base'length-1 loop + arr_m1(i) := top_ser & base(i); + end loop; + return arr_m1; + end if; + end if; + end; + + function concat_arr(base: slv_array_t; top: std_logic_vector; reverse: boolean := false; mode: integer := 0) return slv_array_t is + variable arr_m0 : slv_array_t(base'length-1 downto 0)(base(0)'length+1 -1 downto 0); + variable arr_m1 : slv_array_t(base'length-1 downto 0)(base(0)'length+top'length-1 downto 0); + begin + assert (top'length = base'length) or (mode = 1) + report "concat_arr: The Vector must be as wide as the Array has Items!" + severity Failure; + + if (reverse) then + if (mode = 0) then + for i in 0 to base'length-1 loop + arr_m0(i) := base(i) & top(i); + end loop; + return arr_m0; + else + for i in 0 to base'length-1 loop + arr_m1(i) := base(i) & top; + end loop; + return arr_m1; + end if; + else + if (mode = 0) then + for i in 0 to base'length-1 loop + arr_m0(i) := top(i) & base(i); + end loop; + return arr_m0; + else + for i in 0 to base'length-1 loop + arr_m1(i) := top & base(i); + end loop; + return arr_m1; + end if; + end if; + end; + function slv_array_2d_ser(slv_array_2d: slv_array_2d_t; ITEMS_X: integer; ITEMS_Y: integer; DATA_WIDTH: integer) return std_logic_vector is variable rv : std_logic_vector(ITEMS_X*ITEMS_Y*DATA_WIDTH-1 downto 0); begin diff --git a/comp/mvb_tools/flow/item_collision_resolver/Modules.tcl b/comp/mvb_tools/flow/item_collision_resolver/Modules.tcl new file mode 100644 index 000000000..18358571f --- /dev/null +++ b/comp/mvb_tools/flow/item_collision_resolver/Modules.tcl @@ -0,0 +1,14 @@ +# Modules.tcl: Script to compile single module +# Copyright (C) 2024 CESNET +# Author: Daniel Kondys +# +# SPDX-License-Identifier: BSD-3-Clause + +set FIFO_BASE "$OFM_PATH/comp/base/fifo" + +lappend PACKAGES "$OFM_PATH/comp/base/pkg/math_pack.vhd" +lappend PACKAGES "$OFM_PATH/comp/base/pkg/type_pack.vhd" + +lappend COMPONENTS [list "FIFOX_MULTI" "$FIFO_BASE/fifox_multi" "FULL" ] + +lappend MOD "$ENTITY_BASE/mvb_item_collision_resolver.vhd" diff --git a/comp/mvb_tools/flow/item_collision_resolver/mvb_item_collision_resolver.vhd b/comp/mvb_tools/flow/item_collision_resolver/mvb_item_collision_resolver.vhd new file mode 100644 index 000000000..907d30213 --- /dev/null +++ b/comp/mvb_tools/flow/item_collision_resolver/mvb_item_collision_resolver.vhd @@ -0,0 +1,135 @@ +-- mvb_item_collision_resolver.vhd: +-- Copyright (C) 2024 CESNET +-- Author(s): Daniel Kondys +-- +-- SPDX-License-Identifier: BSD-3-Clause + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; + +use work.math_pack.all; +use work.type_pack.all; + +-- The component MVB_ITEM_COLLISION_RESOLVER ensures that only Items with different data are valid at the output in each clock cycle. +-- When the data at the output are the same, they are invalidated (all but one). +-- +-- The data are stored in a FIFO and await to be read. +-- After each read (TX_DST_RDY='1'), the logic analyzes the output data anew and recalculates the valid signal (TX_VALID). +-- This mechanism nullifies Item collisions at the cost of lowering the throughput in such cases. +-- +entity MVB_ITEM_COLLISION_RESOLVER is +generic ( + ITEM_WIDTH : natural := 10; + META_WIDTH : natural := 10; + ITEMS : natural := 4; + DEVICE : string := "AGILEX" +); +port ( + CLK : in std_logic; + RESET : in std_logic; + + RX_DATA : in slv_array_t (ITEMS-1 downto 0)(ITEM_WIDTH-1 downto 0); + RX_META : in slv_array_t (ITEMS-1 downto 0)(META_WIDTH-1 downto 0); + RX_VALID : in std_logic_vector(ITEMS-1 downto 0); + RX_SRC_RDY : in std_logic; + RX_DST_RDY : out std_logic; + + TX_DATA : out slv_array_t (ITEMS-1 downto 0)(ITEM_WIDTH-1 downto 0); + TX_META : out slv_array_t (ITEMS-1 downto 0)(META_WIDTH-1 downto 0); + TX_VALID : out std_logic_vector(ITEMS-1 downto 0); + TX_SRC_RDY : out std_logic; + TX_DST_RDY : in std_logic + +); +end entity; + +architecture FULL of MVB_ITEM_COLLISION_RESOLVER is + + constant FIFOXM_WIDTH : natural := META_WIDTH + ITEM_WIDTH; + + signal fifoxm_din_arr : slv_array_t (ITEMS-1 downto 0)(FIFOXM_WIDTH-1 downto 0); + signal fifoxm_din : std_logic_vector(ITEMS* FIFOXM_WIDTH-1 downto 0); + signal fifoxm_write : std_logic_vector(ITEMS-1 downto 0); + signal fifoxm_full : std_logic; + signal fifoxm_dout : std_logic_vector(ITEMS* FIFOXM_WIDTH-1 downto 0); + signal fifoxm_read : std_logic_vector(ITEMS-1 downto 0); + signal fifoxm_read_inner : std_logic_vector(ITEMS-1 downto 0); + signal fifoxm_empty : std_logic_vector(ITEMS-1 downto 0); + signal fifoxm_dout_arr : slv_array_t (ITEMS-1 downto 0)(FIFOXM_WIDTH-1 downto 0); + signal tx_meta_arr : slv_array_t (ITEMS-1 downto 0)(META_WIDTH-1 downto 0); + signal tx_data_arr : slv_array_t (ITEMS-1 downto 0)(ITEM_WIDTH-1 downto 0); + signal item_same : std_logic_vector(ITEMS-1 downto 1); + +begin + + fifoxm_din_g : for i in 0 to ITEMS-1 generate + fifoxm_din_arr(i) <= RX_META(i) & RX_DATA(i); + end generate; + + fifoxm_din <= slv_array_ser(fifoxm_din_arr); + fifoxm_write <= RX_VALID and RX_SRC_RDY; + RX_DST_RDY <= not fifoxm_full; + + -- Pure shakedown could be used instead of FIFOXM. + -- Also, no shakedown should be a possibility as well. + shakedown_i : entity work.FIFOX_MULTI + generic map( + DATA_WIDTH => FIFOXM_WIDTH, + ITEMS => 32 , + WRITE_PORTS => ITEMS , + READ_PORTS => ITEMS , + RAM_TYPE => "AUTO" , + DEVICE => DEVICE , + ALMOST_FULL_OFFSET => 0 , + ALMOST_EMPTY_OFFSET => 0 , + ALLOW_SINGLE_FIFO => True , + SAFE_READ_MODE => False + ) + port map( + CLK => CLK , + RESET => RESET , + + DI => fifoxm_din , + WR => fifoxm_write, + FULL => fifoxm_full , + AFULL => open , + + DO => fifoxm_dout , + RD => fifoxm_read , + EMPTY => fifoxm_empty, + AEMPTY => open + ); + + fifoxm_read <= fifoxm_read_inner and TX_DST_RDY; + + fifoxm_dout_arr <= slv_array_deser(fifoxm_dout, ITEMS); + fifoxm_dout_g : for i in 0 to ITEMS-1 generate + tx_meta_arr(i) <= fifoxm_dout_arr(i)(FIFOXM_WIDTH-1 downto ITEM_WIDTH); + tx_data_arr(i) <= fifoxm_dout_arr(i)(ITEM_WIDTH -1 downto 0); + end generate; + + process(all) + begin + item_same <= (others => '0'); -- validated by "not fifoxm_empty" below + for i in 1 to ITEMS-1 loop + for ii in i to ITEMS-1 loop + if (tx_data_arr(i-1) = tx_data_arr(ii)) then + item_same(i) <= '1'; + end if; + end loop; + end loop; + end process; + + -- Component's "inner" read: signals valid (and not same) Data at the output. + fifoxm_read_inner(0) <= not fifoxm_empty(0); + fifoxm_read_inner_g : for i in 1 to ITEMS-1 generate + fifoxm_read_inner(i) <= not fifoxm_empty(i) when (or item_same(i downto 1) = '0') else '0'; + end generate; + + TX_DATA <= tx_data_arr; + TX_META <= tx_meta_arr; + TX_VALID <= fifoxm_read_inner; + TX_SRC_RDY <= or fifoxm_read_inner; + +end architecture; diff --git a/comp/mvb_tools/flow/item_collision_resolver/readme.rst b/comp/mvb_tools/flow/item_collision_resolver/readme.rst new file mode 100644 index 000000000..4323b1cf8 --- /dev/null +++ b/comp/mvb_tools/flow/item_collision_resolver/readme.rst @@ -0,0 +1,6 @@ +.. _mvb_item_collision_resolver: + +MVB Item Collision Resolver +--------------------------- + +.. vhdl:autoentity:: MVB_ITEM_COLLISION_RESOLVER diff --git a/comp/mvb_tools/flow/item_collision_resolver/synth/Makefile b/comp/mvb_tools/flow/item_collision_resolver/synth/Makefile new file mode 100644 index 000000000..dc04b95bd --- /dev/null +++ b/comp/mvb_tools/flow/item_collision_resolver/synth/Makefile @@ -0,0 +1,12 @@ +# Makefile: Makefile to compile module +# Copyright (C) 2024 CESNET +# Author: Daniel Kondys +# +# SPDX-License-Identifier: BSD-3-Clause + +TOP_LEVEL_ENT=MVB_ITEM_COLLISION_RESOLVER +SYNTH=quartus + +all: comp +include ../../../../../build/Makefile +.PHONY: all diff --git a/doc/source/mvb.rst b/doc/source/mvb.rst index f4d623c3d..a623f3c58 100644 --- a/doc/source/mvb.rst +++ b/doc/source/mvb.rst @@ -12,6 +12,7 @@ Components using the MFB bus are typically located in the ``comp/mvb_tools/`` di comp/mvb_tools/readme comp/mvb_tools/flow/channel_router/readme comp/mvb_tools/flow/discard/readme + comp/mvb_tools/flow/item_collision_resolver/readme comp/mvb_tools/flow/merge_items/readme comp/mvb_tools/flow/merge_streams/readme comp/mvb_tools/flow/demux/readme