--- /dev/null
+--------------------------------------------------------------------------------
+-- deserialize - Collect N words into a single, wide word
+--
+-- Useful for collecting bytes streamed over the USB FIFO interface into
+-- strucutred chunks, like two-channel 16-bit PCM streamed in from a WAV file.
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+
+entity deserialize is
+ generic (
+ WIDTH: positive := 8;
+ N: positive := 4
+ );
+ port (
+ rst_i: in std_logic;
+ clk_i: in std_logic;
+
+ stb_i: in std_logic;
+ rdy_o: out std_logic;
+ dat_i: in std_logic_vector(WIDTH-1 downto 0);
+
+ stb_o: out std_logic;
+ rdy_i: in std_logic;
+ dat_o: out std_logic_vector((WIDTH*N)-1 downto 0)
+ );
+end deserialize;
+
+
+architecture behavioral of deserialize is
+
+ type state_t is (S_IDLE, S_COUNT, S_HOLD);
+ type word_array_t is array(natural range <>) of std_logic_vector(WIDTH-1 downto 0);
+
+ signal state_reg: state_t;
+ signal state_next: state_t;
+
+ signal count_en: std_logic;
+ signal count_start: std_logic;
+ signal count_done: std_logic;
+
+ signal shift_en: std_logic;
+ signal shift_reg: word_array_t(3 downto 0);
+
+begin
+
+ process (rst_i, clk_i, state_next)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ state_reg <= S_IDLE;
+ else
+ state_reg <= state_next;
+ end if;
+ end if;
+ end process;
+
+ process (state_reg, count_done, stb_i, rdy_i)
+ begin
+ state_next <= state_reg;
+ count_en <= '0';
+ count_start <= '0';
+ shift_en <= '0';
+ rdy_o <= '0';
+
+ case state_reg is
+ when S_IDLE =>
+ rdy_o <= '1';
+ if stb_i = '1' then
+ count_en <= '1';
+ count_start <= '1';
+ shift_en <= '1';
+ state_next <= S_COUNT;
+ end if;
+
+ when S_COUNT =>
+ if count_done = '1' then
+ -- Done with this group
+ if stb_i = '1' and rdy_i = '1' then
+ -- Source has a byte available and sink is accepting group
+ -- Acknowledge byte, shift it in, drop counter bit and start new count
+ rdy_o <= '1';
+ shift_en <= '1';
+ count_en <= '1';
+ count_start <= '1';
+ elsif stb_i = '0' and rdy_i = '1' then
+ -- Sink is accepting group
+ -- Drop counter bit and return to idle
+ count_en <= '1';
+ state_next <= S_IDLE;
+ end if;
+ else
+ -- Not done with this group yet, source has a byte available
+ -- Acknowledge byte, shift it in, and advance counter
+ if stb_i = '1' then
+ rdy_o <= '1';
+ count_en <= '1';
+ shift_en <= '1';
+ end if;
+ end if;
+
+ when others =>
+ state_next <= S_IDLE;
+ end case;
+ end process;
+
+ -- Word counter SRL
+ e_counter: srl16e
+ port map (
+ CLK => clk_i,
+ CE => count_en,
+ A0 => '1',
+ A1 => '1',
+ A2 => '0',
+ A3 => '0',
+ D => count_start,
+ Q => count_done
+ );
+
+ stb_o <= count_done;
+
+ -- Shift register to collect bytes in a group
+ process (clk_i, shift_en, dat_i)
+ begin
+ if rising_edge(clk_i) then
+ if shift_en = '1' then
+ for i in shift_reg'high-1 downto 0 loop
+ shift_reg(i) <= shift_reg(i+1);
+ end loop;
+ shift_reg(shift_reg'high) <= dat_i;
+ end if;
+ end if;
+ end process;
+
+ -- Assemble bytes from the holding register into concatenated output
+ process (shift_reg)
+ begin
+ for i in N-1 downto 0 loop
+ dat_o(((i+1)*WIDTH)-1 downto i*WIDTH) <= shift_reg(i);
+ end loop;
+ end process;
+
+end behavioral;
--- /dev/null
+--------------------------------------------------------------------------------
+-- merge - merge two data streams into a single pipeline
+--
+-- This contains a combinational path between the input and output - a runout
+-- buffer may be needed to break a long combinational chain to improve clock
+-- rate.
+--
+-- All streams must be in the same clock domain.
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+
+entity merge is
+ port (
+ a_stb_i: in std_logic;
+ a_ack_o: out std_logic;
+
+ b_stb_i: in std_logic;
+ b_ack_o: out std_logic;
+
+ stb_o: out std_logic;
+ ack_i: in std_logic
+ );
+end merge;
+
+
+architecture behavioral of merge is
+
+ signal costrobe: std_logic;
+
+begin
+
+ costrobe <= a_stb_i and b_stb_i;
+ stb_o <= costrobe;
+ a_ack_o <= costrobe and ack_i;
+ b_ack_o <= costrobe and ack_i;
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+library dsp;
+
+
+entity pcm16_2ch_gain is
+ port (
+ rst_i: in std_logic;
+ clk_i: in std_logic;
+
+ gain_l: in std_logic_vector(17 downto 0); -- 9.9 fixed point
+ gain_r: in std_logic_vector(17 downto 0); -- 9.9 fixed point
+
+ stb_i: in std_logic;
+ rdy_o: out std_logic;
+ dat_i: in std_logic_vector(31 downto 0);
+
+ stb_o: out std_logic;
+ rdy_i: in std_logic;
+ dat_o: out std_logic_vector(31 downto 0)
+ );
+end pcm16_2ch_gain;
+
+
+architecture behavioral of pcm16_2ch_gain is
+
+ signal samp_l: std_logic_vector(17 downto 0);
+ signal samp_r: std_logic_vector(17 downto 0);
+
+ signal out_l: std_logic_vector(35 downto 0);
+ signal out_r: std_logic_vector(35 downto 0);
+
+ signal result_l: std_logic_vector(15 downto 0);
+ signal result_r: std_logic_vector(15 downto 0);
+
+ signal result: std_logic_vector(31 downto 0);
+
+begin
+
+ samp_l <= "00" & dat_i(15 downto 0);
+ samp_r <= "00" & dat_i(31 downto 16);
+
+ out_l <= std_logic_vector(signed(samp_l) * signed(gain_l));
+ out_r <= std_logic_vector(signed(samp_r) * signed(gain_r));
+
+ result <= (out_r(24 downto 9)) & (out_l(24 downto 9));
+
+ e_sat_l: entity work.saturate
+ generic map (WIDTH_IN => 27, WIDTH_OUT => 16)
+ port map (dat_i => out_l(35 downto 9), dat_o => result_l);
+
+ e_sat_r: entity work.saturate
+ generic map (WIDTH_IN => 27, WIDTH_OUT => 16)
+ port map (dat_i => out_r(35 downto 9), dat_o => result_r);
+
+ e_interstage: entity dsp.pipectrl
+ generic map (WIDTH => 32)
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+
+ stb_i => stb_i,
+ rdy_o => rdy_o,
+ dat_i => result,
+
+ stb_o => stb_o,
+ rdy_i => rdy_i,
+ dat_o => dat_o
+ );
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+
+
+entity pcm16_2ch_sum is
+ port (
+ rst_i: in std_logic;
+ clk_i: in std_logic;
+
+ a_stb_i: in std_logic;
+ a_rdy_i: out std_logic;
+ a_dat_i: in std_logic_vector(31 downto 0);
+
+ b_stb_i: in std_logic;
+ b_rdy_o: out std_logic;
+ b_dat_i: in std_logic_vector(31 downto 0);
+
+ stb_o: out std_logic;
+ rdy_i: in std_logic;
+ dat_o: out std_logic_vector(31 downto 0)
+ );
+end pcm16_2ch_sum;
+
+
+architecture behavioral of pcm16_2ch_sum is
+
+ signal samp_a_l: signed(15 downto 0);
+ signal samp_a_r: signed(15 downto 0);
+ signal samp_b_l: signed(15 downto 0);
+ signal samp_b_r: signed(15 downto 0);
+
+ -- Extra bit on each for carry
+ signal result_l: signed(16 downto 0);
+ signal result_r: signed(16 downto 0);
+
+ -- Saturated results
+ signal sat_l: std_logic_vector(15 downto 0);
+ signal sat_r: std_logic_vector(15 downto 0);
+
+ -- Packaged result
+ signal result: std_logic_vector(31 downto 0);
+
+ signal stb: std_logic;
+ signal rdy: std_logic;
+
+begin
+
+ samp_a_l <= a_dat_i(15 downto 0);
+ samp_a_r <= a_dat_i(31 downto 16);
+ samp_b_l <= b_dat_i(15 downto 0);
+ samp_b_r <= b_dat_i(31 downto 16);
+
+ result_l <= samp_a_l + samp_b_l;
+ result_r <= samp_a_r + samp_b_r;
+
+ e_sat_l: entity work.saturate
+ generic map (WIDTH_IN => 17, WIDTH_OUT => 16)
+ port map (dat_i => result_l, dat_o => sat_l);
+
+ e_sat_r: entity work.saturate
+ generic map (WIDTH_IN => 17, WIDTH_OUT => 16)
+ port map (dat_i => result_r, dat_o => sat_r);
+
+ result <= sat_r & sat_l;
+
+ e_merge: entity work.merge
+ port map (
+ a_stb_i => a_stb_i,
+ a_rdy_o => a_rdy_o,
+
+ b_stb_i => b_stb_i,
+ b_rdy_o => b_rdy_o,
+
+ stb_o => stb,
+ rdy_i => rdy
+ );
+
+ e_pipectrl: entity work.pipectrl
+ generic map (WIDTH => 32)
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+
+ stb_i => stb,
+ rdy_o => rdy,
+ dat_i => result,
+
+ stb_o => stb_o,
+ rdy_i => rdy_i,
+ dat_o => dat_o
+ );
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity pipectrl is
+ generic (
+ WIDTH: positive := 16
+ );
+ port (
+ rst_i: in std_logic;
+ clk_i: in std_logic;
+
+ stb_i: in std_logic;
+ rdy_o: out std_logic;
+ dat_i: in std_logic_vector(WIDTH-1 downto 0);
+
+ stb_o: out std_logic;
+ rdy_i: in std_logic;
+ dat_o: out std_logic_vector(WIDTH-1 downto 0)
+ );
+end pipectrl;
+
+
+architecture behavioral of pipectrl is
+
+ signal enable: std_logic;
+ signal stb_reg: std_logic;
+ signal dat_reg: std_logic_vector(WIDTH-1 downto 0);
+
+begin
+
+ -- Enable the stage register to latch if:
+ -- * it is currently empty
+ -- * if the downstream stage is accepting the current data
+ enable <= (not stb_reg) or rdy_i;
+
+ stb_o <= stb_reg;
+ rdy_o <= enable;
+ dat_o <= dat_reg;
+
+ process (rst_i, clk_i, enable, stb_i)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ stb_reg <= '0';
+ elsif enable = '1' then
+ stb_reg <= stb_i;
+ end if;
+ end if;
+ end process;
+
+ process (clk_i, enable, dat_i)
+ begin
+ if rising_edge(clk_i) then
+ if enable = '1' then
+ dat_reg <= dat_i;
+ end if;
+ end if;
+ end process;
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity pipectrl_runout is
+ generic (
+ WIDTH: positive := 16
+ );
+ port (
+ rst_i: in std_logic;
+ clk_i: in std_logic;
+
+ stb_i: in std_logic;
+ rdy_o: out std_logic;
+ dat_i: in std_logic_vector(WIDTH-1 downto 0);
+
+ stb_o: out std_logic;
+ rdy_i: in std_logic;
+ dat_o: out std_logic_vector(WIDTH-1 downto 0)
+ );
+end pipectrl_runout;
+
+
+architecture behavioral of pipectrl_runout is
+
+ -- Registered ready signal
+ signal rdy_reg: std_logic := '1';
+
+ -- Normal interstage register
+ signal en: std_logic;
+ signal stb_reg: std_logic := '0';
+ signal dat_reg: std_logic_vector(WIDTH-1 downto 0);
+
+ -- Run-out-buffer
+ signal rob_en: std_logic;
+ signal rob_clr: std_logic;
+ signal rob_stb_reg: std_logic := '0';
+ signal rob_dat_reg: std_logic_vector(WIDTH-1 downto 0);
+
+begin
+
+ stb_o <= stb_reg or rob_stb_reg;
+ rdy_o <= rdy_reg;
+ dat_o <= rob_dat_reg when rob_stb_reg = '1' else dat_reg;
+
+ en <= rdy_reg;
+ rob_en <= rdy_reg and (not rdy_i);
+ rob_clr <= rdy_i;
+
+ -- Registered ready signal
+ process (rst_i, clk_i, rdy_i)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ rdy_reg <= '1';
+ else
+ rdy_reg <= rdy_i;
+ end if;
+ end if;
+ end process;
+
+ -- Normal interstage
+ process (rst_i, clk_i, en, stb_i, dat_i)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ stb_reg <= '0';
+ elsif en = '1' then
+ stb_reg <= stb_i;
+ dat_reg <= dat_i;
+ rob_dat_reg <= dat_reg; --
+ end if;
+ end if;
+ end process;
+
+ -- Runout buffer
+ process (rst_i, clk_i, rob_en, rob_clr, stb_reg, dat_reg)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' or rob_clr = '1' then
+ rob_stb_reg <= '0';
+ elsif rob_en = '1' then
+ rob_stb_reg <= stb_reg;
+ --rob_dat_reg <= dat_reg;
+ end if;
+ end if;
+ end process;
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+
+entity pipectrl_runout_srl is
+ generic (
+ WIDTH: positive := 16
+ );
+ port (
+ rst_i: in std_logic;
+ clk_i: in std_logic;
+
+ stb_i: in std_logic;
+ rdy_o: out std_logic;
+ dat_i: in std_logic_vector(WIDTH-1 downto 0);
+
+ stb_o: out std_logic;
+ rdy_i: in std_logic;
+ dat_o: out std_logic_vector(WIDTH-1 downto 0)
+ );
+end pipectrl_runout_srl;
+
+
+architecture behavioral of pipectrl_runout_srl is
+
+ -- Registered ready signal
+ signal rdy_reg: std_logic := '1';
+
+ -- Normal interstage register
+ signal en: std_logic;
+ signal stb_reg: std_logic := '0';
+ --signal dat_reg: std_logic_vector(WIDTH-1 downto 0);
+
+ -- Run-out-buffer
+ signal rob_en: std_logic;
+ signal rob_clr: std_logic;
+ signal rob_stb_reg: std_logic := '0';
+ --signal rob_dat_reg: std_logic_vector(WIDTH-1 downto 0);
+
+begin
+
+ stb_o <= stb_reg or rob_stb_reg;
+ rdy_o <= rdy_reg;
+ --dat_o <= rob_dat_reg when rob_stb_reg = '1' else dat_reg;
+
+ en <= rdy_reg;
+ rob_en <= rdy_reg and (not rdy_i);
+ rob_clr <= rdy_i;
+
+ -- Registered ready signal
+ process (rst_i, clk_i, rdy_i)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ rdy_reg <= '1';
+ else
+ rdy_reg <= rdy_i;
+ end if;
+ end if;
+ end process;
+
+ g_srl: for i in WIDTH-1 downto 0 generate
+ e_srl: srl16e
+ port map (
+ d => dat_i(i),
+ ce => en,
+ clk => clk_i,
+ a0 => rob_stb_reg,
+ a1 => '0',
+ a2 => '0',
+ a3 => '0',
+ q => dat_o(i)
+ );
+ end generate;
+
+ -- Normal interstage
+ process (rst_i, clk_i, en, stb_i)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ stb_reg <= '0';
+ elsif en = '1' then
+ stb_reg <= stb_i;
+ --dat_reg <= dat_i;
+ --rob_dat_reg <= dat_reg; --
+ end if;
+ end if;
+ end process;
+
+ -- Runout buffer
+ process (rst_i, clk_i, rob_en, rob_clr, stb_reg)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' or rob_clr = '1' then
+ rob_stb_reg <= '0';
+ elsif rob_en = '1' then
+ rob_stb_reg <= stb_reg;
+ --rob_dat_reg <= dat_reg;
+ end if;
+ end if;
+ end process;
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity pipectrl_split is
+ generic (
+ WIDTH: positive := 16
+ );
+ port (
+ rst_i: in std_logic;
+ clk_i: in std_logic;
+
+ stb_i: in std_logic;
+ rdy_o: out std_logic;
+ dat_i: in std_logic_vector(WIDTH-1 downto 0);
+
+ a_stb_o: out std_logic;
+ a_rdy_i: in std_logic;
+
+ b_stb_o: out std_logic;
+ b_rdy_i: in std_logic;
+
+ dat_o: out std_logic_vector(WIDTH-1 downto 0)
+ );
+end pipectrl_split;
+
+
+architecture behavioral of pipectrl_split is
+
+ signal a_stb_reg: std_logic := '0';
+ signal a_rdy: std_logic;
+
+ signal b_stb_reg: std_logic := '0';
+ signal b_rdy: std_logic;
+
+ signal load: std_logic;
+
+ signal dat_reg: std_logic_vector(WIDTH-1 downto 0);
+
+begin
+
+ a_rdy <= (not a_stb_reg) or a_rdy_i;
+ b_rdy <= (not b_stb_reg) or b_rdy_i;
+ load <= a_rdy and b_rdy;
+ rdy_o <= load;
+
+ -- Full registers
+ process (rst_i, clk_i, load, a_rdy_i, b_rdy_i)
+ begin
+ if rising_edge(clk_i) then
+ if load = '1' then
+ a_stb_reg <= stb_i;
+ b_stb_reg <= stb_i;
+ else
+ if a_rdy_i = '1' then
+ a_stb_reg <= '0';
+ end if;
+ if b_rdy_i = '1' then
+ b_stb_reg <= '0';
+ end if;
+ end if;
+ end if;
+ end process;
+ a_stb_o <= a_stb_reg;
+ b_stb_o <= b_stb_reg;
+
+ -- Interstage register
+ process (clk_i, load, dat_i)
+ begin
+ if rising_edge(clk_i) then
+ if load = '1' then
+ dat_reg <= dat_i;
+ end if;
+ end if;
+ end process;
+ dat_o <= dat_reg;
+
+end behavioral;
--- /dev/null
+--------------------------------------------------------------------------------
+-- saturate - reduce the precision of a data stream, saturating at max and min
+--
+-- This is combinational to allow for composition into more complex pipeline
+-- stages. A FIFO or run out buffer can be added to the output to break the
+-- combinational chain when used on its own.
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_misc.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+
+entity saturate is
+ port (
+ dat_i: in std_logic_vector;
+ dat_o: out std_logic_vector
+ );
+end saturate;
+
+
+architecture behavioral of saturate is
+
+ constant WIDTH_IN: positive := dat_i'length;
+ constant WIDTH_OUT: positive := dat_o'length;
+
+ constant MAX: std_logic_vector(WIDTH_OUT-1 downto 0) := (WIDTH_OUT-1 => '0', others => '1');
+ constant MIN: std_logic_vector(WIDTH_OUT-1 downto 0) := (WIDTH_OUT-1 => '1', others => '0');
+
+ signal upper: std_logic_vector(WIDTH_IN downto WIDTH_OUT);
+
+ signal is_negative: std_logic;
+ signal is_saturated: std_logic;
+
+begin
+
+ upper <= dat_i(WIDTH_IN-1 downto WIDTH_OUT-1);
+
+ is_negative <= dat_i(WIDTH_IN-1);
+ is_saturated <= '0' when and_reduce(upper) = '1' or
+ nor_reduce(upper) = '1' else '1';
+
+ dat_o <= dat_i(WIDTH_OUT-1 downto 0) when is_saturated = '0' else
+ MAX when is_negative = '0' else
+ MIN;
+
+end behavioral;
--- /dev/null
+--------------------------------------------------------------------------------
+-- serialize - split a wide word into N smaller words
+--
+-- Useful for taking structured chunks of data, like two-channel 16-bit PCM
+-- samples, and serializing into bytes for transfer over the USB FIFO interface.
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+
+entity serialize is
+ generic (
+ WIDTH: positive := 8;
+ N: positive := 4
+ );
+ port (
+ rst_i: in std_logic;
+ clk_i: in std_logic;
+
+ stb_i: in std_logic;
+ rdy_o: out std_logic;
+ dat_i: in std_logic_vector((WIDTH*N)-1 downto 0);
+
+ stb_o: out std_logic;
+ rdy_i: in std_logic;
+ dat_o: out std_logic_vector(WIDTH-1 downto 0)
+ );
+end serialize;
+
+
+architecture behavioral of serialize is
+
+ constant SRL_TAP: std_logic_vector(3 downto 0) := std_logic_vector(to_unsigned(N-1, 4));
+
+ type state_t is (
+ S_IDLE,
+ S_COUNT
+ );
+ type word_array_t is array(natural range <>) of std_logic_vector(WIDTH-1 downto 0);
+
+ signal state_reg: state_t;
+ signal state_next: state_t;
+
+ signal count_en: std_logic;
+ signal count_start: std_logic;
+ signal count_done: std_logic;
+
+ signal shift_ld: std_logic;
+ signal shift_en: std_logic;
+ signal shift_reg: word_array_t(N-1 downto 0);
+
+begin
+
+ -- State machine
+ process (rst_i, clk_i)
+ begin
+ if rising_edge(clk_i) then
+ if rst_i = '1' then
+ state_reg <= S_IDLE;
+ else
+ state_reg <= state_next;
+ end if;
+ end if;
+ end process;
+
+ process (state_reg, stb_i, rdy_i, count_done)
+ begin
+ state_next <= state_reg;
+ count_start <= '0';
+ count_en <= '0';
+ shift_ld <= '0';
+ shift_en <= '0';
+ stb_o <= '0';
+ rdy_o <= '0';
+
+ case state_reg is
+ when S_IDLE =>
+ rdy_o <= '1';
+ if stb_i = '1' then
+ count_start <= '1';
+ count_en <= '1';
+ shift_ld <= '1';
+ state_next <= S_COUNT;
+ end if;
+
+ when S_COUNT =>
+ stb_o <= '1';
+ if count_done = '1' then
+ if stb_i = '1' and rdy_i = '1' then
+ -- Source has a new group available and sink is accepting the last word
+ rdy_o <= '1';
+ count_start <= '1';
+ count_en <= '1';
+ shift_ld <= '1';
+ elsif stb_i = '0' and rdy_i = '1' then
+ -- Sink is accepting the last word, return to idle
+ count_en <= '1';
+ state_next <= S_IDLE;
+ end if;
+ else
+ -- Not done with this group yet, sink has a byte available
+ -- Acknowledge byte, shift it in, and advance counter
+ if rdy_i = '1' then
+ shift_en <= '1';
+ count_en <= '1';
+ end if;
+ end if;
+
+ when others =>
+ state_next <= S_IDLE;
+ end case;
+ end process;
+
+ -- Word counter SRL
+ e_counter: srl16e
+ port map (
+ CLK => clk_i,
+ CE => count_en,
+ A0 => SRL_TAP(0),
+ A1 => SRL_TAP(1),
+ A2 => SRL_TAP(2),
+ A3 => SRL_TAP(3),
+ D => count_start,
+ Q => count_done
+ );
+
+ -- Shift register
+ process (clk_i, shift_ld, shift_en, shift_reg)
+ begin
+ if rising_edge(clk_i) then
+ if shift_ld = '1' then
+ for i in N-1 downto 0 loop
+ shift_reg(i) <= dat_i(((i+1)*WIDTH)-1 downto i*WIDTH);
+ end loop;
+ elsif shift_en = '1' then
+ for i in N-2 downto 0 loop
+ shift_reg(i) <= shift_reg(i+1);
+ end loop;
+ end if;
+ end if;
+ end process;
+ dat_o <= shift_reg(0);
+
+end behavioral;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+
+entity test_deserialize is
+end test_deserialize;
+
+
+architecture behavior of test_deserialize is
+
+ constant CLK_I_PERIOD: time := 20 ns;
+
+ signal rst_i: std_logic;
+ signal clk_i: std_logic;
+
+ signal stb_i: std_logic;
+ signal ack_o: std_logic;
+ signal dat_i: std_logic_vector(7 downto 0);
+
+ signal stb_o: std_logic;
+ signal ack_i: std_logic;
+ signal dat_o: std_logic_vector(31 downto 0);
+
+begin
+
+ p_test: process
+ begin
+ -- Initial values
+ stb_i <= '0';
+ ack_i <= '0';
+
+ -- Reset
+ rst_i <= '1';
+ wait for CLK_I_PERIOD*17;
+ rst_i <= '0';
+
+ -- Test
+ ack_i <= '1';
+
+ wait until falling_edge(clk_i);
+ stb_i <= '1';
+ dat_i <= x"11";
+ wait until rising_edge(clk_i) and ack_o = '1';
+
+ wait until falling_edge(clk_i);
+ stb_i <= '1';
+ dat_i <= x"22";
+ wait until rising_edge(clk_i) and ack_o = '1';
+
+ wait until falling_edge(clk_i);
+ stb_i <= '1';
+ dat_i <= x"33";
+ wait until rising_edge(clk_i) and ack_o = '1';
+
+ wait until falling_edge(clk_i);
+ stb_i <= '1';
+ dat_i <= x"44";
+ wait until rising_edge(clk_i) and ack_o = '1';
+
+ wait until falling_edge(clk_i);
+ stb_i <= '1';
+ dat_i <= x"55";
+ wait until rising_edge(clk_i) and ack_o = '1';
+
+ wait until falling_edge(clk_i);
+ stb_i <= '1';
+ dat_i <= x"66";
+ wait until rising_edge(clk_i) and ack_o = '1';
+
+ wait until falling_edge(clk_i);
+ stb_i <= '1';
+ dat_i <= x"77";
+ wait until rising_edge(clk_i) and ack_o = '1';
+
+ wait until falling_edge(clk_i);
+ stb_i <= '1';
+ dat_i <= x"88";
+ wait until rising_edge(clk_i) and ack_o = '1';
+
+ stb_i <= '0';
+
+ -- Done
+ wait;
+ end process;
+
+ e_uut: entity work.deserialize
+ generic map (
+ WIDTH => 8,
+ N => 4
+ )
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+ stb_i => stb_i,
+ ack_o => ack_o,
+ dat_i => dat_i,
+ stb_o => stb_o,
+ ack_i => ack_i,
+ dat_o => dat_o
+ );
+
+ p_clk: process
+ begin
+ clk_i <= '0';
+ wait for CLK_I_PERIOD/2;
+ clk_i <= '1';
+ wait for CLK_I_PERIOD/2;
+ end process;
+
+end;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+
+
+entity test_pipectrl is
+end test_pipectrl;
+
+
+architecture behavior of test_pipectrl is
+
+ constant CLK_I_PERIOD: time := 20 ns;
+
+ signal rst_i: std_logic;
+ signal clk_i: std_logic;
+
+ signal src_stb: std_logic;
+ signal src_rdy: std_logic;
+ signal src_dat: std_logic_vector(7 downto 0);
+
+ signal s01_stb: std_logic;
+ signal s01_rdy: std_logic;
+ signal s01_dat: std_logic_vector(7 downto 0);
+
+ signal s12_stb: std_logic;
+ signal s12_rdy: std_logic;
+ signal s12_dat: std_logic_vector(7 downto 0);
+
+ signal snk_stb: std_logic;
+ signal snk_rdy: std_logic;
+ signal snk_dat: std_logic_vector(7 downto 0);
+
+begin
+
+ p_source: process
+ begin
+ -- Initial values
+ src_stb <= '0';
+
+ -- Reset
+ rst_i <= '1';
+ wait for CLK_I_PERIOD*3;
+ rst_i <= '0';
+
+ -- Test
+ wait until falling_edge(clk_i);
+ src_stb <= '1';
+ src_dat <= x"00";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+
+ wait until falling_edge(clk_i);
+ src_stb <= '1';
+ src_dat <= x"01";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+
+ wait until falling_edge(clk_i);
+ src_stb <= '1';
+ src_dat <= x"02";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+
+ wait until falling_edge(clk_i);
+ src_stb <= '1';
+ src_dat <= x"03";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+
+ wait until falling_edge(clk_i);
+ src_stb <= '1';
+ src_dat <= x"04";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+
+ wait until falling_edge(clk_i);
+ src_stb <= '0';
+
+ -- Done
+ wait;
+ end process;
+
+ p_sink: process
+ begin
+ -- Initial values
+ snk_rdy <= '0';
+
+ -- Reset
+ wait for CLK_I_PERIOD*3;
+
+ -- Test
+ wait for CLK_I_PERIOD*5;
+
+ wait until falling_edge(clk_i) and snk_stb = '1';
+ snk_rdy <= '1';
+ wait until rising_edge(clk_i);
+
+ wait until falling_edge(clk_i) and snk_stb = '1';
+ snk_rdy <= '1';
+ wait until rising_edge(clk_i);
+
+ wait until falling_edge(clk_i) and snk_stb = '1';
+ snk_rdy <= '0';
+ wait until rising_edge(clk_i);
+
+ wait until falling_edge(clk_i) and snk_stb = '1';
+ snk_rdy <= '1';
+ wait until rising_edge(clk_i);
+
+ wait until falling_edge(clk_i) and snk_stb = '1';
+ snk_rdy <= '1';
+ wait until rising_edge(clk_i);
+
+ wait until falling_edge(clk_i) and snk_stb = '1';
+ snk_rdy <= '1';
+ wait until rising_edge(clk_i);
+
+ snk_rdy <= '0';
+
+ -- Done
+ wait;
+ end process;
+
+ e_stage0: entity work.pipectrl
+ generic map (WIDTH => 8)
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+ stb_i => src_stb,
+ rdy_o => src_rdy,
+ dat_i => src_dat,
+ stb_o => s01_stb,
+ rdy_i => s01_rdy,
+ dat_o => s01_dat
+ );
+
+ e_stage1: entity work.pipectrl_runout_srl
+ generic map (WIDTH => 8)
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+ stb_i => s01_stb,
+ rdy_o => s01_rdy,
+ dat_i => s01_dat,
+ stb_o => s12_stb,
+ rdy_i => s12_rdy,
+ dat_o => s12_dat
+ );
+
+ e_stage2: entity work.pipectrl
+ generic map (WIDTH => 8)
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+ stb_i => s12_stb,
+ rdy_o => s12_rdy,
+ dat_i => s12_dat,
+ stb_o => snk_stb,
+ rdy_i => snk_rdy,
+ dat_o => snk_dat
+ );
+
+ p_clk: process
+ begin
+ clk_i <= '0';
+ wait for CLK_I_PERIOD/2;
+ clk_i <= '1';
+ wait for CLK_I_PERIOD/2;
+ end process;
+
+end;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+
+
+entity test_pipectrl_split is
+end test_pipectrl_split;
+
+
+architecture behavior of test_pipectrl_split is
+
+ constant CLK_I_PERIOD: time := 20 ns;
+
+ signal rst_i: std_logic;
+ signal clk_i: std_logic;
+
+ -- Source
+ signal src_stb: std_logic;
+ signal src_rdy: std_logic;
+ signal src_dat: std_logic_vector(7 downto 0);
+
+ -- Stage 0 output
+ signal s0_stb: std_logic;
+ signal s0_rdy: std_logic;
+ signal s0_dat: std_logic_vector(7 downto 0);
+
+ -- Stage 1 (splitter) output
+ signal s1a_stb: std_logic;
+ signal s1a_rdy: std_logic;
+ signal s1b_stb: std_logic;
+ signal s1b_rdy: std_logic;
+ signal s1_dat: std_logic_vector(7 downto 0);
+
+ -- Stage 2a
+ signal s2a_stb: std_logic;
+ signal s2a_rdy: std_logic;
+ signal s2a_dat: std_logic_vector(7 downto 0);
+
+ -- Stage 2b
+ signal s2b_stb: std_logic;
+ signal s2b_rdy: std_logic;
+ signal s2b_dat: std_logic_vector(7 downto 0);
+
+begin
+
+ ----------------------------------------------------------------------------
+ -- Data stream source
+ p_source: process
+ begin
+ -- Initial values
+ src_stb <= '0';
+
+ -- Reset
+ rst_i <= '1';
+ wait for CLK_I_PERIOD*3;
+ rst_i <= '0';
+
+ -- Test
+
+ -- Insert 0x00
+ src_dat <= x"00";
+ src_stb <= '1';
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ -- Insert 0x01
+ src_dat <= x"01";
+ src_stb <= '1';
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ -- Insert 0x02
+ src_dat <= x"02";
+ src_stb <= '1';
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ -- Insert 0x03
+ src_dat <= x"03";
+ src_stb <= '1';
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ -- Insert 0x04
+ src_dat <= x"04";
+ src_stb <= '1';
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ -- Done
+ wait;
+ end process;
+
+ ----------------------------------------------------------------------------
+ -- Data sink A
+ p_sink_a: process
+ begin
+ -- Initial values
+ s2a_rdy <= '0';
+
+ -- Test
+ s2a_rdy <= '1'; -- Remove all values
+
+ -- Done
+ wait;
+ end process;
+
+ ----------------------------------------------------------------------------
+ -- Data sink B
+ p_sink_b: process
+ begin
+ -- Initial values
+ s2b_rdy <= '0';
+
+ -- Test
+ wait until s2b_stb = '1'; -- Wait for values to enter
+ wait for CLK_I_PERIOD*4; -- Wait four more clocks
+ s2b_rdy <= '1'; -- remove all values
+
+ -- Done
+ wait;
+ end process;
+
+ ----------------------------------------------------------------------------
+
+ e_s0: entity work.pipectrl
+ generic map (WIDTH => 8)
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+ stb_i => src_stb,
+ rdy_o => src_rdy,
+ dat_i => src_dat,
+ stb_o => s0_stb,
+ rdy_i => s0_rdy,
+ dat_o => s0_dat
+ );
+
+ e_s1: entity work.pipectrl_split
+ generic map (WIDTH => 8)
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+ stb_i => s0_stb,
+ rdy_o => s0_rdy,
+ dat_i => s0_dat,
+ a_stb_o => s1a_stb,
+ a_rdy_i => s1a_rdy,
+ b_stb_o => s1b_stb,
+ b_rdy_i => s1b_rdy,
+ dat_o => s1_dat
+ );
+
+ e_s2a: entity work.pipectrl
+ generic map (WIDTH => 8)
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+ stb_i => s1a_stb,
+ rdy_o => s1a_rdy,
+ dat_i => s1_dat,
+ stb_o => s2a_stb,
+ rdy_i => s2a_rdy,
+ dat_o => s2a_dat
+ );
+
+ e_s2b: entity work.pipectrl
+ generic map (WIDTH => 8)
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+ stb_i => s1b_stb,
+ rdy_o => s1b_rdy,
+ dat_i => s1_dat,
+ stb_o => s2b_stb,
+ rdy_i => s2b_rdy,
+ dat_o => s2b_dat
+ );
+
+ p_clk: process
+ begin
+ clk_i <= '0';
+ wait for CLK_I_PERIOD/2;
+ clk_i <= '1';
+ wait for CLK_I_PERIOD/2;
+ end process;
+
+end;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+library work;
+
+
+entity test_saturate is
+end test_saturate;
+
+
+architecture behavior of test_saturate is
+
+ signal dat_i: std_logic_vector(19 downto 0);
+ signal dat_o: std_logic_vector(15 downto 0);
+
+begin
+
+ p_test: process
+ begin
+ dat_i <= x"00000";
+ wait for 5 ns;
+ assert dat_o = x"0000";
+ wait for 5 ns;
+
+ dat_i <= x"fffff";
+ wait for 5 ns;
+ assert dat_o = x"ffff";
+ wait for 5 ns;
+
+ dat_i <= x"0005a";
+ wait for 5 ns;
+ assert dat_o = x"005a";
+ wait for 5 ns;
+
+ dat_i <= x"fffc3";
+ wait for 5 ns;
+ assert dat_o = x"ffc3";
+ wait for 5 ns;
+
+ dat_i <= x"10045";
+ wait for 5 ns;
+ assert dat_o = x"7fff";
+ wait for 5 ns;
+
+ dat_i <= x"7ff23";
+ wait for 5 ns;
+ assert dat_o = x"7fff";
+ wait for 5 ns;
+
+ dat_i <= x"80056";
+ wait for 5 ns;
+ assert dat_o = x"8000";
+ wait for 5 ns;
+
+ dat_i <= x"f0021";
+ wait for 5 ns;
+ assert dat_o = x"8000";
+ wait for 5 ns;
+
+ dat_i <= x"08045";
+ wait for 5 ns;
+ assert dat_o = x"7fff";
+ wait for 5 ns;
+
+ dat_i <= x"f7009";
+ wait for 5 ns;
+ assert dat_o = x"8000";
+ wait for 5 ns;
+
+ report "done";
+ wait;
+ end process;
+
+ e_uut: entity work.saturate
+ port map (
+ dat_i => dat_i,
+ dat_o => dat_o
+ );
+
+end;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+library work;
+
+
+entity test_serdes is
+end test_serdes;
+
+
+architecture behavior of test_serdes is
+
+ constant CLK_I_PERIOD: time := 20 ns;
+
+ signal rst_i: std_logic;
+ signal clk_i: std_logic;
+
+ signal src_stb: std_logic;
+ signal src_rdy: std_logic;
+ signal src_dat: std_logic_vector(7 downto 0);
+
+ signal x_stb: std_logic;
+ signal x_rdy: std_logic;
+ signal x_dat: std_logic_vector(31 downto 0);
+
+ signal snk_stb: std_logic;
+ signal snk_rdy: std_logic;
+ signal snk_dat: std_logic_vector(7 downto 0);
+
+begin
+
+ p_source: process
+ begin
+ -- Initial values
+ src_stb <= '0';
+
+ -- Reset
+ rst_i <= '1';
+ wait for CLK_I_PERIOD*3;
+ rst_i <= '0';
+
+ -- Test
+
+ src_stb <= '1';
+ src_dat <= x"00";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ src_stb <= '1';
+ src_dat <= x"01";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ src_stb <= '1';
+ src_dat <= x"02";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ src_stb <= '1';
+ src_dat <= x"03";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ src_stb <= '1';
+ src_dat <= x"04";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ src_stb <= '1';
+ src_dat <= x"05";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ src_stb <= '1';
+ src_dat <= x"06";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ src_stb <= '1';
+ src_dat <= x"07";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ src_stb <= '1';
+ src_dat <= x"08";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ src_stb <= '1';
+ src_dat <= x"09";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ src_stb <= '1';
+ src_dat <= x"0a";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ src_stb <= '1';
+ src_dat <= x"0b";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ src_stb <= '1';
+ src_dat <= x"0c";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ src_stb <= '1';
+ src_dat <= x"0d";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ src_stb <= '1';
+ src_dat <= x"0e";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ src_stb <= '1';
+ src_dat <= x"0f";
+ wait until rising_edge(clk_i) and src_rdy = '1';
+ src_stb <= '0';
+
+ -- Done
+ wait;
+ end process;
+
+ p_sink: process
+ begin
+ -- Initial values
+ snk_rdy <= '0';
+
+ -- Test
+ snk_rdy <= '1';
+
+ -- Done
+ wait;
+ end process;
+
+ e_deserialize: entity work.deserialize
+ generic map (WIDTH => 8, N => 4)
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+ stb_i => src_stb,
+ rdy_o => src_rdy,
+ dat_i => src_dat,
+ stb_o => x_stb,
+ rdy_i => x_rdy,
+ dat_o => x_dat
+ );
+
+ e_serialize: entity work.serialize
+ generic map (WIDTH => 8, N => 4)
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+ stb_i => x_stb,
+ rdy_o => x_rdy,
+ dat_i => x_dat,
+ stb_o => snk_stb,
+ rdy_i => snk_rdy,
+ dat_o => snk_dat
+ );
+
+ p_clk: process
+ begin
+ clk_i <= '0';
+ wait for CLK_I_PERIOD/2;
+ clk_i <= '1';
+ wait for CLK_I_PERIOD/2;
+ end process;
+
+end;
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+
+entity test_serialize is
+end test_serialize;
+
+
+architecture behavior of test_serialize is
+
+ constant CLK_I_PERIOD: time := 20 ns;
+
+ signal rst_i: std_logic;
+ signal clk_i: std_logic;
+
+ signal stb_i: std_logic;
+ signal ack_o: std_logic;
+ signal dat_i: std_logic_vector(31 downto 0);
+
+ signal stb_o: std_logic;
+ signal ack_i: std_logic;
+ signal dat_o: std_logic_vector(7 downto 0);
+
+begin
+
+ p_test: process
+ begin
+ -- Initial values
+ stb_i <= '0';
+ ack_i <= '0';
+
+ -- Reset
+ rst_i <= '1';
+ wait for CLK_I_PERIOD*17;
+ rst_i <= '0';
+
+ -- Test
+ ack_i <= '1';
+
+ wait until falling_edge(clk_i);
+ stb_i <= '1';
+ dat_i <= x"44332211";
+ wait until rising_edge(clk_i) and ack_o = '1';
+
+ wait until falling_edge(clk_i);
+ stb_i <= '1';
+ dat_i <= x"88776655";
+ wait until rising_edge(clk_i) and ack_o = '1';
+
+ stb_i <= '0';
+
+ -- Done
+ wait;
+ end process;
+
+ e_uut: entity work.serialize
+ generic map (
+ WIDTH => 8,
+ N => 4
+ )
+ port map (
+ rst_i => rst_i,
+ clk_i => clk_i,
+ stb_i => stb_i,
+ ack_o => ack_o,
+ dat_i => dat_i,
+ stb_o => stb_o,
+ ack_i => ack_i,
+ dat_o => dat_o
+ );
+
+ p_clk: process
+ begin
+ clk_i <= '0';
+ wait for CLK_I_PERIOD/2;
+ clk_i <= '1';
+ wait for CLK_I_PERIOD/2;
+ end process;
+
+end;