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