Project

General

Profile

1155 markw
---------------------------------------------------------------------------
-- (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;

1167 markw
SYNCRESET : IN STD_LOGIC_VECTOR(3 downto 0); -- reset accumulator/step for next update
1159 markw
1167 markw
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;
1169 markw
STEP_VALUE : in std_logic_vector(14 downto 0)
1155 markw
);
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
1164 markw
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);
1155 markw
end case;
end stepadj_fn;

1163 markw
signal acc0_reg : signed(15 downto 0);
signal acc0_next : signed(15 downto 0);
1155 markw
1163 markw
signal acc1_reg : signed(15 downto 0);
signal acc1_next : signed(15 downto 0);
1155 markw
1163 markw
signal acc2_reg : signed(15 downto 0);
signal acc2_next : signed(15 downto 0);
1155 markw
1163 markw
signal acc3_reg : signed(15 downto 0);
signal acc3_next : signed(15 downto 0);
1155 markw
1163 markw
signal acc_next : signed(15 downto 0);
signal acc_mux : signed(15 downto 0);
1155 markw
1164 markw
signal decstep0_reg : unsigned(6 downto 0);
signal decstep0_next : unsigned(6 downto 0);
1155 markw
1164 markw
signal decstep1_reg : unsigned(6 downto 0);
signal decstep1_next : unsigned(6 downto 0);
1155 markw
1164 markw
signal decstep2_reg : unsigned(6 downto 0);
signal decstep2_next : unsigned(6 downto 0);
1155 markw
1164 markw
signal decstep3_reg : unsigned(6 downto 0);
signal decstep3_next : unsigned(6 downto 0);
1155 markw
1164 markw
signal decstep_next : unsigned(6 downto 0);
signal decstep_mux : unsigned(6 downto 0);
1155 markw
1158 markw
signal write_ch0 : std_logic;
signal write_ch1 : std_logic;
signal write_ch2 : std_logic;
signal write_ch3 : std_logic;
1155 markw
1167 markw
signal sel : std_logic_vector(1 downto 0);
1159 markw
signal syncreset_next : std_logic_vector(3 downto 0);
signal syncreset_reg : std_logic_vector(3 downto 0);
1167 markw
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);

1283 markw
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";
1155 markw
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');
1159 markw
syncreset_reg <= (others=>'0');
1167 markw
dirty_reg <= (others=>'0');
code_reg <= (others=>'0');
state_reg <= state_ch0_mem_req;
1155 markw
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;
1159 markw
syncreset_reg <= syncreset_next;
1167 markw
dirty_reg <= dirty_next;
code_reg <= code_next;
state_reg <= state_next;
1155 markw
end if;
end process;

1169 markw
process(state_reg, dirty, dirty_reg, code_reg, data_in, data_ready, step_ready)
1167 markw
begin
code_next <= code_reg;
dirty_next <= dirty_reg or dirty;
state_next <= state_reg;

1174 markw
data_request <= '0';
1167 markw
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;

1155 markw
process(acc0_reg, acc1_reg, acc2_reg, acc3_reg,
decstep0_reg, decstep1_reg, decstep2_reg, decstep3_reg,
1158 markw
acc_next, decstep_next,
write_ch0,write_ch1,write_ch2,write_ch3)
1155 markw
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;
1158 markw
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;
1155 markw
1158 markw
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;
1155 markw
end process;

1167 markw
process(sel,syncreset_reg, syncreset, step_ready,
1155 markw
acc0_reg, acc1_reg, acc2_reg, acc3_reg,
1167 markw
decstep0_reg, decstep1_reg, decstep2_reg, decstep3_reg
1155 markw
)
1171 markw
variable rst : std_logic;
1155 markw
begin
acc_mux <= (others=>'0');
decstep_mux <= (others=>'0');
1159 markw
1167 markw
syncreset_next <= (syncreset or syncreset_reg);
1171 markw
rst := '0';
1159 markw
1158 markw
case sel is
1167 markw
when "00" =>
1155 markw
acc_mux <= acc0_reg;
decstep_mux <= decstep0_reg;
1171 markw
rst := syncreset_reg(0) or syncreset(0);
1167 markw
syncreset_next(0) <= (syncreset_reg(0) or syncreset(0)) and not(step_ready);
when "01" =>
1155 markw
acc_mux <= acc1_reg;
decstep_mux <= decstep1_reg;
1171 markw
rst := syncreset_reg(1) or syncreset(1);
1167 markw
syncreset_next(1) <= (syncreset_reg(1) or syncreset(1)) and not(step_ready);
when "10" =>
1155 markw
acc_mux <= acc2_reg;
1171 markw
decstep_mux <= decstep2_reg;
rst := syncreset_reg(2) or syncreset(2);
1167 markw
syncreset_next(2) <= (syncreset_reg(2) or syncreset(2)) and not(step_ready);
when "11" =>
1155 markw
acc_mux <= acc3_reg;
decstep_mux <= decstep3_reg;
1171 markw
rst := syncreset_reg(3) or syncreset(3);
1167 markw
syncreset_next(3) <= (syncreset_reg(3) or syncreset(3)) and not(step_ready);
1155 markw
when others =>
end case;
1158 markw
1171 markw
if (rst='1') then
1158 markw
acc_mux <= (others=>'0');
decstep_mux <= (others=>'0');
end if;
1155 markw
end process;

1158 markw
process(acc_mux,decstep_mux,
1167 markw
code_reg, step_value)
1155 markw
variable code : std_logic_vector(3 downto 0);
variable codeadj : signed(8 downto 0);
1160 markw
variable stepsize : signed(17 downto 0);
variable vlue : signed(26 downto 0);
1166 markw
variable vlue8 : signed(16 downto 0);
1164 markw
variable decstepnext : signed(7 downto 0);
1165 markw
variable acc_sum : signed(16 downto 0);
variable oflow : boolean;
1155 markw
begin
1156 markw
acc_next <= acc_mux;
decstep_next <= decstep_mux;
1158 markw
codeadj:= (others=>'0');
1164 markw
1167 markw
codeadj := resize(signed('0'&code_reg(2 downto 0)),8)&"1";
1158 markw
1167 markw
stepsize := resize(signed('0'&step_value),18);
1155 markw
1158 markw
vlue :=codeadj*stepsize;
1166 markw
1167 markw
if (code_reg(3)='0') then
1166 markw
vlue8 := vlue(19 downto 3);
else
vlue8 := -vlue(19 downto 3);
end if;

acc_sum := resize(acc_mux,17) + vlue8;
1165 markw
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;
1155 markw
1167 markw
decstepnext := resize(stepadj_fn(code_reg(2 downto 0)),8) + signed(resize(decstep_mux,8));
1164 markw
if (decstepnext>88) then
decstepnext := to_signed(88,8);
1158 markw
elsif (decstepnext<0) then
1164 markw
decstepnext := to_signed(0,8);
1155 markw
end if;
1164 markw
decstep_next <= unsigned(decstepnext(6 downto 0));
1155 markw
end process;

1163 markw
data_out(15) <= not(acc_mux(15));
data_out(14 downto 0) <= std_logic_vector(acc_mux(14 downto 0));
1167 markw
select_channel <= sel;
step_addr <= std_logic_vector(decstep_mux);
1155 markw
end vhdl;