]> git.the-white-hart.net Git - vhdl/commitdiff
Update a lot of things at once for mp3tape project
authorrs <>
Sat, 31 Jan 2026 21:59:04 +0000 (15:59 -0600)
committerrs <>
Sat, 31 Jan 2026 21:59:04 +0000 (15:59 -0600)
Doing all of this in one commit was not a good move.  I'm sorry, but it
had to be done.

53 files changed:
libraries/dsp/deserialize.vhd
libraries/dsp/i2s_ctrl.vhd [deleted file]
libraries/dsp/i2s_input.vhd [deleted file]
libraries/dsp/i2s_output.vhd [deleted file]
libraries/dsp/i2s_pmod.vhd [deleted file]
libraries/dsp/pcm16_2ch_gain.vhd [deleted file]
libraries/dsp/pcm16_2ch_sum.vhd [deleted file]
libraries/dsp/pcm16_2ch_tapeeffect.vhd [deleted file]
libraries/dsp/pcm16_2ch_vardelay.vhd [deleted file]
libraries/dsp/pcm16_2ch_windowsum.vhd [deleted file]
libraries/i2s/i2s_ctrl.vhd [new file with mode: 0644]
libraries/i2s/i2s_input.vhd [new file with mode: 0644]
libraries/i2s/i2s_output.vhd [new file with mode: 0644]
libraries/i2s/i2s_pmod.vhd [new file with mode: 0644]
libraries/nexys2/mem_wb16_0_opt.vhd [new file with mode: 0644]
libraries/pipe/ctrl.vhd [new file with mode: 0644]
libraries/pipe/ctrl_merge.vhd [new file with mode: 0644]
libraries/pipe/ctrl_split.vhd [new file with mode: 0644]
libraries/pipe/stage_delay.vhd [new file with mode: 0644]
libraries/pipe/stage_merge.vhd [new file with mode: 0644]
libraries/pipe/stage_mux2.vhd [new file with mode: 0644]
libraries/pipe/stage_reg.vhd [new file with mode: 0644]
libraries/pipe/stage_skid.vhd [new file with mode: 0644]
libraries/pipe/stage_split.vhd [new file with mode: 0644]
libraries/pipe/tests/test_ctrl.vhd [new file with mode: 0644]
libraries/pipe/tests/test_ctrl_split.vhd [new file with mode: 0644]
libraries/pipe/tests/test_splitmux.vhd [new file with mode: 0644]
libraries/utility/sync_fifo_1k_16.vhd [new file with mode: 0644]
libraries/utility/sync_sig.vhd
projects/mp3tape/ifft_control.vhd [new file with mode: 0644]
projects/mp3tape/ifft_counter.vhd [new file with mode: 0644]
projects/mp3tape/ifft_datapath.vhd [new file with mode: 0644]
projects/mp3tape/nexys2.vhd
projects/mp3tape/pcm16_1ch_gain.vhd [new file with mode: 0644]
projects/mp3tape/pcm16_1ch_noise.vhd [new file with mode: 0644]
projects/mp3tape/pcm16_1ch_sum.vhd [new file with mode: 0644]
projects/mp3tape/pcm16_1ch_tapeeffect.vhd [new file with mode: 0644]
projects/mp3tape/pcm16_1ch_vardelay.vhd [new file with mode: 0644]
projects/mp3tape/pcm16_1ch_windowsum.vhd [new file with mode: 0644]
projects/mp3tape/pcm16_2ch_gain.vhd [new file with mode: 0644]
projects/mp3tape/pcm16_2ch_noise.vhd [new file with mode: 0644]
projects/mp3tape/pcm16_2ch_sum.vhd [new file with mode: 0644]
projects/mp3tape/pcm16_2ch_tapeeffect.vhd [new file with mode: 0644]
projects/mp3tape/pcm16_2ch_vardelay.vhd [new file with mode: 0644]
projects/mp3tape/pcm16_2ch_windowsum.vhd [new file with mode: 0644]
projects/mp3tape/test_tapeeffect.vhd
projects/mp3tape/tests/test_ifft.vhd [new file with mode: 0644]
projects/mp3tape/tests/test_ifft_counter.vhd [new file with mode: 0644]
projects/mp3tape/tests/test_ifft_datapath.vhd [new file with mode: 0644]
projects/mp3tape/tests/test_nexys2.vhd
projects/mp3tape/tools/jankman.py
projects/nexys2_host_controller/host/build.sh
projects/nexys2_host_controller/host/stm_test.c

index d7231608c6de268dcc2edd1e7877278cfcb763fb..09086c600a72c9f84983951da02c9a7cebf0a305 100644 (file)
@@ -1,5 +1,5 @@
 --------------------------------------------------------------------------------
--- deserialize - Collect N words into a single, wide word
+-- deserialize - Collect N words into a single, wide word (little-endian)
 --
 -- 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.
