repo2/atari_chips/pokeyv2/SID/envelope.vhdl @ 1476
1057 | 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;
|
|||
1062 | markw | use IEEE.STD_LOGIC_MISC.all;
|
|
1057 | markw | ||
1058 | markw | ENTITY SID_envelope IS
|
|
1057 | markw | PORT
|
|
(
|
|||
CLK : IN STD_LOGIC;
|
|||
RESET_N : IN STD_LOGIC;
|
|||
ENABLE : IN STD_LOGIC;
|
|||
1266 | markw | TAPMATCH : IN STD_LOGIC;
|
|
1057 | markw | ATTACK : IN STD_LOGIC_VECTOR(3 downto 0);
|
|
SUSTAIN : IN STD_LOGIC_VECTOR(3 downto 0);
|
|||
DECAY : IN STD_LOGIC_VECTOR(3 downto 0);
|
|||
RELEASE_IN : IN STD_LOGIC_VECTOR(3 downto 0);
|
|||
GATE : IN STD_LOGIC;
|
|||
1266 | markw | ENVELOPE : OUT STD_LOGIC_VECTOR(7 downto 0);
|
|
delay_lfsr : OUT std_logic_vector(14 downto 0);
|
|||
tapkey : OUT std_logic_vector(3 downto 0)
|
|||
1057 | markw | );
|
|
1058 | markw | END SID_envelope;
|
|
1057 | markw | ||
1058 | markw | ARCHITECTURE vhdl OF SID_envelope IS
|
|
1057 | markw | signal envelope_reg: unsigned(7 downto 0);
|
|
signal envelope_next:unsigned(7 downto 0);
|
|||
signal delay_lfsr_reg : std_logic_vector(14 downto 0);
|
|||
signal delay_lfsr_next : std_logic_vector(14 downto 0);
|
|||
signal expdelay_lfsr_reg : std_logic_vector(4 downto 0);
|
|||
signal expdelay_lfsr_next : std_logic_vector(4 downto 0);
|
|||
1062 | markw | signal exptapmatch_reg : std_logic_vector(2 downto 0);
|
|
signal exptapmatch_next : std_logic_vector(2 downto 0);
|
|||
1266 | markw | signal tapkey_next : std_logic_vector(3 downto 0);
|
|
signal tapkey_reg : std_logic_vector(3 downto 0);
|
|||
1324 | markw | signal tapkey_del1_next : std_logic_vector(3 downto 0);
|
|
signal tapkey_del1_reg : std_logic_vector(3 downto 0);
|
|||
signal tapkey_del2_next : std_logic_vector(3 downto 0);
|
|||
signal tapkey_del2_reg : std_logic_vector(3 downto 0);
|
|||
signal tapkey_del3_next : std_logic_vector(3 downto 0);
|
|||
signal tapkey_del3_reg : std_logic_vector(3 downto 0);
|
|||
1071 | markw | ||
1057 | markw | signal exptap : std_logic_vector(2 downto 0);
|
|
1284 | markw | signal exptapmatching : std_logic;
|
|
1057 | markw | ||
1283 | markw | signal state_reg : std_logic_vector(1 downto 0);
|
|
signal state_next : std_logic_vector(1 downto 0);
|
|||
constant state_attack : std_logic_vector(1 downto 0) := "00";
|
|||
constant state_decay : std_logic_vector(1 downto 0) := "10";
|
|||
constant state_release : std_logic_vector(1 downto 0) := "11";
|
|||
1057 | markw | ||
1283 | markw | signal count_state_reg : std_logic_vector(1 downto 0);
|
|
signal count_state_next : std_logic_vector(1 downto 0);
|
|||
constant count_state_up : std_logic_vector(1 downto 0) := "00";
|
|||
constant count_state_down : std_logic_vector(1 downto 0) := "10";
|
|||
constant count_state_stopped : std_logic_vector(1 downto 0) := "11";
|
|||
1077 | markw | ||
signal gate_changed : std_logic;
|
|||
signal hold_counter : std_logic;
|
|||
1324 | markw | signal gatedel : std_logic;
|
|
signal gateshift_reg : std_logic_vector(1 downto 0);
|
|||
signal gateshift_next : std_logic_vector(1 downto 0);
|
|||
signal r0_next : std_logic;
|
|||
signal r0_reg : std_logic;
|
|||
signal adrmux_next : std_logic_vector(1 downto 0);
|
|||
signal adrmux_reg : std_logic_vector(1 downto 0);
|
|||
signal adrmux_del1_next : std_logic_vector(1 downto 0);
|
|||
signal adrmux_del1_reg : std_logic_vector(1 downto 0);
|
|||
signal adrmux_del2_next : std_logic_vector(1 downto 0);
|
|||
signal adrmux_del2_reg : std_logic_vector(1 downto 0);
|
|||
signal attack_del1_reg : std_logic_vector(3 downto 0);
|
|||
signal attack_del2_reg : std_logic_vector(3 downto 0);
|
|||
signal attack_del3_reg : std_logic_vector(3 downto 0);
|
|||
signal attack_del1_next : std_logic_vector(3 downto 0);
|
|||
signal attack_del2_next : std_logic_vector(3 downto 0);
|
|||
signal attack_del3_next : std_logic_vector(3 downto 0);
|
|||
signal attack_delayed : std_logic_vector(3 downto 0);
|
|||
signal decay_del1_reg : std_logic_vector(3 downto 0);
|
|||
signal decay_del2_reg : std_logic_vector(3 downto 0);
|
|||
signal decay_del3_reg : std_logic_vector(3 downto 0);
|
|||
signal decay_del1_next : std_logic_vector(3 downto 0);
|
|||
signal decay_del2_next : std_logic_vector(3 downto 0);
|
|||
signal decay_del3_next : std_logic_vector(3 downto 0);
|
|||
signal decay_delayed : std_logic_vector(3 downto 0);
|
|||
signal release_del1_reg : std_logic_vector(3 downto 0);
|
|||
signal release_del2_reg : std_logic_vector(3 downto 0);
|
|||
signal release_del3_reg : std_logic_vector(3 downto 0);
|
|||
signal release_del1_next : std_logic_vector(3 downto 0);
|
|||
signal release_del2_next : std_logic_vector(3 downto 0);
|
|||
signal release_del3_next : std_logic_vector(3 downto 0);
|
|||
signal release_delayed : std_logic_vector(3 downto 0);
|
|||
signal sustain_del1_reg : std_logic_vector(3 downto 0);
|
|||
signal sustain_del2_reg : std_logic_vector(3 downto 0);
|
|||
signal sustain_del3_reg : std_logic_vector(3 downto 0);
|
|||
signal sustain_del1_next : std_logic_vector(3 downto 0);
|
|||
signal sustain_del2_next : std_logic_vector(3 downto 0);
|
|||
signal sustain_del3_next : std_logic_vector(3 downto 0);
|
|||
signal sustain_delayed : std_logic_vector(3 downto 0);
|
|||
1057 | markw | BEGIN
|
|
-- register
|
|||
process(clk, reset_n)
|
|||
begin
|
|||
if (reset_n = '0') then
|
|||
envelope_reg <= (others=>'0');
|
|||
delay_lfsr_reg <= (others=>'1');
|
|||
expdelay_lfsr_reg <= (others=>'1');
|
|||
1062 | markw | exptapmatch_reg <= (others=>'0');
|
|
1057 | markw | state_reg <= state_release;
|
|
1077 | markw | count_state_reg <= count_state_stopped;
|
|
1266 | markw | tapkey_reg <= (others=>'0');
|
|
1324 | markw | tapkey_del1_reg <= (others=>'0');
|
|
tapkey_del2_reg <= (others=>'0');
|
|||
tapkey_del3_reg <= (others=>'0');
|
|||
gateshift_reg <= (others=>'0');
|
|||
r0_reg <= '0';
|
|||
adrmux_reg <= (others=>'0');
|
|||
adrmux_del1_reg <= (others=>'0');
|
|||
adrmux_del2_reg <= (others=>'0');
|
|||
attack_del1_reg <= (others=>'0');
|
|||
attack_del2_reg <= (others=>'0');
|
|||
attack_del3_reg <= (others=>'0');
|
|||
decay_del1_reg <= (others=>'0');
|
|||
decay_del2_reg <= (others=>'0');
|
|||
decay_del3_reg <= (others=>'0');
|
|||
release_del1_reg <= (others=>'0');
|
|||
release_del2_reg <= (others=>'0');
|
|||
release_del3_reg <= (others=>'0');
|
|||
sustain_del1_reg <= (others=>'0');
|
|||
sustain_del2_reg <= (others=>'0');
|
|||
sustain_del3_reg <= (others=>'0');
|
|||
1057 | markw | elsif (clk'event and clk='1') then
|
|
envelope_reg <= envelope_next;
|
|||
delay_lfsr_reg <= delay_lfsr_next;
|
|||
expdelay_lfsr_reg <= expdelay_lfsr_next;
|
|||
1062 | markw | exptapmatch_reg <= exptapmatch_next;
|
|
1057 | markw | state_reg <= state_next;
|
|
1077 | markw | count_state_reg <= count_state_next;
|
|
1266 | markw | tapkey_reg <= tapkey_next;
|
|
1324 | markw | tapkey_del1_reg <= tapkey_del1_next;
|
|
tapkey_del2_reg <= tapkey_del2_next;
|
|||
tapkey_del3_reg <= tapkey_del3_next;
|
|||
gateshift_reg <= gateshift_next;
|
|||
r0_reg <= r0_next;
|
|||
adrmux_reg <= adrmux_next;
|
|||
adrmux_del1_reg <= adrmux_del1_next;
|
|||
adrmux_del2_reg <= adrmux_del2_next;
|
|||
attack_del1_reg <= attack_del1_next;
|
|||
attack_del2_reg <= attack_del2_next;
|
|||
attack_del3_reg <= attack_del3_next;
|
|||
decay_del1_reg <= decay_del1_next;
|
|||
decay_del2_reg <= decay_del2_next;
|
|||
decay_del3_reg <= decay_del3_next;
|
|||
release_del1_reg <= release_del1_next;
|
|||
release_del2_reg <= release_del2_next;
|
|||
release_del3_reg <= release_del3_next;
|
|||
sustain_del1_reg <= sustain_del1_next;
|
|||
sustain_del2_reg <= sustain_del2_next;
|
|||
sustain_del3_reg <= sustain_del3_next;
|
|||
1057 | markw | end if;
|
|
end process;
|
|||
1324 | markw | process(gateshift_reg,gate,enable)
|
|
begin
|
|||
gateshift_next <= gateshift_reg;
|
|||
if (enable='1') then
|
|||
gateshift_next(1) <= gate;
|
|||
gateshift_next(0) <= gateshift_reg(1);
|
|||
end if;
|
|||
end process;
|
|||
gatedel <= gateshift_reg(0);
|
|||
process(attack_del1_reg,attack_del2_reg,attack_del3_reg,attack,enable)
|
|||
begin
|
|||
attack_del1_next <= attack_del1_reg;
|
|||
attack_del2_next <= attack_del2_reg;
|
|||
attack_del3_next <= attack_del3_reg;
|
|||
if (enable='1') then
|
|||
attack_del1_next <= attack;
|
|||
attack_del2_next <= attack_del1_reg;
|
|||
attack_del3_next <= attack_del2_reg;
|
|||
end if;
|
|||
end process;
|
|||
attack_delayed <= attack_del3_reg;
|
|||
process(decay_del1_reg,decay_del2_reg,decay_del3_reg,decay,enable)
|
|||
begin
|
|||
decay_del1_next <= decay_del1_reg;
|
|||
decay_del2_next <= decay_del2_reg;
|
|||
decay_del3_next <= decay_del3_reg;
|
|||
if (enable='1') then
|
|||
decay_del1_next <= decay;
|
|||
decay_del2_next <= decay_del1_reg;
|
|||
decay_del3_next <= decay_del2_reg;
|
|||
end if;
|
|||
end process;
|
|||
decay_delayed <= decay_del3_reg;
|
|||
process(release_del1_reg,release_del2_reg,release_del3_reg,release_in,enable)
|
|||
begin
|
|||
release_del1_next <= release_del1_reg;
|
|||
release_del2_next <= release_del2_reg;
|
|||
release_del3_next <= release_del3_reg;
|
|||
if (enable='1') then
|
|||
release_del1_next <= release_in;
|
|||
release_del2_next <= release_del1_reg;
|
|||
release_del3_next <= release_del2_reg;
|
|||
end if;
|
|||
end process;
|
|||
release_delayed <= release_del3_reg;
|
|||
process(sustain_del1_reg,sustain_del2_reg,sustain_del3_reg,sustain,enable)
|
|||
begin
|
|||
sustain_del1_next <= sustain_del1_reg;
|
|||
sustain_del2_next <= sustain_del2_reg;
|
|||
sustain_del3_next <= sustain_del3_reg;
|
|||
if (enable='1') then
|
|||
sustain_del1_next <= sustain;
|
|||
sustain_del2_next <= sustain_del1_reg;
|
|||
sustain_del3_next <= sustain_del2_reg;
|
|||
end if;
|
|||
end process;
|
|||
sustain_delayed <= sustain_del2_reg;
|
|||
1057 | markw | -- next state
|
|
--VALUE ATTACK RATE DECAY/RELEASE RATE
|
|||
-- Time/Cycle Time/Cycle
|
|||
--- ------------------------------------------
|
|||
-- 0 2 ms 6 ms
|
|||
-- 1 8 ms 24 ms
|
|||
-- 2 16 ms 48 ms
|
|||
-- 3 24 ms 72 ms
|
|||
-- 4 38 ms 114 ms
|
|||
-- 5 56 ms 168 ms
|
|||
-- 6 68 ms 204 ms
|
|||
-- 7 80 ms 240 ms
|
|||
-- 8 100 ms 300 ms
|
|||
-- 9 240 ms 750 ms
|
|||
--10 500 ms 1.5 s
|
|||
--11 800 ms 2.4 s
|
|||
--12 1 s 3 s
|
|||
--13 3 s 9 s
|
|||
--14 5 s 15 s
|
|||
--15 8 s 24 s
|
|||
--
|
|||
--
|
|||
--
|
|||
--ref1: https://www.codebase64.org/doku.php?id=base:classic_hard-restart_and_about_adsr_in_generally
|
|||
--ref2: https://sourceforge.net/p/sidplay-residfp/wiki/SID%20internals%20-%20Envelope%20Overview/
|
|||
-- up:linear, down: exponential approx
|
|||
1324 | markw | process(envelope_reg,enable,tapmatch,count_state_reg,exptapmatch_reg,exptap,exptapmatching,gatedel,gate_changed,hold_counter,r0_reg)
|
|
1284 | markw | variable no_delay : std_logic;
|
|
variable delay_match : std_logic;
|
|||
1057 | markw | begin
|
|
1077 | markw | count_state_next <= count_state_reg;
|
|
1057 | markw | envelope_next <= envelope_reg;
|
|
exptapmatch_next <= exptapmatch_reg;
|
|||
1284 | markw | exptapmatching <= '0';
|
|
1057 | markw | ||
1324 | markw | r0_next <= r0_reg;
|
|
1284 | markw | if (enable='1') then
|
|
no_delay := nor_reduce(exptapmatch_reg);
|
|||
delay_match := '0';
|
|||
if (exptapmatch_reg = exptap) then
|
|||
delay_match := '1';
|
|||
end if;
|
|||
1077 | markw | case count_state_reg is
|
|
when count_state_up =>
|
|||
1324 | markw | r0_next <= '1';
|
|
if (exptapmatching='1') then -- and hold_counter='0') then
|
|||
1077 | markw | envelope_next <= envelope_reg+1;
|
|
if (envelope_reg=x"fe") then
|
|||
count_state_next <= count_state_down;
|
|||
end if;
|
|||
end if;
|
|||
when count_state_down =>
|
|||
1324 | markw | r0_next <= '0';
|
|
1284 | markw | if (exptapmatching='1' and hold_counter='0') then
|
|
1077 | markw | envelope_next <= envelope_reg-1;
|
|
if (envelope_reg=x"01") then
|
|||
count_state_next <= count_state_stopped;
|
|||
end if;
|
|||
end if;
|
|||
when others=>
|
|||
end case;
|
|||
1324 | markw | exptapmatching <= (tapmatch and (no_delay or r0_reg)) or (delay_match and not(no_delay));
|
|
1284 | markw | ||
1077 | markw | if (gate_changed='1') then
|
|
1324 | markw | if (gatedel='1') then
|
|
1077 | markw | count_state_next <= count_state_up;
|
|
else
|
|||
count_state_next <= count_state_down;
|
|||
1062 | markw | end if;
|
|
1057 | markw | end if;
|
|
case envelope_reg is
|
|||
1324 | markw | when x"00" =>
|
|
exptapmatch_next <= "000";
|
|||
1057 | markw | when x"06" =>
|
|
exptapmatch_next <= "101";
|
|||
when x"0e" =>
|
|||
exptapmatch_next <= "100";
|
|||
when x"1a" =>
|
|||
exptapmatch_next <= "011";
|
|||
when x"36" =>
|
|||
exptapmatch_next <= "010";
|
|||
when x"5d" =>
|
|||
exptapmatch_next <= "001";
|
|||
when x"ff" =>
|
|||
exptapmatch_next <= "000";
|
|||
1065 | markw | when others =>
|
|
1057 | markw | end case;
|
|
end if;
|
|||
end process;
|
|||
1324 | markw | process(
|
|
enable,
|
|||
tapkey_reg,tapkey_del1_reg,tapkey_del2_reg,tapkey_del3_reg,
|
|||
attack_delayed,decay_delayed,release_delayed,
|
|||
1331 | markw | adrmux_reg
|
|
1324 | markw | )
|
|
begin
|
|||
tapkey_next <= tapkey_reg;
|
|||
tapkey_del1_next <= tapkey_del1_reg;
|
|||
tapkey_del2_next <= tapkey_del2_reg;
|
|||
tapkey_del3_next <= tapkey_del3_reg;
|
|||
if (enable='1') then
|
|||
tapkey_del1_next <= tapkey_reg;
|
|||
tapkey_del2_next <= tapkey_del1_reg;
|
|||
tapkey_del3_next <= tapkey_del2_reg;
|
|||
case adrmux_reg is
|
|||
when "00" =>
|
|||
tapkey_next <= attack_delayed;
|
|||
when "01" =>
|
|||
tapkey_next <= decay_delayed;
|
|||
when "10" =>
|
|||
tapkey_next <= release_delayed;
|
|||
when others =>
|
|||
tapkey_next <= (others=>'0');
|
|||
end case;
|
|||
end if;
|
|||
end process;
|
|||
process(enable,state_reg,envelope_reg,gatedel,tapmatch,sustain_delayed,adrmux_reg,adrmux_del1_reg,adrmux_del2_reg)
|
|||
1062 | markw | variable envelope_over_sustain : std_logic;
|
|
1057 | markw | begin
|
|
state_next <= state_reg;
|
|||
1077 | markw | gate_changed <= '0';
|
|
hold_counter <= '0';
|
|||
1062 | markw | ||
1324 | markw | adrmux_next <= adrmux_reg;
|
|
adrmux_del1_next <= adrmux_del1_reg;
|
|||
adrmux_del2_next <= adrmux_del2_reg;
|
|||
1062 | markw | envelope_over_sustain := '0';
|
|
1324 | markw | if (unsigned(envelope_reg) > unsigned(sustain_delayed&sustain_delayed)) then
|
|
1062 | markw | envelope_over_sustain := '1';
|
|
end if;
|
|||
1057 | markw | if (enable='1') then
|
|
1324 | markw | adrmux_del1_next <= adrmux_reg;
|
|
adrmux_del2_next <= adrmux_del1_reg;
|
|||
1057 | markw | case state_reg is
|
|
when state_attack =>
|
|||
1324 | markw | adrmux_next <= "00";
|
|
1062 | markw | if (and_reduce(std_logic_vector(envelope_reg))='1') then
|
|
1057 | markw | state_next <= state_decay;
|
|
end if;
|
|||
1324 | markw | if (gatedel='0') then
|
|
1057 | markw | state_next <= state_release;
|
|
1324 | markw | --state_next <= state_decay;
|
|
1077 | markw | gate_changed <= '1';
|
|
1057 | markw | end if;
|
|
when state_decay =>
|
|||
1324 | markw | adrmux_next <= "01";
|
|
1077 | markw | if (envelope_over_sustain='0') then
|
|
hold_counter <= '1';
|
|||
1057 | markw | end if;
|
|
1324 | markw | if (gatedel='0') then
|
|
1057 | markw | state_next <= state_release;
|
|
1077 | markw | gate_changed <= '1';
|
|
1057 | markw | end if;
|
|
when state_release =>
|
|||
1324 | markw | adrmux_next <= "10";
|
|
if (gatedel='1') then
|
|||
adrmux_next <= "01";
|
|||
1057 | markw | state_next <= state_attack;
|
|
1077 | markw | gate_changed <= '1';
|
|
1057 | markw | end if;
|
|
when others=>
|
|||
state_next <= state_release;
|
|||
end case;
|
|||
end if;
|
|||
end process;
|
|||
1077 | markw | process(delay_lfsr_reg,tapmatch,enable)
|
|
1057 | markw | begin
|
|
delay_lfsr_next <= delay_lfsr_reg;
|
|||
if (enable='1') then
|
|||
1077 | markw | if (tapmatch='1') then
|
|
1057 | markw | delay_lfsr_next <= (others=>'1');
|
|
else
|
|||
delay_lfsr_next(0) <= delay_lfsr_reg(14) xor delay_lfsr_reg(13);
|
|||
delay_lfsr_next(14 downto 1) <= delay_lfsr_reg(13 downto 0);
|
|||
end if;
|
|||
end if;
|
|||
end process;
|
|||
1324 | markw | process(expdelay_lfsr_reg,exptapmatching,tapmatch,enable)
|
|
1057 | markw | begin
|
|
expdelay_lfsr_next <= expdelay_lfsr_reg;
|
|||
if (enable='1') then
|
|||
1284 | markw | if (exptapmatching='1') then
|
|
expdelay_lfsr_next <= "11111";
|
|||
1057 | markw | else
|
|
1077 | markw | if (tapmatch='1') then
|
|
1071 | markw | expdelay_lfsr_next(0) <= expdelay_lfsr_reg(4) xor expdelay_lfsr_reg(2);
|
|
expdelay_lfsr_next(4 downto 1) <= expdelay_lfsr_reg(3 downto 0);
|
|||
end if;
|
|||
1057 | markw | end if;
|
|
end if;
|
|||
end process;
|
|||
process(expdelay_lfsr_reg)
|
|||
begin
|
|||
exptap <= (others=>'0');
|
|||
case expdelay_lfsr_reg is
|
|||
when "11100" => --2
|
|||
exptap <= "001";
|
|||
when "10001" => --4
|
|||
exptap <= "010";
|
|||
when "11011" => --8
|
|||
exptap <= "011";
|
|||
when "01000" => --16
|
|||
exptap <= "100";
|
|||
1065 | markw | when "01111" => --30
|
|
1057 | markw | exptap <= "101";
|
|
when others=>
|
|||
exptap <= "000";
|
|||
end case;
|
|||
1062 | markw | end process;
|
|
1057 | markw | ||
-- output
|
|||
1062 | markw | envelope <= std_logic_vector(envelope_reg);
|
|
1266 | markw | delay_lfsr <= delay_lfsr_reg;
|
|
tapkey <= tapkey_reg;
|
|||
1057 | markw | ||
END vhdl;
|