--------------------------------------------------------------------------- -- (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 sample_adpcm IS PORT ( CLK : IN STD_LOGIC; RESET_N : IN STD_LOGIC; SYNCRESET : IN STD_LOGIC_VECTOR(3 downto 0); -- reset accumulator/step for next update select_channel : out std_logic_vector(1 downto 0); -- ask for current data for this channel store : OUT std_logic; data_out : OUT std_logic_vector(15 downto 0); -- current output dirty : IN STD_LOGIC_VECTOR(3 downto 0); -- channel needs updating data_request : out std_logic; data_ready : in std_logic; data_in : in std_logic_vector(3 downto 0); STEP_ADDR : out std_logic_vector(6 downto 0); -- ask for step value STEP_REQUEST : out std_logic; STEP_READY : in std_logic; STEP_VALUE : in std_logic_vector(14 downto 0) ); END sample_adpcm; ARCHITECTURE vhdl OF sample_adpcm IS function stepadj_fn(x: std_logic_vector(2 downto 0)) return signed is begin case x is when "000" => return to_signed(-1,5); when "001" => return to_signed(-1,5); when "010" => return to_signed(-1,5); when "011" => return to_signed(-1,5); when "100" => return to_signed(2,5); when "101" => return to_signed(4,5); when "110" => return to_signed(6,5); when "111" => return to_signed(8,5); end case; end stepadj_fn; signal acc0_reg : signed(15 downto 0); signal acc0_next : signed(15 downto 0); signal acc1_reg : signed(15 downto 0); signal acc1_next : signed(15 downto 0); signal acc2_reg : signed(15 downto 0); signal acc2_next : signed(15 downto 0); signal acc3_reg : signed(15 downto 0); signal acc3_next : signed(15 downto 0); signal acc_next : signed(15 downto 0); signal acc_mux : signed(15 downto 0); signal decstep0_reg : unsigned(6 downto 0); signal decstep0_next : unsigned(6 downto 0); signal decstep1_reg : unsigned(6 downto 0); signal decstep1_next : unsigned(6 downto 0); signal decstep2_reg : unsigned(6 downto 0); signal decstep2_next : unsigned(6 downto 0); signal decstep3_reg : unsigned(6 downto 0); signal decstep3_next : unsigned(6 downto 0); signal decstep_next : unsigned(6 downto 0); signal decstep_mux : unsigned(6 downto 0); signal write_ch0 : std_logic; signal write_ch1 : std_logic; signal write_ch2 : std_logic; signal write_ch3 : std_logic; signal sel : std_logic_vector(1 downto 0); signal syncreset_next : std_logic_vector(3 downto 0); signal syncreset_reg : std_logic_vector(3 downto 0); signal dirty_reg : std_logic_vector(3 downto 0); signal dirty_next : std_logic_vector(3 downto 0); signal code_reg : std_logic_vector(3 downto 0); signal code_next : std_logic_vector(3 downto 0); signal state_reg : std_logic_vector(2 downto 0); signal state_next: std_logic_vector(2 downto 0); constant state_ch0_mem_req : std_logic_vector(2 downto 0) := "000"; constant state_ch0_step_req : std_logic_vector(2 downto 0) := "001"; constant state_ch1_mem_req : std_logic_vector(2 downto 0) := "010"; constant state_ch1_step_req : std_logic_vector(2 downto 0) := "011"; constant state_ch2_mem_req : std_logic_vector(2 downto 0) := "100"; constant state_ch2_step_req : std_logic_vector(2 downto 0) := "101"; constant state_ch3_mem_req : std_logic_vector(2 downto 0) := "110"; constant state_ch3_step_req : std_logic_vector(2 downto 0) := "111"; BEGIN -- register process(clk,reset_n) begin if (reset_n='0') then acc0_reg <= (others=>'0'); acc1_reg <= (others=>'0'); acc2_reg <= (others=>'0'); acc3_reg <= (others=>'0'); decstep0_reg <= (others=>'0'); decstep1_reg <= (others=>'0'); decstep2_reg <= (others=>'0'); decstep3_reg <= (others=>'0'); syncreset_reg <= (others=>'0'); dirty_reg <= (others=>'0'); code_reg <= (others=>'0'); state_reg <= state_ch0_mem_req; elsif (clk'event and clk='1') then acc0_reg <= acc0_next; acc1_reg <= acc1_next; acc2_reg <= acc2_next; acc3_reg <= acc3_next; decstep0_reg <= decstep0_next; decstep1_reg <= decstep1_next; decstep2_reg <= decstep2_next; decstep3_reg <= decstep3_next; syncreset_reg <= syncreset_next; dirty_reg <= dirty_next; code_reg <= code_next; state_reg <= state_next; end if; end process; process(state_reg, dirty, dirty_reg, code_reg, data_in, data_ready, step_ready) begin code_next <= code_reg; dirty_next <= dirty_reg or dirty; state_next <= state_reg; data_request <= '0'; step_request <= '0'; sel <= (others=>'0'); write_ch0 <= '0'; write_ch1 <= '0'; write_ch2 <= '0'; write_ch3 <= '0'; store <= step_ready; if (data_ready='1') then code_next <= data_in; end if; case state_reg is when state_ch0_mem_req => sel <= "00"; data_request <= dirty_reg(0); if (data_ready='1') then code_next <= data_in; state_next <= state_ch0_step_req; end if; if (dirty_reg(0)='0') then state_next <= state_ch1_mem_req; end if; when state_ch0_step_req => step_request <= '1'; sel <= "00"; write_ch0 <= step_ready; if (step_ready='1') then state_next <= state_ch1_mem_req; dirty_next(0) <= '0'; end if; when state_ch1_mem_req => sel <= "01"; data_request <= dirty_reg(1); if (data_ready='1') then code_next <= data_in; state_next <= state_ch1_step_req; end if; if (dirty_reg(1)='0') then state_next <= state_ch2_mem_req; end if; when state_ch1_step_req => step_request <= '1'; sel <= "01"; write_ch1 <= step_ready; if (step_ready='1') then state_next <= state_ch2_mem_req; dirty_next(1) <= '0'; end if; when state_ch2_mem_req => sel <= "10"; data_request <= dirty_reg(2); if (data_ready='1') then code_next <= data_in; state_next <= state_ch2_step_req; end if; if (dirty_reg(2)='0') then state_next <= state_ch3_mem_req; end if; when state_ch2_step_req => step_request <= '1'; sel <= "10"; write_ch2 <= step_ready; if (step_ready='1') then state_next <= state_ch3_mem_req; dirty_next(2) <= '0'; end if; when state_ch3_mem_req => sel <= "11"; data_request <= dirty_reg(3); if (data_ready='1') then code_next <= data_in; state_next <= state_ch3_step_req; end if; if (dirty_reg(3)='0') then state_next <= state_ch0_mem_req; end if; when state_ch3_step_req => step_request <= '1'; sel <= "11"; write_ch3 <= step_ready; if (step_ready='1') then state_next <= state_ch0_mem_req; dirty_next(3) <= '0'; end if; when others => state_next <= state_ch0_mem_req; end case; end process; process(acc0_reg, acc1_reg, acc2_reg, acc3_reg, decstep0_reg, decstep1_reg, decstep2_reg, decstep3_reg, acc_next, decstep_next, write_ch0,write_ch1,write_ch2,write_ch3) begin acc0_next <= acc0_reg; acc1_next <= acc1_reg; acc2_next <= acc2_reg; acc3_next <= acc3_reg; decstep0_next <= decstep0_reg; decstep1_next <= decstep1_reg; decstep2_next <= decstep2_reg; decstep3_next <= decstep3_reg; if (write_ch0='1') then acc0_next <= acc_next; decstep0_next <= decstep_next; end if; if (write_ch1='1') then acc1_next <= acc_next; decstep1_next <= decstep_next; end if; if (write_ch2='1') then acc2_next <= acc_next; decstep2_next <= decstep_next; end if; if (write_ch3='1') then acc3_next <= acc_next; decstep3_next <= decstep_next; end if; end process; process(sel,syncreset_reg, syncreset, step_ready, acc0_reg, acc1_reg, acc2_reg, acc3_reg, decstep0_reg, decstep1_reg, decstep2_reg, decstep3_reg ) variable rst : std_logic; begin acc_mux <= (others=>'0'); decstep_mux <= (others=>'0'); syncreset_next <= (syncreset or syncreset_reg); rst := '0'; case sel is when "00" => acc_mux <= acc0_reg; decstep_mux <= decstep0_reg; rst := syncreset_reg(0) or syncreset(0); syncreset_next(0) <= (syncreset_reg(0) or syncreset(0)) and not(step_ready); when "01" => acc_mux <= acc1_reg; decstep_mux <= decstep1_reg; rst := syncreset_reg(1) or syncreset(1); syncreset_next(1) <= (syncreset_reg(1) or syncreset(1)) and not(step_ready); when "10" => acc_mux <= acc2_reg; decstep_mux <= decstep2_reg; rst := syncreset_reg(2) or syncreset(2); syncreset_next(2) <= (syncreset_reg(2) or syncreset(2)) and not(step_ready); when "11" => acc_mux <= acc3_reg; decstep_mux <= decstep3_reg; rst := syncreset_reg(3) or syncreset(3); syncreset_next(3) <= (syncreset_reg(3) or syncreset(3)) and not(step_ready); when others => end case; if (rst='1') then acc_mux <= (others=>'0'); decstep_mux <= (others=>'0'); end if; end process; process(acc_mux,decstep_mux, code_reg, step_value) variable code : std_logic_vector(3 downto 0); variable codeadj : signed(8 downto 0); variable stepsize : signed(17 downto 0); variable vlue : signed(26 downto 0); variable vlue8 : signed(16 downto 0); variable decstepnext : signed(7 downto 0); variable acc_sum : signed(16 downto 0); variable oflow : boolean; begin acc_next <= acc_mux; decstep_next <= decstep_mux; codeadj:= (others=>'0'); codeadj := resize(signed('0'&code_reg(2 downto 0)),8)&"1"; stepsize := resize(signed('0'&step_value),18); vlue :=codeadj*stepsize; if (code_reg(3)='0') then vlue8 := vlue(19 downto 3); else vlue8 := -vlue(19 downto 3); end if; acc_sum := resize(acc_mux,17) + vlue8; oflow := acc_sum(16)/=acc_sum(15); if (oflow) then acc_next <= resize(acc_sum(16 downto 16),16); else acc_next <= acc_sum(15 downto 0); end if; decstepnext := resize(stepadj_fn(code_reg(2 downto 0)),8) + signed(resize(decstep_mux,8)); if (decstepnext>88) then decstepnext := to_signed(88,8); elsif (decstepnext<0) then decstepnext := to_signed(0,8); end if; decstep_next <= unsigned(decstepnext(6 downto 0)); end process; data_out(15) <= not(acc_mux(15)); data_out(14 downto 0) <= std_logic_vector(acc_mux(14 downto 0)); select_channel <= sel; step_addr <= std_logic_vector(decstep_mux); end vhdl;