diff --git a/libraries/dsp/i2s_ctrl.vhd b/libraries/dsp/i2s_ctrl.vhd
deleted file mode 100644 (file)
index 13cf406..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-
-library unisim;
-use unisim.vcomponents.all;
-
-
-entity i2s_ctrl is
-       port (
-               rst_i:  in  std_logic;
-               clk_50: in  std_logic;  -- 50 MHz
-
-               -- For external use
-               mclk:   out std_logic;  -- MCLK, 256*LRCLK(WS)
-               ws:     out std_logic;  -- WS/LRCLK, 44.1028 kHz (good enough for government work)
-               sck:    out std_logic;
-
-               -- For internal use, rising and falling edges of SCK in MCLK domain
-               rise:   out std_logic;
-               fall:   out std_logic
-       );
-end i2s_ctrl;
-
-
-architecture behavioral of i2s_ctrl is
-
-       signal mclk_orig: std_logic;  -- Output from DCM
-       signal mclk_int:  std_logic;  -- DCM output after clock buffer
-       signal sck_int:   std_logic;
-       signal sck_reg:   std_logic;
-
-       signal ws_tick:   std_logic;  -- For WS generation
-       signal ws_carry:  std_logic;
-       signal ws_reg:    std_logic := '0';
-
-       signal rise_int:  std_logic;
-       signal fall_int:  std_logic;
-       signal rise_reg:  std_logic;
-       signal fall_reg:  std_logic;
-
-begin
-
-       e_dcm: dcm_sp
-               generic map (
-                       CLK_FEEDBACK          => "NONE",
-                       --CLKDV_DIVIDE          => 1,
-                       CLKFX_DIVIDE          => 31,
-                       CLKFX_MULTIPLY        => 7,
-                       CLKIN_DIVIDE_BY_2     => false,
-                       CLKIN_PERIOD          => 20.0,
-                       --CLKOUT_PHASE_SHIFT    => "NONE",
-                       --DESKEW_ADJUST         => "SYSTEM_SYNCHRONOUS",
-                       --FACTORY_JF            =>
-                       --PHASE_SHIFT           => 0,
-                       DFS_FREQUENCY_MODE    => "LOW",
-                       --DLL_FREQUENCY_MODE    => "LOW",
-                       --DSS_MODE              => "NONE",
-                       --DUTY_CYCLE_CORRECTION => false,
-                       STARTUP_WAIT          => true
-               )
-               port map (
-                       CLKIN    => clk_50,
-                       CLKFB    => '0',
-                       DSSEN    => '0',
-                       RST      => rst_i,
-                       PSINCDEC => '0',
-                       PSEN     => '0',
-                       PSCLK    => '0',
-                       CLK0     => open,
-                       CLK90    => open,
-                       CLK180   => open,
-                       CLK270   => open,
-                       CLK2X    => open,
-                       CLK2X180 => open,
-                       CLKDV    => open,
-                       CLKFX    => mclk_orig,
-                       CLKFX180 => open,
-                       LOCKED   => open,
-                       STATUS   => open,
-                       PSDONE   => open
-               );
-
-       e_mclkbuf: bufg
-               port map (
-                       I => mclk_orig,
-                       O => mclk_int
-               );
-
-       e_sck_gen: srl16
-               generic map (INIT => x"0003")
-               port map (
-                       D   => sck_int,
-                       CLK => mclk_int,
-                       A0  => '1',
-                       A1  => '1',
-                       A2  => '0',
-                       A3  => '0',
-                       Q   => sck_int
-               );
-
-       process (mclk_int, sck_int, sck_reg)
-       begin
-               if rising_edge(mclk_int) then
-                       sck_reg <= sck_int;
-               end if;
-       end process;
-       rise_int <= '1' when sck_reg = '0' and sck_int = '1' else '0';
-       fall_int <= '1' when sck_reg = '1' and sck_int = '0' else '0';
-
-       e_ws_count_0: srlc16e
-               generic map (INIT => x"0000")
-               port map (
-                       D   => ws_tick,
-                       CE  => fall_int,
-                       CLK => mclk_int,
-                       A0  => '0',
-                       A1  => '0',
-                       A2  => '0',
-                       A3  => '0',
-                       Q   => open,
-                       Q15 => ws_carry
-               );
-
-       e_ws_count_1: srlc16e
-               generic map (INIT => x"0001")
-               port map (
-                       D   => ws_carry,
-                       CE  => fall_int,
-                       CLK => mclk_int,
-                       A0  => '0',
-                       A1  => '0',
-                       A2  => '0',
-                       A3  => '0',
-                       Q   => open,
-                       Q15 => ws_tick
-               );
-
-       process (mclk_int, ws_tick, fall_int, ws_reg)
-       begin
-               if rising_edge(mclk_int) then
-                       if ws_tick = '1' and fall_int = '1' then
-                               ws_reg <= not ws_reg;
-                       end if;
-               end if;
-       end process;
-
-       mclk <= mclk_int;
-       sck  <= sck_reg;
-       ws   <= ws_reg;
-
-       process (mclk_int, rise_int, fall_int)
-       begin
-               if rising_edge(mclk_int) then
-                       rise_reg <= rise_int;
-                       fall_reg <= fall_int;
-               end if;
-       end process;
-
-       rise <= rise_reg;
-       fall <= fall_reg;
-
-end behavioral;
diff --git a/libraries/dsp/i2s_input.vhd b/libraries/dsp/i2s_input.vhd
deleted file mode 100644 (file)
index 43a0c4c..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
---------------------------------------------------------------------------------
--- i2s_input - receives a stream of samples from an I2S interface
---------------------------------------------------------------------------------
-
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-
-library unisim;
-use unisim.vcomponents.all;
-
-
-entity i2s_input is
-       generic (WIDTH: positive := 32);
-       port (
-               mclk:    in  std_logic;
-               sck:     in  std_logic;
-               ws:      in  std_logic;
-               sd:      in  std_logic;
-
-               rise:    in  std_logic;
-               fall:    in  std_logic;
-
-               stb_o:   out std_logic;
-               rdy_i:   in  std_logic;
-               l_dat_o: out std_logic_vector(WIDTH-1 downto 0);
-               r_dat_o: out std_logic_vector(WIDTH-1 downto 0)
-       );
-end i2s_input;
-
-
-architecture behavioral of i2s_input is
-
-       signal shift_reg:  std_logic_vector(WIDTH-1 downto 0);
-       signal ws_reg:     std_logic;
-       signal ws2_reg:    std_logic;
-
-       signal latch_l:    std_logic;
-       signal latch_r:    std_logic;
-
-       signal samp_l_reg: std_logic_vector(WIDTH-1 downto 0);
-       signal samp_r_reg: std_logic_vector(WIDTH-1 downto 0);
-
-       signal stb_reg:    std_logic;
-
-begin
-
-       process (mclk, rise, ws)
-       begin
-               if rising_edge(mclk) then
-                       if rise = '1' then
-                               shift_reg <= shift_reg(WIDTH-2 downto 0) & sd;
-                               ws2_reg   <= ws_reg;
-                               ws_reg    <= ws;
-                       end if;
-               end if;
-       end process;
-
-       latch_l <= '1' when ws_reg = '1' and ws2_reg = '0' else '0';
-       latch_r <= '1' when ws_reg = '0' and ws2_reg = '1' else '0';
-
-       process (mclk, rise, latch_l, latch_r, shift_reg)
-       begin
-               if rising_edge(mclk) then
-                       if rise = '1' then
-                               if latch_l = '1' then
-                                       samp_l_reg <= shift_reg;
-                               end if;
-                               if latch_r = '1' then
-                                       samp_r_reg <= shift_reg;
-                               end if;
-                       end if;
-               end if;
-       end process;
-
-       process (mclk, rise, latch_r, rdy_i)
-       begin
-               if rising_edge(mclk) then
-                       if rise = '1' then
-                               if latch_r = '1' then
-                                       stb_reg <= '1';
-                               elsif rdy_i = '1' then
-                                       stb_reg <= '0';
-                               end if;
-                       end if;
-               end if;
-       end process;
-
-       stb_o   <= stb_reg;
-       l_dat_o <= samp_l_reg;
-       r_dat_o <= samp_r_reg;
-
-end behavioral;
diff --git a/libraries/dsp/i2s_output.vhd b/libraries/dsp/i2s_output.vhd
deleted file mode 100644 (file)
index 11fda1b..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
---------------------------------------------------------------------------------
--- i2s_output - transmits a stream of samples to an I2S interface
---------------------------------------------------------------------------------
-
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-
-library unisim;
-use unisim.vcomponents.all;
-
-
-entity i2s_output is
-       generic (WIDTH: positive := 32);
-       port (
-               mclk:    in  std_logic;
-               sck:     in  std_logic;
-               ws:      in  std_logic;
-               sd:      out std_logic;
-
-               rise:    in  std_logic;
-               fall:    in  std_logic;
-
-               stb_i:   in  std_logic;
-               rdy_o:   out std_logic;
-               l_dat_i: in  std_logic_vector(WIDTH-1 downto 0);
-               r_dat_i: in  std_logic_vector(WIDTH-1 downto 0)
-       );
-end i2s_output;
-
-
-architecture behavioral of i2s_output is
-
-       signal ws_reg:    std_logic;
-       signal ws2_reg:   std_logic;
-       signal shift_reg: std_logic_vector(WIDTH-1 downto 0);
-
-       signal latch_l:   std_logic;
-       signal latch_r:   std_logic;
-
-begin
-
-       sd <= shift_reg(WIDTH-1);
-
-       process (mclk, fall, ws, ws_reg)
-       begin
-               if rising_edge(mclk) then
-                       if fall = '1' then
-                               ws2_reg <= ws_reg;
-                               ws_reg <= ws;
-                       end if;
-               end if;
-       end process;
-
-       latch_l <= '1' when ws_reg = '0' and ws2_reg = '1' else '0';
-       latch_r <= '1' when ws_reg = '1' and ws2_reg = '0' else '0';
-
-       process (mclk, fall, latch_l, latch_r, l_dat_i, r_dat_i, shift_reg)
-       begin
-               if rising_edge(mclk) then
-                       if fall = '1' then
-                               if latch_l = '1' then
-                                       shift_reg <= l_dat_i;
-                               elsif latch_r = '1' then
-                                       shift_reg <= r_dat_i;
-                               else
-                                       shift_reg <= shift_reg(WIDTH-2 downto 0) & '0';
-                               end if;
-                       end if;
-               end if;
-       end process;
-
-       rdy_o <= latch_r and fall;
-
-end behavioral;
diff --git a/libraries/dsp/i2s_pmod.vhd b/libraries/dsp/i2s_pmod.vhd
deleted file mode 100644 (file)
index 984cfaf..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-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;
diff --git a/libraries/dsp/pcm16_2ch_gain.vhd b/libraries/dsp/pcm16_2ch_gain.vhd
deleted file mode 100644 (file)
index 9938214..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-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 <= dat_i(15) & dat_i(15) & dat_i(15 downto  0);
-       samp_r <= dat_i(31) & dat_i(31) & 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));
-
-       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);
-
-       result <= result_r & result_l;
-
-       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;
diff --git a/libraries/dsp/pcm16_2ch_sum.vhd b/libraries/dsp/pcm16_2ch_sum.vhd
deleted file mode 100644 (file)
index 2f4c89d..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-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_o: 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 <= signed(a_dat_i(15 downto  0));
-       samp_a_r <= signed(a_dat_i(31 downto 16));
-       samp_b_l <= signed(b_dat_i(15 downto  0));
-       samp_b_r <= signed(b_dat_i(31 downto 16));
-
-       result_l <= (samp_a_l(15) & samp_a_l) + ((samp_b_l(15)) & samp_b_l);
-       result_r <= (samp_a_r(15) & samp_a_r) + ((samp_b_r(15)) & samp_b_r);
-
-       e_sat_l: entity work.saturate
-               generic map (WIDTH_IN => 17, WIDTH_OUT => 16)
-               port map (dat_i => std_logic_vector(result_l), dat_o => sat_l);
-
-       e_sat_r: entity work.saturate
-               generic map (WIDTH_IN => 17, WIDTH_OUT => 16)
-               port map (dat_i => std_logic_vector(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;
diff --git a/libraries/dsp/pcm16_2ch_tapeeffect.vhd b/libraries/dsp/pcm16_2ch_tapeeffect.vhd
deleted file mode 100644 (file)
index 1769458..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-
-library work;
-
-
-entity pcm16_2ch_tapeeffect is
-       port (
-               rst_i:      in  std_logic;
-               clk_i:      in  std_logic;
-
-               en_rolloff: in  std_logic;
-               en_flutter: in  std_logic;
-               en_wow:     in  std_logic;
-               en_noise:   in  std_logic;
-
-               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_tapeeffect;
-
-
-architecture behavioral of pcm16_2ch_tapeeffect is
-
-       -- Stage 1 - High frequency rolloff
-
-       signal split_a_stb: std_logic;
-       signal split_a_rdy: std_logic;
-       signal split_b_stb: std_logic;
-       signal split_b_rdy: std_logic;
-       signal split_dat:   std_logic_vector(31 downto 0);
-
-       signal filter_stb:  std_logic;
-       signal filter_rdy:  std_logic;
-       signal filter_dat:  std_logic_vector(31 downto 0);
-
-       signal bypass_stb:  std_logic;
-       signal bypass_rdy:  std_logic;
-       signal bypass_dat:  std_logic_vector(31 downto 0);
-
-       signal merge_stb:   std_logic;
-       signal merge_rdy:   std_logic;
-       signal merge_dat:   std_logic_vector(31 downto 0);
-
-       signal stage1_stb:  std_logic;
-       signal stage1_rdy:  std_logic;
-       signal stage1_dat:  std_logic_vector(31 downto 0);
-
-       -- Stage 2 - Wow and flutter
-
-       constant FLUTTER_WIDTH: integer := 9;
-       constant FLUTTER_INC:   std_logic_vector(15 downto 0) := "00000000"&"00100000";
-       signal flutter_stb: std_logic;
-       signal flutter_rdy: std_logic;
-       signal flutter_dat: std_logic_vector(FLUTTER_WIDTH-1 downto 0);
-
-       signal delay_dat:   std_logic_vector(9 downto 0);
-
-       signal stage2_stb:  std_logic;
-       signal stage2_rdy:  std_logic;
-       signal stage2_dat:  std_logic_vector(31 downto 0);
-
-       -- Stage 3 - Hiss
-
-       signal noise_stb:   std_logic;
-       signal noise_rdy:   std_logic;
-       signal noise_raw:   std_logic_vector( 9 downto 0);
-       signal noise_dat:   std_logic_vector(31 downto 0);
-
-begin
-
-       ----------------------------------------------------------------------------
-       -- Low pass filter the audio stream
-
-       e_split: entity work.pipectrl_split
-               generic map (WIDTH => 32)
-               port map (
-                       rst_i   => rst_i,
-                       clk_i   => clk_i,
-
-                       stb_i   => stb_i,
-                       rdy_o   => rdy_o,
-                       dat_i   => dat_i,
-
-                       a_stb_o => split_a_stb,
-                       a_rdy_i => split_a_rdy,
-
-                       b_stb_o => split_b_stb,
-                       b_rdy_i => split_b_rdy,
-
-                       dat_o   => split_dat
-               );
-
-       e_filter: entity work.pcm16_2ch_windowsum
-               generic map (WINDOW => 16)
-               port map (
-                       rst_i => rst_i,
-                       clk_i => clk_i,
-
-                       stb_i => split_a_stb,
-                       rdy_o => split_a_rdy,
-                       dat_i => split_dat,
-
-                       stb_o => filter_stb,
-                       rdy_i => filter_rdy,
-                       dat_o => filter_dat
-               );
-
-       e_bypass: entity work.pipectrl
-               generic map (WIDTH => 32)
-               port map (
-                       rst_i => rst_i,
-                       clk_i => clk_i,
-
-                       stb_i => split_b_stb,
-                       rdy_o => split_b_rdy,
-                       dat_i => split_dat,
-
-                       stb_o => bypass_stb,
-                       rdy_i => bypass_rdy,
-                       dat_o => bypass_dat
-               );
-
-       e_filter_merge: entity work.merge
-               port map (
-                       a_stb_i => filter_stb,
-                       a_rdy_o => filter_rdy,
-
-                       b_stb_i => bypass_stb,
-                       b_rdy_o => bypass_rdy,
-
-                       stb_o   => merge_stb,
-                       rdy_i   => merge_rdy
-               );
-       merge_dat <= filter_dat when en_rolloff = '1' else bypass_dat;
-
-       e_filter_ctrl: entity work.pipectrl
-               generic map (WIDTH => 32)
-               port map (
-                       rst_i => rst_i,
-                       clk_i => clk_i,
-
-                       stb_i => merge_stb,
-                       rdy_o => merge_rdy,
-                       dat_i => merge_dat,
-
-                       stb_o => stage1_stb,
-                       rdy_i => stage1_rdy,
-                       dat_o => stage1_dat
-               );
-
-       ----------------------------------------------------------------------------
-       -- Variable delay for wow and flutter
-
-       e_flutter: entity work.src_fracstep
-               generic map (WIDTH_OUT => FLUTTER_WIDTH)
-               port map (
-                       rst_i => rst_i,
-                       clk_i => clk_i,
-
-                       inc_i => std_logic_vector(unsigned(FLUTTER_INC)),
-
-                       stb_o => flutter_stb,
-                       rdy_i => flutter_rdy,
-                       dat_o => flutter_dat
-               );
-
-       delay_dat <= std_logic_vector(resize(unsigned(flutter_dat), 10)) when en_flutter = '1' else (others => '0');
-
-       e_vardelay: entity work.pcm16_2ch_vardelay
-               port map (
-                       rst_i       => rst_i,
-                       clk_i       => clk_i,
-
-                       delay_stb_i => flutter_stb,
-                       delay_rdy_o => flutter_rdy,
-                       delay_dat_i => delay_dat,
-
-                       audio_stb_i => stage1_stb,
-                       audio_rdy_o => stage1_rdy,
-                       audio_dat_i => stage1_dat,
-
-                       stb_o       => stage2_stb,
-                       rdy_i       => stage2_rdy,
-                       dat_o       => stage2_dat
-               );
-
-       ----------------------------------------------------------------------------
-       -- Add noise stream to audio stream
-
-       e_noise: entity work.src_noise
-               generic map (WIDTH => 10)
-               port map (
-                       clk_i => clk_i,
-
-                       stb_o => noise_stb,
-                       rdy_i => noise_rdy,
-                       dat_o => noise_raw
-               );
-
-       noise_dat <= std_logic_vector(resize(signed(noise_raw), 16)) &
-                    std_logic_vector(resize(signed(noise_raw), 16)) when en_noise = '1' else (others => '0');
-
-       e_sum: entity work.pcm16_2ch_sum
-               port map (
-                       rst_i   => rst_i,
-                       clk_i   => clk_i,
-
-                       a_stb_i => stage2_stb,
-                       a_rdy_o => stage2_rdy,
-                       a_dat_i => stage2_dat,
-
-                       b_stb_i => noise_stb,
-                       b_rdy_o => noise_rdy,
-                       b_dat_i => noise_dat,
-
-                       stb_o   => stb_o,
-                       rdy_i   => rdy_i,
-                       dat_o   => dat_o
-               );
-
-end behavioral;
diff --git a/libraries/dsp/pcm16_2ch_vardelay.vhd b/libraries/dsp/pcm16_2ch_vardelay.vhd
deleted file mode 100644 (file)
index d79d347..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-
-library unisim;
-use unisim.vcomponents.all;
-
-library work;
-
-
-entity pcm16_2ch_vardelay is
-       port (
-               rst_i:       in  std_logic;
-               clk_i:       in  std_logic;
-
-               delay_stb_i: in  std_logic;
-               delay_rdy_o: out std_logic;
-               delay_dat_i: in  std_logic_vector(9 downto 0);
-
-               audio_stb_i: in  std_logic;
-               audio_rdy_o: out std_logic;
-               audio_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_vardelay;
-
-
-architecture behavioral of pcm16_2ch_vardelay is
-
-       constant COUNT_WIDTH: integer := 10;
-
-       signal en:           std_logic;
-       signal stb:          std_logic;
-       signal rdy:          std_logic;
-
-       signal samp_l:       std_logic_vector(15 downto 0);
-       signal samp_r:       std_logic_vector(15 downto 0);
-
-       signal result_l:     std_logic_vector(15 downto 0);
-       signal result_r:     std_logic_vector(15 downto 0);
-
-       signal ptr_head_reg: unsigned(COUNT_WIDTH-1 downto 0) := (others => '0');
-       signal ptr_tail:     unsigned(COUNT_WIDTH-1 downto 0);
-
-begin
-
-       e_merge: entity work.merge
-               port map (
-                       a_stb_i => delay_stb_i,
-                       a_rdy_o => delay_rdy_o,
-                       b_stb_i => audio_stb_i,
-                       b_rdy_o => audio_rdy_o,
-                       stb_o   => stb,
-                       rdy_i   => rdy
-               );
-
-       e_ctrl: entity work.pipectrl
-               generic map (WIDTH => 0)
-               port map (
-                       rst_i => rst_i,
-                       clk_i => clk_i,
-                       en_o  => en,
-                       stb_i => stb,
-                       rdy_o => rdy,
-                       dat_i => open,
-                       stb_o => stb_o,
-                       rdy_i => rdy_i,
-                       dat_o => open
-               );
-
-       process (rst_i, clk_i, en, ptr_head_reg)
-       begin
-               if rising_edge(clk_i) then
-                       if rst_i = '1' then
-                               -- Probably don't need reset logic
-                       elsif en = '1' then
-                               ptr_head_reg <= ptr_head_reg + 1;
-                       end if;
-               end if;
-       end process;
-
-       samp_l <= audio_dat_i(15 downto  0);
-       samp_r <= audio_dat_i(31 downto 16);
-
-       ptr_tail <= (ptr_head_reg - unsigned(delay_dat_i)) - 1;
-
-       e_fifo_l: ramb16_s18_s18
-               port map (
-                       -- Head port (insertion)
-                       WEA   => '1',
-                       ENA   => en,
-                       SSRA  => '0',
-                       CLKA  => clk_i,
-                       ADDRA => std_logic_vector(ptr_head_reg),
-                       DIA   => samp_l,
-                       DIPA  => (others => '0'),
-
-                       DOA   => open,
-                       DOPA  => open,
-
-                       -- Tail port (removal)
-                       WEB   => '0',
-                       ENB   => en,
-                       SSRB  => '0',
-                       CLKB  => clk_i,
-                       ADDRB => std_logic_vector(ptr_tail),
-                       DIB   => (others => '0'),
-                       DIPB  => (others => '0'),
-
-                       DOB   => result_l,
-                       DOPB  => open
-               );
-
-       e_fifo_r: ramb16_s18_s18
-               port map (
-                       -- Head port (insertion)
-                       WEA   => '1',
-                       ENA   => en,
-                       SSRA  => '0',
-                       CLKA  => clk_i,
-                       ADDRA => std_logic_vector(ptr_head_reg),
-                       DIA   => samp_r,
-                       DIPA  => (others => '0'),
-
-                       DOA   => open,
-                       DOPA  => open,
-
-                       -- Tail port (removal)
-                       WEB   => '0',
-                       ENB   => en,
-                       SSRB  => '0',
-                       CLKB  => clk_i,
-                       ADDRB => std_logic_vector(ptr_tail),
-                       DIB   => (others => '0'),
-                       DIPB  => (others => '0'),
-
-                       DOB   => result_r,
-                       DOPB  => open
-               );
-
-       dat_o <= result_r & result_l;
-
-end behavioral;
diff --git a/libraries/dsp/pcm16_2ch_windowsum.vhd b/libraries/dsp/pcm16_2ch_windowsum.vhd
deleted file mode 100644 (file)
index 83bff1c..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.math_real.all;
-
-library work;
-
-
-entity pcm16_2ch_windowsum is
-       generic (
-               WINDOW: 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(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_windowsum;
-
-
-architecture behavioral of pcm16_2ch_windowsum is
-
-       constant FILT_WIDTH: positive := 16+integer(ceil(log2(real(WINDOW))));
-
-       signal en:       std_logic;
-
-       signal samp_l:   std_logic_vector(15 downto 0);
-       signal samp_r:   std_logic_vector(15 downto 0);
-
-       signal filt_l:   std_logic_vector(FILT_WIDTH-1 downto 0);
-       signal filt_r:   std_logic_vector(FILT_WIDTH-1 downto 0);
-
-       signal result_l: std_logic_vector(15 downto 0);
-       signal result_r: std_logic_vector(15 downto 0);
-
-begin
-
-       e_ctrl: entity work.pipectrl
-               generic map (WIDTH => 0)
-               port map (
-                       rst_i => rst_i,
-                       clk_i => clk_i,
-                       en_o  => en,
-                       stb_i => stb_i,
-                       rdy_o => rdy_o,
-                       dat_i => open,
-                       stb_o => stb_o,
-                       rdy_i => rdy_i,
-                       dat_o => open
-               );
-
-       samp_l <= dat_i(15 downto  0);
-       samp_r <= dat_i(31 downto 16);
-
-       e_filter_l: entity work.filter_windowsum
-               generic map (
-                       WIDTH  => 16,
-                       WINDOW => WINDOW
-               )
-               port map (
-                       rst_i => rst_i,
-                       clk_i => clk_i,
-
-                       en_i  => en,
-
-                       dat_i => samp_l,
-                       dat_o => filt_l
-               );
-
-       e_filter_r: entity work.filter_windowsum
-               generic map (
-                       WIDTH  => 16,
-                       WINDOW => WINDOW
-               )
-               port map (
-                       rst_i => rst_i,
-                       clk_i => clk_i,
-
-                       en_i  => en,
-
-                       dat_i => samp_r,
-                       dat_o => filt_r
-               );
-
-       result_l <= filt_l(FILT_WIDTH-1 downto FILT_WIDTH-16);
-       result_r <= filt_r(FILT_WIDTH-1 downto FILT_WIDTH-16);
-
-       dat_o <= result_r & result_l;
-
-end behavioral;
diff --git a/libraries/i2s/i2s_ctrl.vhd b/libraries/i2s/i2s_ctrl.vhd
new file mode 100644 (file)
index 0000000..13cf406
--- /dev/null
@@ -0,0 +1,163 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+
+entity i2s_ctrl is
+       port (
+               rst_i:  in  std_logic;
+               clk_50: in  std_logic;  -- 50 MHz
+
+               -- For external use
+               mclk:   out std_logic;  -- MCLK, 256*LRCLK(WS)
+               ws:     out std_logic;  -- WS/LRCLK, 44.1028 kHz (good enough for government work)
+               sck:    out std_logic;
+
+               -- For internal use, rising and falling edges of SCK in MCLK domain
+               rise:   out std_logic;
+               fall:   out std_logic
+       );
+end i2s_ctrl;
+
+
+architecture behavioral of i2s_ctrl is
+
+       signal mclk_orig: std_logic;  -- Output from DCM
+       signal mclk_int:  std_logic;  -- DCM output after clock buffer
+       signal sck_int:   std_logic;
+       signal sck_reg:   std_logic;
+
+       signal ws_tick:   std_logic;  -- For WS generation
+       signal ws_carry:  std_logic;
+       signal ws_reg:    std_logic := '0';
+
+       signal rise_int:  std_logic;
+       signal fall_int:  std_logic;
+       signal rise_reg:  std_logic;
+       signal fall_reg:  std_logic;
+
+begin
+
+       e_dcm: dcm_sp
+               generic map (
+                       CLK_FEEDBACK          => "NONE",
+                       --CLKDV_DIVIDE          => 1,
+                       CLKFX_DIVIDE          => 31,
+                       CLKFX_MULTIPLY        => 7,
+                       CLKIN_DIVIDE_BY_2     => false,
+                       CLKIN_PERIOD          => 20.0,
+                       --CLKOUT_PHASE_SHIFT    => "NONE",
+                       --DESKEW_ADJUST         => "SYSTEM_SYNCHRONOUS",
+                       --FACTORY_JF            =>
+                       --PHASE_SHIFT           => 0,
+                       DFS_FREQUENCY_MODE    => "LOW",
+                       --DLL_FREQUENCY_MODE    => "LOW",
+                       --DSS_MODE              => "NONE",
+                       --DUTY_CYCLE_CORRECTION => false,
+                       STARTUP_WAIT          => true
+               )
+               port map (
+                       CLKIN    => clk_50,
+                       CLKFB    => '0',
+                       DSSEN    => '0',
+                       RST      => rst_i,
+                       PSINCDEC => '0',
+                       PSEN     => '0',
+                       PSCLK    => '0',
+                       CLK0     => open,
+                       CLK90    => open,
+                       CLK180   => open,
+                       CLK270   => open,
+                       CLK2X    => open,
+                       CLK2X180 => open,
+                       CLKDV    => open,
+                       CLKFX    => mclk_orig,
+                       CLKFX180 => open,
+                       LOCKED   => open,
+                       STATUS   => open,
+                       PSDONE   => open
+               );
+
+       e_mclkbuf: bufg
+               port map (
+                       I => mclk_orig,
+                       O => mclk_int
+               );
+
+       e_sck_gen: srl16
+               generic map (INIT => x"0003")
+               port map (
+                       D   => sck_int,
+                       CLK => mclk_int,
+                       A0  => '1',
+                       A1  => '1',
+                       A2  => '0',
+                       A3  => '0',
+                       Q   => sck_int
+               );
+
+       process (mclk_int, sck_int, sck_reg)
+       begin
+               if rising_edge(mclk_int) then
+                       sck_reg <= sck_int;
+               end if;
+       end process;
+       rise_int <= '1' when sck_reg = '0' and sck_int = '1' else '0';
+       fall_int <= '1' when sck_reg = '1' and sck_int = '0' else '0';
+
+       e_ws_count_0: srlc16e
+               generic map (INIT => x"0000")
+               port map (
+                       D   => ws_tick,
+                       CE  => fall_int,
+                       CLK => mclk_int,
+                       A0  => '0',
+                       A1  => '0',
+                       A2  => '0',
+                       A3  => '0',
+                       Q   => open,
+                       Q15 => ws_carry
+               );
+
+       e_ws_count_1: srlc16e
+               generic map (INIT => x"0001")
+               port map (
+                       D   => ws_carry,
+                       CE  => fall_int,
+                       CLK => mclk_int,
+                       A0  => '0',
+                       A1  => '0',
+                       A2  => '0',
+                       A3  => '0',
+                       Q   => open,
+                       Q15 => ws_tick
+               );
+
+       process (mclk_int, ws_tick, fall_int, ws_reg)
+       begin
+               if rising_edge(mclk_int) then
+                       if ws_tick = '1' and fall_int = '1' then
+                               ws_reg <= not ws_reg;
+                       end if;
+               end if;
+       end process;
+
+       mclk <= mclk_int;
+       sck  <= sck_reg;
+       ws   <= ws_reg;
+
+       process (mclk_int, rise_int, fall_int)
+       begin
+               if rising_edge(mclk_int) then
+                       rise_reg <= rise_int;
+                       fall_reg <= fall_int;
+               end if;
+       end process;
+
+       rise <= rise_reg;
+       fall <= fall_reg;
+
+end behavioral;
diff --git a/libraries/i2s/i2s_input.vhd b/libraries/i2s/i2s_input.vhd
new file mode 100644 (file)
index 0000000..43a0c4c
--- /dev/null
@@ -0,0 +1,93 @@
+--------------------------------------------------------------------------------
+-- i2s_input - receives a stream of samples from an I2S interface
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+
+entity i2s_input is
+       generic (WIDTH: positive := 32);
+       port (
+               mclk:    in  std_logic;
+               sck:     in  std_logic;
+               ws:      in  std_logic;
+               sd:      in  std_logic;
+
+               rise:    in  std_logic;
+               fall:    in  std_logic;
+
+               stb_o:   out std_logic;
+               rdy_i:   in  std_logic;
+               l_dat_o: out std_logic_vector(WIDTH-1 downto 0);
+               r_dat_o: out std_logic_vector(WIDTH-1 downto 0)
+       );
+end i2s_input;
+
+
+architecture behavioral of i2s_input is
+
+       signal shift_reg:  std_logic_vector(WIDTH-1 downto 0);
+       signal ws_reg:     std_logic;
+       signal ws2_reg:    std_logic;
+
+       signal latch_l:    std_logic;
+       signal latch_r:    std_logic;
+
+       signal samp_l_reg: std_logic_vector(WIDTH-1 downto 0);
+       signal samp_r_reg: std_logic_vector(WIDTH-1 downto 0);
+
+       signal stb_reg:    std_logic;
+
+begin
+
+       process (mclk, rise, ws)
+       begin
+               if rising_edge(mclk) then
+                       if rise = '1' then
+                               shift_reg <= shift_reg(WIDTH-2 downto 0) & sd;
+                               ws2_reg   <= ws_reg;
+                               ws_reg    <= ws;
+                       end if;
+               end if;
+       end process;
+
+       latch_l <= '1' when ws_reg = '1' and ws2_reg = '0' else '0';
+       latch_r <= '1' when ws_reg = '0' and ws2_reg = '1' else '0';
+
+       process (mclk, rise, latch_l, latch_r, shift_reg)
+       begin
+               if rising_edge(mclk) then
+                       if rise = '1' then
+                               if latch_l = '1' then
+                                       samp_l_reg <= shift_reg;
+                               end if;
+                               if latch_r = '1' then
+                                       samp_r_reg <= shift_reg;
+                               end if;
+                       end if;
+               end if;
+       end process;
+
+       process (mclk, rise, latch_r, rdy_i)
+       begin
+               if rising_edge(mclk) then
+                       if rise = '1' then
+                               if latch_r = '1' then
+                                       stb_reg <= '1';
+                               elsif rdy_i = '1' then
+                                       stb_reg <= '0';
+                               end if;
+                       end if;
+               end if;
+       end process;
+
+       stb_o   <= stb_reg;
+       l_dat_o <= samp_l_reg;
+       r_dat_o <= samp_r_reg;
+
+end behavioral;
diff --git a/libraries/i2s/i2s_output.vhd b/libraries/i2s/i2s_output.vhd
new file mode 100644 (file)
index 0000000..11fda1b
--- /dev/null
@@ -0,0 +1,75 @@
+--------------------------------------------------------------------------------
+-- i2s_output - transmits a stream of samples to an I2S interface
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+
+entity i2s_output is
+       generic (WIDTH: positive := 32);
+       port (
+               mclk:    in  std_logic;
+               sck:     in  std_logic;
+               ws:      in  std_logic;
+               sd:      out std_logic;
+
+               rise:    in  std_logic;
+               fall:    in  std_logic;
+
+               stb_i:   in  std_logic;
+               rdy_o:   out std_logic;
+               l_dat_i: in  std_logic_vector(WIDTH-1 downto 0);
+               r_dat_i: in  std_logic_vector(WIDTH-1 downto 0)
+       );
+end i2s_output;
+
+
+architecture behavioral of i2s_output is
+
+       signal ws_reg:    std_logic;
+       signal ws2_reg:   std_logic;
+       signal shift_reg: std_logic_vector(WIDTH-1 downto 0);
+
+       signal latch_l:   std_logic;
+       signal latch_r:   std_logic;
+
+begin
+
+       sd <= shift_reg(WIDTH-1);
+
+       process (mclk, fall, ws, ws_reg)
+       begin
+               if rising_edge(mclk) then
+                       if fall = '1' then
+                               ws2_reg <= ws_reg;
+                               ws_reg <= ws;
+                       end if;
+               end if;
+       end process;
+
+       latch_l <= '1' when ws_reg = '0' and ws2_reg = '1' else '0';
+       latch_r <= '1' when ws_reg = '1' and ws2_reg = '0' else '0';
+
+       process (mclk, fall, latch_l, latch_r, l_dat_i, r_dat_i, shift_reg)
+       begin
+               if rising_edge(mclk) then
+                       if fall = '1' then
+                               if latch_l = '1' then
+                                       shift_reg <= l_dat_i;
+                               elsif latch_r = '1' then
+                                       shift_reg <= r_dat_i;
+                               else
+                                       shift_reg <= shift_reg(WIDTH-2 downto 0) & '0';
+                               end if;
+                       end if;
+               end if;
+       end process;
+
+       rdy_o <= latch_r and fall;
+
+end behavioral;
diff --git a/libraries/i2s/i2s_pmod.vhd b/libraries/i2s/i2s_pmod.vhd
new file mode 100644 (file)
index 0000000..984cfaf
--- /dev/null
@@ -0,0 +1,174 @@
+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;
diff --git a/libraries/nexys2/mem_wb16_0_opt.vhd b/libraries/nexys2/mem_wb16_0_opt.vhd
new file mode 100644 (file)
index 0000000..d953f59
--- /dev/null
@@ -0,0 +1,178 @@
+--------------------------------------------------------------------------------
+-- mem_wb16_0 - Simple, non-caching 16-bit interface to Nexys2 onboard memory
+--------------------------------------------------------------------------------
+-- WISHBONE DATASHEET
+--
+-- Wishbone specification used: Rev B.3
+-- Interface type: device
+-- Port size: 8-bit
+-- Operand sizes: 8-bit
+-- Endianness: undefined (port size same as granularity)
+-- Data transfer sequence: undefined
+-- Clock constraints: max 50 MHz
+-- Signals:
+-- * rst_i
+-- * clk_i
+-- * fls_cyc_i (CYC_I for flash)
+-- * ram_cyc_i (CYC_I for RAM)
+-- * stb_i
+-- * we_i
+-- * ack_o
+-- * adr_i (24-bit)
+-- * dat_i (8-bit)
+-- * dat_o (8-bit)
+--------------------------------------------------------------------------------
+
+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 mem_wb16_0_opt is
+       generic (
+               CYCLES_ACTIVE: std_logic_vector(3 downto 0) := "0110";
+               CYCLES_TOTAL:  std_logic_vector(3 downto 0) := "1000"
+       );
+       port (
+               -- Wishbone SYSCON
+               rst_i:       in  std_logic;
+               clk_i:       in  std_logic;
+
+               -- Wishbone system interface
+               fls_cyc_i:   in  std_logic;
+               ram_cyc_i:   in  std_logic;
+               stb_i:       in  std_logic;
+               we_i:        in  std_logic;
+               ack_o:       out std_logic;
+               adr_i:       in  std_logic_vector(23 downto 0);
+               dat_i:       in  std_logic_vector(15 downto 0);
+               dat_o:       out std_logic_vector(15 downto 0);
+
+               -- Memory interface
+               MemOE:       out std_logic;
+               MemWR:       out std_logic;
+               RamAdv:      out std_logic;
+               RamCS:       out std_logic;
+               RamClk:      out std_logic;
+               RamCRE:      out std_logic;
+               RamUB:       out std_logic;
+               RamLB:       out std_logic;
+               RamWait:     in  std_logic;
+               FlashRp:     out std_logic;
+               FlashCS:     out std_logic;
+               FlashStSts:  in  std_logic;
+               MemAdr:      out std_logic_vector(23 downto 1);
+               MemDB_i:     in  std_logic_vector(15 downto 0);  -- Inbound: from memory to device
+               MemDB_o:     out std_logic_vector(15 downto 0)   -- Outbound: from device to memory
+       );
+end mem_wb16_0_opt;
+
+
+architecture behavioral of mem_wb16_0_opt is
+
+       signal state_idle:       std_logic;
+       signal state_total:      std_logic;
+
+       signal state_idle_next:  std_logic;
+       signal state_total_next: std_logic;
+
+       signal count_cycles:     std_logic_vector(3 downto 0);
+       signal count_start:      std_logic;
+       signal count_done:       std_logic;
+
+       signal mem_enable:     std_logic;
+
+       -- Replacement for original cyc_i when separating cyc for ram and flash
+       signal cyc_i:          std_logic;
+
+begin
+
+       cyc_i <= fls_cyc_i or ram_cyc_i;
+
+       process (rst_i, clk_i, state_idle_next, state_total_next)
+       begin
+               if rising_edge(clk_i) then
+                       if rst_i = '1' then
+                               state_idle  <= '1';
+                               state_total <= '0';
+                       else
+                               state_idle  <= state_idle_next;
+                               state_total <= state_total_next;
+                       end if;
+               end if;
+       end process;
+
+       process (state_idle, state_total, cyc_i, stb_i, we_i, count_done)
+       begin
+               state_idle_next  <= state_idle;
+               state_total_next <= state_total;
+               count_start <= '0';
+
+               ack_o       <= '0';
+
+               mem_enable  <= '0';
+               MemOE       <= '1';
+               MemWR       <= '1';
+
+               if state_idle = '1' then
+                       -- Idle, waiting for transaction request
+                       if cyc_i = '1' and stb_i = '1' then
+                               state_idle_next <= '0';
+                               count_start     <= '1';
+                       end if;
+               elsif state_total = '0' then
+                       -- Memory active
+                       mem_enable <= '1';
+                       MemOE      <= we_i;
+                       MemWR      <= not we_i;
+
+                       if count_done = '1' then
+                               ack_o <= '1';
+                               state_total_next <= '1';
+                       end if;
+               else
+                       -- Memory inactive
+                       if count_done = '1' then
+                               state_idle_next  <= '1';
+                               state_total_next <= '0';
+                       end if;
+               end if;
+       end process;
+
+       -- Little-endian memory interface
+       RamCS   <= not (mem_enable and ram_cyc_i);
+       RamAdv  <= '0';
+       RamClk  <= '0';
+       RamCRE  <= '0';
+       RamUB   <= '1';
+       RamLB   <= '1';
+       FlashCS <= not (mem_enable and fls_cyc_i);
+       FlashRp <= '1';
+       MemAdr  <= adr_i(23 downto 1);
+       MemDB_o <= dat_i;
+       dat_o   <= MemDB_i;
+
+
+       -- Cycle counter
+       count_cycles <= CYCLES_TOTAL when state_total = '1' else CYCLES_ACTIVE;
+
+       e_count: srl16
+               generic map (INIT => x"0000")
+               port map (
+                       clk => clk_i,
+
+                       a0  => count_cycles(0),
+                       a1  => count_cycles(1),
+                       a2  => count_cycles(2),
+                       a3  => count_cycles(3),
+
+                       d   => count_start,
+
+                       q   => count_done
+               );
+
+end behavioral;
diff --git a/libraries/pipe/ctrl.vhd b/libraries/pipe/ctrl.vhd
new file mode 100644 (file)
index 0000000..cb8200c
--- /dev/null
@@ -0,0 +1,85 @@
+--------------------------------------------------------------------------------
+-- ctrl - Pipeline stage control logic
+--
+-- Keeps track of the full/empty status of a pipeline stage and propagates stall
+-- signals upstream.
+--
+-- There is a combinational logic chain between the rdy_i and rdy_o signals.  It
+-- may be be necessary to include skid buffers periodically to break the chain
+-- for timing closure purposes.
+--
+-- The interstage register is assumed to be external because some components
+-- like BRAMs have built-in output registers that a design may want to use as
+-- the interstage register.
+--
+-- Also, some pipeline stages may have internal state that needs the "enable"
+-- signal to know when to perform their actions (such as delay lines or
+-- accumulators).
+--------------------------------------------------------------------------------
+-- Ports:
+--
+-- rst_i - Active high synchronous reset
+-- clk_i - Clock
+--
+-- stb_i - Input strobe, high when upstream stage has a value to accept
+-- rdy_o - Ready output, high when the upstream stage can release its value
+--
+-- stb_o - Output strobe, high when this stage has a value to pass downstream
+-- rdy_i - Ready input, high when this stage can release its value
+--
+-- en_o  - Enable signal to external interstage register
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity ctrl is
+       port (
+               rst_i: in  std_logic;
+               clk_i: in  std_logic;
+
+               stb_i: in  std_logic;
+               rdy_o: out std_logic;
+
+               stb_o: out std_logic;
+               rdy_i: in  std_logic;
+
+               en_o:  out std_logic
+       );
+end ctrl;
+
+
+architecture behavioral of ctrl is
+
+       signal enable:  std_logic;
+       signal rdy:     std_logic;
+       signal stb_reg: std_logic;
+
+begin
+
+       -- Enable the (external) stage register to latch if:
+       -- * it is currently empty
+       -- * it is currently full, but the downstream stage is accepting the current data
+       --
+       -- But not if we're in reset - if the upstream source is in a different reset
+       -- domain and comes out of reset before this, we don't want to respond as ready
+       enable <= ((not stb_reg) or rdy_i) and stb_i and (not rst_i);
+       en_o   <= enable;
+
+       stb_o <= stb_reg;
+       rdy   <= ((not stb_reg) or rdy_i) and (not rst_i);
+       rdy_o <= rdy;
+
+       process (rst_i, clk_i, enable, stb_i)
+       begin
+               if rising_edge(clk_i) then
+                       if rst_i = '1' then
+                               stb_reg <= '0';
+                       elsif rdy = '1' then
+                               stb_reg <= stb_i;
+                       end if;
+               end if;
+       end process;
+
+end behavioral;
diff --git a/libraries/pipe/ctrl_merge.vhd b/libraries/pipe/ctrl_merge.vhd
new file mode 100644 (file)
index 0000000..b014194
--- /dev/null
@@ -0,0 +1,72 @@
+--------------------------------------------------------------------------------
+-- ctrl_merge - Merge two upstream pipelines into a single pipeline
+--
+-- Both upstream stages must strobe before either are given a ready signal, and
+-- both are given a ready signal at the same time.  This entity is for pipeline
+-- stages that require and consume information from two upstream pipes, not for
+-- stages that take one *or* another or interleave streams.
+--------------------------------------------------------------------------------
+-- Ports:
+--
+-- rst_i   - Active high synchronous reset
+-- clk_i   - Clock
+--
+-- a_stb_i - Upstream source A strobe
+-- b_rdy_o - Ready signal to source A
+--
+-- b_stb_i - Upstream source B strobe
+-- b_rdy_o - Ready signal to source B
+--
+-- stb_o   - Combined strobe for both sources
+-- rdy_i   - Ready signal from downstream
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity ctrl_merge is
+       port (
+               rst_i:   in  std_logic;
+               clk_i:   in  std_logic;
+
+               a_stb_i: in  std_logic;
+               a_rdy_o: out std_logic;
+
+               b_stb_i: in  std_logic;
+               b_rdy_o: out std_logic;
+
+               stb_o:   out std_logic;
+               rdy_i:   in  std_logic;
+
+               en_o:    out std_logic
+       );
+end ctrl_merge;
+
+
+architecture behavioral of ctrl_merge is
+
+       signal costrobe: std_logic;
+       signal rdy:      std_logic;
+
+begin
+
+       costrobe <= a_stb_i and b_stb_i;
+       a_rdy_o  <= costrobe and rdy;
+       b_rdy_o  <= costrobe and rdy;
+
+       e_ctrl: entity work.ctrl
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+
+                       stb_i => costrobe,
+                       rdy_o => rdy,
+
+                       stb_o => stb_o,
+                       rdy_i => rdy_i,
+
+                       en_o  => en_o
+               );
+
+end behavioral;
diff --git a/libraries/pipe/ctrl_split.vhd b/libraries/pipe/ctrl_split.vhd
new file mode 100644 (file)
index 0000000..350b6f9
--- /dev/null
@@ -0,0 +1,91 @@
+--------------------------------------------------------------------------------
+-- ctrl_split - Split a pipeline into two downstream pipelines
+--
+-- Both downstream stages must respond with ready signals before an enable
+-- signal will be passed to the stage and a ready signal is passed upstream.
+-- This entity is for situations where both downstream stages consume values
+-- from the current stage, not where one *or* the other may, or for
+-- demultiplexing data streams.
+--------------------------------------------------------------------------------
+-- Ports:
+--
+-- rst_i   - Active high synchronous reset
+-- clk_i   - Clock
+--
+-- stb_i   - Input strobe, high when upstream stage has a value to accept
+-- rdy_o   - Ready output, high when the upstream stage can release its value
+--
+-- a_stb_o - Strobe to sink A
+-- a_rdy_i - Ready from sink A
+--
+-- b_stb_o - Strobe to sink B
+-- b_rdy_i - Ready from sink B
+--
+-- en_o    - Enable signal to current stage's logic and interstage register
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity ctrl_split is
+       port (
+               rst_i:   in  std_logic;
+               clk_i:   in  std_logic;
+
+               stb_i:   in  std_logic;
+               rdy_o:   out std_logic;
+
+               a_stb_o: out std_logic;
+               a_rdy_i: in  std_logic;
+
+               b_stb_o: out std_logic;
+               b_rdy_i: in  std_logic;
+
+               en_o:    out std_logic
+       );
+end ctrl_split;
+
+
+architecture behavioral of ctrl_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 rdy:       std_logic;
+
+begin
+
+       a_rdy <= (not a_stb_reg) or a_rdy_i;
+       b_rdy <= (not b_stb_reg) or b_rdy_i;
+       rdy   <= a_rdy and b_rdy and (not rst_i);
+       rdy_o <= rdy;
+       en_o  <= rdy and stb_i;
+
+       -- Full registers
+       process (rst_i, clk_i, rdy, stb_i, a_rdy_i, b_rdy_i)
+       begin
+               if rising_edge(clk_i) then
+                       if rst_i = '1' then
+                               a_stb_reg <= '0';
+                               b_stb_reg <= '0';
+                       elsif rdy = '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;
+
+end behavioral;
diff --git a/libraries/pipe/stage_delay.vhd b/libraries/pipe/stage_delay.vhd
new file mode 100644 (file)
index 0000000..e30bc45
--- /dev/null
@@ -0,0 +1,60 @@
+--------------------------------------------------------------------------------
+-- stage_delay - Ready-made pipeline stage that delays a data stream
+--
+-- The first DELAY samples coming out will be all zeroes.
+--
+-- rst_i should be held active for DELAY or 16 clock cycles, whichever is lower.
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+library dsp;
+library work;
+
+
+entity stage_delay is
+       generic (
+               WIDTH: positive := 16;
+               DELAY: 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 stage_delay;
+
+
+architecture behavioral of stage_delay is
+
+       signal en: std_logic;
+
+begin
+
+       stb_o <= stb_i;
+       rdy_o <= rdy_i;
+
+       en <= stb_i and rdy_i;
+
+       e_delay: entity dap.delay_srl
+               generic map (
+                       WIDTH => WIDTH,
+                       DELAY => DELAY
+               )
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+                       en_i  => en,
+                       dat_i => dat_i,
+                       dat_o => dat_o
+               );
+
+end behavioral;
diff --git a/libraries/pipe/stage_merge.vhd b/libraries/pipe/stage_merge.vhd
new file mode 100644 (file)
index 0000000..5a9a28a
--- /dev/null
@@ -0,0 +1,76 @@
+--------------------------------------------------------------------------------
+-- stage_merge - Ready-made empty pipeline stage that merges a pipeline
+--
+-- Can be used as a generic interstage register at the end of a pipeline stage
+-- that needs to merge two data streams.
+--
+-- There is only one data input dat_i, which will be registered to the data
+-- output dat_o.  It is up to the rest of the logic to decide what that value
+-- should be as a combination of the two data values from the upstream stage.
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+library work;
+
+
+entity stage_merge is
+       generic (
+               WIDTH: positive := 16
+       );
+       port (
+               rst_i:   in  std_logic;
+               clk_i:   in  std_logic;
+
+               a_stb_i: in  std_logic;
+               a_rdy_o: out std_logic;
+
+               b_stb_i: in  std_logic;
+               b_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 stage_merge;
+
+
+architecture behavioral of stage_merge is
+
+       signal en:      std_logic;
+       signal dat_reg: std_logic_vector(WIDTH-1 downto 0);
+
+begin
+
+       e_ctrl: entity work.ctrl_merge
+               port map (
+                       rst_i   => rst_i,
+                       clk_i   => clk_i,
+
+                       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_o,
+                       rdy_i   => rdy_i,
+
+                       en_o    => en
+               );
+
+       process (clk_i, en, dat_i)
+       begin
+               if rising_edge(clk_i) then
+                       if en = '1' then
+                               dat_reg <= dat_i;
+                       end if;
+               end if;
+       end process;
+
+       dat_o <= dat_reg;
+
+end behavioral;
diff --git a/libraries/pipe/stage_mux2.vhd b/libraries/pipe/stage_mux2.vhd
new file mode 100644 (file)
index 0000000..23a9174
--- /dev/null
@@ -0,0 +1,63 @@
+--------------------------------------------------------------------------------
+-- stage_mux2 - Ready-made pipeline stage that multiplexes two pipelines to one
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+library work;
+
+
+entity stage_mux2 is
+       generic (
+               WIDTH: positive := 16
+       );
+       port (
+               rst_i:   in  std_logic;
+               clk_i:   in  std_logic;
+
+               sel:     in  std_logic;
+
+               stb_0_i: in  std_logic;
+               rdy_0_o: out std_logic;
+               dat_0_i: in  std_logic_vector(WIDTH-1 downto 0);
+
+               stb_1_i: in  std_logic;
+               rdy_1_o: out std_logic;
+               dat_1_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 stage_mux2;
+
+
+architecture behavioral of stage_mux2 is
+
+       signal dat:     std_logic_vector(WIDTH-1 downto 0);
+
+begin
+
+       dat <= dat_0_i when sel = '0' else dat_1_i;
+
+       e_ctrl: entity work.stage_merge
+               generic map (WIDTH => WIDTH)
+               port map (
+                       rst_i   => rst_i,
+                       clk_i   => clk_i,
+
+                       a_stb_i => stb_0_i,
+                       a_rdy_o => rdy_0_o,
+
+                       b_stb_i => stb_1_i,
+                       b_rdy_o => rdy_1_o,
+
+                       dat_i   => dat,
+
+                       stb_o   => stb_o,
+                       rdy_i   => rdy_i,
+                       dat_o   => dat_o
+               );
+
+end behavioral;
diff --git a/libraries/pipe/stage_reg.vhd b/libraries/pipe/stage_reg.vhd
new file mode 100644 (file)
index 0000000..3b67681
--- /dev/null
@@ -0,0 +1,64 @@
+--------------------------------------------------------------------------------
+-- stage_empty - Ready-made empty pipeline stage
+--
+-- Can be used as a generic interstage register at the end of a pipeline stage.
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+library work;
+
+
+entity stage_reg 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 stage_reg;
+
+
+architecture behavioral of stage_reg is
+
+       signal en:      std_logic;
+       signal dat_reg: std_logic_vector(WIDTH-1 downto 0);
+
+begin
+
+       e_ctrl: entity work.ctrl
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+
+                       stb_i => stb_i,
+                       rdy_o => rdy_o,
+
+                       stb_o => stb_o,
+                       rdy_i => rdy_i,
+
+                       en_o  => en
+               );
+
+       process (clk_i, en, dat_i)
+       begin
+               if rising_edge(clk_i) then
+                       if en = '1' then
+                               dat_reg <= dat_i;
+                       end if;
+               end if;
+       end process;
+
+       dat_o <= dat_reg;
+
+end behavioral;
diff --git a/libraries/pipe/stage_skid.vhd b/libraries/pipe/stage_skid.vhd
new file mode 100644 (file)
index 0000000..c1d6354
--- /dev/null
@@ -0,0 +1,93 @@
+--------------------------------------------------------------------------------
+-- stage_skid - Skid buffer to break combinational ready (stall) signal chains
+--
+-- Can be placed inline between any two pipeline stages to break all
+-- combinational logic chains in the control signalling between the two.
+--
+-- This does add a multiplexer delay to the data signal, so it may adversely
+-- affect timing if placed before the pipeline stage that is already the
+-- critical path for clock cycle timing.
+--------------------------------------------------------------------------------
+-- Ports:
+--
+-- rst_i - Active high synchronous reset
+-- clk_i - Clock
+--
+-- stb_i - Input strobe, high when upstream stage has a value to accept
+-- rdy_o - Ready output, high when the upstream stage can release its value
+-- dat_i - Value being passed downstream
+--
+-- stb_o - Output strobe, high when a value can pass downstream
+-- rdy_i - Ready input, high when downstream can accept a value
+-- dat_o - Value from upstream
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity stage_skid 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 stage_skid;
+
+
+architecture behavioral of stage_skid is
+
+       -- Registered ready signal
+       signal rdy_reg:     std_logic := '1';
+
+       -- Skid buffer
+       signal skid_en:      std_logic;
+       signal skid_clr:     std_logic;
+       signal skid_stb_reg: std_logic := '0';
+       signal skid_dat_reg: std_logic_vector(WIDTH-1 downto 0);
+
+begin
+
+       stb_o <= stb_reg or skid_stb_reg;
+       rdy_o <= rdy_reg;
+       dat_o <= skid_dat_reg when skid_stb_reg = '1' else dat_i;
+
+       skid_en  <= rdy_reg and (not rdy_i);  -- Upstream thinks downstream is ready, but it's not
+       skid_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;
+
+       -- Skid buffer
+       process (rst_i, clk_i, skid_en, skid_clr, stb_reg, dat_i)
+       begin
+               if rising_edge(clk_i) then
+                       if rst_i = '1' or skid_clr = '1' then
+                               skid_stb_reg <= '0';
+                       elsif skid_en = '1' then
+                               skid_stb_reg <= stb_i;
+                               skid_dat_reg <= dat_i;
+                       end if;
+               end if;
+       end process;
+
+end behavioral;
diff --git a/libraries/pipe/stage_split.vhd b/libraries/pipe/stage_split.vhd
new file mode 100644 (file)
index 0000000..f92259f
--- /dev/null
@@ -0,0 +1,68 @@
+--------------------------------------------------------------------------------
+-- stage_split - Ready-made empty pipeline stage that splits a pipeline
+--
+-- Can be used as a generic interstage register at the end of a pipeline stage
+-- that needs to split in twain.
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+
+library work;
+
+
+entity stage_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 stage_split;
+
+
+architecture behavioral of stage_split is
+
+       signal en:      std_logic;
+       signal dat_reg: std_logic_vector(WIDTH-1 downto 0);
+
+begin
+
+       e_ctrl: entity work.ctrl_split
+               port map (
+                       rst_i   => rst_i,
+                       clk_i   => clk_i,
+                       stb_i   => stb_i,
+                       rdy_o   => rdy_o,
+                       a_stb_o => a_stb_o,
+                       a_rdy_i => a_rdy_i,
+                       b_stb_o => b_stb_o,
+                       b_rdy_i => b_rdy_i,
+                       en_o    => en
+               );
+
+       process (clk_i, en, dat_i)
+       begin
+               if rising_edge(clk_i) then
+                       if en = '1' then
+                               dat_reg <= dat_i;
+                       end if;
+               end if;
+       end process;
+
+       dat_o <= dat_reg;
+
+end behavioral;
diff --git a/libraries/pipe/tests/test_ctrl.vhd b/libraries/pipe/tests/test_ctrl.vhd
new file mode 100644 (file)
index 0000000..8ace096
--- /dev/null
@@ -0,0 +1,176 @@
+library ieee;
+use ieee.std_logic_1164.all;
+
+library work;
+
+
+entity test_ctrl is
+end test_ctrl;
+
+
+architecture behavior of test_ctrl is
+
+       type test_t is (
+               T_RESET,
+               T_0_NO_OP,
+               T_1_NO_OP,
+               T_4_EMPTY_WITH_STALL,
+               T_6_FULL_STALL,
+               T_7_FULL_NO_STALL,
+               T_2_FULL_STALL_2,
+               T_3_DRAIN,
+               T_5_NORMAL,
+               T_DONE
+       );
+       constant CLK_I_PERIOD: time := 20 ns;
+
+       signal test:  test_t;
+
+       signal rst_i: std_logic;
+       signal clk_i: std_logic;
+
+       signal stb_i: std_logic;
+       signal rdy_o: std_logic;
+
+       signal stb_o: std_logic;
+       signal rdy_i: std_logic;
+
+       signal en_o:  std_logic;
+
+begin
+
+       p_test: process
+       begin
+               -- Initial values
+               stb_i <= '0';
+               rdy_i <= '0';
+
+               -- Reset
+               test <= T_RESET;
+               rst_i <= '1';
+               wait for CLK_I_PERIOD*2;
+               rst_i <= '0';
+               wait until falling_edge(clk_i);
+
+               -- Test
+
+               --    stb_i  stb_o  rdy_i | rdy_o  stb_o'  en_o
+               -- 0  0      0      0     |
+               -- 1  0      0      1     |
+               -- 2  0      1      0     |
+               -- 3  0      1      1     |
+               -- 4  1      0      0     |
+               -- 5  1      0      1     |
+               -- 6  1      1      0     |
+               -- 7  1      1      1     |
+
+               test <= T_0_NO_OP;
+               stb_i <= '0';        -- Nothing from upstream
+               rdy_i <= '0';        -- Downstream stalled
+               wait for 1 ns;
+               assert stb_o = '0';  -- Currently empty
+               assert rdy_o = '1';  -- Report ready to upstream
+               assert en_o  = '0';  -- Don't load
+               wait until falling_edge(clk_i);
+               assert stb_o = '0';  -- Still empty
+
+               test <= T_1_NO_OP;
+               stb_i <= '0';        -- Nothing from upstream
+               rdy_i <= '1';        -- Downstream ready
+               wait for 1 ns;
+               assert stb_o = '0';  -- Currently empty
+               assert rdy_o = '1';  -- Report ready to upstream
+               assert en_o  = '0';  -- Don't load
+               wait until falling_edge(clk_i);
+               assert stb_o = '0';  -- Still empty
+
+               test <= T_4_EMPTY_WITH_STALL;
+               stb_i <= '1';        -- Upstream pushing
+               rdy_i <= '0';        -- Downstream stalled
+               wait for 1 ns;
+               assert stb_o = '0' report "a";  -- Currently empty
+               assert rdy_o = '1' report "b";  -- Report ready to upstream
+               assert en_o  = '1' report "c";  -- Perform load
+               wait until falling_edge(clk_i);
+               assert stb_o = '1' report "d";  -- Ends up full
+
+               test <= T_6_FULL_STALL;
+               stb_i <= '1';        -- Upstream pushing
+               rdy_i <= '0';        -- Downstream stalled
+               wait for 1 ns;
+               assert stb_o = '1';  -- Currently full
+               assert rdy_o = '0';  -- Propagate stall
+               assert en_o  = '0';  -- Don't load
+               wait until falling_edge(clk_i);
+               assert stb_o = '1';  -- Still full
+
+               test <= T_7_FULL_NO_STALL;
+               stb_i <= '1';        -- Upstream pushing
+               rdy_i <= '1';        -- Downstream ready
+               wait for 1 ns;
+               assert stb_o = '1';  -- Currently full
+               assert rdy_o = '1';  -- Report ready to upstream
+               assert en_o  = '1';  -- Perform load
+               wait until falling_edge(clk_i);
+               assert stb_o = '1';  -- Ends up full
+
+               test <= T_2_FULL_STALL_2;
+               stb_i <= '0';        -- Upstream not pushing
+               rdy_i <= '0';        -- Downstream stalled
+               wait for 1 ns;
+               assert stb_o = '1';  -- Currently full
+               assert rdy_o = '0';  -- Propagate stall
+               assert en_o  = '0';  -- Don't load
+               wait until falling_edge(clk_i);
+               assert stb_o = '1';  -- Still full
+
+               test <= T_3_DRAIN;
+               stb_i <= '0';        -- Upstream not pushing
+               rdy_i <= '1';        -- Downstream ready
+               wait for 1 ns;
+               assert stb_o = '1';  -- Currently full
+               assert rdy_o = '1';  -- Report ready to upstream
+               assert en_o  = '0';  -- Don't load
+               wait until falling_edge(clk_i);
+               assert stb_o = '0';  -- Ends up empty
+
+               test <= T_5_NORMAL;
+               stb_i <= '1';        -- Upstream pushing
+               rdy_i <= '1';        -- Downstream ready
+               wait for 1 ns;
+               assert stb_o = '0';  -- Currently empty
+               assert rdy_o = '1';  -- Report ready to upstream
+               assert en_o  = '1';  -- Perform load
+               wait until falling_edge(clk_i);
+               assert stb_o = '1';  -- Ends up full
+
+               -- Done
+               test <= T_DONE;
+               wait;
+       end process;
+
+
+       e_uut: entity work.ctrl
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+
+                       stb_i => stb_i,
+                       rdy_o => rdy_o,
+
+                       stb_o => stb_o,
+                       rdy_i => rdy_i,
+
+                       en_o  => en_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;
diff --git a/libraries/pipe/tests/test_ctrl_split.vhd b/libraries/pipe/tests/test_ctrl_split.vhd
new file mode 100644 (file)
index 0000000..b368bf1
--- /dev/null
@@ -0,0 +1,434 @@
+library ieee;
+use ieee.std_logic_1164.all;
+
+library work;
+
+
+entity test_ctrl_split is
+end test_ctrl_split;
+
+
+architecture behavior of test_ctrl_split is
+
+       constant CLK_I_PERIOD: time := 20 ns;
+
+       -- Some tests are redundant due to symmetry and skipped, see table below
+       type test_t is (
+               T_RESET,
+               T_00, T_01, T_02, T_03, T_04, T_05, T_06, T_07,
+               T_08, T_09, T_0A, T_0B, T_0C, T_0D, T_0E, T_0F,
+               T_10, T_11, T_12, T_13, T_14, T_15, T_16, T_17,
+               T_18, T_19, T_1A, T_1B, T_1C, T_1D, T_1E, T_1F,
+               T_DONE
+       );
+
+       signal test: test_t;
+
+       signal rst_i:   std_logic;
+       signal clk_i:   std_logic;
+
+       signal stb_i:   std_logic;
+       signal rdy_o:   std_logic;
+
+       signal a_stb_o: std_logic;
+       signal a_rdy_i: std_logic;
+
+       signal b_stb_o: std_logic;
+       signal b_rdy_i: std_logic;
+
+       signal en_o:    std_logic;
+
+begin
+
+       p_test: process
+       begin
+               -- Inital values
+
+               -- Reset
+               rst_i <= '1';
+               wait for CLK_I_PERIOD*2;
+               rst_i <= '0';
+               wait until falling_edge(clk_i);
+
+               -- Tests
+
+               -- Full test enumeration
+               -- stb_i  a_rdy_i  b_rdy_i  a_stb_o  b_stb_o  |  rdy_o  a_stb_o'  b_stb_o'  en_o  test (symmetric-test)
+               -- -------------------------------------------+--------------------------------------------------------
+               -- 0      0        0        0        0        |  1      0         0         0     T_00
+               -- 0      0        0        0        1        |  0      0         1         0     T_01 (T_02)
+               -- 0      0        0        1        0        |  0      1         0         0     T_02 (T_01)
+               -- 0      0        0        1        1        |  0      1         1         0     T_03
+               -- 0      0        1        0        0        |  1      0         0         0     T_04 (T_08)
+               -- 0      0        1        0        1        |  1      0         0         0     T_05 (T_0A)
+               -- 0      0        1        1        0        |  0      1         0         0     T_06 (T_09)
+               -- 0      0        1        1        1        |  0      1         0         0     T_07 (T_0B)
+               -- 0      1        0        0        0        |  1      0         0         0     T_08 (T_04)
+               -- 0      1        0        0        1        |  0      0         1         0     T_09 (T_06)
+               -- 0      1        0        1        0        |  1      0         0         0     T_0A (T_05)
+               -- 0      1        0        1        1        |  0      0         1         0     T_0B (T_07)
+               -- 0      1        1        0        0        |  1      0         0         0     T_0C
+               -- 0      1        1        0        1        |  1      0         0         0     T_0D (T_0E)
+               -- 0      1        1        1        0        |  1      0         0         0     T_0E (T_0D)
+               -- 0      1        1        1        1        |  1      0         0         0     T_0F
+               -- 1      0        0        0        0        |  1      1         1         1     T_10
+               -- 1      0        0        0        1        |  0      0         1         0     T_11 (T_12)
+               -- 1      0        0        1        0        |  0      1         0         0     T_12 (T_11)
+               -- 1      0        0        1        1        |  0      1         1         0     T_13
+               -- 1      0        1        0        0        |  1      1         1         1     T_14 (T_18)
+               -- 1      0        1        0        1        |  1      1         1         1     T_15 (T_1A)
+               -- 1      0        1        1        0        |  0      1         0         0     T_16 (T_19)
+               -- 1      0        1        1        1        |  0      1         0         0     T_17 (T_1B)
+               -- 1      1        0        0        0        |  1      1         1         1     T_18 (T_14)
+               -- 1      1        0        0        1        |  0      0         1         0     T_19 (T_16)
+               -- 1      1        0        1        0        |  1      1         1         1     T_1A (T_15)
+               -- 1      1        0        1        1        |  0      0         1         0     T_1B (T_17)
+               -- 1      1        1        0        0        |  1      1         1         1     T_1C
+               -- 1      1        1        0        1        |  1      1         1         1     T_1D (T_1E)
+               -- 1      1        1        1        0        |  1      1         1         1     T_1E (T_1D)
+               -- 1      1        1        1        1        |  1      1         1         1     T_1F
+
+               -- Test sequence with reduncancies removed (T_0B run three times to traverse state graph)
+               -- stb_i  a_rdy_i  b_rdy_i  a_stb_o  b_stb_o  |  rdy_o  a_stb_o'  b_stb_o'  en_o  test (symmetric-test)
+               -- -------------------------------------------+--------------------------------------------------------
+               -- 0      0        0        0        0        |  1      0         0         0     T_00
+               -- 0      0        1        0        0        |  1      0         0         0     T_04 (T_08)
+               -- 0      1        1        0        0        |  1      0         0         0     T_0C
+               -- 1      0        0        0        0        |  1      1         1         1     T_10
+               -- 0      0        0        1        1        |  0      1         1         0     T_03
+               -- 1      0        0        1        1        |  0      1         1         0     T_13
+               -- 1      1        1        1        1        |  1      1         1         1     T_1F
+               -- 0      1        1        1        1        |  1      0         0         0     T_0F
+               -- 1      0        1        0        0        |  1      1         1         1     T_14 (T_18)
+               -- 0      1        0        1        1        |  0      0         1         0     T_0B (T_07)
+               -- 0      0        0        0        1        |  0      0         1         0     T_01 (T_02)
+               -- 0      1        0        0        1        |  0      0         1         0     T_09 (T_06)
+               -- 1      0        0        0        1        |  0      0         1         0     T_11 (T_12)
+               -- 1      1        0        0        1        |  0      0         1         0     T_19 (T_16)
+               -- 1      0        1        0        1        |  1      1         1         1     T_15 (T_1A)
+               -- 1      1        0        1        1        |  0      0         1         0     T_1B (T_17)
+               -- 1      1        1        0        1        |  1      1         1         1     T_1D (T_1E)
+               -- 0      1        0        1        1        |  0      0         1         0     T_0B (T_07)*
+               -- 0      0        1        0        1        |  1      0         0         0     T_05 (T_0A)
+               -- 1      1        1        0        0        |  1      1         1         1     T_1C
+               -- 0      1        0        1        1        |  0      0         1         0     T_0B (T_07)*
+               -- 0      1        1        0        1        |  1      0         0         0     T_0D (T_0E)
+               -- stb_i  a_rdy_i  b_rdy_i  a_stb_o  b_stb_o  |  rdy_o  a_stb_o'  b_stb_o'  en_o  test (symmetric-test)
+
+               test    <= T_00;
+               stb_i   <= '0';
+               a_rdy_i <= '0';
+               b_rdy_i <= '0';
+               wait for 1 ns;
+               assert a_stb_o = '0' report "a_stb_o";
+               assert b_stb_o = '0' report "b_stb_o";
+               assert rdy_o   = '1' report "rdy_o";
+               assert en_o    = '0' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '0' report "a_stb_o'";
+               assert b_stb_o = '0' report "b_stb_o'";
+
+               test    <= T_04;
+               stb_i   <= '0';
+               a_rdy_i <= '0';
+               b_rdy_i <= '1';
+               wait for 1 ns;
+               assert a_stb_o = '0' report "a_stb_o";
+               assert b_stb_o = '0' report "b_stb_o";
+               assert rdy_o   = '1' report "rdy_o";
+               assert en_o    = '0' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '0' report "a_stb_o'";
+               assert b_stb_o = '0' report "b_stb_o'";
+
+               test    <= T_0C;
+               stb_i   <= '0';
+               a_rdy_i <= '1';
+               b_rdy_i <= '1';
+               wait for 1 ns;
+               assert a_stb_o = '0' report "a_stb_o";
+               assert b_stb_o = '0' report "b_stb_o";
+               assert rdy_o   = '1' report "rdy_o";
+               assert en_o    = '0' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '0' report "a_stb_o'";
+               assert b_stb_o = '0' report "b_stb_o'";
+
+               test    <= T_10;
+               stb_i   <= '1';
+               a_rdy_i <= '0';
+               b_rdy_i <= '0';
+               wait for 1 ns;
+               assert a_stb_o = '0' report "a_stb_o";
+               assert b_stb_o = '0' report "b_stb_o";
+               assert rdy_o   = '1' report "rdy_o";
+               assert en_o    = '1' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '1' report "a_stb_o'";
+               assert b_stb_o = '1' report "b_stb_o'";
+
+               test    <= T_03;
+               stb_i   <= '0';
+               a_rdy_i <= '0';
+               b_rdy_i <= '0';
+               wait for 1 ns;
+               assert a_stb_o = '1' report "a_stb_o";
+               assert b_stb_o = '1' report "b_stb_o";
+               assert rdy_o   = '0' report "rdy_o";
+               assert en_o    = '0' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '1' report "a_stb_o'";
+               assert b_stb_o = '1' report "b_stb_o'";
+
+               test    <= T_13;
+               stb_i   <= '1';
+               a_rdy_i <= '0';
+               b_rdy_i <= '0';
+               wait for 1 ns;
+               assert a_stb_o = '1' report "a_stb_o";
+               assert b_stb_o = '1' report "b_stb_o";
+               assert rdy_o   = '0' report "rdy_o";
+               assert en_o    = '0' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '1' report "a_stb_o'";
+               assert b_stb_o = '1' report "b_stb_o'";
+
+               test    <= T_1F;
+               stb_i   <= '1';
+               a_rdy_i <= '1';
+               b_rdy_i <= '1';
+               wait for 1 ns;
+               assert a_stb_o = '1' report "a_stb_o";
+               assert b_stb_o = '1' report "b_stb_o";
+               assert rdy_o   = '1' report "rdy_o";
+               assert en_o    = '1' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '1' report "a_stb_o'";
+               assert b_stb_o = '1' report "b_stb_o'";
+
+               test    <= T_0F;
+               stb_i   <= '0';
+               a_rdy_i <= '1';
+               b_rdy_i <= '1';
+               wait for 1 ns;
+               assert a_stb_o = '1' report "a_stb_o";
+               assert b_stb_o = '1' report "b_stb_o";
+               assert rdy_o   = '1' report "rdy_o";
+               assert en_o    = '0' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '0' report "a_stb_o'";
+               assert b_stb_o = '0' report "b_stb_o'";
+
+               test    <= T_14;
+               stb_i   <= '1';
+               a_rdy_i <= '0';
+               b_rdy_i <= '1';
+               wait for 1 ns;
+               assert a_stb_o = '0' report "a_stb_o";
+               assert b_stb_o = '0' report "b_stb_o";
+               assert rdy_o   = '1' report "rdy_o";
+               assert en_o    = '1' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '1' report "a_stb_o'";
+               assert b_stb_o = '1' report "b_stb_o'";
+
+               test    <= T_0B;
+               stb_i   <= '0';
+               a_rdy_i <= '1';
+               b_rdy_i <= '0';
+               wait for 1 ns;
+               assert a_stb_o = '1' report "a_stb_o";
+               assert b_stb_o = '1' report "b_stb_o";
+               assert rdy_o   = '0' report "rdy_o";
+               assert en_o    = '0' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '0' report "a_stb_o'";
+               assert b_stb_o = '1' report "b_stb_o'";
+
+               test    <= T_01;
+               stb_i   <= '0';
+               a_rdy_i <= '0';
+               b_rdy_i <= '0';
+               wait for 1 ns;
+               assert a_stb_o = '0' report "a_stb_o";
+               assert b_stb_o = '1' report "b_stb_o";
+               assert rdy_o   = '0' report "rdy_o";
+               assert en_o    = '0' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '0' report "a_stb_o'";
+               assert b_stb_o = '1' report "b_stb_o'";
+
+               test    <= T_09;
+               stb_i   <= '0';
+               a_rdy_i <= '1';
+               b_rdy_i <= '0';
+               wait for 1 ns;
+               assert a_stb_o = '0' report "a_stb_o";
+               assert b_stb_o = '1' report "b_stb_o";
+               assert rdy_o   = '0' report "rdy_o";
+               assert en_o    = '0' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '0' report "a_stb_o'";
+               assert b_stb_o = '1' report "b_stb_o'";
+
+               test    <= T_11;
+               stb_i   <= '1';
+               a_rdy_i <= '0';
+               b_rdy_i <= '0';
+               wait for 1 ns;
+               assert a_stb_o = '0' report "a_stb_o";
+               assert b_stb_o = '1' report "b_stb_o";
+               assert rdy_o   = '0' report "rdy_o";
+               assert en_o    = '0' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '0' report "a_stb_o'";
+               assert b_stb_o = '1' report "b_stb_o'";
+
+               test    <= T_19;
+               stb_i   <= '1';
+               a_rdy_i <= '1';
+               b_rdy_i <= '0';
+               wait for 1 ns;
+               assert a_stb_o = '0' report "a_stb_o";
+               assert b_stb_o = '1' report "b_stb_o";
+               assert rdy_o   = '0' report "rdy_o";
+               assert en_o    = '0' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '0' report "a_stb_o'";
+               assert b_stb_o = '1' report "b_stb_o'";
+
+               test    <= T_15;
+               stb_i   <= '1';
+               a_rdy_i <= '0';
+               b_rdy_i <= '1';
+               wait for 1 ns;
+               assert a_stb_o = '0' report "a_stb_o";
+               assert b_stb_o = '1' report "b_stb_o";
+               assert rdy_o   = '1' report "rdy_o";
+               assert en_o    = '1' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '1' report "a_stb_o'";
+               assert b_stb_o = '1' report "b_stb_o'";
+
+               test    <= T_1B;
+               stb_i   <= '1';
+               a_rdy_i <= '1';
+               b_rdy_i <= '0';
+               wait for 1 ns;
+               assert a_stb_o = '1' report "a_stb_o";
+               assert b_stb_o = '1' report "b_stb_o";
+               assert rdy_o   = '0' report "rdy_o";
+               assert en_o    = '0' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '0' report "a_stb_o'";
+               assert b_stb_o = '1' report "b_stb_o'";
+
+               test    <= T_1D;
+               stb_i   <= '1';
+               a_rdy_i <= '1';
+               b_rdy_i <= '1';
+               wait for 1 ns;
+               assert a_stb_o = '0' report "a_stb_o";
+               assert b_stb_o = '1' report "b_stb_o";
+               assert rdy_o   = '1' report "rdy_o";
+               assert en_o    = '1' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '1' report "a_stb_o'";
+               assert b_stb_o = '1' report "b_stb_o'";
+
+               test    <= T_0B;
+               stb_i   <= '0';
+               a_rdy_i <= '1';
+               b_rdy_i <= '0';
+               wait for 1 ns;
+               assert a_stb_o = '1' report "a_stb_o";
+               assert b_stb_o = '1' report "b_stb_o";
+               assert rdy_o   = '0' report "rdy_o";
+               assert en_o    = '0' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '0' report "a_stb_o'";
+               assert b_stb_o = '1' report "b_stb_o'";
+
+               test    <= T_05;
+               stb_i   <= '0';
+               a_rdy_i <= '0';
+               b_rdy_i <= '1';
+               wait for 1 ns;
+               assert a_stb_o = '0' report "a_stb_o";
+               assert b_stb_o = '1' report "b_stb_o";
+               assert rdy_o   = '1' report "rdy_o";
+               assert en_o    = '0' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '0' report "a_stb_o'";
+               assert b_stb_o = '0' report "b_stb_o'";
+
+               test    <= T_1C;
+               stb_i   <= '1';
+               a_rdy_i <= '1';
+               b_rdy_i <= '1';
+               wait for 1 ns;
+               assert a_stb_o = '0' report "a_stb_o";
+               assert b_stb_o = '0' report "b_stb_o";
+               assert rdy_o   = '1' report "rdy_o";
+               assert en_o    = '1' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '1' report "a_stb_o'";
+               assert b_stb_o = '1' report "b_stb_o'";
+
+               test    <= T_0B;
+               stb_i   <= '0';
+               a_rdy_i <= '1';
+               b_rdy_i <= '0';
+               wait for 1 ns;
+               assert a_stb_o = '1' report "a_stb_o";
+               assert b_stb_o = '1' report "b_stb_o";
+               assert rdy_o   = '0' report "rdy_o";
+               assert en_o    = '0' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '0' report "a_stb_o'";
+               assert b_stb_o = '1' report "b_stb_o'";
+
+               test    <= T_0D;
+               stb_i   <= '0';
+               a_rdy_i <= '1';
+               b_rdy_i <= '1';
+               wait for 1 ns;
+               assert a_stb_o = '0' report "a_stb_o";
+               assert b_stb_o = '1' report "b_stb_o";
+               assert rdy_o   = '1' report "rdy_o";
+               assert en_o    = '0' report "en_o";
+               wait until falling_edge(clk_i);
+               assert a_stb_o = '0' report "a_stb_o'";
+               assert b_stb_o = '0' report "b_stb_o'";
+
+               -- Done
+               test <= T_DONE;
+               wait;
+       end process;
+
+       e_uut: entity work.ctrl_split
+               port map (
+                       rst_i   => rst_i,
+                       clk_i   => clk_i,
+
+                       stb_i   => stb_i,
+                       rdy_o   => rdy_o,
+
+                       a_stb_o => a_stb_o,
+                       a_rdy_i => a_rdy_i,
+
+                       b_stb_o => b_stb_o,
+                       b_rdy_i => b_rdy_i,
+
+                       en_o    => en_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;
diff --git a/libraries/pipe/tests/test_splitmux.vhd b/libraries/pipe/tests/test_splitmux.vhd
new file mode 100644 (file)
index 0000000..05973bb
--- /dev/null
@@ -0,0 +1,151 @@
+library ieee;
+use ieee.std_logic_1164.all;
+
+library work;
+
+
+entity test_splitmux is
+end test_splitmux;
+
+
+architecture behavior of test_splitmux is
+
+       constant CLK_I_PERIOD: time := 20 ns;
+
+       signal rst_i:       std_logic;
+       signal clk_i:       std_logic;
+
+       signal in_stb_i:    std_logic;
+       signal in_rdy_o:    std_logic;
+       signal in_dat_i:    std_logic_vector(7 downto 0);
+
+       signal split_a_stb: std_logic;
+       signal split_a_rdy: std_logic;
+       signal split_b_stb: std_logic;
+       signal split_b_rdy: std_logic;
+       signal split_dat:   std_logic_vector(7 downto 0);
+
+       signal path_a_stb:  std_logic;
+       signal path_a_rdy:  std_logic;
+       signal path_a_dat:  std_logic_vector(7 downto 0);
+
+       signal path_b_stb:  std_logic;
+       signal path_b_rdy:  std_logic;
+       signal path_b_dat:  std_logic_vector(7 downto 0);
+
+       signal sel:         std_logic;
+       signal out_stb_o:   std_logic;
+       signal out_rdy_i:   std_logic;
+       signal out_dat_o:   std_logic_vector(7 downto 0);
+
+begin
+
+       p_test: process
+       begin
+               -- Initial values
+               in_stb_i  <= '0';
+               out_rdy_i <= '0';
+               sel       <= '0';
+               in_dat_i  <= x"a5";
+
+               -- Reset
+               rst_i <= '1';
+               wait for CLK_I_PERIOD*2;
+               rst_i <= '0';
+               wait until falling_edge(clk_i);
+
+               -- Test
+               wait for CLK_I_PERIOD*3;
+               in_stb_i <= '1';
+               wait for CLK_I_PERIOD;
+               in_stb_i <= '0';
+
+               wait for CLK_I_PERIOD*3;
+               out_rdy_i <= '1';
+
+               -- Done
+               wait;
+       end process;
+
+
+       e_split: entity work.stage_split
+               generic map (WIDTH => 8)
+               port map (
+                       rst_i   => rst_i,
+                       clk_i   => clk_i,
+
+                       stb_i   => in_stb_i,
+                       rdy_o   => in_rdy_o,
+                       dat_i   => in_dat_i,
+
+                       a_stb_o => split_a_stb,
+                       a_rdy_i => split_a_rdy,
+
+                       b_stb_o => split_b_stb,
+                       b_rdy_i => split_b_rdy,
+
+                       dat_o   => split_dat
+               );
+
+
+       e_path_a: entity work.stage_reg
+               generic map (WIDTH => 8)
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+
+                       stb_i => split_a_stb,
+                       rdy_o => split_a_rdy,
+                       dat_i => split_dat,
+
+                       stb_o => path_a_stb,
+                       rdy_i => path_a_rdy,
+                       dat_o => path_a_dat
+               );
+       e_path_b: entity work.stage_reg
+               generic map (WIDTH => 8)
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+
+                       stb_i => split_b_stb,
+                       rdy_o => split_b_rdy,
+                       dat_i => split_dat,
+
+                       stb_o => path_b_stb,
+                       rdy_i => path_b_rdy,
+                       dat_o => path_b_dat
+               );
+
+
+       e_mux: entity work.stage_mux2
+               generic map (WIDTH => 8)
+               port map (
+                       rst_i   => rst_i,
+                       clk_i   => clk_i,
+
+                       sel     => sel,
+
+                       stb_0_i => path_a_stb,
+                       rdy_0_o => path_a_rdy,
+                       dat_0_i => path_a_dat,
+
+                       stb_1_i => path_b_stb,
+                       rdy_1_o => path_b_rdy,
+                       dat_1_i => path_b_dat,
+
+                       stb_o   => out_stb_o,
+                       rdy_i   => out_rdy_i,
+                       dat_o   => out_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;
diff --git a/libraries/utility/sync_fifo_1k_16.vhd b/libraries/utility/sync_fifo_1k_16.vhd
new file mode 100644 (file)
index 0000000..086f01c
--- /dev/null
@@ -0,0 +1,181 @@
+--------------------------------------------------------------------------------
+-- sync_fifo_1k_16 - cross clock domain FIFO, 1024x16-bit
+--
+-- Generics:
+-- SYNC_STAGES - number of shift register stages to use when synchronizing
+--
+-- Ports:
+-- head_rst_i  - synchronous reset in head clock domain
+-- head_clk_i  - clock domain for data insertion
+-- head_stb_i  - high to trigger insertion of a byte
+-- head_rdy_o  - high when head can accept bytes
+-- head_dat_i  - byte to insert into the head
+-- tail_rst_i  - synchronous reset in tail clock domain
+-- tail_clk_i  - clock domain for data removal
+-- tail_stb_o  - high when a byte is available for removal
+-- tail_ack_i  - high to trigger acknowledgement of current tail byte
+-- tail_dat_o  - current tail byte when tail_stb_o is asserted
+--
+-- The head and tail reset are only separate to prevent duplication of reset
+-- synchronization logic.  Both ends should always be reset together, although
+-- it is acceptable for one end to come out of reset before the other due to
+-- differences in clock rates.
+--------------------------------------------------------------------------------
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+library utility;
+
+
+entity sync_fifo_1k_16 is
+       generic (SYNC_STAGES: positive := 2);
+       port (
+               head_rst_i: in  std_logic;
+               head_clk_i: in  std_logic;
+               head_stb_i: in  std_logic;
+               head_rdy_o: out std_logic;
+               head_dat_i: in  std_logic_vector(15 downto 0);
+
+               tail_rst_i: in  std_logic;
+               tail_clk_i: in  std_logic;
+               tail_stb_o: out std_logic;
+               tail_ack_i: in  std_logic;
+               tail_dat_o: out std_logic_vector(15 downto 0)
+       );
+end sync_fifo_1k_16;
+
+
+architecture behavioral of sync_fifo_1k_16 is
+
+       signal head_rst_wait: std_logic;
+       signal tail_adr_sync: std_logic_vector(9 downto 0);
+       signal head_adr_reg:  std_logic_vector(9 downto 0) := (others => '0');
+       signal head_adr_next: std_logic_vector(9 downto 0);
+       signal head_rdy:      std_logic;
+       signal head_step:     std_logic;
+       signal is_full:       std_logic;
+
+       signal tail_rst_wait: std_logic;
+       signal head_adr_sync: std_logic_vector(9 downto 0);
+       signal tail_adr_reg:  std_logic_vector(9 downto 0) := (others => '0');
+       signal tail_adr_inc:  std_logic_vector(9 downto 0);
+       signal tail_adr_next: std_logic_vector(9 downto 0);
+       signal tail_stb:      std_logic;
+       signal tail_step:     std_logic;
+       signal is_empty:      std_logic;
+
+begin
+
+       -- Head logic
+
+       e_sync_tail_rst: entity utility.sync_sig
+               generic map (SYNC_STAGES => SYNC_STAGES)
+               port map (
+                       clk_i => head_clk_i,
+                       sig_i => tail_rst_i,
+                       sig_o => head_rst_wait
+               );
+
+       e_sync_tail: entity utility.sync_vec
+               generic map (SYNC_STAGES => SYNC_STAGES)
+               port map (
+                       clk_i => head_clk_i,
+                       sig_i => std_logic_vector(tail_adr_reg),
+                       sig_o => tail_adr_sync
+               );
+
+       is_full <= '1' when std_logic_vector(head_adr_next) = tail_adr_sync or
+                           head_rst_i = '1' or head_rst_wait = '1'
+                      else '0';
+
+       head_rdy <= not is_full;
+       head_rdy_o <= head_rdy;
+
+       head_step <= head_stb_i and head_rdy;
+
+       e_head_adr: entity utility.gray_counter
+               generic map (N => 10)
+               port map (
+                       rst_i => head_rst_i,
+                       clk_i => head_clk_i,
+                       ena_i => head_step,
+                       gray  => head_adr_reg,
+                       inc   => head_adr_next
+               );
+
+
+       -- Tail logic
+
+       e_sync_head_rst: entity utility.sync_sig
+               generic map (SYNC_STAGES => SYNC_STAGES)
+               port map (
+                       clk_i => tail_clk_i,
+                       sig_i => head_rst_i,
+                       sig_o => tail_rst_wait
+               );
+
+       e_sync_head: entity utility.sync_vec
+               generic map (SYNC_STAGES => SYNC_STAGES)
+               port map (
+                       clk_i => tail_clk_i,
+                       sig_i => std_logic_vector(head_adr_reg),
+                       sig_o => head_adr_sync
+               );
+
+       is_empty <= '1' when std_logic_vector(tail_adr_reg) = head_adr_sync or
+                            tail_rst_i = '1' or tail_rst_wait = '1'
+                       else '0';
+
+       tail_stb <= not is_empty;
+       tail_stb_o <= tail_stb;
+
+       tail_step <= tail_stb and tail_ack_i;
+       tail_adr_next <= tail_adr_inc when tail_step = '1' else tail_adr_reg;
+
+       e_tail_adr: entity utility.gray_counter
+               generic map (N => 10)
+               port map (
+                       rst_i => tail_rst_i,
+                       clk_i => tail_clk_i,
+                       ena_i => tail_step,
+                       gray  => tail_adr_reg,
+                       inc   => tail_adr_inc
+               );
+
+
+       -- FIFO memory
+
+       e_fifo: ramb16_s18_s18
+               generic map (
+                       SIM_COLLISION_CHECK => "GENERATE_X_ONLY"
+               )
+               port map (
+                       -- Port A is the FIFO head
+                       wea   => head_step,
+                       ena   => '1',
+                       ssra  => '0',
+                       clka  => head_clk_i,
+                       addra => std_logic_vector(head_adr_reg),
+                       dia   => head_dat_i,
+                       dipa  => "00",
+                       doa   => open,
+                       dopa  => open,
+
+                       -- Port B is the FIFO tail
+                       web   => '0',
+                       enb   => '1',
+                       ssrb  => '0',
+                       clkb  => tail_clk_i,
+                       addrb => std_logic_vector(tail_adr_next),
+                       dib   => x"0000",
+                       dipb  => "00",
+                       dob   => tail_dat_o,
+                       dopb  => open
+               );
+
+end behavioral;
index ae761f075e246bd75450287ccc719d3ae3d67a75..f43130a0c9e6ad9ddefb5f2287e891f5351593a0 100644 (file)
@@ -50,7 +50,7 @@ architecture behavioral of sync_sig is
 
 begin
 
-       process (clk_i, sig_i, shift_reg)
+       process (rst_i, clk_i, sig_i, shift_reg)
        begin
                if rst_i = '1' then
                        shift_reg <= (others => INIT);
diff --git a/projects/mp3tape/ifft_control.vhd b/projects/mp3tape/ifft_control.vhd
new file mode 100644 (file)
index 0000000..0cd2d35
--- /dev/null
@@ -0,0 +1,172 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+library work;
+
+
+entity ifft_control is
+       port (
+               rst_i:      in  std_logic;
+               clk_i:      in  std_logic;
+
+               -- Loading
+               stb_i:      in  std_logic;
+               rdy_o:      out std_logic;
+               fin_i:      in  std_logic;
+
+               -- Unloading
+               stb_o:      out std_logic;
+               rdy_i:      in  std_logic;
+
+               -- Datapath control connections
+               load:       out std_logic;
+               unload:     out std_logic;
+               adr_unload: out std_logic_vector(9 downto 0);
+
+               count_en:   out std_logic;
+               count_done: in  std_logic;
+
+               use_j:      out std_logic;
+               s_en:       out std_logic;
+               s_wr:       out std_logic;
+               w_read:     out std_logic;
+
+               mult_en:    out std_logic
+       );
+end ifft_control;
+
+
+architecture behavioral of ifft_control is
+
+       type state_t is (
+               S_LOAD,
+               S_FETCH_W_J,
+               S_FETCH_I_MUL,
+               S_STORE_I,
+               S_STORE_J,
+               S_PRE_UNLOAD,
+               S_UNLOAD
+       );
+
+       signal state_reg:   state_t;
+       signal state_next:  state_t;
+
+       signal unload_reg:  unsigned( 9 downto 0);
+       signal unload_next: unsigned(10 downto 0);
+       signal unload_en:   std_logic;
+       signal unload_done: std_logic;
+
+begin
+
+       process (rst_i, clk_i, state_next)
+       begin
+               if rising_edge(clk_i) then
+                       if rst_i = '1' then
+                               state_reg  <= S_LOAD;
+                       else
+                               state_reg  <= state_next;
+                       end if;
+               end if;
+       end process;
+
+       process (rst_i, clk_i, unload_en, unload_next)
+       begin
+               if rising_edge(clk_i) then
+                       if rst_i = '1' then
+                               unload_reg <= (others => '0');
+                       elsif unload_en = '1' then
+                               unload_reg <= unload_next(9 downto 0);
+                       end if;
+               end if;
+       end process;
+       unload_next <= ('0' & unload_reg) + 1;
+       unload_done <= unload_next(unload_next'high);
+       adr_unload  <= std_logic_vector(unload_reg);
+
+       process (state_reg, count_done, stb_i, rdy_i, fin_i, unload_done, count_done)
+       begin
+               state_next <= state_reg;
+               load       <= '0';
+               unload     <= '0';
+               count_en   <= '0';
+               use_j      <= '0';
+               s_en       <= '0';
+               s_wr       <= '0';
+               w_read     <= '0';
+               mult_en    <= '0';
+
+               unload_en  <= '0';
+
+               rdy_o      <= '0';
+               stb_o      <= '0';
+
+               case state_reg is
+                       when S_LOAD =>
+                               if stb_i = '1' and fin_i = '1' then
+                                       state_next <= S_FETCH_W_J;
+                               end if;
+
+                               load  <= stb_i;
+                               rdy_o <= '1';
+
+                       when S_PRE_UNLOAD =>
+                               state_next <= S_UNLOAD;
+
+                               unload    <= '1';  -- Signal to datapath
+                               unload_en <= '1';  -- Unload address counter
+
+                       when S_UNLOAD =>
+                               if rdy_i = '1' then
+                                       if unload_done = '1' then
+                                               state_next <= S_LOAD;
+                                       end if;
+
+                                       -- Sample data is cleared while unloading, so we can't hold unload active
+                                       -- or else we'll load our own zero out if the downstream isn't ready
+                                       unload    <= '1';
+                                       unload_en <= '1';
+                               end if;
+
+                               stb_o <= '1';
+
+                       when S_FETCH_W_J =>
+                               state_next <= S_FETCH_I_MUL;
+
+                               use_j  <= '1';
+                               s_en   <= '1';
+                               w_read <= '1';
+
+                       when S_FETCH_I_MUL =>
+                               state_next <= S_STORE_I;
+
+                               mult_en <= '1';
+                               s_en    <= '1';
+
+                       when S_STORE_I =>
+                               state_next <= S_STORE_J;
+
+                               s_en <= '1';
+                               s_wr <= '1';
+
+                       when S_STORE_J =>
+                               if count_done = '1' then
+                                       state_next <= S_PRE_UNLOAD;
+                               else
+                                       state_next <= S_FETCH_W_J;
+                               end if;
+
+                               use_j    <= '1';
+                               s_en     <= '1';
+                               s_wr     <= '1';
+                               count_en <= '1';
+
+                       when others =>
+                               state_next <= S_LOAD;
+               end case;
+       end process;
+
+end behavioral;
diff --git a/projects/mp3tape/ifft_counter.vhd b/projects/mp3tape/ifft_counter.vhd
new file mode 100644 (file)
index 0000000..86d20fc
--- /dev/null
@@ -0,0 +1,94 @@
+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 ifft_counter is
+       generic (
+               IDX_WIDTH: positive := 10
+       );
+       port (
+               rst_i:  in  std_logic;
+               clk_i:  in  std_logic;
+
+               en_i:   in  std_logic;
+               done_o: out std_logic;
+
+               i_idx:  out std_logic_vector(IDX_WIDTH-1 downto 0);
+               j_idx:  out std_logic_vector(IDX_WIDTH-1 downto 0);
+               w_idx:  out std_logic_vector(IDX_WIDTH-2 downto 0)
+       );
+end ifft_counter;
+
+
+architecture behavioral of ifft_counter is
+
+       -- Indicates stage number
+       signal group_size_reg:  unsigned(IDX_WIDTH-1 downto 0);
+       signal group_size_next: unsigned(IDX_WIDTH-1 downto 0);
+
+       -- Indicates which group within the stage
+       signal group_base_reg:  unsigned(IDX_WIDTH-1 downto 0);
+       signal group_base_next: unsigned(IDX_WIDTH   downto 0);
+       signal inc_stage:       std_logic;
+
+       -- Indicates which sample within the group
+       signal n_reg:           unsigned(IDX_WIDTH-2 downto 0);
+       signal n_next:          unsigned(IDX_WIDTH-1 downto 0);
+       signal inc_group:       std_logic;
+
+       -- Twiddle factor index
+       signal w_reg:           unsigned(IDX_WIDTH-2 downto 0);
+       signal w_inc:           unsigned(IDX_WIDTH-1 downto 0);
+
+begin
+
+       n_next <= ('0' & n_reg) + 1;
+       inc_group <= or_reduce(std_logic_vector(n_next) and std_logic_vector(group_size_reg));
+
+       group_base_next <= ('0' & group_base_reg) + (group_size_reg & '0');
+       inc_stage <= group_base_next(IDX_WIDTH);
+
+       group_size_next <= group_size_reg(IDX_WIDTH-2 downto 0) & group_size_reg(IDX_WIDTH-1);
+
+       done_o <= group_size_next(0) and inc_stage and inc_group;
+
+       g_w_inc: for i in IDX_WIDTH-1 downto 0 generate
+               w_inc(i) <= group_size_reg(IDX_WIDTH-1 - i);
+       end generate;
+
+       process (rst_i, clk_i, en_i, inc_group, inc_stage, group_base_next, n_next, group_size_next, w_reg, w_inc)
+       begin
+               if rising_edge(clk_i) then
+                       if rst_i = '1' then
+                               group_base_reg <= (others => '0');
+                               group_size_reg(IDX_WIDTH-1 downto 1) <= (others => '0');
+                               group_size_reg(0) <= '1';
+                               n_reg <= (others => '0');
+                               w_reg <= (others => '0');
+                       elsif en_i = '1' then
+                               if inc_group = '1' then
+                                       -- Will naturally overflow to 0 when done, no need for reset logic
+                                       group_base_reg <= group_base_next(IDX_WIDTH-1 downto 0);
+                                       n_reg <= (others => '0');
+
+                                       if inc_stage = '1' then
+                                               group_size_reg <= group_size_next;
+                                       end if;
+                               else
+                                       n_reg <= n_next(IDX_WIDTH-2 downto 0);
+                               end if;
+                               w_reg <= w_reg + w_inc(IDX_WIDTH-2 downto 0);
+                       end if;
+               end if;
+       end process;
+
+       i_idx <= std_logic_vector(group_base_reg + n_reg);
+       j_idx <= std_logic_vector(group_base_reg + n_reg + group_size_reg);
+       w_idx <= std_logic_vector(w_reg);
+
+end behavioral;
diff --git a/projects/mp3tape/ifft_datapath.vhd b/projects/mp3tape/ifft_datapath.vhd
new file mode 100644 (file)
index 0000000..c8d814d
--- /dev/null
@@ -0,0 +1,297 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+
+entity ifft_datapath is
+       port (
+               rst_i:      in  std_logic;
+               clk_i:      in  std_logic;
+
+               -- Control signals for loading and unloading
+               load:       in  std_logic;
+               adr_load:   in  std_logic_vector( 9 downto 0);
+               dat_load:   in  std_logic_vector(15 downto 0);
+
+               unload:     in  std_logic;
+               adr_unload: in  std_logic_vector( 9 downto 0);
+               dat_unload: out std_logic_vector(15 downto 0);
+
+               -- Control signals for managing scratch state
+               use_j:      in  std_logic;  -- Use the J sample index instead of I
+               s_en:       in  std_logic;  -- Load sample from scratch, also write if s_wr asserted
+               s_wr:       in  std_logic;  -- Write sample value to scratch memory
+               w_read:     in  std_logic;  -- Load twiddle factor
+               i_idx:      in  std_logic_vector(9 downto 0);  -- Even-group sample index
+               j_idx:      in  std_logic_vector(9 downto 0);  -- Odd-group sample index
+               w_idx:      in  std_logic_vector(8 downto 0);  -- Twiddle factor index
+
+               -- Control signals for computation
+               mult_en:    in  std_logic
+       );
+end ifft_datapath;
+
+
+architecture behavioral of ifft_datapath is
+
+       -- Currently looked-up sample, could be I or J
+       signal s_addr:     std_logic_vector( 9 downto 0);
+       signal s_real:     std_logic_vector(15 downto 0);
+       signal s_imag:     std_logic_vector(15 downto 0);
+       signal s_real_x:   std_logic_vector(17 downto 0);
+       signal s_imag_x:   std_logic_vector(17 downto 0);
+       signal s_real_new: std_logic_vector(15 downto 0);
+       signal s_imag_new: std_logic_vector(15 downto 0);
+
+       -- Omega root-of-unity twiddle factor
+       signal w_comp:     std_logic_vector(31 downto 0);
+       signal w_real:     std_logic_vector(15 downto 0);
+       signal w_imag:     std_logic_vector(15 downto 0);
+       signal w_real_x:   std_logic_vector(17 downto 0);
+       signal w_imag_x:   std_logic_vector(17 downto 0);
+
+       -- Complex multiplication partial products and result
+       signal pp_wr_sr:   std_logic_vector(35 downto 0);
+       signal pp_wi_si:   std_logic_vector(35 downto 0);
+       signal pp_wr_si:   std_logic_vector(35 downto 0);
+       signal pp_wi_sr:   std_logic_vector(35 downto 0);
+       signal wj_real:    signed(15 downto 0);
+       signal wj_imag:    signed(15 downto 0);
+
+       -- Updated I and J samples
+       signal i_real_new: std_logic_vector(16 downto 0);
+       signal i_imag_new: std_logic_vector(16 downto 0);
+       signal j_real_new: std_logic_vector(16 downto 0);
+       signal j_imag_new: std_logic_vector(16 downto 0);
+
+       -- Sideloading samples into and out of scratch space
+       signal side_en:    std_logic;
+       signal side_addr:  std_logic_vector( 9 downto 0);
+       signal addr_rev:   std_logic_vector( 9 downto 0);
+       signal side_samp:  std_logic_vector(15 downto 0);
+
+begin
+
+       -- Add and subtract I and wJ samples to create new samples
+       i_real_new <= std_logic_vector(signed(s_real(15) & s_real) + wj_real);
+       i_imag_new <= std_logic_vector(signed(s_imag(15) & s_imag) + wj_imag);
+       j_real_new <= std_logic_vector(signed(s_real(15) & s_real) - wj_real);
+       j_imag_new <= std_logic_vector(signed(s_imag(15) & s_imag) - wj_imag);
+
+
+       -- Complex multiplication of sample with twiddle factor
+       -- Samples are integers, twiddle factors are purely fractional (0.16 fixed-point)
+       s_real_x <= s_real & "00";
+       s_imag_x <= s_imag & "00";
+       w_real_x <= w_real & "00";
+       w_imag_x <= w_imag & "00";
+       e_mul_w_real_s_real: mult18x18s
+               port map (
+                       A  => w_real_x,
+                       B  => s_real_x,
+                       C  => clk_i,
+                       CE => mult_en,
+                       R  => '0',
+                       P  => pp_wr_sr
+               );
+       e_mul_w_imag_s_imag: mult18x18s
+               port map (
+                       A  => w_imag_x,
+                       B  => s_imag_x,
+                       C  => clk_i,
+                       CE => mult_en,
+                       R  => '0',
+                       P  => pp_wi_si
+               );
+       e_mul_w_real_s_imag: mult18x18s
+               port map (
+                       A  => w_real_x,
+                       B  => s_imag_x,
+                       C  => clk_i,
+                       CE => mult_en,
+                       R  => '0',
+                       P  => pp_wr_si
+               );
+       e_mul_w_imag_s_real: mult18x18s
+               port map (
+                       A  => w_imag_x,
+                       B  => s_real_x,
+                       C  => clk_i,
+                       CE => mult_en,
+                       R  => '0',
+                       P  => pp_wi_sr
+               );
+       -- Lose some precision to save logic, but no big deal (I hope)
+       wj_real <= signed(pp_wr_sr(35 downto 20)) - signed(pp_wi_si(35 downto 20));
+       wj_imag <= signed(pp_wr_si(35 downto 20)) + signed(pp_wi_sr(35 downto 20));
+
+
+       -- Select sample I or J in scratch space
+       s_addr     <= j_idx                   when use_j = '1' else i_idx;
+       --s_real_new <= j_real_new(16 downto 1) when use_j = '1' else i_real_new(16 downto 1);
+       --s_imag_new <= j_imag_new(16 downto 1) when use_j = '1' else i_imag_new(16 downto 1);
+       s_real_new <= j_real_new(15 downto 0) when use_j = '1' else i_real_new(15 downto 0);
+       s_imag_new <= j_imag_new(15 downto 0) when use_j = '1' else i_imag_new(15 downto 0);
+
+
+       -- Select data to sideload into port B
+       -- When loading samples, address bits get reversed to perform even/odd reordering
+       g_reverse_addr: for i in 0 to 9 generate
+               addr_rev(i) <= adr_load(9-i);
+       end generate;
+       side_en   <= load or unload;
+       side_samp <= dat_load when load = '1' else (others => '0');
+       side_addr <= addr_rev when load = '1' else adr_unload;
+
+
+       -- Scratch buffer within which to perform iFFT, separate real and imaginary components
+       e_scratch_real: ramb16_s18_s18
+               generic map (
+                       -- When writing, don't change the previously read value (allows writing xj without clobbering previous xi read)
+                       WRITE_MODE_A => "NO_CHANGE",
+
+                       -- When reading and writing, read the old value (allows resetting to zero while unloading transformed values)
+                       WRITE_MODE_B => "READ_FIRST"
+               )
+               port map (
+                       -- Internal port for algorithm sample access
+                       WEA   => s_wr,
+                       ENA   => s_en,
+                       SSRA  => '0',
+                       CLKA  => clk_i,
+                       ADDRA => s_addr,
+                       DIA   => s_real_new,
+                       DIPA  => (others => '0'),
+                       DOPA  => open,
+                       DOA   => s_real,
+
+                       -- Secondary port for loading, unloading, and clearing samples
+                       WEB   => side_en,  -- Always writing when sideloading, either loading samples or clearing while unloading
+                       ENB   => side_en,
+                       SSRB  => '0',
+                       CLKB  => clk_i,
+                       ADDRB => side_addr,
+                       DIB   => side_samp,
+                       DIPB  => (others => '0'),
+                       DOPB  => open,
+                       DOB   => dat_unload
+               );
+       e_scratch_imag: ramb16_s18_s18
+               generic map (
+                       -- When writing, don't change the previously read value (allows writing xj without clobbering previous xi read)
+                       WRITE_MODE_A => "NO_CHANGE",
+
+                       -- When reading and writing, read the old value (allows resetting to zero while unloading transformed values)
+                       WRITE_MODE_B => "READ_FIRST"
+               )
+               port map (
+                       -- Internal port for algorithm sample access
+                       WEA   => s_wr,
+                       ENA   => s_en,
+                       SSRA  => '0',
+                       CLKA  => clk_i,
+                       ADDRA => s_addr,
+                       DIA   => s_imag_new,
+                       DIPA  => (others => '0'),
+                       DOPA  => open,
+                       DOA   => s_imag,
+
+                       -- Secondary port for loading, unloading, and clearing samples
+                       WEB   => side_en,  -- Always writing when sideloading, either loading samples or clearing while unloading
+                       ENB   => side_en,
+                       SSRB  => '0',
+                       CLKB  => clk_i,
+                       ADDRB => side_addr,
+                       DIB   => (others => '0'),  -- Compressed audio is real-valued (cosines) only
+                       DIPB  => (others => '0'),
+                       DOPB  => open,
+                       DOB   => open
+               );
+
+
+       -- Twiddle factor lookup table
+       e_twiddle_lut: ramb16_s36
+               generic map (
+                       INIT_00 => x"7fe0057e7fe804b67fef03ed7ff503247ff9025b7ffc01927ffe00c97fff0000",
+                       INIT_01 => x"7f740bc37f860afb7f960a327fa6096a7fb408a17fc107d97fcd07107fd70647",
+                       INIT_02 => x"7eb912007ed411397eef10727f080fab7f200ee37f370e1b7f4c0d537f610c8b",
+                       INIT_03 => x"7db018337dd5176d7df916a77e1c15e17e3e151b7e5e14557e7e138e7e9c12c7",
+                       INIT_04 => x"7c591e567c881d937cb61ccf7ce21c0b7d0e1b467d381a827d6119bd7d8918f8",
+                       INIT_05 => x"7ab524677aee23a67b2522e47b5c22237b9121617bc4209f7bf71fdc7c291f19",
+                       INIT_06 => x"78c62a61790829a3794928e57989282679c727677a0426a77a4125e77a7c2527",
+                       INIT_07 => x"768d304176d82f8677222ecc776b2e1077b32d5477f92c98783f2bdb78832b1e",
+                       INIT_08 => x"740a3603745e354d74b13496750333de7554332675a4326d75f331b4764030fb",
+                       INIT_09 => x"71403ba4719d3af271f93a3f7254398c72ae38d873063824735e376f73b536b9",
+                       INIT_0A => x"6e3041206e9540736efa3fc56f5e3f166fc03e6770223db770823d0770e13c56",
+                       INIT_0B => x"6adb46746b4a45cc6bb745236c23447a6c8e43d06cf843256d6142796dc941cd",
+                       INIT_0C => x"67454b9d67bc4afa68314a5768a549b36919490e698b486969fc47c36a6c471c",
+                       INIT_0D => x"6370509763ee4ffa646b4f5d64e74ebf65624e2065dd4d8066564ce066ce4c3f",
+                       INIT_0E => x"5f5d555f5fe254c96067543260eb539a616e530161f05268627151ce62f15133",
+                       INIT_0F => x"5b0f59f35b9c59635c2858d35cb358425d3d57b05dc6571d5e4f56895ed655f4",
+                       INIT_10 => x"56895e4f571d5dc657b05d3d58425cb358d35c2859635b9c59f35b0f5a815a81",
+                       INIT_11 => x"51ce6271526861f05301616e539a60eb5432606754c95fe2555f5f5d55f45ed6",
+                       INIT_12 => x"4ce066564d8065dd4e2065624ebf64e74f5d646b4ffa63ee50976370513362f1",
+                       INIT_13 => x"47c369fc4869698b490e691949b368a54a5768314afa67bc4b9d67454c3f66ce",
+                       INIT_14 => x"42796d6143256cf843d06c8e447a6c2345236bb745cc6b4a46746adb471c6a6c",
+                       INIT_15 => x"3d0770823db770223e676fc03f166f5e3fc56efa40736e9541206e3041cd6dc9",
+                       INIT_16 => x"376f735e3824730638d872ae398c72543a3f71f93af2719d3ba471403c5670e1",
+                       INIT_17 => x"31b475f3326d75a43326755433de7503349674b1354d745e3603740a36b973b5",
+                       INIT_18 => x"2bdb783f2c9877f92d5477b32e10776b2ecc77222f8676d83041768d30fb7640",
+                       INIT_19 => x"25e77a4126a77a04276779c72826798928e5794929a379082a6178c62b1e7883",
+                       INIT_1A => x"1fdc7bf7209f7bc421617b9122237b5c22e47b2523a67aee24677ab525277a7c",
+                       INIT_1B => x"19bd7d611a827d381b467d0e1c0b7ce21ccf7cb61d937c881e567c591f197c29",
+                       INIT_1C => x"138e7e7e14557e5e151b7e3e15e17e1c16a77df9176d7dd518337db018f87d89",
+                       INIT_1D => x"0d537f4c0e1b7f370ee37f200fab7f0810727eef11397ed412007eb912c77e9c",
+                       INIT_1E => x"07107fcd07d97fc108a17fb4096a7fa60a327f960afb7f860bc37f740c8b7f61",
+                       INIT_1F => x"00c97ffe01927ffc025b7ff903247ff503ed7fef04b67fe8057e7fe006477fd7",
+                       INIT_20 => x"fa827fe0fb4a7fe8fc137feffcdc7ff5fda57ff9fe6e7ffcff377ffe00007fff",
+                       INIT_21 => x"f43d7f74f5057f86f5ce7f96f6967fa6f75f7fb4f8277fc1f8f07fcdf9b97fd7",
+                       INIT_22 => x"ee007eb9eec77ed4ef8e7eeff0557f08f11d7f20f1e57f37f2ad7f4cf3757f61",
+                       INIT_23 => x"e7cd7db0e8937dd5e9597df9ea1f7e1ceae57e3eebab7e5eec727e7eed397e9c",
+                       INIT_24 => x"e1aa7c59e26d7c88e3317cb6e3f57ce2e4ba7d0ee57e7d38e6437d61e7087d89",
+                       INIT_25 => x"db997ab5dc5a7aeedd1c7b25dddd7b5cde9f7b91df617bc4e0247bf7e0e77c29",
+                       INIT_26 => x"d59f78c6d65d7908d71b7949d7da7989d89979c7d9597a04da197a41dad97a7c",
+                       INIT_27 => x"cfbf768dd07a76d8d1347722d1f0776bd2ac77b3d36877f9d425783fd4e27883",
+                       INIT_28 => x"c9fd740acab3745ecb6a74b1cc227503ccda7554cd9375a4ce4c75f3cf057640",
+                       INIT_29 => x"c45c7140c50e719dc5c171f9c6747254c72872aec7dc7306c891735ec94773b5",
+                       INIT_2A => x"bee06e30bf8d6e95c03b6efac0ea6f5ec1996fc0c2497022c2f97082c3aa70e1",
+                       INIT_2B => x"b98c6adbba346b4abadd6bb7bb866c23bc306c8ebcdb6cf8bd876d61be336dc9",
+                       INIT_2C => x"b4636745b50667bcb5a96831b64d68a5b6f26919b797698bb83d69fcb8e46a6c",
+                       INIT_2D => x"af696370b00663eeb0a3646bb14164e7b1e06562b28065ddb3206656b3c166ce",
+                       INIT_2E => x"aaa15f5dab375fe2abce6067ac6660ebacff616ead9861f0ae326271aecd62f1",
+                       INIT_2F => x"a60d5b0fa69d5b9ca72d5c28a7be5cb3a8505d3da8e35dc6a9775e4faa0c5ed6",
+                       INIT_30 => x"a1b15689a23a571da2c357b0a34d5842a3d858d3a4645963a4f159f3a57f5a81",
+                       INIT_31 => x"9d8f51ce9e1052689e9253019f15539a9f995432a01e54c9a0a3555fa12a55f4",
+                       INIT_32 => x"99aa4ce09a234d809a9e4e209b194ebf9b954f5d9c124ffa9c9050979d0f5133",
+                       INIT_33 => x"960447c39675486996e7490e975b49b397cf4a5798444afa98bb4b9d99324c3f",
+                       INIT_34 => x"929f427993084325937243d093dd447a9449452394b645cc952546749594471c",
+                       INIT_35 => x"8f7e3d078fde3db790403e6790a23f1691063fc5916b407391d04120923741cd",
+                       INIT_36 => x"8ca2376f8cfa38248d5238d88dac398c8e073a3f8e633af28ec03ba48f1f3c56",
+                       INIT_37 => x"8a0d31b48a5c326d8aac33268afd33de8b4f34968ba2354d8bf636038c4b36b9",
+                       INIT_38 => x"87c12bdb88072c98884d2d5488952e1088de2ecc89282f868973304189c030fb",
+                       INIT_39 => x"85bf25e785fc26a7863927678677282686b728e586f829a3873a2a61877d2b1e",
+                       INIT_3A => x"84091fdc843c209f846f216184a4222384db22e4851223a6854b246785842527",
+                       INIT_3B => x"829f19bd82c81a8282f21b46831e1c0b834a1ccf83781d9383a71e5683d71f19",
+                       INIT_3C => x"8182138e81a2145581c2151b81e415e1820716a7822b176d82501833827718f8",
+                       INIT_3D => x"80b40d5380c90e1b80e00ee380f80fab81111072812c113981471200816412c7",
+                       INIT_3E => x"80330710803f07d9804c08a1805a096a806a0a32807a0afb808c0bc3809f0c8b",
+                       INIT_3F => x"800200c9800401928007025b800b0324801103ed801804b68020057e80290647"
+               )
+               port map (
+                       WE   => '0',
+                       EN   => w_read,
+                       SSR  => '0',
+                       CLK  => clk_i,
+                       ADDR => w_idx,
+                       DI   => (others => '0'),
+                       DIP  => (others => '0'),
+                       DOP  => open,
+                       DO   => w_comp
+               );
+       w_real <= w_comp(31 downto 16);
+       w_imag <= w_comp(15 downto  0);
+
+end behavioral;
index 09eb77f1092ab76cdff2f3e70516c1bedb620a4c..a03f1222943bcfef60aaeeb894120a906e8a2ec8 100644 (file)
@@ -4,6 +4,8 @@ use ieee.std_logic_1164.all;
 library utility;
 library dsp;
 library nexys2_lib;
+library i2s;
+library work;
 
 
 entity nexys2 is
@@ -51,6 +53,7 @@ architecture behavioral of nexys2 is
        signal dl_stb:          std_logic;
        signal dl_rdy:          std_logic;
        signal dl_dat:          std_logic_vector(7 downto 0);
+
        signal ul_stb:          std_logic;
        signal ul_rdy:          std_logic;
        signal ul_dat:          std_logic_vector(7 downto 0);
@@ -65,34 +68,125 @@ architecture behavioral of nexys2 is
        signal debug_to_host:   std_logic_vector(63 downto 0);
        signal debug_from_host: std_logic_vector(63 downto 0);
 
+       --------------------------------------------------------
        -- Audio pipelines
-       signal audio_dl_stb:    std_logic;
-       signal audio_dl_rdy:    std_logic;
-       signal audio_dl_dat:    std_logic_vector(31 downto 0);
 
-       signal audio_ul_stb:    std_logic;
-       signal audio_ul_rdy:    std_logic;
-       signal audio_ul_dat:    std_logic_vector(31 downto 0);
+       -- Data streamed from host computer, little-endian 32-bit words
+       signal host_dl_stb:    std_logic;
+       signal host_dl_rdy:    std_logic;
+       signal host_dl_dat:    std_logic_vector(31 downto 0);
+
+       -- Compressed audio data stream
+       signal comp_stb:       std_logic;
+       signal comp_rdy:       std_logic;
+       signal comp_bin_dat:   std_logic_vector(9 downto 0);
+       signal comp_amp_dat:   std_logic_vector(15 downto 0);
+       signal comp_fin_dat:   std_logic;
+
+       -- Decompressed audio
+       signal decomp_stb:     std_logic;
+       signal decomp_rdy:     std_logic;
+       signal decomp_dat:     std_logic_vector(15 downto 0);
+
+       -- Buffered decompressed audio
+       signal uneffected_stb: std_logic;
+       signal uneffected_rdy: std_logic;
+       signal uneffected_dat: std_logic_vector(15 downto 0);
+
+       -- Samples output to DAC
+       signal dac_stb:        std_logic;
+       signal dac_rdy:        std_logic;
+       signal dac_dat:        std_logic_vector(15 downto 0);
+
+
+       --------------------------------------------------------
 
-       signal audio_i_stb:     std_logic;
-       signal audio_i_rdy:     std_logic;
-       signal audio_i_dat:     std_logic_vector(31 downto 0);
+       -- Samples input from ADC
+       signal adc_stb:        std_logic;
+       signal adc_rdy:        std_logic;
+       signal adc_dat:        std_logic_vector(31 downto 0);
 
-       signal audio_o_stb:     std_logic;
-       signal audio_o_rdy:     std_logic;
-       signal audio_o_dat:     std_logic_vector(31 downto 0);
+       -- Data streamed to host computer
+       signal host_ul_stb:    std_logic;
+       signal host_ul_rdy:    std_logic;
+       signal host_ul_dat:    std_logic_vector(31 downto 0);
+
+
+       signal debug: std_logic_vector(7 downto 0);  -- Debug only
 
 begin
 
        seg <= (others => '1');
        dp  <= '1';
        an  <= (others => '1');
-       Led <= (others => '0');
+       Led <= debug;  --(others => '0');
+
+       ----------------------------------------------------------------------------
+       -- Deserialization
+
+       e_deser: entity dsp.deserialize
+               generic map (WIDTH => 8, N => 4)
+               port map (
+                       rst_i => rst_50,
+                       clk_i => clk_50,
+
+                       stb_i => dl_stb,
+                       rdy_o => dl_rdy,
+                       dat_i => dl_dat,
+
+                       stb_o => host_dl_stb,
+                       rdy_i => host_dl_rdy,
+                       dat_o => host_dl_dat
+               );
+
+       comp_stb     <= host_dl_stb;
+       host_dl_rdy  <= comp_rdy;
+       comp_bin_dat <= host_dl_dat( 9 downto  0);
+       comp_amp_dat <= host_dl_dat(31 downto 16);
+       comp_fin_dat <= host_dl_dat(15);
+
+       ----------------------------------------------------------------------------
+       -- Decompression
+
+       e_decomp: entity work.ifft
+               port map (
+                       rst_i      => rst_50,
+                       clk_i      => clk_50,
+
+                       stb_i      => comp_stb,
+                       rdy_o      => comp_rdy,
+                       bin_dat_i  => comp_bin_dat,
+                       amp_dat_i  => comp_amp_dat,
+                       fin_dat_i  => comp_fin_dat,
+
+                       stb_o      => decomp_stb,
+                       rdy_i      => decomp_rdy,
+                       samp_dat_o => decomp_dat
+               );
+
+       ----------------------------------------------------------------------------
+       -- Drainage FIFO
+       -- Doesn't cross a clock domain, but it's here so I'm using it
+
+       e_drain: entity utility.sync_fifo_1k_16
+               port map (
+                       head_rst_i => rst_50,
+                       head_clk_i => clk_50,
+                       head_stb_i => decomp_stb,
+                       head_rdy_o => decomp_rdy,
+                       head_dat_i => decomp_dat,
+
+                       tail_rst_i => rst_50,
+                       tail_clk_i => clk_50,
+                       tail_stb_o => uneffected_stb,
+                       tail_ack_i => uneffected_rdy,
+                       tail_dat_o => uneffected_dat
+               );
 
        ----------------------------------------------------------------------------
        -- Processing pipeline
 
-       e_effect: entity dsp.pcm16_2ch_tapeeffect
+       e_effect: entity work.pcm16_1ch_tapeeffect
                port map (
                        rst_i      => rst_50,
                        clk_i      => clk_50,
@@ -102,18 +196,21 @@ begin
                        en_wow     => sw(2),
                        en_noise   => sw(3),
 
-                       stb_i      => audio_dl_stb,
-                       rdy_o      => audio_dl_rdy,
-                       dat_i      => audio_dl_dat,
+                       stb_i      => uneffected_stb,
+                       rdy_o      => uneffected_rdy,
+                       dat_i      => uneffected_dat,
+
+                       stb_o      => dac_stb,
+                       rdy_i      => dac_rdy,
+                       dat_o      => dac_dat,
 
-                       stb_o      => audio_o_stb,
-                       rdy_i      => audio_o_rdy,
-                       dat_o      => audio_o_dat
+                       debug_o    => debug
                );
 
-       audio_ul_stb <= audio_i_stb;
-       audio_ul_rdy <= audio_i_rdy;
-       audio_ul_dat <= audio_i_dat;
+       -- Input to the host from the ADC, just to have a place to put it
+       host_ul_stb <= adc_stb;
+       host_ul_dat <= adc_dat;
+       adc_rdy     <= host_ul_rdy;
 
 
        ----------------------------------------------------------------------------
@@ -179,30 +276,15 @@ begin
                        debug_o => debug_from_host
                );
 
-       e_deser: entity dsp.deserialize
-               generic map (WIDTH => 8, N => 4)
-               port map (
-                       rst_i => rst_50,
-                       clk_i => clk_50,
-
-                       stb_i => dl_stb,
-                       rdy_o => dl_rdy,
-                       dat_i => dl_dat,
-
-                       stb_o => audio_dl_stb,
-                       rdy_i => audio_dl_rdy,
-                       dat_o => audio_dl_dat
-               );
-
        e_ser: entity dsp.serialize
                generic map (WIDTH => 8, N => 4)
                port map (
                        rst_i => rst_50,
                        clk_i => clk_50,
 
-                       stb_i => audio_ul_stb,
-                       rdy_o => audio_ul_rdy,
-                       dat_i => audio_ul_dat,
+                       stb_i => host_ul_stb,
+                       rdy_o => host_ul_rdy,
+                       dat_i => host_ul_dat,
 
                        stb_o => ul_stb,
                        rdy_i => ul_rdy,
@@ -213,25 +295,27 @@ begin
        ----------------------------------------------------------------------------
        -- I2S interface
 
-       e_i2s_pmod: entity dsp.i2s_pmod
+       e_i2s_pmod: entity i2s.i2s_pmod
                port map (
                        rst_50  => rst_50,
                        clk_50  => clk_50,
 
-                       stb_i   => audio_o_stb,
-                       rdy_o   => audio_o_rdy,
+                       stb_i   => dac_stb,
+                       rdy_o   => dac_rdy,
                        l_dat_i => i2s_tx_l_dat,
                        r_dat_i => i2s_tx_r_dat,
 
-                       stb_o   => audio_i_stb,
-                       rdy_i   => audio_i_rdy,
+                       stb_o   => adc_stb,
+                       rdy_i   => adc_rdy,
                        l_dat_o => i2s_rx_l_dat,
                        r_dat_o => i2s_rx_r_dat,
 
                        pmod    => JA
                );
-       i2s_tx_r_dat <= audio_o_dat(31 downto 16) & x"00";
-       i2s_tx_l_dat <= audio_o_dat(15 downto  0) & x"00";
-       audio_i_dat <= i2s_rx_r_dat(23 downto  8) & i2s_rx_l_dat(23 downto 8);
+
+       i2s_tx_r_dat <= dac_dat & x"00";
+       i2s_tx_l_dat <= dac_dat & x"00";
+
+       adc_dat  <= i2s_rx_r_dat(23 downto 8) & i2s_rx_l_dat(23 downto 8);
 
 end behavioral;
diff --git a/projects/mp3tape/pcm16_1ch_gain.vhd b/projects/mp3tape/pcm16_1ch_gain.vhd
new file mode 100644 (file)
index 0000000..927ba72
--- /dev/null
@@ -0,0 +1,69 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+library dsp;
+library pipe;
+library work;
+
+
+entity pcm16_1ch_gain is
+       port (
+               rst_i: in  std_logic;
+               clk_i: in  std_logic;
+
+               gain:  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(15 downto 0);
+
+               stb_o: out std_logic;
+               rdy_i: in  std_logic;
+               dat_o: out std_logic_vector(15 downto 0)
+       );
+end pcm16_1ch_gain;
+
+
+architecture behavioral of pcm16_1ch_gain is
+
+       signal samp_in:  std_logic_vector(17 downto 0);
+       signal samp_out: std_logic_vector(35 downto 0);
+
+       signal out_r:    std_logic_vector(35 downto 0);
+
+       signal result:   std_logic_vector(15 downto 0);
+
+begin
+
+       -- Sign extend
+       samp_in <= dat_i(15) & dat_i(15) & dat_i;
+
+       -- Multiply
+       result <= std_logic_vector(signed(samp_in) * signed(gain));
+
+       -- Saturate
+       e_saturate: entity dsp.saturate
+               generic map (WIDTH_IN => 27, WIDTH_OUT => 16)
+               port map (dat_i => result(35 downto 9), dat_o => samp_out);
+
+       -- Interstage register and control logic
+       e_interstage: entity pipe.stage_reg
+               generic map (WIDTH => 16)
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+
+                       stb_i => stb_i,
+                       rdy_o => rdy_o,
+                       dat_i => samp_out,
+
+                       stb_o => stb_o,
+                       rdy_i => rdy_i,
+                       dat_o => dat_o
+               );
+
+end behavioral;
diff --git a/projects/mp3tape/pcm16_1ch_noise.vhd b/projects/mp3tape/pcm16_1ch_noise.vhd
new file mode 100644 (file)
index 0000000..95e0b5f
--- /dev/null
@@ -0,0 +1,51 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library pipe;
+library dsp;
+
+
+entity pcm16_1ch_noise is
+       generic (
+               SIGFIGS: positive := 10
+       );
+       port (
+               clk_i: in  std_logic;
+
+               en_i:  in  std_logic;
+
+               stb_o: out std_logic;
+               rdy_i: in  std_logic;
+               dat_o: out std_logic_vector(15 downto 0)
+       );
+end pcm16_1ch_noise;
+
+
+architecture behavioral of pcm16_1ch_noise is
+
+       constant X: std_logic_vector(15 downto 0) := x"0001";
+
+       signal noise_dat: std_logic_vector(SIGFIGS-1 downto 0);
+
+begin
+
+       g_bits: for i in SIGFIGS-1 downto 0 generate
+               e_lfsr: entity dsp.lfsr
+                       generic map (
+                               -- First part guarantees at least one bit set to prevent stuck-at-zero bits
+                               -- Second part is an attempt at pseudorandom initial state per-bit
+                               INIT => std_logic_vector(rotate_left(unsigned(X), i)) or std_logic_vector(to_unsigned(i*13, 16) xor x"a5c3")
+                       )
+                       port map (
+                               clk_i => clk_i,
+                               en_i  => rdy_i,
+                               dat_o => noise_dat(i)
+                       );
+       end generate;
+
+       stb_o <= '1';
+
+       dat_o <= std_logic_vector(resize(signed(noise_dat), 16)) when en_i = '1' else (others => '0');
+
+end behavioral;
diff --git a/projects/mp3tape/pcm16_1ch_sum.vhd b/projects/mp3tape/pcm16_1ch_sum.vhd
new file mode 100644 (file)
index 0000000..6464ac6
--- /dev/null
@@ -0,0 +1,65 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library dsp;
+library pipe;
+library work;
+
+
+entity pcm16_1ch_sum is
+       port (
+               rst_i:   in  std_logic;
+               clk_i:   in  std_logic;
+
+               a_stb_i: in  std_logic;
+               a_rdy_o: out std_logic;
+               a_dat_i: in  std_logic_vector(15 downto 0);
+
+               b_stb_i: in  std_logic;
+               b_rdy_o: out std_logic;
+               b_dat_i: in  std_logic_vector(15 downto 0);
+
+               stb_o:   out std_logic;
+               rdy_i:   in  std_logic;
+               dat_o:   out std_logic_vector(15 downto 0)
+       );
+end pcm16_1ch_sum;
+
+
+architecture behavioral of pcm16_1ch_sum is
+
+       -- Extra bit for carry
+       signal result: signed(16 downto 0);
+
+       -- Saturated results
+       signal sat:    std_logic_vector(15 downto 0);
+
+begin
+
+       result <= signed(a_dat_i(15) & a_dat_i) + signed((b_dat_i(15)) & b_dat_i);
+
+       e_sat: entity dsp.saturate
+               generic map (WIDTH_IN => 17, WIDTH_OUT => 16)
+               port map (dat_i => std_logic_vector(result), dat_o => sat);
+
+       e_ctrl: entity pipe.stage_merge
+               generic map (WIDTH => 16)
+               port map (
+                       rst_i   => rst_i,
+                       clk_i   => clk_i,
+
+                       a_stb_i => a_stb_i,
+                       a_rdy_o => a_rdy_o,
+
+                       b_stb_i => b_stb_i,
+                       b_rdy_o => b_rdy_o,
+
+                       dat_i   => sat,
+
+                       stb_o   => stb_o,
+                       rdy_i   => rdy_i,
+                       dat_o   => dat_o
+               );
+
+end behavioral;
diff --git a/projects/mp3tape/pcm16_1ch_tapeeffect.vhd b/projects/mp3tape/pcm16_1ch_tapeeffect.vhd
new file mode 100644 (file)
index 0000000..6dce38e
--- /dev/null
@@ -0,0 +1,236 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library pipe;
+library work;
+
+
+entity pcm16_1ch_tapeeffect is
+       port (
+               rst_i:      in  std_logic;
+               clk_i:      in  std_logic;
+
+               en_rolloff: in  std_logic;
+               en_flutter: in  std_logic;
+               en_wow:     in  std_logic;
+               en_noise:   in  std_logic;
+
+               stb_i:      in  std_logic;
+               rdy_o:      out std_logic;
+               dat_i:      in  std_logic_vector(15 downto 0);
+
+               stb_o:      out std_logic;
+               rdy_i:      in  std_logic;
+               dat_o:      out std_logic_vector(15 downto 0);
+
+               debug_o:    out std_logic_vector(7 downto 0)
+       );
+end pcm16_1ch_tapeeffect;
+
+
+architecture behavioral of pcm16_1ch_tapeeffect is
+
+       -- Stage 1 - High frequency rolloff
+
+       signal split_a_stb:   std_logic;
+       signal split_a_rdy:   std_logic;
+       signal split_b_stb:   std_logic;
+       signal split_b_rdy:   std_logic;
+       signal split_dat:     std_logic_vector(15 downto 0);
+       signal split_dat_reg: std_logic_vector(15 downto 0);
+
+       signal filter_stb:  std_logic;
+       signal filter_rdy:  std_logic;
+       signal filter_dat:  std_logic_vector(15 downto 0);
+
+       signal bypass_stb:  std_logic;
+       signal bypass_rdy:  std_logic;
+       signal bypass_dat:  std_logic_vector(15 downto 0);
+
+       signal merge_stb:   std_logic;
+       signal merge_rdy:   std_logic;
+       signal merge_dat:   std_logic_vector(15 downto 0);
+
+       signal stage1_stb:  std_logic;
+       signal stage1_rdy:  std_logic;
+       signal stage1_dat:  std_logic_vector(15 downto 0);
+
+       -- Stage 2 - Wow and flutter
+
+       constant WOW_WIDTH: integer := 9;
+
+       constant FLUTTER_WIDTH: integer := 9;
+       constant FLUTTER_INC:   std_logic_vector(15 downto 0) := "00000000"&"00100000";
+       signal flutter_stb: std_logic;
+       signal flutter_rdy: std_logic;
+       signal flutter_dat: std_logic_vector(FLUTTER_WIDTH-1 downto 0);
+
+       signal delay_dat:   std_logic_vector(9 downto 0);
+
+       signal stage2_stb:  std_logic;
+       signal stage2_rdy:  std_logic;
+       signal stage2_dat:  std_logic_vector(15 downto 0);
+
+       -- Stage 3 - Hiss
+
+       signal noise_stb:   std_logic;
+       signal noise_rdy:   std_logic;
+       signal noise_dat:   std_logic_vector(15 downto 0);
+
+begin
+
+       ----------------------------------------------------------------------------
+       -- Low pass filter the audio stream
+
+       e_split: entity pipe.stage_split
+               generic map (WIDTH => 16)
+               port map (
+                       rst_i   => rst_i,
+                       clk_i   => clk_i,
+
+                       stb_i   => stb_i,
+                       rdy_o   => rdy_o,
+                       dat_i   => dat_i,
+
+                       a_stb_o => split_a_stb,
+                       a_rdy_i => split_a_rdy,
+
+                       b_stb_o => split_b_stb,
+                       b_rdy_i => split_b_rdy,
+
+                       dat_o   => split_dat
+               );
+
+       e_filter: entity work.pcm16_1ch_windowsum
+               generic map (WINDOW => 16)
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+
+                       stb_i => split_a_stb,
+                       rdy_o => split_a_rdy,
+                       dat_i => split_dat,
+
+                       stb_o => filter_stb,
+                       rdy_i => filter_rdy,
+                       dat_o => filter_dat
+               );
+       e_bypass: entity pipe.stage_reg
+               generic map (WIDTH => 16)
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+
+                       stb_i => split_b_stb,
+                       rdy_o => split_b_rdy,
+                       dat_i => split_dat,
+
+                       stb_o => bypass_stb,
+                       rdy_i => bypass_rdy,
+                       dat_o => bypass_dat
+               );
+
+       e_filter_mux: entity pipe.stage_mux2
+               generic map (WIDTH => 16)
+               port map (
+                       rst_i   => rst_i,
+                       clk_i   => clk_i,
+
+                       sel     => en_rolloff,
+
+                       stb_0_i => bypass_stb,
+                       rdy_0_o => bypass_rdy,
+                       dat_0_i => bypass_dat,
+
+                       stb_1_i => filter_stb,
+                       rdy_1_o => filter_rdy,
+                       dat_1_i => filter_dat,
+
+                       stb_o   => stage1_stb,
+                       rdy_i   => stage1_rdy,
+                       dat_o   => stage1_dat
+               );
+
+       ----------------------------------------------------------------------------
+       -- Variable delay for wow and flutter
+
+       stage2_stb <= stage1_stb;
+       stage1_rdy <= stage2_rdy;
+       stage2_dat <= stage1_dat;
+
+       --e_wowgen: entity dsp.src_fracstep
+       --      generic map (WIDTH_OUT => 10)
+       --      port map (
+       --              rst_i => rst_i,
+       --              clk_i => clk_i,
+
+       --              inc_i => std_logic_vector(unsigned(FLUTTER_INC)),
+
+       --              stb_o => flutter_stb,
+       --              rdy_i => flutter_rdy,
+       --              dat_o => flutter_dat
+       --      );
+
+       --e_sintab: entity dsp.table_sine_1k_16
+       --      port map (
+       --              en    =>
+
+       --              adr_i => flutter_dat,
+       --              dat_o => 
+       --      );
+
+       --delay_dat <= std_logic_vector(resize(unsigned(flutter_dat), 10)) when en_flutter = '1' else (others => '0');
+
+       --e_vardelay: entity work.pcm16_1ch_vardelay
+       --      port map (
+       --              rst_i       => rst_i,
+       --              clk_i       => clk_i,
+
+       --              delay_stb_i => '1',
+       --              delay_rdy_o => open,
+       --              delay_dat_i => (others => '0'),
+
+       --              data_stb_i  => stage1_stb,
+       --              data_rdy_o  => stage1_rdy,
+       --              data_dat_i  => stage1_dat,
+
+       --              stb_o       => stage2_stb,
+       --              rdy_i       => stage2_rdy,
+       --              dat_o       => stage2_dat
+       --      );
+
+       ----------------------------------------------------------------------------
+       -- Add noise stream to audio stream
+
+       e_noise: entity work.pcm16_1ch_noise
+               generic map (SIGFIGS => 10)
+               port map (
+                       clk_i => clk_i,
+
+                       en_i  => en_noise,
+
+                       stb_o => noise_stb,
+                       rdy_i => noise_rdy,
+                       dat_o => noise_dat
+               );
+
+       e_sum: entity work.pcm16_1ch_sum
+               port map (
+                       rst_i   => rst_i,
+                       clk_i   => clk_i,
+
+                       a_stb_i => stage2_stb,
+                       a_rdy_o => stage2_rdy,
+                       a_dat_i => stage2_dat,
+
+                       b_stb_i => noise_stb,
+                       b_rdy_o => noise_rdy,
+                       b_dat_i => noise_dat,
+
+                       stb_o   => stb_o,
+                       rdy_i   => rdy_i,
+                       dat_o   => dat_o
+               );
+
+end behavioral;
diff --git a/projects/mp3tape/pcm16_1ch_vardelay.vhd b/projects/mp3tape/pcm16_1ch_vardelay.vhd
new file mode 100644 (file)
index 0000000..8ded750
--- /dev/null
@@ -0,0 +1,101 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+library dsp;
+library pipe;
+library work;
+
+
+entity pcm16_1ch_vardelay is
+       port (
+               rst_i:       in  std_logic;
+               clk_i:       in  std_logic;
+
+               delay_stb_i: in  std_logic;
+               delay_rdy_o: out std_logic;
+               delay_dat_i: in  std_logic_vector(9 downto 0);
+
+               data_stb_i:  in  std_logic;
+               data_rdy_o:  out std_logic;
+               data_dat_i:  in  std_logic_vector(15 downto 0);
+
+               stb_o:       out std_logic;
+               rdy_i:       in  std_logic;
+               dat_o:       out std_logic_vector(15 downto 0)
+       );
+end pcm16_1ch_vardelay;
+
+
+architecture behavioral of pcm16_1ch_vardelay is
+
+       constant COUNT_WIDTH: integer := 10;
+
+       signal en:           std_logic;
+
+       signal ptr_head_reg: unsigned(COUNT_WIDTH-1 downto 0) := (others => '0');
+       signal ptr_tail:     unsigned(COUNT_WIDTH-1 downto 0);
+
+begin
+
+       e_ctrl: entity pipe.ctrl_merge
+               port map (
+                       rst_i   => rst_i,
+                       clk_i   => clk_i,
+
+                       a_stb_i => delay_stb_i,
+                       a_rdy_o => delay_rdy_o,
+
+                       b_stb_i => data_stb_i,
+                       b_rdy_o => data_rdy_o,
+
+                       stb_o   => stb_o,
+                       rdy_i   => rdy_i,
+
+                       en_o    => en
+               );
+
+       process (rst_i, clk_i, en, ptr_head_reg)
+       begin
+               if rising_edge(clk_i) then
+                       if rst_i = '1' then
+                               -- Probably don't need reset logic
+                       elsif en = '1' then
+                               ptr_head_reg <= ptr_head_reg + 1;
+                       end if;
+               end if;
+       end process;
+
+       ptr_tail <= (ptr_head_reg - unsigned(delay_dat_i)) - 1;
+
+       e_fifo: ramb16_s18_s18
+               port map (
+                       -- Head port (insertion)
+                       WEA   => '1',
+                       ENA   => en,
+                       SSRA  => '0',
+                       CLKA  => clk_i,
+                       ADDRA => std_logic_vector(ptr_head_reg),
+                       DIA   => data_dat_i,
+                       DIPA  => (others => '0'),
+
+                       DOA   => open,
+                       DOPA  => open,
+
+                       -- Tail port (removal)
+                       WEB   => '0',
+                       ENB   => en,
+                       SSRB  => '0',
+                       CLKB  => clk_i,
+                       ADDRB => std_logic_vector(ptr_tail),
+                       DIB   => (others => '0'),
+                       DIPB  => (others => '0'),
+
+                       DOB   => dat_o,
+                       DOPB  => open
+               );
+
+end behavioral;
diff --git a/projects/mp3tape/pcm16_1ch_windowsum.vhd b/projects/mp3tape/pcm16_1ch_windowsum.vhd
new file mode 100644 (file)
index 0000000..bbef579
--- /dev/null
@@ -0,0 +1,69 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.math_real.all;
+
+library dsp;
+library pipe;
+library work;
+
+
+entity pcm16_1ch_windowsum is
+       generic (
+               WINDOW: 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(15 downto 0);
+
+               stb_o: out std_logic;
+               rdy_i: in  std_logic;
+               dat_o: out std_logic_vector(15 downto 0)
+       );
+end pcm16_1ch_windowsum;
+
+
+architecture behavioral of pcm16_1ch_windowsum is
+
+       constant FILT_WIDTH: positive := 16+integer(ceil(log2(real(WINDOW))));
+
+       signal en:     std_logic;
+       signal filt:   std_logic_vector(FILT_WIDTH-1 downto 0);
+
+begin
+
+       e_ctrl: entity pipe.ctrl
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+
+                       stb_i => stb_i,
+                       rdy_o => rdy_o,
+
+                       stb_o => stb_o,
+                       rdy_i => rdy_i,
+
+                       en_o  => en
+               );
+
+       e_filter: entity dsp.filter_windowsum
+               generic map (
+                       WIDTH  => 16,
+                       WINDOW => WINDOW
+               )
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+
+                       en_i  => en,
+
+                       dat_i => dat_i,
+                       dat_o => filt
+               );
+
+       dat_o <= filt(FILT_WIDTH-1 downto FILT_WIDTH-16);
+
+end behavioral;
diff --git a/projects/mp3tape/pcm16_2ch_gain.vhd b/projects/mp3tape/pcm16_2ch_gain.vhd
new file mode 100644 (file)
index 0000000..f25faca
--- /dev/null
@@ -0,0 +1,77 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+library dsp;
+library work;
+
+
+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 <= dat_i(15) & dat_i(15) & dat_i(15 downto  0);
+       samp_r <= dat_i(31) & dat_i(31) & 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));
+
+       e_sat_l: entity dsp.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 dsp.saturate
+               generic map (WIDTH_IN => 27, WIDTH_OUT => 16)
+               port map (dat_i => out_r(35 downto 9), dat_o => result_r);
+
+       result <= result_r & result_l;
+
+       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;
diff --git a/projects/mp3tape/pcm16_2ch_noise.vhd b/projects/mp3tape/pcm16_2ch_noise.vhd
new file mode 100644 (file)
index 0000000..0fde6cb
--- /dev/null
@@ -0,0 +1,51 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library dsp;
+
+
+entity pcm16_2ch_noise is
+       generic (
+               SIGFIGS: positive := 10
+       );
+       port (
+               clk_i: in  std_logic;
+
+               en_i:  in  std_logic;
+
+               stb_o: out std_logic;
+               rdy_i: in  std_logic;
+               dat_o: out std_logic_vector(31 downto 0)
+       );
+end pcm16_2ch_noise;
+
+
+architecture behavioral of pcm16_2ch_noise is
+
+       constant X: std_logic_vector(15 downto 0) := x"0001";
+
+       signal noise_dat: std_logic_vector(SIGFIGS-1 downto 0);
+
+begin
+
+       g_bits: for i in SIGFIGS-1 downto 0 generate
+               e_lfsr: entity dsp.lfsr
+                       generic map (
+                               -- First part guarantees at least one bit set
+                               -- Second part is an attempt at pseudorandomness
+                               INIT => std_logic_vector(rotate_left(unsigned(X), i)) or std_logic_vector(to_unsigned(i*13, 16) xor x"a5c3")
+                       )
+                       port map (
+                               clk_i => clk_i,
+                               en_i  => rdy_i,
+                               dat_o => noise_dat(i)
+                       );
+       end generate;
+
+       stb_o <= '1';
+
+       dat_o <= std_logic_vector(resize(signed(noise_dat), 16)) &
+                std_logic_vector(resize(signed(noise_dat), 16)) when en_i = '1' else (others => '0');
+
+end behavioral;
diff --git a/projects/mp3tape/pcm16_2ch_sum.vhd b/projects/mp3tape/pcm16_2ch_sum.vhd
new file mode 100644 (file)
index 0000000..031b697
--- /dev/null
@@ -0,0 +1,90 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library dsp;
+library pipe;
+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_o: 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 <= signed(a_dat_i(15 downto  0));
+       samp_a_r <= signed(a_dat_i(31 downto 16));
+       samp_b_l <= signed(b_dat_i(15 downto  0));
+       samp_b_r <= signed(b_dat_i(31 downto 16));
+
+       result_l <= (samp_a_l(15) & samp_a_l) + ((samp_b_l(15)) & samp_b_l);
+       result_r <= (samp_a_r(15) & samp_a_r) + ((samp_b_r(15)) & samp_b_r);
+
+       e_sat_l: entity dsp.saturate
+               generic map (WIDTH_IN => 17, WIDTH_OUT => 16)
+               port map (dat_i => std_logic_vector(result_l), dat_o => sat_l);
+
+       e_sat_r: entity dsp.saturate
+               generic map (WIDTH_IN => 17, WIDTH_OUT => 16)
+               port map (dat_i => std_logic_vector(result_r), dat_o => sat_r);
+
+       result <= sat_r & sat_l;
+
+       e_ctrl: entity pipe.stage_merge
+               generic map (WIDTH => 32)
+               port map (
+                       rst_i   => rst_i,
+                       clk_i   => clk_i,
+
+                       a_stb_i => a_stb_i,
+                       a_rdy_o => a_rdy_o,
+
+                       b_stb_i => b_stb_i,
+                       b_rdy_o => b_rdy_o,
+
+                       dat_i   => result,
+
+                       stb_o   => stb_o,
+                       rdy_i   => rdy_i,
+                       dat_o   => dat_o
+               );
+
+end behavioral;
diff --git a/projects/mp3tape/pcm16_2ch_tapeeffect.vhd b/projects/mp3tape/pcm16_2ch_tapeeffect.vhd
new file mode 100644 (file)
index 0000000..033d9b3
--- /dev/null
@@ -0,0 +1,227 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library pipe;
+library work;
+
+
+entity pcm16_2ch_tapeeffect is
+       port (
+               rst_i:      in  std_logic;
+               clk_i:      in  std_logic;
+
+               en_rolloff: in  std_logic;
+               en_flutter: in  std_logic;
+               en_wow:     in  std_logic;
+               en_noise:   in  std_logic;
+
+               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);
+
+               debug_o:    out std_logic_vector(7 downto 0)
+       );
+end pcm16_2ch_tapeeffect;
+
+
+architecture behavioral of pcm16_2ch_tapeeffect is
+
+       -- Stage 1 - High frequency rolloff
+
+       signal split_a_stb:   std_logic;
+       signal split_a_rdy:   std_logic;
+       signal split_b_stb:   std_logic;
+       signal split_b_rdy:   std_logic;
+       signal split_dat:     std_logic_vector(31 downto 0);
+       signal split_dat_reg: std_logic_vector(31 downto 0);
+
+       signal filter_stb:  std_logic;
+       signal filter_rdy:  std_logic;
+       signal filter_dat:  std_logic_vector(31 downto 0);
+
+       signal bypass_stb:  std_logic;
+       signal bypass_rdy:  std_logic;
+       signal bypass_dat:  std_logic_vector(31 downto 0);
+
+       signal merge_stb:   std_logic;
+       signal merge_rdy:   std_logic;
+       signal merge_dat:   std_logic_vector(31 downto 0);
+
+       signal stage1_stb:  std_logic;
+       signal stage1_rdy:  std_logic;
+       signal stage1_dat:  std_logic_vector(31 downto 0);
+
+       -- Stage 2 - Wow and flutter
+
+       constant FLUTTER_WIDTH: integer := 9;
+       constant FLUTTER_INC:   std_logic_vector(15 downto 0) := "00000000"&"00100000";
+       signal flutter_stb: std_logic;
+       signal flutter_rdy: std_logic;
+       signal flutter_dat: std_logic_vector(FLUTTER_WIDTH-1 downto 0);
+
+       signal delay_dat:   std_logic_vector(9 downto 0);
+
+       signal stage2_stb:  std_logic;
+       signal stage2_rdy:  std_logic;
+       signal stage2_dat:  std_logic_vector(31 downto 0);
+
+       -- Stage 3 - Hiss
+
+       signal noise_stb:   std_logic;
+       signal noise_rdy:   std_logic;
+       signal noise_raw:   std_logic_vector( 9 downto 0);
+       signal noise_dat:   std_logic_vector(31 downto 0);
+
+begin
+
+       ----------------------------------------------------------------------------
+       -- Low pass filter the audio stream
+
+       e_split: entity pipe.stage_split
+               generic map (WIDTH => 32)
+               port map (
+                       rst_i   => rst_i,
+                       clk_i   => clk_i,
+
+                       stb_i   => stb_i,
+                       rdy_o   => rdy_o,
+                       dat_i   => dat_i,
+
+                       a_stb_o => split_a_stb,
+                       a_rdy_i => split_a_rdy,
+
+                       b_stb_o => split_b_stb,
+                       b_rdy_i => split_b_rdy,
+
+                       dat_o   => split_dat
+               );
+
+       e_filter: entity work.pcm16_2ch_windowsum
+               generic map (WINDOW => 16)
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+
+                       stb_i => split_a_stb,
+                       rdy_o => split_a_rdy,
+                       dat_i => split_dat,
+
+                       stb_o => filter_stb,
+                       rdy_i => filter_rdy,
+                       dat_o => filter_dat
+               );
+       e_bypass: entity pipe.stage_reg
+               generic map (WIDTH => 32)
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+
+                       stb_i => split_b_stb,
+                       rdy_o => split_b_rdy,
+                       dat_i => split_dat,
+
+                       stb_o => bypass_stb,
+                       rdy_i => bypass_rdy,
+                       dat_o => bypass_dat
+               );
+
+       e_filter_mux: entity pipe.stage_mux2
+               generic map (WIDTH => 32)
+               port map (
+                       rst_i   => rst_i,
+                       clk_i   => clk_i,
+
+                       sel     => en_rolloff,
+
+                       stb_0_i => bypass_stb,
+                       rdy_0_o => bypass_rdy,
+                       dat_0_i => bypass_dat,
+
+                       stb_1_i => filter_stb,
+                       rdy_1_o => filter_rdy,
+                       dat_1_i => filter_dat,
+
+                       stb_o   => stage1_stb,
+                       rdy_i   => stage1_rdy,
+                       dat_o   => stage1_dat
+               );
+
+       ----------------------------------------------------------------------------
+       -- Variable delay for wow and flutter
+
+       stage2_stb <= stage1_stb;
+       stage1_rdy <= stage2_rdy;
+       stage2_dat <= stage1_dat;
+
+       --e_flutter: entity dsp.src_fracstep
+       --      generic map (WIDTH_OUT => FLUTTER_WIDTH)
+       --      port map (
+       --              rst_i => rst_i,
+       --              clk_i => clk_i,
+
+       --              inc_i => std_logic_vector(unsigned(FLUTTER_INC)),
+
+       --              stb_o => flutter_stb,
+       --              rdy_i => flutter_rdy,
+       --              dat_o => flutter_dat
+       --      );
+
+       --delay_dat <= std_logic_vector(resize(unsigned(flutter_dat), 10)) when en_flutter = '1' else (others => '0');
+
+       --e_vardelay: entity work.pcm16_2ch_vardelay
+       --      port map (
+       --              rst_i       => rst_i,
+       --              clk_i       => clk_i,
+
+       --              delay_stb_i => flutter_stb,
+       --              delay_rdy_o => flutter_rdy,
+       --              delay_dat_i => delay_dat,
+
+       --              audio_stb_i => stage1_stb,
+       --              audio_rdy_o => stage1_rdy,
+       --              audio_dat_i => stage1_dat,
+
+       --              stb_o       => stage2_stb,
+       --              rdy_i       => stage2_rdy,
+       --              dat_o       => stage2_dat
+       --      );
+
+       ----------------------------------------------------------------------------
+       -- Add noise stream to audio stream
+
+       e_noise: entity work.pcm16_2ch_noise
+               generic map (SIGFIGS => 10)
+               port map (
+                       clk_i => clk_i,
+
+                       en_i  => en_noise,
+
+                       stb_o => noise_stb,
+                       rdy_i => noise_rdy,
+                       dat_o => noise_dat
+               );
+
+       e_sum: entity work.pcm16_2ch_sum
+               port map (
+                       rst_i   => rst_i,
+                       clk_i   => clk_i,
+
+                       a_stb_i => stage2_stb,
+                       a_rdy_o => stage2_rdy,
+                       a_dat_i => stage2_dat,
+
+                       b_stb_i => noise_stb,
+                       b_rdy_o => noise_rdy,
+                       b_dat_i => noise_dat,
+
+                       stb_o   => stb_o,
+                       rdy_i   => rdy_i,
+                       dat_o   => dat_o
+               );
+
+end behavioral;
diff --git a/projects/mp3tape/pcm16_2ch_vardelay.vhd b/projects/mp3tape/pcm16_2ch_vardelay.vhd
new file mode 100644 (file)
index 0000000..0f4c2d9
--- /dev/null
@@ -0,0 +1,147 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library unisim;
+use unisim.vcomponents.all;
+
+library dsp;
+library work;
+
+
+entity pcm16_2ch_vardelay is
+       port (
+               rst_i:       in  std_logic;
+               clk_i:       in  std_logic;
+
+               delay_stb_i: in  std_logic;
+               delay_rdy_o: out std_logic;
+               delay_dat_i: in  std_logic_vector(9 downto 0);
+
+               audio_stb_i: in  std_logic;
+               audio_rdy_o: out std_logic;
+               audio_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_vardelay;
+
+
+architecture behavioral of pcm16_2ch_vardelay is
+
+       constant COUNT_WIDTH: integer := 10;
+
+       signal en:           std_logic;
+       signal stb:          std_logic;
+       signal rdy:          std_logic;
+
+       signal samp_l:       std_logic_vector(15 downto 0);
+       signal samp_r:       std_logic_vector(15 downto 0);
+
+       signal result_l:     std_logic_vector(15 downto 0);
+       signal result_r:     std_logic_vector(15 downto 0);
+
+       signal ptr_head_reg: unsigned(COUNT_WIDTH-1 downto 0) := (others => '0');
+       signal ptr_tail:     unsigned(COUNT_WIDTH-1 downto 0);
+
+begin
+
+       e_merge: entity dsp.merge
+               port map (
+                       a_stb_i => delay_stb_i,
+                       a_rdy_o => delay_rdy_o,
+                       b_stb_i => audio_stb_i,
+                       b_rdy_o => audio_rdy_o,
+                       stb_o   => stb,
+                       rdy_i   => rdy
+               );
+
+       e_ctrl: entity dsp.pipectrl
+               generic map (WIDTH => 0)
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+                       en_o  => en,
+                       stb_i => stb,
+                       rdy_o => rdy,
+                       dat_i => open,
+                       stb_o => stb_o,
+                       rdy_i => rdy_i,
+                       dat_o => open
+               );
+
+       process (rst_i, clk_i, en, ptr_head_reg)
+       begin
+               if rising_edge(clk_i) then
+                       if rst_i = '1' then
+                               -- Probably don't need reset logic
+                       elsif en = '1' then
+                               ptr_head_reg <= ptr_head_reg + 1;
+                       end if;
+               end if;
+       end process;
+
+       samp_l <= audio_dat_i(15 downto  0);
+       samp_r <= audio_dat_i(31 downto 16);
+
+       ptr_tail <= (ptr_head_reg - unsigned(delay_dat_i)) - 1;
+
+       e_fifo_l: ramb16_s18_s18
+               port map (
+                       -- Head port (insertion)
+                       WEA   => '1',
+                       ENA   => en,
+                       SSRA  => '0',
+                       CLKA  => clk_i,
+                       ADDRA => std_logic_vector(ptr_head_reg),
+                       DIA   => samp_l,
+                       DIPA  => (others => '0'),
+
+                       DOA   => open,
+                       DOPA  => open,
+
+                       -- Tail port (removal)
+                       WEB   => '0',
+                       ENB   => en,
+                       SSRB  => '0',
+                       CLKB  => clk_i,
+                       ADDRB => std_logic_vector(ptr_tail),
+                       DIB   => (others => '0'),
+                       DIPB  => (others => '0'),
+
+                       DOB   => result_l,
+                       DOPB  => open
+               );
+
+       e_fifo_r: ramb16_s18_s18
+               port map (
+                       -- Head port (insertion)
+                       WEA   => '1',
+                       ENA   => en,
+                       SSRA  => '0',
+                       CLKA  => clk_i,
+                       ADDRA => std_logic_vector(ptr_head_reg),
+                       DIA   => samp_r,
+                       DIPA  => (others => '0'),
+
+                       DOA   => open,
+                       DOPA  => open,
+
+                       -- Tail port (removal)
+                       WEB   => '0',
+                       ENB   => en,
+                       SSRB  => '0',
+                       CLKB  => clk_i,
+                       ADDRB => std_logic_vector(ptr_tail),
+                       DIB   => (others => '0'),
+                       DIPB  => (others => '0'),
+
+                       DOB   => result_r,
+                       DOPB  => open
+               );
+
+       dat_o <= result_r & result_l;
+
+end behavioral;
diff --git a/projects/mp3tape/pcm16_2ch_windowsum.vhd b/projects/mp3tape/pcm16_2ch_windowsum.vhd
new file mode 100644 (file)
index 0000000..59f3b9e
--- /dev/null
@@ -0,0 +1,98 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.math_real.all;
+
+library dsp;
+library pipe;
+library work;
+
+
+entity pcm16_2ch_windowsum is
+       generic (
+               WINDOW: 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(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_windowsum;
+
+
+architecture behavioral of pcm16_2ch_windowsum is
+
+       constant FILT_WIDTH: positive := 16+integer(ceil(log2(real(WINDOW))));
+
+       signal en:       std_logic;
+
+       signal samp_l:   std_logic_vector(15 downto 0);
+       signal samp_r:   std_logic_vector(15 downto 0);
+
+       signal filt_l:   std_logic_vector(FILT_WIDTH-1 downto 0);
+       signal filt_r:   std_logic_vector(FILT_WIDTH-1 downto 0);
+
+       signal result_l: std_logic_vector(15 downto 0);
+       signal result_r: std_logic_vector(15 downto 0);
+
+begin
+
+       e_ctrl: entity pipe.ctrl
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+
+                       stb_i => stb_i,
+                       rdy_o => rdy_o,
+
+                       stb_o => stb_o,
+                       rdy_i => rdy_i,
+
+                       en_o  => en
+               );
+
+       samp_l <= dat_i(15 downto  0);
+       samp_r <= dat_i(31 downto 16);
+
+       e_filter_l: entity dsp.filter_windowsum
+               generic map (
+                       WIDTH  => 16,
+                       WINDOW => WINDOW
+               )
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+
+                       en_i  => en,
+
+                       dat_i => samp_l,
+                       dat_o => filt_l
+               );
+
+       e_filter_r: entity dsp.filter_windowsum
+               generic map (
+                       WIDTH  => 16,
+                       WINDOW => WINDOW
+               )
+               port map (
+                       rst_i => rst_i,
+                       clk_i => clk_i,
+
+                       en_i  => en,
+
+                       dat_i => samp_r,
+                       dat_o => filt_r
+               );
+
+       result_l <= filt_l(FILT_WIDTH-1 downto FILT_WIDTH-16);
+       result_r <= filt_r(FILT_WIDTH-1 downto FILT_WIDTH-16);
+
+       dat_o <= result_r & result_l;
+
+end behavioral;
index 072d66236cb2811cc7ad7820a5a45c7169951266..1a5914235b8779af15db2b046a758afa66968f82 100644 (file)
@@ -2,6 +2,7 @@ library ieee;
 use ieee.std_logic_1164.all;
 
 library dsp;
