--------------------------------------------------------------------------- -- (c) 2014 mark watson -- I am happy for anyone to use this for non-commercial use. -- If my vhdl files are used commercially or otherwise sold, -- please contact me for explicit permission at scrameta (gmail). -- This applies for source and binary form and derived works. --------------------------------------------------------------------------- LIBRARY ieee; USE ieee.std_logic_1164.all; use ieee.numeric_std.all; use IEEE.STD_LOGIC_MISC.all; ENTITY pokey_mixer_mux IS PORT ( CLK : IN STD_LOGIC; ENABLE_179 : IN STD_LOGIC; CHANNEL_L_0 : IN STD_LOGIC_VECTOR(3 downto 0); CHANNEL_L_1 : IN STD_LOGIC_VECTOR(3 downto 0); CHANNEL_L_2 : IN STD_LOGIC_VECTOR(3 downto 0); CHANNEL_L_3 : IN STD_LOGIC_VECTOR(3 downto 0); CHANNEL_R_0 : IN STD_LOGIC_VECTOR(3 downto 0); CHANNEL_R_1 : IN STD_LOGIC_VECTOR(3 downto 0); CHANNEL_R_2 : IN STD_LOGIC_VECTOR(3 downto 0); CHANNEL_R_3 : IN STD_LOGIC_VECTOR(3 downto 0); VOLUME_OUT_M : OUT STD_LOGIC_vector(15 downto 0); VOLUME_OUT_L : OUT STD_LOGIC_vector(15 downto 0); VOLUME_OUT_R : OUT STD_LOGIC_vector(15 downto 0) ); END pokey_mixer_mux; ARCHITECTURE vhdl OF pokey_mixer_mux IS signal CHANNEL_NEXT : STD_LOGIC_VECTOR(2 downto 0); signal CHANNEL_REG : STD_LOGIC_VECTOR(2 downto 0) := "100"; -- 100->left -- 010->right -- 001->both! signal CHANNEL_0_SEL : STD_LOGIC_VECTOR(3 downto 0); signal CHANNEL_1_SEL : STD_LOGIC_VECTOR(3 downto 0); signal CHANNEL_2_SEL : STD_LOGIC_VECTOR(3 downto 0); signal CHANNEL_3_SEL : STD_LOGIC_VECTOR(3 downto 0); signal VOLUME_OUT_NEXT : STD_LOGIC_VECTOR(15 downto 0); signal VOLUME_OUT_L_NEXT : STD_LOGIC_VECTOR(15 downto 0); signal VOLUME_OUT_L_REG : STD_LOGIC_VECTOR(15 downto 0); signal VOLUME_OUT_R_NEXT : STD_LOGIC_VECTOR(15 downto 0); signal VOLUME_OUT_R_REG : STD_LOGIC_VECTOR(15 downto 0); signal VOLUME_OUT_M_NEXT : STD_LOGIC_VECTOR(15 downto 0); signal VOLUME_OUT_M_REG : STD_LOGIC_VECTOR(15 downto 0); signal VOLUME_POSTLOWPASS_L_REG : STD_LOGIC_VECTOR(15 downto 0); signal VOLUME_POSTLOWPASS_R_REG : STD_LOGIC_VECTOR(15 downto 0); signal VOLUME_POSTLOWPASS_M_REG : STD_LOGIC_VECTOR(15 downto 0); signal channel_sum : std_logic_vector(6 downto 0); BEGIN process(clk) begin if (clk'event and clk='1') then CHANNEL_REG <= CHANNEL_NEXT; CHANNEL_REG <= CHANNEL_NEXT; VOLUME_OUT_L_REG <= VOLUME_OUT_L_NEXT; VOLUME_OUT_R_REG <= VOLUME_OUT_R_NEXT; VOLUME_OUT_M_REG <= VOLUME_OUT_M_NEXT; END IF; END PROCESS; -- takes a few cycles for each channel CHANNEL_NEXT(1 downto 0) <= CHANNEL_REG(2 downto 1); CHANNEL_NEXT(2) <= CHANNEL_REG(0); CHANNEL_NEXT(1 downto 0) <= CHANNEL_REG(2 downto 1); CHANNEL_NEXT(2) <= CHANNEL_REG(0); -- mux input PROCESS( CHANNEL_L_0, CHANNEL_L_1, CHANNEL_L_2, CHANNEL_L_3, CHANNEL_R_0, CHANNEL_R_1, CHANNEL_R_2, CHANNEL_R_3, channel_reg ) variable left_sum : unsigned(6 downto 0); variable right_sum : unsigned(6 downto 0); variable both_sum : unsigned(6 downto 0); BEGIN channel_sum <= (OTHERS=>'0'); left_sum := (resize(unsigned(CHANNEL_L_0),7) + resize(unsigned(CHANNEL_L_1),7)) + (resize(unsigned(CHANNEL_L_2),7) + resize(unsigned(CHANNEL_L_3),7)); right_sum := (resize(unsigned(CHANNEL_R_0),7) + resize(unsigned(CHANNEL_R_1),7)) + (resize(unsigned(CHANNEL_R_2),7) + resize(unsigned(CHANNEL_R_3),7)); both_sum := left_sum + right_sum; if (both_sum(6)='1') then both_sum(5 downto 0) := (others=>'1'); end if; case channel_reg is when "100" => -- left channel_sum <= std_logic_vector(left_sum); when "010" => -- right channel_sum <= std_logic_vector(right_sum); when others => -- both channel_sum <= std_logic_vector(both_sum); end case; END PROCESS; -- shared mixer shared_pokey_mixer : entity work.pokey_mixer port map ( CLK => CLK, -- takes 2 cycle... sum => channel_sum, VOLUME_OUT_NEXT => VOLUME_OUT_NEXT ); -- mux output PROCESS( VOLUME_OUT_NEXT, VOLUME_OUT_L_REG, VOLUME_OUT_R_REG, VOLUME_OUT_M_REG, CHANNEL_REG) BEGIN VOLUME_OUT_L_NEXT <= VOLUME_OUT_L_REG; VOLUME_OUT_R_NEXT <= VOLUME_OUT_R_REG; VOLUME_OUT_M_NEXT <= VOLUME_OUT_M_REG; case channel_reg is when "010" => -- left VOLUME_OUT_L_NEXT <= VOLUME_OUT_NEXT; when "001" => -- right VOLUME_OUT_R_NEXT <= VOLUME_OUT_NEXT; when others => -- both VOLUME_OUT_M_NEXT <= VOLUME_OUT_NEXT; end case; END PROCESS; -- low pass filter output filter_left : entity work.simple_low_pass_filter port map ( CLK => CLK, AUDIO_IN => VOLUME_OUT_L_REG, SAMPLE_IN => ENABLE_179, AUDIO_OUT => VOLUME_POSTLOWPASS_L_REG ); filter_right : entity work.simple_low_pass_filter port map ( CLK => CLK, AUDIO_IN => VOLUME_OUT_R_REG, SAMPLE_IN => ENABLE_179, AUDIO_OUT => VOLUME_POSTLOWPASS_R_REG ); filter_both : entity work.simple_low_pass_filter port map ( CLK => CLK, AUDIO_IN => VOLUME_OUT_M_REG, SAMPLE_IN => ENABLE_179, AUDIO_OUT => VOLUME_POSTLOWPASS_M_REG ); -- output VOLUME_OUT_L <= VOLUME_POSTLOWPASS_L_REG; VOLUME_OUT_R <= VOLUME_POSTLOWPASS_R_REG; VOLUME_OUT_M <= VOLUME_POSTLOWPASS_M_REG; END vhdl;