|
---------------------------------------------------------------------------
|
|
-- (c) 2020 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;
|
|
RESET_N : IN STD_LOGIC;
|
|
|
|
CHANNEL_0 : IN unsigned(5 downto 0);
|
|
CHANNEL_1 : IN unsigned(5 downto 0);
|
|
CHANNEL_2 : IN unsigned(5 downto 0);
|
|
CHANNEL_3 : IN unsigned(5 downto 0);
|
|
|
|
VOLUME_OUT_0 : OUT unsigned(15 downto 0);
|
|
VOLUME_OUT_1 : OUT unsigned(15 downto 0);
|
|
VOLUME_OUT_2 : OUT unsigned(15 downto 0);
|
|
VOLUME_OUT_3 : OUT unsigned(15 downto 0);
|
|
|
|
PROFILE_ADDR : OUT std_logic_vector(5 downto 0);
|
|
PROFILE_REQUEST : OUT std_logic;
|
|
PROFILE_READY : IN std_logic;
|
|
PROFILE_DATA : IN std_logic_vector(15 downto 0)
|
|
);
|
|
END pokey_mixer_mux;
|
|
|
|
ARCHITECTURE vhdl OF pokey_mixer_mux IS
|
|
signal CHANNEL_STATE_NEXT : STD_LOGIC_VECTOR(2 downto 0);
|
|
signal CHANNEL_STATE_REG : STD_LOGIC_VECTOR(2 downto 0);
|
|
constant CHANNEL_STATE_WAIT0 : STD_LOGIC_VECTOR(2 downto 0) := "000";
|
|
constant CHANNEL_STATE_WAIT1 : STD_LOGIC_VECTOR(2 downto 0) := "001";
|
|
constant CHANNEL_STATE_WAIT2 : STD_LOGIC_VECTOR(2 downto 0) := "010";
|
|
constant CHANNEL_STATE_WAIT3 : STD_LOGIC_VECTOR(2 downto 0) := "011";
|
|
constant CHANNEL_STATE_REQUEST0 : STD_LOGIC_VECTOR(2 downto 0) := "100";
|
|
constant CHANNEL_STATE_REQUEST1 : STD_LOGIC_VECTOR(2 downto 0) := "101";
|
|
constant CHANNEL_STATE_REQUEST2 : STD_LOGIC_VECTOR(2 downto 0) := "110";
|
|
constant CHANNEL_STATE_REQUEST3 : STD_LOGIC_VECTOR(2 downto 0) := "111";
|
|
|
|
signal CHANNEL_DIRTY_NEXT : STD_LOGIC_VECTOR(3 downto 0);
|
|
signal CHANNEL_DIRTY_REG : STD_LOGIC_VECTOR(3 downto 0);
|
|
signal CHANNEL_CHANGED : STD_LOGIC_VECTOR(3 downto 0);
|
|
|
|
signal CHANNEL_IN_0_NEXT : unsigned(5 downto 0);
|
|
signal CHANNEL_IN_0_REG : unsigned(5 downto 0);
|
|
signal CHANNEL_IN_1_NEXT : unsigned(5 downto 0);
|
|
signal CHANNEL_IN_1_REG : unsigned(5 downto 0);
|
|
signal CHANNEL_IN_2_NEXT : unsigned(5 downto 0);
|
|
signal CHANNEL_IN_2_REG : unsigned(5 downto 0);
|
|
signal CHANNEL_IN_3_NEXT : unsigned(5 downto 0);
|
|
signal CHANNEL_IN_3_REG : unsigned(5 downto 0);
|
|
|
|
signal VOLUME_OUT_0_NEXT : unsigned(15 downto 0);
|
|
signal VOLUME_OUT_0_REG : unsigned(15 downto 0);
|
|
signal VOLUME_OUT_1_NEXT : unsigned(15 downto 0);
|
|
signal VOLUME_OUT_1_REG : unsigned(15 downto 0);
|
|
signal VOLUME_OUT_2_NEXT : unsigned(15 downto 0);
|
|
signal VOLUME_OUT_2_REG : unsigned(15 downto 0);
|
|
signal VOLUME_OUT_3_NEXT : unsigned(15 downto 0);
|
|
signal VOLUME_OUT_3_REG : unsigned(15 downto 0);
|
|
|
|
signal CHANNEL_MUX : STD_LOGIC_VECTOR(1 downto 0);
|
|
signal CHANNEL_SUM_OUT : unsigned(5 downto 0);
|
|
BEGIN
|
|
|
|
process(clk,reset_n)
|
|
begin
|
|
if (reset_n='0') then
|
|
CHANNEL_STATE_REG <= CHANNEL_STATE_WAIT0;
|
|
CHANNEL_DIRTY_REG <= (others=>'1');
|
|
|
|
CHANNEL_IN_0_REG <= (others=>'0');
|
|
CHANNEL_IN_1_REG <= (others=>'0');
|
|
CHANNEL_IN_2_REG <= (others=>'0');
|
|
CHANNEL_IN_3_REG <= (others=>'0');
|
|
|
|
VOLUME_OUT_0_REG <= (others=>'0');
|
|
VOLUME_OUT_1_REG <= (others=>'0');
|
|
VOLUME_OUT_2_REG <= (others=>'0');
|
|
VOLUME_OUT_3_REG <= (others=>'0');
|
|
elsif (clk'event and clk='1') then
|
|
CHANNEL_STATE_REG <= CHANNEL_STATE_NEXT;
|
|
CHANNEL_DIRTY_REG <= CHANNEL_DIRTY_NEXT;
|
|
|
|
CHANNEL_IN_0_REG <= CHANNEL_IN_0_NEXT;
|
|
CHANNEL_IN_1_REG <= CHANNEL_IN_1_NEXT;
|
|
CHANNEL_IN_2_REG <= CHANNEL_IN_2_NEXT;
|
|
CHANNEL_IN_3_REG <= CHANNEL_IN_3_NEXT;
|
|
|
|
VOLUME_OUT_0_REG <= VOLUME_OUT_0_NEXT;
|
|
VOLUME_OUT_1_REG <= VOLUME_OUT_1_NEXT;
|
|
VOLUME_OUT_2_REG <= VOLUME_OUT_2_NEXT;
|
|
VOLUME_OUT_3_REG <= VOLUME_OUT_3_NEXT;
|
|
END IF;
|
|
END PROCESS;
|
|
|
|
-- takes a few cycles for each channel
|
|
process(
|
|
CHANNEL_IN_0_REG,CHANNEL_IN_1_REG,CHANNEL_IN_2_REG,CHANNEL_IN_3_REG,
|
|
CHANNEL_0,CHANNEL_1,CHANNEL_2,CHANNEL_3
|
|
)
|
|
begin
|
|
CHANNEL_IN_0_NEXT <= CHANNEL_0;
|
|
CHANNEL_IN_1_NEXT <= CHANNEL_1;
|
|
CHANNEL_IN_2_NEXT <= CHANNEL_2;
|
|
CHANNEL_IN_3_NEXT <= CHANNEL_3;
|
|
|
|
CHANNEL_CHANGED(0) <= '0';
|
|
if (CHANNEL_0 /= CHANNEL_IN_0_REG) then
|
|
CHANNEL_CHANGED(0) <= '1';
|
|
end if;
|
|
CHANNEL_CHANGED(1) <= '0';
|
|
if (CHANNEL_1 /= CHANNEL_IN_1_REG) then
|
|
CHANNEL_CHANGED(1) <= '1';
|
|
end if;
|
|
CHANNEL_CHANGED(2) <= '0';
|
|
if (CHANNEL_2 /= CHANNEL_IN_2_REG) then
|
|
CHANNEL_CHANGED(2) <= '1';
|
|
end if;
|
|
CHANNEL_CHANGED(3) <= '0';
|
|
if (CHANNEL_3 /= CHANNEL_IN_3_REG) then
|
|
CHANNEL_CHANGED(3) <= '1';
|
|
end if;
|
|
end process;
|
|
|
|
process(channel_state_reg,profile_ready,CHANNEL_DIRTY_REG,CHANNEL_CHANGED)
|
|
begin
|
|
CHANNEL_STATE_NEXT <= CHANNEL_STATE_REG;
|
|
CHANNEL_DIRTY_NEXT <= CHANNEL_DIRTY_REG or channel_changed;
|
|
|
|
CHANNEL_MUX <= (others=>'0');
|
|
PROFILE_REQUEST <= '0';
|
|
|
|
case CHANNEL_STATE_REG is
|
|
when CHANNEL_STATE_WAIT0 =>
|
|
if (CHANNEL_DIRTY_REG(0)='1') then
|
|
CHANNEL_STATE_NEXT <= CHANNEL_STATE_REQUEST0;
|
|
else
|
|
CHANNEL_STATE_NEXT <= CHANNEL_STATE_WAIT1;
|
|
end if;
|
|
when CHANNEL_STATE_WAIT1 =>
|
|
if (CHANNEL_DIRTY_REG(1)='1') then
|
|
CHANNEL_STATE_NEXT <= CHANNEL_STATE_REQUEST1;
|
|
else
|
|
CHANNEL_STATE_NEXT <= CHANNEL_STATE_WAIT2;
|
|
end if;
|
|
when CHANNEL_STATE_WAIT2 =>
|
|
if (CHANNEL_DIRTY_REG(2)='1') then
|
|
CHANNEL_STATE_NEXT <= CHANNEL_STATE_REQUEST2;
|
|
else
|
|
CHANNEL_STATE_NEXT <= CHANNEL_STATE_WAIT3;
|
|
end if;
|
|
when CHANNEL_STATE_WAIT3 =>
|
|
if (CHANNEL_DIRTY_REG(3)='1') then
|
|
CHANNEL_STATE_NEXT <= CHANNEL_STATE_REQUEST3;
|
|
else
|
|
CHANNEL_STATE_NEXT <= CHANNEL_STATE_WAIT0;
|
|
end if;
|
|
when CHANNEL_STATE_REQUEST0 =>
|
|
CHANNEL_MUX <= "00";
|
|
PROFILE_REQUEST <= '1';
|
|
CHANNEL_DIRTY_NEXT(0) <= not(profile_ready);
|
|
if (profile_ready='1') then
|
|
CHANNEL_STATE_NEXT <= CHANNEL_STATE_WAIT1;
|
|
end if;
|
|
when CHANNEL_STATE_REQUEST1 =>
|
|
CHANNEL_MUX <= "01";
|
|
PROFILE_REQUEST <= '1';
|
|
CHANNEL_DIRTY_NEXT(1) <= not(profile_ready);
|
|
if (profile_ready='1') then
|
|
CHANNEL_STATE_NEXT <= CHANNEL_STATE_WAIT2;
|
|
end if;
|
|
when CHANNEL_STATE_REQUEST2 =>
|
|
CHANNEL_MUX <= "10";
|
|
PROFILE_REQUEST <= '1';
|
|
CHANNEL_DIRTY_NEXT(2) <= not(profile_ready);
|
|
if (profile_ready='1') then
|
|
CHANNEL_STATE_NEXT <= CHANNEL_STATE_WAIT3;
|
|
end if;
|
|
when CHANNEL_STATE_REQUEST3 =>
|
|
CHANNEL_MUX <= "11";
|
|
PROFILE_REQUEST <= '1';
|
|
CHANNEL_DIRTY_NEXT(3) <= not(profile_ready);
|
|
if (profile_ready='1') then
|
|
CHANNEL_STATE_NEXT <= CHANNEL_STATE_WAIT0;
|
|
end if;
|
|
when OTHERS =>
|
|
CHANNEL_STATE_NEXT <= CHANNEL_STATE_WAIT0;
|
|
end case;
|
|
end process;
|
|
|
|
-- mux input
|
|
PROCESS(
|
|
CHANNEL_0,CHANNEL_1,CHANNEL_2,CHANNEL_3,
|
|
CHANNEL_MUX
|
|
)
|
|
variable channel_sum : unsigned(5 downto 0);
|
|
BEGIN
|
|
channel_sum := (OTHERS=>'0');
|
|
|
|
case channel_mux is
|
|
when "00" => -- 0
|
|
channel_sum := CHANNEL_0;
|
|
when "01" => -- 1
|
|
channel_sum := CHANNEL_1;
|
|
when "10" => -- 2
|
|
channel_sum := CHANNEL_2;
|
|
--when "0000001" => -- 3
|
|
when others =>
|
|
channel_sum := CHANNEL_3;
|
|
end case;
|
|
|
|
channel_sum_out <= channel_sum;
|
|
|
|
END PROCESS;
|
|
|
|
-- shared mixer
|
|
--shared_pokey_mixer : entity work.pokey_mixer
|
|
-- port map
|
|
-- (
|
|
-- sum => channel_sum_out,
|
|
--
|
|
-- saturate => saturate,
|
|
--
|
|
-- VOLUME_OUT_NEXT => VOLUME_OUT_NEXT
|
|
-- );
|
|
|
|
-- mux output
|
|
PROCESS(
|
|
PROFILE_DATA,
|
|
PROFILE_READY,
|
|
VOLUME_OUT_0_REG,
|
|
VOLUME_OUT_1_REG,
|
|
VOLUME_OUT_2_REG,
|
|
VOLUME_OUT_3_REG,
|
|
CHANNEL_MUX
|
|
)
|
|
BEGIN
|
|
VOLUME_OUT_0_NEXT <= VOLUME_OUT_0_REG;
|
|
VOLUME_OUT_1_NEXT <= VOLUME_OUT_1_REG;
|
|
VOLUME_OUT_2_NEXT <= VOLUME_OUT_2_REG;
|
|
VOLUME_OUT_3_NEXT <= VOLUME_OUT_3_REG;
|
|
|
|
if (profile_ready='1') then
|
|
case channel_mux is
|
|
when "00" => -- 0
|
|
VOLUME_OUT_0_NEXT <= unsigned(PROFILE_DATA);
|
|
when "01" => -- 1
|
|
VOLUME_OUT_1_NEXT <= unsigned(PROFILE_DATA);
|
|
when "10" => -- 2
|
|
VOLUME_OUT_2_NEXT <= unsigned(PROFILE_DATA);
|
|
when others=> -- 3
|
|
VOLUME_OUT_3_NEXT <= unsigned(PROFILE_DATA);
|
|
end case;
|
|
end if;
|
|
END PROCESS;
|
|
|
|
-- output
|
|
VOLUME_OUT_0 <= VOLUME_OUT_0_REG;
|
|
VOLUME_OUT_1 <= VOLUME_OUT_1_REG;
|
|
VOLUME_OUT_2 <= VOLUME_OUT_2_REG;
|
|
VOLUME_OUT_3 <= VOLUME_OUT_3_REG;
|
|
|
|
PROFILE_ADDR <= std_logic_vector(CHANNEL_SUM_OUT);
|
|
END vhdl;
|
|
|