+library work;
 
 
 entity test_tapeeffect is
@@ -42,7 +43,7 @@ begin
                wait;
        end process;
 
-       e_uut: entity dsp.pcm16_2ch_tapeeffect
+       e_uut: entity work.pcm16_2ch_tapeeffect
                port map (
                        rst_i      => rst_i,
                        clk_i      => clk_i,
diff --git a/projects/mp3tape/tests/test_ifft.vhd b/projects/mp3tape/tests/test_ifft.vhd
new file mode 100644 (file)
index 0000000..5e04c90
--- /dev/null
@@ -0,0 +1,106 @@
+library ieee;
+use ieee.std_logic_1164.all;
+
+
+entity test_ifft is
+end test_ifft;
+
+
+architecture behavior of test_ifft is
+
+       constant CLK_I_PERIOD: time := 20 ns;
+
+       signal rst_i:      std_logic;
+       signal clk_i:      std_logic;
+
+       signal stb_i:      std_logic;
+       signal rdy_o:      std_logic;
+       signal bin_dat_i:  std_logic_vector( 9 downto 0);
+       signal amp_dat_i:  std_logic_vector(15 downto 0);
+       signal fin_dat_i:  std_logic;
+
+       signal stb_o:      std_logic;
+       signal rdy_i:      std_logic;
+       signal samp_dat_o: std_logic_vector(15 downto 0);
+
+       type test_t is (
+               T_RESET,
+               T_BIN_1,
+               T_BIN_5,
+               T_COMPUTE,
+               T_UNLOAD,
+               T_DONE
+       );
+
+       signal test: test_t;
+
+begin
+
+       p_test: process
+       begin
+               -- Initial values
+               stb_i <= '0';
+               rdy_i <= '1';
+
+               -- Reset
+               test  <= T_RESET;
+               rst_i <= '1';
+               wait for CLK_I_PERIOD*2;
+               rst_i <= '0';
+               wait until falling_edge(clk_i);
+
+               -- Test
+               test <= T_BIN_1;
+               bin_dat_i <= "0000000001";
+               amp_dat_i <= x"7fff";
+               fin_dat_i <= '0';
+               stb_i <= '1';
+               wait until falling_edge(clk_i);
+               stb_i <= '0';
+
+               test <= T_BIN_5;
+               bin_dat_i <= "0000000101";
+               amp_dat_i <= x"07ff";
+               fin_dat_i <= '1';
+               stb_i <= '1';
+               wait until falling_edge(clk_i);
+               stb_i <= '0';
+
+               test <= T_COMPUTE;
+               wait until stb_o = '1';
+
+               test <= T_UNLOAD;
+               wait until stb_o = '0';
+
+               -- Done
+               test <= T_DONE;
+               wait;
+       end process;
+
+
+       e_uut: entity work.ifft
+               port map (
+                       rst_i      => rst_i,
+                       clk_i      => clk_i,
+
+                       stb_i      => stb_i,
+                       rdy_o      => rdy_o,
+                       bin_dat_i  => bin_dat_i,
+                       amp_dat_i  => amp_dat_i,
+                       fin_dat_i  => fin_dat_i,
+
+                       stb_o      => stb_o,
+                       rdy_i      => rdy_i,
+                       samp_dat_o => samp_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;
\ No newline at end of file
diff --git a/projects/mp3tape/tests/test_ifft_counter.vhd b/projects/mp3tape/tests/test_ifft_counter.vhd
new file mode 100644 (file)
index 0000000..23068f9
--- /dev/null
@@ -0,0 +1,80 @@
+library ieee;
+use ieee.std_logic_1164.all;
+
+library work;
+
+
+entity test_ifft_counter is
+end test_ifft_counter;
+
+
+architecture behavior of test_ifft_counter is
+
+       constant CLK_I_PERIOD: time     := 20 ns;
+       constant IDX_WIDTH:    positive := 3;
+
+       signal rst_i:  std_logic;
+       signal clk_i:  std_logic;
+
+       signal en_i:   std_logic;
+       signal done_o: std_logic;
+
+       signal i_idx:  std_logic_vector(IDX_WIDTH-1 downto 0);
+       signal j_idx:  std_logic_vector(IDX_WIDTH-1 downto 0);
+       signal w_idx:  std_logic_vector(IDX_WIDTH-2 downto 0);
+
+begin
+
+       p_test: process
+       begin
+               -- Initial values
+               en_i <= '0';
+
+               -- Reset
+               rst_i <= '1'; 
+               wait for CLK_I_PERIOD*2;
+               rst_i <= '0';
+               wait until falling_edge(clk_i);
+
+               -- Test
+               en_i <= '1';
+
+               wait until done_o = '1';
+               wait until rising_edge(clk_i);
+               en_i <= '0';
+               wait for CLK_I_PERIOD*3;
+               wait until falling_edge(clk_i);
+               en_i <= '1';
+               wait until done_o = '1';
+               wait until rising_edge(clk_i);
+               en_i <= '0';
+
+               -- Done
+               wait;
+       end process;
+
+
+       e_uut: entity work.ifft_counter
+               generic map (IDX_WIDTH => IDX_WIDTH)
+               port map (
+                       rst_i  => rst_i,
+                       clk_i  => clk_i,
+
+                       en_i   => en_i,
+                       done_o => done_o,
+
+                       i_idx  => i_idx,
+                       j_idx  => j_idx,
+                       w_idx  => w_idx
+               );
+
+
+       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;
diff --git a/projects/mp3tape/tests/test_ifft_datapath.vhd b/projects/mp3tape/tests/test_ifft_datapath.vhd
new file mode 100644 (file)
index 0000000..b691d0f
--- /dev/null
@@ -0,0 +1,160 @@
+library ieee;
+use ieee.std_logic_1164.all;
+
+library work;
+
+
+entity test_ifft_datapath is
+end test_ifft_datapath;
+
+
+architecture behavior of test_ifft_datapath is
+
+       constant CLK_I_PERIOD: time := 20 ns;
+
+       signal rst_i:      std_logic;
+       signal clk_i:      std_logic;
+
+       signal load:       std_logic;
+       signal unload:     std_logic;
+       signal addr:       std_logic_vector(9 downto 0);
+       signal dat_load:   std_logic_vector(15 downto 0);
+       signal dat_unload: std_logic_vector(15 downto 0);
+
+       signal use_j:      std_logic;
+       signal s_en:       std_logic;
+       signal s_wr:       std_logic;
+       signal w_read:     std_logic;
+       signal i_idx:      std_logic_vector(9 downto 0);
+       signal j_idx:      std_logic_vector(9 downto 0);
+       signal w_idx:      std_logic_vector(8 downto 0);
+       signal mult_en:    std_logic;
+
+       type test_t is (
+               T_RESET,
+               T_LOAD,
+               T_LOOKUP,
+               T_MULT,
+               T_STORE_XI,
+               T_STORE_XJ,
+               T_UNLOAD_XI,
+               T_UNLOAD_XJ,
+               T_VERIFY_CLEAR,
+               T_DONE
+       );
+
+       signal test: test_t;
+
+begin
+
+       p_test: process
+       begin
+               -- Initial values
+               load    <= '0';
+               unload  <= '0';
+               use_j   <= '0';
+               s_en    <= '0';
+               s_wr    <= '0';
+               w_read  <= '0';
+               mult_en <= '0';
+
+               -- Reset
+               test <= T_RESET;
+               rst_i <= '1';
+               wait for CLK_I_PERIOD*2;
+               rst_i <= '0';
+               wait until falling_edge(clk_i);
+
+               -- Test
+               test     <= T_LOAD;
+               load     <= '1';
+               addr     <= "0000110101";
+               dat_load <= x"1234";
+               wait until falling_edge(clk_i);
+               addr     <= "0000110100";
+               dat_load <= x"4321";
+               wait until falling_edge(clk_i);
+               load     <= '0';
+               dat_load <= (others => '0');
+               addr     <= (others => '0');
+
+               test   <= T_LOOKUP;
+               i_idx  <= "1010110000";
+               j_idx  <= "0010110000";
+               w_idx  <= "000000001";
+               use_j  <= '1';
+               s_en   <= '1';
+               w_read <= '1';
+               wait until falling_edge(clk_i);
+               use_j  <= '0';
+               s_en   <= '0';
+               w_read <= '0';
+
+               test    <= T_MULT;
+               mult_en <= '1';
+               s_en    <= '1';
+               wait until falling_edge(clk_i);
+               mult_en <= '0';
+               s_en    <= '0';
+
+               test  <= T_STORE_XI;
+               s_en  <= '1';
+               s_wr  <= '1';
+               wait until falling_edge(clk_i);
+               test  <= T_STORE_XJ;
+               use_j <= '1';
+               wait until falling_edge(clk_i);
+               use_j <= '0';
+               s_en  <= '0';
+               s_wr  <= '0';
+
+               test   <= T_UNLOAD_XI;
+               unload <= '1';
+               addr   <= "1010110000";
+               wait until falling_edge(clk_i);
+               test   <= T_UNLOAD_XJ;
+               addr   <= "0010110000";
+               wait until falling_edge(clk_i);
+
+               test   <= T_VERIFY_CLEAR;
+               unload <= '1';
+               wait until falling_edge(clk_i);
+               unload <= '0';
+
+               -- Done
+               test <= T_DONE;
+               wait;
+       end process;
+
+
+       e_uut: entity work.ifft_datapath
+               port map (
+                       rst_i      => rst_i,
+                       clk_i      => clk_i,
+
+                       load       => load,
+                       unload     => unload,
+                       addr       => addr,
+                       dat_load   => dat_load,
+                       dat_unload => dat_unload,
+
+                       use_j      => use_j,
+                       s_en       => s_en,
+                       s_wr       => s_wr,
+                       w_read     => w_read,
+                       i_idx      => i_idx,
+                       j_idx      => j_idx,
+                       w_idx      => w_idx,
+                       mult_en    => mult_en
+               );
+
+
+       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;
index 6e28142960703760da0952ab883483a419a1997d..8faa0005f0bd56c5b2b19b5d323aee589a917d73 100644 (file)
@@ -32,6 +32,10 @@ architecture behavior of test_nexys2 is
        signal sw:            std_logic_vector(7 downto 0);
        signal JA:            std_logic_vector(7 downto 0);
 
+       signal file_read:     string(1 to 100);
+       signal is_empty:      boolean;
+       signal file_write:    string(1 to 100);
+
 begin
 
        p_test: process
@@ -85,11 +89,12 @@ begin
                );
 
 
-       e_i2s: entity simulated.proto_i2s_tx
+       e_i2s_pmod: entity simulated.dev_pmod_i2s
                port map (
-                       sck => JA(6),
-                       ws  => JA(5),
-                       sd  => JA(7)
+                       J          => JA,
+                       file_read  => file_read,
+                       is_empty   => is_empty,
+                       file_write => file_write
                );
 
 
index c1129ccb44d8aa30c2549663de7b363950b3d5a3..71f37665fe618eefe015859263a0faea62593ce1 100755 (executable)
@@ -112,6 +112,8 @@ def do_jankify(f: BinaryIO, g: BinaryIO):
         if len(block) < 1024:
             block += [0.0]*(1024-len(block))
         x = compress_chunk(block, 0)
+        last_i, last_p = x[-1]
+        x[-1] = (last_i | 0x8000, last_p)  # Set the end-of-block marker
         for i, p in x:
             f_write_u16_le(g, i)
             f_write_u16_le(g, p)
@@ -125,8 +127,11 @@ def do_unjank(f: BinaryIO, g: BinaryIO):
         for i in range(num_blocks):
             print(i, num_blocks)  # Obnoxious, but less obnoxious than not knowing
             block = [fft.C(0,0)]*1024
-            for i in range(20):
+            for x in range(20):
                 i = f_chomp_u16_le(f)
+                if x == 19:
+                    assert i & 0x8000 != 0  # Check for the end of block flag
+                i &= 0x7fff
                 p = f_chomp_u16_le(f)
                 block[i] = fft.C(p*scale,0)
             c0 = fft.ifft_iter(block)
index 3709245382f8bfc02c2b2486f689b52ac761cc47..0ccdd8314346d474cec5922a340831ec10f8d089 100755 (executable)
@@ -12,3 +12,4 @@ gcc -o digdude digdude.c fileformat.c memctrl.c ec.c $CFLAGS -I $INC -L $LIBDIR
 gcc -o jtag jtag.c ec.c $CFLAGS -I $INC -L $LIBDIR -ldmgr -ldjtg
 
 gcc -o stm stm.c ec.c $CFLAGS -I $INC -L $LIBDIR -ldmgr -ldstm
+gcc -o stm_test stm_test.c ec.c $CFLAGS -I $INC -L $LIBDIR -ldmgr -ldstm
index 74cc75c805f1b934287e8473a7743d2e19a0d61c..25ec2ca5845740c7abd1fe6dbb8dad881fba1a5c 100644 (file)
@@ -376,6 +376,16 @@ int main(int argc, char **argv)
                EC_FALSE(file_emit_wav_header(out_file, &info));
                in_len = info.data_block_size;  // Make sure we don't download metadata
        }
+       else if (!strcmp(format, "jank"))
+       {
+               // Jankfile
+               uint32_t num_blocks;
+
+               EC_FALSE(file_read_u32(in_file, &num_blocks));
+               printf("Block count: %" PRIi32 "\n", num_blocks);
+               in_len = num_blocks * 20 * 4;
+               out_len = num_blocks * 1024;
+       }
        else if (!strcmp(format, "bin"))
        {
                // Binary format, nothing to do