+--------------------------------------------------------------------------------
+-- 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;