From d61462d4ce7bf6621aa8ad0020a19d9183633832 Mon Sep 17 00:00:00 2001 From: Tobias Weber Date: Mon, 27 Nov 2017 11:37:00 +0100 Subject: [PATCH] simple multiplexer for data fifos. --- mupix/Mupix8/sources/DataMux.vhd | 141 +++++++++++++++++++++++++++ mupix/Mupix8/tb/DataMuxTest.vhd | 158 +++++++++++++++++++++++++++++++ 2 files changed, 299 insertions(+) create mode 100644 mupix/Mupix8/sources/DataMux.vhd create mode 100644 mupix/Mupix8/tb/DataMuxTest.vhd diff --git a/mupix/Mupix8/sources/DataMux.vhd b/mupix/Mupix8/sources/DataMux.vhd new file mode 100644 index 0000000..f7fe6a1 --- /dev/null +++ b/mupix/Mupix8/sources/DataMux.vhd @@ -0,0 +1,141 @@ +------------------------------------------------------------------ +--FIFO Data Multiplexer for n input channels to 1 output channels +--T. Weber, Ruhr Universität Bochum +------------------------------------------------------------------ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.StdTypes.all; + +entity FiFoDataMux is + generic( + g_datawidth : integer := 32; -- data width + g_inputs : integer := 4; -- number of inputs to multiplexer + g_clockspeed : integer := 1e8 -- fpga clock speed + ); + port( + clk : in std_logic; -- clock input + rst : in std_logic; -- reset input + fifo_empty : in std_logic_vector(g_inputs - 1 downto 0); -- input FIFO empty flags + fifo_full : in std_logic_vector(g_inputs - 1 downto 0); -- input FIFO full flags + fifo_datain : in std_logic_vector(g_inputs*g_datawidth - 1 downto 0); -- input data from FIFOs + fifo_mask : in std_logic_vector(g_inputs - 1 downto 0); -- enable mask for FIFO inputs + fifo_rden : out std_logic_vector(g_inputs - 1 downto 0); -- read enable to FIFOs + buff_wren : out std_logic; -- write enable to output buffer + dataout : out std_logic_vector(g_datawidth - 1 downto 0); -- data output + wordin_freq : out std_logic_vector(32*g_inputs - 1 downto 0); -- number of input words from FIFOs + fifo_full_o : out std_logic -- or over input fifo full flags + ); +end entity FiFoDataMux; + + +architecture RTL of FiFoDataMux is + + signal ticks_counter : unsigned(f_log2(g_clockspeed) - 1 downto 0) := (others => '0'); + signal inword_counter : t_counter_array(0 to g_inputs - 1) := (others => (others => '0')); + signal increase_counter : std_logic_vector(g_inputs - 1 downto 0) := (others => '0'); + + signal fifo_full_i : std_logic; + + signal fifo_sel_i : integer range -1 to g_inputs - 1 := -1; + signal fifo_sel_reg : integer range 0 to g_inputs - 1 := 0; + + type t_mux_state is (idle, wait_fifo, write); + signal mux_fsm : t_mux_state := idle; + +begin + + fifo_select_proc : process(fifo_empty, fifo_mask) is + variable sel : integer range -1 to g_inputs - 1; + begin + sel := -1; + for i in 0 to g_inputs - 1 loop + if fifo_empty(i) = '0' and fifo_mask(i) = '1' then + sel := i; + end if; + end loop; + fifo_sel_i <= sel; + end process fifo_select_proc; + + full_flag_proc : process(fifo_full) is + variable full : std_logic := '0'; + begin + full := '0'; + for i in 0 to fifo_full'length - 1 loop + full := full or fifo_full(i); + end loop; + fifo_full_i <= full; + end process full_flag_proc; + + input_freq : process (clk) is + begin + if rising_edge(clk) then + if rst = '1' then + ticks_counter <= (others => '0'); + inword_counter <= (others => (others => '0')); + else + if increase_counter(fifo_sel_reg) = '1' then + inword_counter(fifo_sel_reg) <= inword_counter(fifo_sel_reg) + 1; + else + inword_counter(fifo_sel_reg) <= inword_counter(fifo_sel_reg); + end if; + if ticks_counter = g_clockspeed - 1 then + inword_counter <= (others => (others => '0')); + ticks_counter <= (others => '0'); + wordin_freq <= counter_array_to_stdvec(inword_counter); + else + ticks_counter <= ticks_counter + 1; + end if; + end if; + end if; + end process input_freq; + + + mux_proc : process(clk) is + begin + if rising_edge(clk) then + if rst = '1' then + fifo_sel_reg <= 0; + buff_wren <= '0'; + dataout <= (others => '0'); + fifo_rden <= (others => '0'); + else + case mux_fsm is + when idle => + fifo_rden <= (others => '0'); + buff_wren <= '0'; + dataout <= (others => '0'); + if fifo_sel_i /= -1 then + fifo_sel_reg <= fifo_sel_i; + fifo_rden(fifo_sel_i) <= '1'; + mux_fsm <= wait_fifo; + else + fifo_sel_reg <= 0; + mux_fsm <= idle; + end if; + when wait_fifo => + fifo_rden(fifo_sel_i) <= '1'; + mux_fsm <= write; + when write => + dataout <= fifo_datain((fifo_sel_reg + 1)*g_datawidth - 1 downto g_datawidth*fifo_sel_reg); + if fifo_empty(fifo_sel_reg) = '0' then + mux_fsm <= write; + fifo_rden(fifo_sel_reg) <= '1'; + buff_wren <= '1'; + increase_counter(fifo_sel_reg) <= '1'; + else + mux_fsm <= idle; + fifo_rden(fifo_sel_reg) <= '0'; + buff_wren <= '1'; + increase_counter <= (others => '0'); + end if; + end case; + end if; + end if; + end process mux_proc; + + + fifo_full_o <= fifo_full_i; + +end architecture RTL; diff --git a/mupix/Mupix8/tb/DataMuxTest.vhd b/mupix/Mupix8/tb/DataMuxTest.vhd new file mode 100644 index 0000000..b0f5f3a --- /dev/null +++ b/mupix/Mupix8/tb/DataMuxTest.vhd @@ -0,0 +1,158 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.StdTypes.all; + +entity DataMuxTest is +end entity DataMuxTest; + +architecture sim of DataMuxTest is + + component FiFoDataMux + generic( + g_datawidth : integer := 32; + g_inputs : integer := 4; + g_clockspeed : integer := 1e8 + ); + port( + clk : in std_logic; + rst : in std_logic; + fifo_empty : in std_logic_vector(g_inputs - 1 downto 0); + fifo_full : in std_logic_vector(g_inputs - 1 downto 0); + fifo_datain : in std_logic_vector(g_inputs*g_datawidth - 1 downto 0); + fifo_mask : in std_logic_vector(g_inputs - 1 downto 0); + fifo_rden : out std_logic_vector(g_inputs - 1 downto 0); + buff_wren : out std_logic; + dataout : out std_logic_vector(g_datawidth - 1 downto 0); + wordin_freq : out std_logic_vector(32*g_inputs - 1 downto 0); + fifo_full_o : out std_logic + ); + end component FiFoDataMux; + + component STD_FIFO + generic( + DATA_WIDTH : positive := 8; + FIFO_DEPTH : positive := 256 + ); + port( + CLK : in std_logic; + RST : in std_logic; + WriteEn : in std_logic; + DataIn : in std_logic_vector(DATA_WIDTH - 1 downto 0); + ReadEn : in std_logic; + DataOut : out std_logic_vector(DATA_WIDTH - 1 downto 0); + Empty : out std_logic; + Full : out std_logic + ); + end component STD_FIFO; + + constant c_datawidth : integer := 8; + constant c_inputs : integer := 2; + constant c_clockspeed : integer := 1e3; + constant c_fifo_depth : integer := 16; + + constant c_clk_period : time := 10 ns; + + signal clk : std_logic; + signal rst : std_logic := '0'; + signal WriteEn : std_logic_vector(c_inputs - 1 downto 0) := (others => '0'); + signal DataIn : std_logic_vector(c_inputs*c_datawidth - 1 downto 0) := (others => '0'); + signal ReadEn : std_logic_vector(c_inputs - 1 downto 0); + signal DataOut : std_logic_vector(c_inputs*c_datawidth - 1 downto 0); + signal Empty : std_logic_vector(c_inputs - 1 downto 0); + signal Full : std_logic_vector(c_inputs - 1 downto 0); + signal fifo_mask : std_logic_vector(c_inputs - 1 downto 0) := (others => '0'); + signal buff_wren : std_logic; + signal wordin_freq : std_logic_vector(32*c_inputs - 1 downto 0); + signal fifo_full_o : std_logic; + signal dataout_buf : std_logic_vector(c_datawidth - 1 downto 0); + +begin + + generate_fifo : for i in 0 to c_inputs - 1 generate + fifo :component STD_FIFO + generic map( + DATA_WIDTH => c_datawidth, + FIFO_DEPTH => c_fifo_depth + ) + port map( + CLK => clk, + RST => rst, + WriteEn => WriteEn(i), + DataIn => DataIn((i + 1)*c_datawidth - 1 downto i*c_datawidth), + ReadEn => ReadEn(i), + DataOut => DataOut((i + 1)*c_datawidth - 1 downto i*c_datawidth), + Empty => Empty(i), + Full => Full(i) + ); + end generate generate_fifo; + + dut : component FiFoDataMux + generic map( + g_datawidth => c_datawidth, + g_inputs => c_inputs, + g_clockspeed => c_clockspeed + ) + port map( + clk => clk, + rst => rst, + fifo_empty => Empty, + fifo_full => Full, + fifo_datain => dataout, + fifo_mask => fifo_mask, + fifo_rden => ReadEn, + buff_wren => buff_wren, + dataout => dataout_buf, + wordin_freq => wordin_freq, + fifo_full_o => fifo_full_o + ); + + clk_gen : process is + begin + clk <= '0'; + wait for c_clk_period/2; + clk <= '1'; + wait for c_clk_period/2; + end process clk_gen; + + stimulus : process is + begin + wait for 100 ns; + fifo_mask <= "11"; + --write to single fifo + for i in 0 to 10 loop + WriteEn(1) <= '1'; + DataIn(2*c_datawidth - 1 downto c_datawidth) <= x"A" & std_logic_vector(to_unsigned(i, 4)); + wait for c_clk_period; + end loop; + WriteEn(1) <= '0'; + DataIn(2*c_datawidth - 1 downto c_datawidth) <= (others => '0'); + wait for 100 ns; + --write to both fifos at same time, reading should start at last fifo + for i in 0 to 10 loop + WriteEn <= "11"; + DataIn <= x"A" & std_logic_vector(to_unsigned(i, 4)) & x"B" & std_logic_vector(to_unsigned(i, 4)); + wait for c_clk_period; + end loop; + WriteEn <= (others => '0'); + DataIn <= (others => '0'); + wait for 200 ns; + --start writing into first fifo then in second fifo, state machine should finish reading fifo 1 and then start reading other fifo + for i in 0 to 10 loop + if i < 5 then + WriteEn(0) <= '1'; + DataIn(c_datawidth - 1 downto 0) <= x"B" & std_logic_vector(to_unsigned(i, 4)); + else + WriteEn <= "11"; + DataIn <= x"A" & std_logic_vector(to_unsigned(i, 4)) & x"B" & std_logic_vector(to_unsigned(i, 4)); + end if; + wait for c_clk_period; + end loop; + WriteEn <= (others => '0'); + DataIn <= (others => '0'); + wait; + end process stimulus; + + +end architecture sim; -- 2.43.0