--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+
+library utility;
+library work;
+
+
+entity i2s_pmod is
+ port (
+ rst_50: in std_logic;
+ clk_50: in std_logic;
+
+ stb_i: in std_logic;
+ rdy_o: out std_logic;
+ l_dat_i: in std_logic_vector(23 downto 0);
+ r_dat_i: in std_logic_vector(23 downto 0);
+
+ stb_o: out std_logic;
+ rdy_i: in std_logic;
+ l_dat_o: out std_logic_vector(23 downto 0);
+ r_dat_o: out std_logic_vector(23 downto 0);
+
+ pmod: inout std_logic_vector(7 downto 0)
+ );
+end i2s_pmod;
+
+
+architecture behavioral of i2s_pmod is
+
+ signal rst_i2s: std_logic;
+ signal mclk: std_logic;
+ signal sck: std_logic;
+ signal ws: std_logic;
+ signal txsd: std_logic;
+ signal rxsd: std_logic;
+
+ signal rise: std_logic;
+ signal fall: std_logic;
+
+ signal rx_stb: std_logic;
+ signal rx_rdy: std_logic;
+ signal rx_l_dat: std_logic_vector(31 downto 0);
+ signal rx_r_dat: std_logic_vector(31 downto 0);
+
+ signal tx_stb: std_logic;
+ signal tx_rdy: std_logic;
+ signal tx_l_dat: std_logic_vector(31 downto 0);
+ signal tx_r_dat: std_logic_vector(31 downto 0);
+
+ signal rx_head_dat: std_logic_vector(47 downto 0);
+ signal rx_tail_dat: std_logic_vector(47 downto 0);
+
+ signal tx_head_dat: std_logic_vector(47 downto 0);
+ signal tx_tail_dat: std_logic_vector(47 downto 0);
+
+begin
+
+ -- The ADC and DAC decide choose their modes based on the values of their
+ -- pins at powerup, so the rst_i2s signal is here to gate the pins and
+ -- leave them in an high-Z state after powerup for a couple MCLK cycles
+ -- to let them sense their settings. This is probably unnecessary, as the
+ -- FPGA will leave all its IO blocks disabled until configuration is
+ -- complete, but it doesn't hurt to be sure.
+ e_rst: entity utility.sync_sig
+ generic map (INIT => '1')
+ port map (
+ rst_i => rst_50,
+ clk_i => mclk,
+ sig_i => '0',
+ sig_o => rst_i2s
+ );
+
+ e_ctrl: entity work.i2s_ctrl
+ port map (
+ rst_i => rst_50,
+ clk_50 => clk_50,
+
+ mclk => mclk,
+ sck => sck,
+ ws => ws,
+
+ rise => rise,
+ fall => fall
+ );
+
+ e_rx: entity work.i2s_input
+ generic map (WIDTH => 32)
+ port map (
+ mclk => mclk,
+ sck => sck,
+ ws => ws,
+ sd => rxsd,
+
+ rise => rise,
+ fall => fall,
+
+ stb_o => rx_stb,
+ rdy_i => rx_rdy,
+ l_dat_o => rx_l_dat,
+ r_dat_o => rx_r_dat
+ );
+
+ e_rx_fifo: entity utility.sync_fifo_16
+ generic map (WIDTH => 48)
+ port map (
+ head_rst_i => rst_i2s,
+ head_clk_i => mclk,
+ head_stb_i => rx_stb,
+ head_rdy_o => rx_rdy,
+ head_dat_i => rx_head_dat,
+
+ tail_rst_i => rst_50,
+ tail_clk_i => clk_50,
+ tail_stb_o => stb_o,
+ tail_rdy_i => rdy_i,
+ tail_dat_o => rx_tail_dat
+ );
+ rx_head_dat <= rx_r_dat(31 downto 8) & rx_l_dat(31 downto 8);
+ r_dat_o <= rx_tail_dat(47 downto 24);
+ l_dat_o <= rx_tail_dat(23 downto 0);
+
+ e_tx: entity work.i2s_output
+ generic map (WIDTH => 32)
+ port map (
+ mclk => mclk,
+ sck => sck,
+ ws => ws,
+ sd => txsd,
+
+ rise => rise,
+ fall => fall,
+
+ stb_i => tx_stb,
+ rdy_o => tx_rdy,
+ l_dat_i => tx_l_dat,
+ r_dat_i => tx_r_dat
+ );
+
+ e_tx_fifo: entity utility.sync_fifo_16
+ generic map (WIDTH => 48)
+ port map (
+ head_rst_i => rst_50,
+ head_clk_i => clk_50,
+ head_stb_i => stb_i,
+ head_rdy_o => rdy_o,
+ head_dat_i => tx_head_dat,
+
+ tail_rst_i => rst_i2s,
+ tail_clk_i => mclk,
+ tail_stb_o => tx_stb,
+ tail_rdy_i => tx_rdy,
+ tail_dat_o => tx_tail_dat
+ );
+ tx_head_dat <= r_dat_i & l_dat_i;
+ tx_r_dat <= tx_tail_dat(47 downto 24) & x"00";
+ tx_l_dat <= tx_tail_dat(23 downto 0) & x"00";
+
+ -- pmod(3 downto 0) <= JA4 & JA3 & JA2 & JA1 -- TOP
+ -- pmod(7 downto 4) <= JA10 & JA9 & JA8 & JA7 -- BOTTOM
+
+ -- Top row
+ pmod(0) <= 'Z' when rst_i2s = '1' else mclk;
+ pmod(1) <= 'Z' when rst_i2s = '1' else ws;
+ pmod(2) <= 'Z' when rst_i2s = '1' else sck;
+ pmod(3) <= 'Z' when rst_i2s = '1' else txsd;
+
+ -- Bottom row
+ pmod(4) <= 'Z' when rst_i2s = '1' else mclk;
+ pmod(5) <= 'Z' when rst_i2s = '1' else ws;
+ pmod(6) <= 'Z' when rst_i2s = '1' else sck;
+ pmod(7) <= 'Z';
+ rxsd <= pmod(7);
+
+end behavioral;