Project

General

Profile

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

(1-1/3)