From 9a7bffadec0512b7edeb3ddac08ffd3e9f27e91e Mon Sep 17 00:00:00 2001 From: MaxP Date: Wed, 16 Apr 2025 17:25:35 +0000 Subject: [PATCH] Adds configurable PipelineFilter with AXI-like handshake Implements a generic VHDL entity for data filtering based on a bitmask and comparison modes. Supports configurable filtering modes such as 'none', 'or', 'and', 'xor', 'equal', and 'not_equal'. Integrates AXI-like valid/ready handshake for synchronous data transfer. Ensures proper handling of unrecognized modes and validates mask size at runtime. --- src/PipelineFilter.vhd | 140 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 src/PipelineFilter.vhd diff --git a/src/PipelineFilter.vhd b/src/PipelineFilter.vhd new file mode 100644 index 0000000..9ef65f2 --- /dev/null +++ b/src/PipelineFilter.vhd @@ -0,0 +1,140 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.math_real.all; + +entity PipelineFilter is + generic ( + --@ Width of the comparison input and mask. + G_MaskWidth : integer := 4; + + --@ Bit mask to be compared against `I_Match` input. + G_Mask : std_logic_vector := "1010"; + + --@ Comparison mode that defines the filter behavior. + --@ Available modes: + --@ - `"none"`: Disables filtering; always passes data. + --@ - `"or"`: Filters if **any** bit in `I_Match` matches a bit set in `G_Mask`. + --@ - `"and"`: Filters if **all** bits set in `G_Mask` are also set in `I_Match`. + --@ - `"xor"`: Filters if **any** bit differs between `I_Match` and `G_Mask`. + --@ - `"equal"`: Filters if `I_Match` is **bitwise equal** to `G_Mask`. + --@ - `"not_equal"`: Filters if `I_Match` is **not equal** to `G_Mask`. + G_MaskMode : string := "equal" + ); + port ( + I_Match : in std_logic_vector(G_MaskWidth - 1 downto 0) := (others => '0'); + + --@ @virtualbus AXI-Flags-In @dir In Input interface for AXI-like handshake + --@ AXI like valid; (**Synchronous**, **Active high**) + I_Valid : in std_logic := '0'; + --@ AXI like ready; (**Synchronous**, **Active high**) + O_Ready : out std_logic := '0'; + --@ @end + + --@ @virtualbus AXI-Flags-Out @dir Out Output interface for AXI-like handshake + --@ AXI like valid; (**Synchronous**, **Active high**) + O_Valid : out std_logic := '0'; + --@ AXI like ready; (**Synchronous**, **Active high**) + I_Ready : in std_logic := '0' + --@ @end + ); +end entity PipelineFilter; + +architecture RTL of PipelineFilter is + function strings_equal(A, B : string) return boolean is + begin + if A'length /= B'length then + return false; + end if; + + for i in A'range loop + if A(i) /= B(i) then + return false; + end if; + end loop; + + return true; + end function; + + constant K_Mode_None : string := "none"; + constant K_Mode_OR : string := "or"; + constant K_Mode_XOR : string := "xor"; + constant K_Mode_AND : string := "and"; + constant K_Mode_Equal : string := "equal"; + constant K_Mode_NotEqual : string := "not_equal"; + + signal C_ShouldFiltered : std_logic := '0'; +begin + assert G_Mask'length = G_MaskWidth + report "G_Mask length does not match G_MaskWidth" severity failure; + + process (I_Match) + begin + if strings_equal(G_MaskMode, K_Mode_None) then + --@ No filtering: Always pass the data through. + C_ShouldFiltered <= '0'; + + elsif strings_equal(G_MaskMode, K_Mode_OR) then + --@ Filter if **any** bit in I_Match matches a bit set in G_Mask. + --@ Equivalent to: (I_Match AND G_Mask) /= 0 + if (I_Match and G_Mask) /= (G_MaskWidth - 1 downto 0 => '0') then + C_ShouldFiltered <= '1'; + else + C_ShouldFiltered <= '0'; + end if; + + elsif strings_equal(G_MaskMode, K_Mode_XOR) then + --@ Filter if **any** bit differs between I_Match and G_Mask. + --@ This checks if the vectors are **not bitwise equal**. + if (I_Match xor G_Mask) /= (G_MaskWidth - 1 downto 0 => '0') then + C_ShouldFiltered <= '1'; + else + C_ShouldFiltered <= '0'; + end if; + + elsif strings_equal(G_MaskMode, K_Mode_AND) then + --@ Filter if **all bits** set in G_Mask are also set in I_Match. + --@ In other words, I_Match must contain the full mask. + if (I_Match and G_Mask) = G_Mask then + C_ShouldFiltered <= '1'; + else + C_ShouldFiltered <= '0'; + end if; + + elsif strings_equal(G_MaskMode, K_Mode_Equal) then + --@ Filter if I_Match is **exactly equal** to G_Mask. + if I_Match = G_Mask then + C_ShouldFiltered <= '1'; + else + C_ShouldFiltered <= '0'; + end if; + + elsif strings_equal(G_MaskMode, K_Mode_NotEqual) then + --@ Filter if I_Match is **not equal** to G_Mask. + if I_Match /= G_Mask then + C_ShouldFiltered <= '1'; + else + C_ShouldFiltered <= '0'; + end if; + + else + --@ Unknown mode: fallback to no filtering. + C_ShouldFiltered <= '0'; + end if; + end process; + + process (I_Valid, I_Ready, C_ShouldFiltered) + begin + if C_ShouldFiltered = '1' then + --@ Data is filtered: do not pass it through. + O_Valid <= '0'; + --@ Assert O_Ready to indicate that the input is ready to accept data. + O_Ready <= '1'; + else + --@ Data is not filtered: pass it through. + O_Valid <= I_Valid; + O_Ready <= I_Ready; + end if; + end process; + +end architecture;