Revision 1324
Added by markw about 4 years ago
atari_chips/pokeyv2/SID/envelope.vhdl | ||
---|---|---|
|
||
signal tapkey_next : std_logic_vector(3 downto 0);
|
||
signal tapkey_reg : std_logic_vector(3 downto 0);
|
||
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);
|
||
|
||
signal exptap : std_logic_vector(2 downto 0);
|
||
signal exptapmatching : std_logic;
|
||
... | ... | |
signal gate_changed : std_logic;
|
||
signal hold_counter : std_logic;
|
||
|
||
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);
|
||
|
||
BEGIN
|
||
-- register
|
||
process(clk, reset_n)
|
||
... | ... | |
state_reg <= state_release;
|
||
count_state_reg <= count_state_stopped;
|
||
tapkey_reg <= (others=>'0');
|
||
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');
|
||
elsif (clk'event and clk='1') then
|
||
envelope_reg <= envelope_next;
|
||
delay_lfsr_reg <= delay_lfsr_next;
|
||
... | ... | |
state_reg <= state_next;
|
||
count_state_reg <= count_state_next;
|
||
tapkey_reg <= tapkey_next;
|
||
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;
|
||
end if;
|
||
end process;
|
||
|
||
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;
|
||
|
||
-- next state
|
||
--VALUE ATTACK RATE DECAY/RELEASE RATE
|
||
-- Time/Cycle Time/Cycle
|
||
... | ... | |
--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
|
||
process(envelope_reg,enable,tapmatch,count_state_reg,exptapmatch_reg,exptap,exptapmatching,gate,gate_changed,hold_counter)
|
||
process(envelope_reg,enable,tapmatch,count_state_reg,exptapmatch_reg,exptap,exptapmatching,gatedel,gate_changed,hold_counter,r0_reg)
|
||
variable no_delay : std_logic;
|
||
variable delay_match : std_logic;
|
||
variable r0 : std_logic;
|
||
begin
|
||
count_state_next <= count_state_reg;
|
||
envelope_next <= envelope_reg;
|
||
... | ... | |
|
||
exptapmatching <= '0';
|
||
|
||
r0_next <= r0_reg;
|
||
|
||
if (enable='1') then
|
||
no_delay := nor_reduce(exptapmatch_reg);
|
||
delay_match := '0';
|
||
if (exptapmatch_reg = exptap) then
|
||
delay_match := '1';
|
||
end if;
|
||
r0 := '0';
|
||
|
||
case count_state_reg is
|
||
when count_state_up =>
|
||
r0 := '1';
|
||
if (exptapmatching='1' and hold_counter='0') then
|
||
r0_next <= '1';
|
||
if (exptapmatching='1') then -- and hold_counter='0') then
|
||
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 =>
|
||
r0 := '0';
|
||
r0_next <= '0';
|
||
if (exptapmatching='1' and hold_counter='0') then
|
||
envelope_next <= envelope_reg-1;
|
||
if (envelope_reg=x"01") then
|
||
... | ... | |
when others=>
|
||
end case;
|
||
|
||
exptapmatching <= (tapmatch and (no_delay or r0)) or (delay_match and not(no_delay));
|
||
exptapmatching <= (tapmatch and (no_delay or r0_reg)) or (delay_match and not(no_delay));
|
||
|
||
if (gate_changed='1') then
|
||
if (gate='1') then
|
||
if (gatedel='1') then
|
||
count_state_next <= count_state_up;
|
||
else
|
||
count_state_next <= count_state_down;
|
||
... | ... | |
end if;
|
||
|
||
case envelope_reg is
|
||
when x"00" =>
|
||
exptapmatch_next <= "000";
|
||
when x"06" =>
|
||
exptapmatch_next <= "101";
|
||
when x"0e" =>
|
||
... | ... | |
end if;
|
||
end process;
|
||
|
||
process(enable,state_reg,envelope_reg,tapkey_reg,gate,tapmatch,attack,sustain,decay,release_in)
|
||
process(
|
||
enable,
|
||
tapkey_reg,tapkey_del1_reg,tapkey_del2_reg,tapkey_del3_reg,
|
||
attack_delayed,decay_delayed,release_delayed,
|
||
adrmux_del2_reg
|
||
)
|
||
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)
|
||
variable envelope_over_sustain : std_logic;
|
||
begin
|
||
state_next <= state_reg;
|
||
tapkey_next <= tapkey_reg;
|
||
gate_changed <= '0';
|
||
hold_counter <= '0';
|
||
|
||
adrmux_next <= adrmux_reg;
|
||
adrmux_del1_next <= adrmux_del1_reg;
|
||
adrmux_del2_next <= adrmux_del2_reg;
|
||
|
||
envelope_over_sustain := '0';
|
||
if (unsigned(envelope_reg) > unsigned(sustain&sustain)) then
|
||
if (unsigned(envelope_reg) > unsigned(sustain_delayed&sustain_delayed)) then
|
||
envelope_over_sustain := '1';
|
||
end if;
|
||
|
||
if (enable='1') then
|
||
adrmux_del1_next <= adrmux_reg;
|
||
adrmux_del2_next <= adrmux_del1_reg;
|
||
case state_reg is
|
||
when state_attack =>
|
||
tapkey_next <= attack;
|
||
adrmux_next <= "00";
|
||
if (and_reduce(std_logic_vector(envelope_reg))='1') then
|
||
state_next <= state_decay;
|
||
end if;
|
||
if (gate='0') then
|
||
if (gatedel='0') then
|
||
state_next <= state_release;
|
||
--state_next <= state_decay;
|
||
gate_changed <= '1';
|
||
end if;
|
||
when state_decay =>
|
||
tapkey_next <= decay;
|
||
adrmux_next <= "01";
|
||
if (envelope_over_sustain='0') then
|
||
hold_counter <= '1';
|
||
end if;
|
||
if (gate='0') then
|
||
if (gatedel='0') then
|
||
state_next <= state_release;
|
||
gate_changed <= '1';
|
||
end if;
|
||
when state_release =>
|
||
tapkey_next <= release_in;
|
||
if (gate='1') then
|
||
adrmux_next <= "10";
|
||
if (gatedel='1') then
|
||
adrmux_next <= "01";
|
||
state_next <= state_attack;
|
||
gate_changed <= '1';
|
||
end if;
|
||
... | ... | |
end if;
|
||
end process;
|
||
|
||
process(expdelay_lfsr_reg,exptapmatching,enable)
|
||
process(expdelay_lfsr_reg,exptapmatching,tapmatch,enable)
|
||
begin
|
||
expdelay_lfsr_next <= expdelay_lfsr_reg;
|
||
if (enable='1') then
|
atari_chips/pokeyv2/SID/investigation/sig_sigmoid.m | ||
---|---|---|
%M.T. Tommiska
|
||
|
||
%337p
|
||
%358p
|
||
x = min(x,8);
|
||
x = max(x,-8);
|
||
sgn = sign(x);
|
||
x = x.*sgn;
|
||
|
||
x = floor(x*32)/32;
|
||
x = floor(x*8)/8;
|
||
|
||
sigmoidreal = @(x) 1./(1.+e.^-x);
|
||
y = sigmoidreal(x);
|
||
y = floor(y*256)/256;
|
||
y = floor(y*128)/128;
|
||
|
||
res = y;
|
||
res(sgn<0) = 1-res(sgn<0);
|
atari_chips/pokeyv2/SID/preFilterSum.vhdl | ||
---|---|---|
ENABLE : IN STD_LOGIC;
|
||
|
||
BIAS_CHANNEL : IN STD_LOGIC;
|
||
BIAS_FILTER : IN STD_LOGIC;
|
||
|
||
CHANNEL_A : IN SIGNED(15 downto 0);
|
||
CHANNEL_B : IN SIGNED(15 downto 0);
|
||
CHANNEL_C : IN SIGNED(15 downto 0);
|
||
CHANNEL_C_CUTDIRECT : IN STD_LOGIC;
|
||
CHANNEL_D : IN SIGNED(15 downto 0);
|
||
FILTER_EN : IN STD_LOGIC_VECTOR(3 downto 0);
|
||
|
||
PREFILTER_OUT : OUT SIGNED(15 downto 0);
|
||
... | ... | |
signal phase_next : unsigned(2 downto 0);
|
||
|
||
signal channel_mux : signed(15 downto 0);
|
||
signal channel_sel : std_logic_vector(1 downto 0);
|
||
signal channel_sel : std_logic_vector(2 downto 0);
|
||
|
||
function logic_to_unsigned(a : std_logic; b : integer) return unsigned is
|
||
variable ret : unsigned(2 downto 0);
|
||
... | ... | |
end process;
|
||
|
||
-- next state
|
||
process(phase_reg,acc_reg,prefilter_reg,direct_reg,enable,channel_c_cutdirect,filter_en,channel_mux,bias_channel,bias_filter)
|
||
variable filter_en0_ext : std_logic_vector(1 downto 0);
|
||
variable filter_en1_ext : std_logic_vector(1 downto 0);
|
||
variable filter_en2_ext : std_logic_vector(1 downto 0);
|
||
variable filter_en2cd_ext : std_logic_vector(1 downto 0);
|
||
process(phase_reg,acc_reg,prefilter_reg,direct_reg,enable,channel_c_cutdirect,filter_en,channel_mux,bias_channel,channel_d)
|
||
variable filter_en0_ext : std_logic_vector(2 downto 0);
|
||
variable filter_en1_ext : std_logic_vector(2 downto 0);
|
||
variable filter_en2_ext : std_logic_vector(2 downto 0);
|
||
variable filter_en2cd_ext : std_logic_vector(2 downto 0);
|
||
variable filter_en3_ext : std_logic_vector(2 downto 0);
|
||
|
||
variable adder_result : signed(17 downto 0);
|
||
|
||
... | ... | |
filter_en1_ext := (others=>filter_en(1));
|
||
filter_en2_ext := (others=>filter_en(2));
|
||
filter_en2cd_ext := (others=>filter_en(2) or channel_c_cutdirect);
|
||
filter_en3_ext := (others=>filter_en(3));
|
||
|
||
channel_sel <= (others=>'0');
|
||
|
||
... | ... | |
|
||
case phase_reg is
|
||
when "000" =>
|
||
channel_sel <= "01" and filter_en0_ext;
|
||
channel_sel <= "001" and filter_en0_ext;
|
||
when "001" =>
|
||
channel_sel <= "10" and filter_en1_ext;
|
||
channel_sel <= "010" and filter_en1_ext;
|
||
when "010" =>
|
||
channel_sel <= "11" and filter_en2_ext;
|
||
channel_sel <= "011" and filter_en2_ext;
|
||
when "011" =>
|
||
channel_sel <= "100" and filter_en3_ext;
|
||
prefilter_next <= adder_result(17 downto 2);
|
||
acc_next <= (others=>'0'); --base for direct
|
||
bias:=
|
||
logic_to_unsigned(not(filter_en(0)) and bias_channel,0) +
|
||
logic_to_unsigned(not(filter_en(1)) and bias_channel,0) +
|
||
logic_to_unsigned(not(filter_en2cd_ext(0)) and bias_channel,0) +
|
||
logic_to_unsigned(not(filter_en(3)) and bias_filter,1);
|
||
acc_next(14 downto 12) <= signed(std_logic_vector(bias));
|
||
when "011" =>
|
||
channel_sel <= "01" and not(filter_en0_ext);
|
||
logic_to_unsigned(not(filter_en2cd_ext(0)) and bias_channel,0);
|
||
acc_next(16 downto 14) <= signed(std_logic_vector(bias));
|
||
when "100" =>
|
||
channel_sel <= "10" and not(filter_en1_ext);
|
||
channel_sel <= "001" and not(filter_en0_ext);
|
||
when "101" =>
|
||
channel_sel <= "11" and not(filter_en2cd_ext);
|
||
channel_sel <= "010" and not(filter_en1_ext);
|
||
when "110" =>
|
||
channel_sel <= "011" and not(filter_en2cd_ext);
|
||
when "111" =>
|
||
channel_sel <= "100" and not(filter_en3_ext);
|
||
phase_next <= (others=>'0');
|
||
direct_next <= adder_result(17 downto 2);
|
||
acc_next <= (others=>'0'); --base for filter
|
||
bias:=
|
||
logic_to_unsigned(filter_en(0) and bias_channel,0) +
|
||
logic_to_unsigned(filter_en(1) and bias_channel,0) +
|
||
logic_to_unsigned(filter_en(2) and bias_channel,0) +
|
||
logic_to_unsigned(filter_en(3) and bias_filter,1);
|
||
acc_next(14 downto 12) <= signed(std_logic_vector(bias));
|
||
logic_to_unsigned(filter_en(2) and bias_channel,0);
|
||
acc_next(16 downto 14) <= signed(std_logic_vector(bias));
|
||
when others =>
|
||
end case;
|
||
|
||
end process;
|
||
|
||
process(channel_sel,channel_a,channel_b,channel_c)
|
||
process(channel_sel,channel_a,channel_b,channel_c,channel_d)
|
||
begin
|
||
channel_mux <= (others=>'0');
|
||
case channel_sel is
|
||
when "01" =>
|
||
when "001" =>
|
||
channel_mux <= channel_a;
|
||
when "10" =>
|
||
when "010" =>
|
||
channel_mux <= channel_b;
|
||
when "11" =>
|
||
when "011" =>
|
||
channel_mux <= channel_c;
|
||
when "100" =>
|
||
channel_mux <= channel_d;
|
||
when others =>
|
||
end case;
|
||
end process;
|
atari_chips/pokeyv2/SID/top.vhdl | ||
---|---|---|
ENABLE : in std_logic; -- Typically ~1MHz
|
||
|
||
ADDR : in std_logic_vector(4 downto 0);
|
||
READ_ENABLE : in std_logic;
|
||
WRITE_ENABLE : in std_logic;
|
||
|
||
POTX : in std_logic_vector(7 downto 0) := (others=> '1');
|
||
POTY : in std_logic_vector(7 downto 0) := (others=> '1');
|
||
POT_X : in std_logic;
|
||
POT_Y : in std_logic;
|
||
POT_RESET : out std_logic;
|
||
|
||
DI : in std_logic_vector(7 downto 0);
|
||
DO : out std_logic_vector(7 downto 0);
|
||
... | ... | |
DEBUG_EV1 : out unsigned(7 downto 0);
|
||
DEBUG_AM1 : out signed(15 downto 0);
|
||
|
||
sidtype : in std_logic_vector(1 downto 0); -- 0=8580 filter, 1=6581 filter, 2=digifix
|
||
sidtype : in std_logic; -- 0=8580 filter, 1=6581 filter
|
||
EXT : in std_logic_vector(1 downto 0); -- 00=GND,01=digifix,10=ADC
|
||
EXT_ADC : in unsigned(15 downto 0);
|
||
|
||
rom_addr : out std_logic_vector(16 downto 0);
|
||
rom_data : in std_logic_vector(31 downto 0);
|
||
... | ... | |
signal channel_a_modulated : signed(15 downto 0);
|
||
signal channel_b_modulated : signed(15 downto 0);
|
||
signal channel_c_modulated : signed(15 downto 0);
|
||
signal channel_d : signed(15 downto 0);
|
||
|
||
-- prefilter
|
||
signal channel_prefilter : signed(15 downto 0);
|
||
... | ... | |
signal filter_lp : signed(17 downto 0); -- extra bit due to Jammer causing filter to clip
|
||
signal filter_bp : signed(17 downto 0);
|
||
signal filter_hp : signed(17 downto 0);
|
||
|
||
-- paddles
|
||
signal potx_reg : std_logic_vector(7 downto 0);
|
||
signal potx_next : std_logic_vector(7 downto 0);
|
||
signal poty_reg : std_logic_vector(7 downto 0);
|
||
signal poty_next : std_logic_vector(7 downto 0);
|
||
signal potcount_reg : std_logic_vector(8 downto 0);
|
||
signal potcount_next : std_logic_vector(8 downto 0);
|
||
signal potread_x_reg : std_logic;
|
||
signal potread_y_reg : std_logic;
|
||
signal potread_x_next : std_logic;
|
||
signal potread_y_next : std_logic;
|
||
|
||
-- do internal bus
|
||
signal do_out_next : std_logic_vector(7 downto 0);
|
||
signal do_out_reg : std_logic_vector(7 downto 0);
|
||
signal reset_readcount : std_logic;
|
||
signal readcount_reg : unsigned(15 downto 0);
|
||
signal readcount_next : unsigned(15 downto 0);
|
||
BEGIN
|
||
process(clk,reset_n)
|
||
begin
|
||
... | ... | |
vol_reg <= (others=>'0');
|
||
statevariable_f_dirty_reg <= '1';
|
||
statevariable_q_dirty_reg <= '1';
|
||
potx_reg <= (others=>'0');
|
||
poty_reg <= (others=>'0');
|
||
potread_x_reg <= '0';
|
||
potread_y_reg <= '0';
|
||
potcount_reg <= (others=>'0');
|
||
do_out_reg <= (others=>'0');
|
||
readcount_reg <= (others=>'0');
|
||
elsif (clk'event and clk='1') then
|
||
freq_adj_channel_a_reg <= freq_adj_channel_a_next;
|
||
freq_adj_channel_b_reg <= freq_adj_channel_b_next;
|
||
... | ... | |
vol_reg <= vol_next;
|
||
statevariable_f_dirty_reg <= statevariable_f_dirty_next;
|
||
statevariable_q_dirty_reg <= statevariable_q_dirty_next;
|
||
potx_reg <= potx_next;
|
||
poty_reg <= poty_next;
|
||
potread_x_reg <= potread_x_next;
|
||
potread_y_reg <= potread_y_next;
|
||
potcount_reg <= potcount_next;
|
||
do_out_reg <= do_out_next;
|
||
readcount_reg <= readcount_next;
|
||
end if;
|
||
end process;
|
||
|
||
... | ... | |
end if;
|
||
end process;
|
||
|
||
process(addr_decoded,
|
||
process(addr,addr_decoded,
|
||
do_out_reg,do_out_next,
|
||
read_enable,
|
||
wave_c_reg,
|
||
envelope_c_reg,
|
||
potx,
|
||
poty
|
||
potx_reg,
|
||
poty_reg,
|
||
readcount_reg
|
||
)
|
||
begin
|
||
do <= (others=>'0');
|
||
drive_do <= ADDR(4) and ADDR(3) and or_reduce(ADDR(2 downto 0));
|
||
|
||
if (addr_decoded(25)='1') then
|
||
do <= potx;
|
||
drive_do <= '1';
|
||
--ADDR(4) and ADDR(3) and or_reduce(ADDR(2 downto 0));
|
||
do_out_next <= do_out_reg;
|
||
|
||
reset_readcount <= '0';
|
||
|
||
if (read_enable='1') then
|
||
if (addr_decoded(25)='1') then
|
||
do_out_next <= potx_reg;
|
||
reset_readcount <= '1';
|
||
end if;
|
||
if (addr_decoded(26)='1') then
|
||
do_out_next <= poty_reg;
|
||
reset_readcount <= '1';
|
||
end if;
|
||
if (addr_decoded(27)='1') then
|
||
do_out_next <= wave_c_reg(11 downto 4);
|
||
reset_readcount <= '1';
|
||
end if;
|
||
if (addr_decoded(28)='1') then
|
||
do_out_next <= envelope_c_reg;
|
||
reset_readcount <= '1';
|
||
end if;
|
||
else
|
||
if (or_reduce(std_logic_vector(readcount_reg))='0') then
|
||
do_out_next <= (others=>'0');
|
||
end if;
|
||
end if;
|
||
if (addr_decoded(26)='1') then
|
||
do <= poty;
|
||
end if;
|
||
if (addr_decoded(27)='1') then
|
||
do <= wave_c_reg(11 downto 4);
|
||
end if;
|
||
if (addr_decoded(28)='1') then
|
||
do <= envelope_c_reg;
|
||
end if;
|
||
do <= do_out_next;
|
||
end process;
|
||
|
||
process(readcount_reg,enable,reset_readcount)
|
||
begin
|
||
readcount_next <= readcount_reg;
|
||
|
||
if (reset_readcount='1') then
|
||
if (sidtype ='1') then --6581
|
||
readcount_next <=to_unsigned(8000,16);
|
||
else
|
||
readcount_next <=to_unsigned(65535,16);
|
||
end if;
|
||
else
|
||
if (enable='1') then
|
||
readcount_next <=readcount_reg-1;
|
||
end if;
|
||
end if;
|
||
end process;
|
||
|
||
-- osc a
|
||
osc_a : entity work.SID_oscillator
|
||
PORT MAP
|
||
... | ... | |
|
||
CHANGING => osc_a_changing,
|
||
|
||
DELAYSAWTOOTH => not(sidtype),
|
||
RINGMOD => control_a_reg(2),
|
||
RINGMOD_OSC_MSB => osc_c_reg(11),
|
||
TEST => control_a_next(3),
|
||
... | ... | |
|
||
CHANGING => osc_b_changing,
|
||
|
||
DELAYSAWTOOTH => not(sidtype),
|
||
RINGMOD => control_b_reg(2),
|
||
RINGMOD_OSC_MSB => osc_a_reg(11),
|
||
TEST => control_b_next(3),
|
||
... | ... | |
|
||
CHANGING => osc_c_changing,
|
||
|
||
DELAYSAWTOOTH => not(sidtype),
|
||
RINGMOD => control_c_reg(2),
|
||
RINGMOD_OSC_MSB => osc_b_reg(11),
|
||
TEST => control_c_next(3),
|
||
... | ... | |
RESET_N => reset_n,
|
||
ENABLE => enable,
|
||
|
||
BIAS_CHANNEL => sidtype(0),
|
||
BIAS_FILTER => sidtype(1),
|
||
BIAS_CHANNEL => sidtype,
|
||
|
||
CHANNEL_A => channel_a_modulated,
|
||
CHANNEL_B => channel_b_modulated,
|
||
CHANNEL_C => channel_c_modulated,
|
||
CHANNEL_C_CUTDIRECT => ch3silent_reg,
|
||
CHANNEL_D => channel_d,
|
||
FILTER_EN => filter_en_reg,
|
||
|
||
PREFILTER_OUT => channel_prefilter,
|
||
... | ... | |
rom_osc,rom_high_word)
|
||
|
||
variable rom_wave_addr: std_logic_vector(16 downto 0);
|
||
variable sidtype2: std_logic_vector(0 downto 0);
|
||
begin
|
||
rom_addr <= (others=>'0');
|
||
rom_high_word <= '0';
|
||
... | ... | |
rom_wave_3bit <= (others=>'0');
|
||
rom_osc <= (others=>'0');
|
||
|
||
sidtype2(0) := sidtype;
|
||
|
||
case rom_wave_3bit is
|
||
when "011" =>
|
||
when "011" => -- ST
|
||
rom_wave_2bit <= "00";
|
||
when "101" =>
|
||
when "101" => --P T
|
||
rom_wave_2bit <= "01";
|
||
when "110" =>
|
||
when "110" => --PS
|
||
rom_wave_2bit <= "10";
|
||
when "111" =>
|
||
when "111" => --PST
|
||
rom_wave_2bit <= "11";
|
||
when others =>
|
||
end case;
|
||
|
||
|
||
rom_wave_addr := std_logic_vector(unsigned(wave_base)+resize(unsigned(sidtype(0 downto 0)&rom_wave_2bit&rom_osc),17)); --1:2:11
|
||
rom_wave_addr := std_logic_vector(unsigned(wave_base)+resize(unsigned(sidtype2(0 downto 0)&rom_wave_2bit&rom_osc),17)); --1:2:11
|
||
|
||
case rom_addr_mux is
|
||
when "000" =>
|
||
rom_addr <= "00000"&std_logic_vector(unsigned('0'&sidtype(0 downto 0))+1)&statevariable_fcutoff_reg(10 downto 1);
|
||
rom_addr <= "00000"&std_logic_vector(unsigned('0'&sidtype2(0 downto 0))+1)&statevariable_fcutoff_reg(10 downto 1);
|
||
rom_high_word <= statevariable_fcutoff_reg(0);
|
||
when "001" =>
|
||
rom_osc <= osc_a_reg(11 downto 1);
|
||
... | ... | |
rom_addr <= rom_wave_addr;
|
||
rom_high_word <= osc_c_reg(0);
|
||
when "100" =>
|
||
rom_addr <= "000000010000"&sidtype(0 downto 0)&statevariable_q_reg;
|
||
rom_addr <= "000000010000"&sidtype2(0 downto 0)&statevariable_q_reg;
|
||
when others =>
|
||
end case;
|
||
|
||
... | ... | |
|
||
INPUT => channel_prefilter,
|
||
|
||
SIDTYPE => sidtype(0),
|
||
SIDTYPE => sidtype,
|
||
|
||
LOWPASS => filter_lp,
|
||
BANDPASS => filter_bp,
|
||
... | ... | |
CHANNEL_OUT => audio_reg
|
||
);
|
||
|
||
-- paddles
|
||
process (potx_reg,poty_reg,pot_x,pot_y,potcount_reg,enable,potread_x_reg,potread_y_reg)
|
||
begin
|
||
potx_next <= potx_reg;
|
||
poty_next <= poty_reg;
|
||
potread_x_next <= potread_x_reg and not(potcount_reg(8));
|
||
potread_y_next <= potread_y_reg and not(potcount_reg(8));
|
||
potcount_next <= potcount_reg;
|
||
|
||
pot_reset <= potcount_reg(8);
|
||
if (enable='1') then
|
||
potcount_next <= std_logic_vector(unsigned(potcount_reg)+1);
|
||
if ((pot_x='1' or potcount_reg="011111111") and potread_x_reg='0') then
|
||
potx_next <= potcount_reg(7 downto 0);
|
||
potread_x_next <= '1';
|
||
end if;
|
||
if ((pot_y='1' or potcount_reg="011111111") and potread_y_reg='0') then
|
||
poty_next <= potcount_reg(7 downto 0);
|
||
potread_y_next <= '1';
|
||
end if;
|
||
end if;
|
||
|
||
end process;
|
||
|
||
-- ext audio
|
||
process(ext_adc,ext)
|
||
begin
|
||
--EXT : in std_logic_vector(1 downto 0); -- 00=GND,01=digifix,10=ADC
|
||
--EXT_ADC : in unsigned(7 downto 0);
|
||
channel_d <= to_signed(0,16);
|
||
|
||
case EXT is
|
||
when "01" =>
|
||
channel_d <= signed("000"&ext&"00000000000");
|
||
when "10" =>
|
||
channel_d <= signed(not(ext_adc(15))&ext_adc(14 downto 0));
|
||
when others=>
|
||
end case;
|
||
end process;
|
||
|
||
--------------------------------
|
||
-- TODO
|
atari_chips/pokeyv2/SID/wavegen.vhdl | ||
---|---|---|
|
||
CHANGING : IN STD_LOGIC;
|
||
|
||
DELAYSAWTOOTH : IN STD_LOGIC;
|
||
RINGMOD : IN STD_LOGIC;
|
||
RINGMOD_OSC_MSB : IN STD_LOGIC;
|
||
TEST : IN STD_LOGIC;
|
||
... | ... | |
ARCHITECTURE vhdl OF SID_wavegen IS
|
||
signal wave_reg : std_logic_vector(11 downto 0);
|
||
signal wave_next : std_logic_vector(11 downto 0);
|
||
signal wave0count1_reg : unsigned(9 downto 0);
|
||
signal wave0count1_next : unsigned(9 downto 0);
|
||
signal lfsr_reg : std_logic_vector(22 downto 0);
|
||
signal lfsr_next : std_logic_vector(22 downto 0);
|
||
signal wave_data_needed_reg : std_logic;
|
||
... | ... | |
signal pulse_comparator_reg : std_logic;
|
||
signal pulse_comparator_next : std_logic;
|
||
signal multiple_wave_bits : std_logic;
|
||
signal no_wave_bits : std_logic;
|
||
signal osc_del_reg : std_logic_vector(11 downto 0);
|
||
signal osc_del_next : std_logic_vector(11 downto 0);
|
||
BEGIN
|
||
-- register
|
||
process(clk, reset_n)
|
||
begin
|
||
if (reset_n = '0') then
|
||
wave_reg <= (others=>'0');
|
||
wave0count1_reg <= (others=>'0');
|
||
lfsr_reg <= (others=>'1');
|
||
pulse_comparator_reg <= '0';
|
||
wave_data_needed_reg <= '0';
|
||
osc_del_reg <= (others=>'0');
|
||
elsif (clk'event and clk='1') then
|
||
wave_reg <= wave_next;
|
||
wave0count1_reg <= wave0count1_next;
|
||
lfsr_reg <= lfsr_next;
|
||
pulse_comparator_reg <= pulse_comparator_next;
|
||
wave_data_needed_reg <= wave_data_needed_next;
|
||
osc_del_reg <= osc_del_next;
|
||
end if;
|
||
end process;
|
||
|
||
... | ... | |
end process;
|
||
|
||
-- next state - wave
|
||
process(multiple_wave_bits,wave_reg,osc_in,waveselect_in,pulse_width_in,lfsr_reg,test,ringmod,ringmod_osc_msb,pulse_comparator_reg,wave_data,wave_data_ready,enable)
|
||
process(no_wave_bits,multiple_wave_bits,wave_reg,osc_in,waveselect_in,pulse_width_in,lfsr_reg,test,ringmod,ringmod_osc_msb,pulse_comparator_reg,wave_data,wave_data_ready,enable,osc_del_reg,delaysawtooth,wave0count1_reg)
|
||
variable noise : std_logic_vector(11 downto 0);
|
||
variable pulse : std_logic_vector(11 downto 0);
|
||
variable triangle : std_logic_vector(11 downto 0);
|
||
... | ... | |
variable triangle_xor : std_logic;
|
||
variable triangle_xor_ext : std_logic_vector(10 downto 0);
|
||
variable osc_xored : std_logic_vector(10 downto 0);
|
||
variable osc_sawtooth : std_logic_vector(11 downto 0);
|
||
|
||
variable wave0tmp : unsigned(12 downto 0);
|
||
begin
|
||
wave_next <= wave_reg;
|
||
wave0count1_next <= wave0count1_reg;
|
||
osc_del_next <= osc_del_reg;
|
||
|
||
if (enable='1') then
|
||
osc_del_next <= osc_in;
|
||
end if;
|
||
|
||
noise:= (others=>'0');
|
||
pulse:= (others=>'0');
|
||
triangle:= (others=>'0');
|
||
... | ... | |
end if;
|
||
|
||
--ref: https://sourceforge.net/p/sidplay-residfp/wiki/SID%20internals%20-%20Triangle%20Waveform/
|
||
|
||
if (delaysawtooth='1') then
|
||
osc_sawtooth:= osc_del_reg;
|
||
else
|
||
osc_sawtooth := osc_in;
|
||
end if;
|
||
|
||
triangle_xor := not(waveselect_in(1)) and -- sawtooth on->disable invert
|
||
((not(ringmod) and osc_in(11)) or -- not ringmod ->msb makes it invert
|
||
(ringmod and (osc_in(11) xnor ringmod_osc_msb))); -- ringmod -> both 0 or 1 -> invert
|
||
((not(ringmod) and osc_sawtooth(11)) or -- not ringmod ->msb makes it invert
|
||
(ringmod and (osc_sawtooth(11) xnor ringmod_osc_msb))); -- ringmod -> both 0 or 1 -> invert
|
||
triangle_xor_ext := (others=>triangle_xor);
|
||
osc_xored:= osc_in(10 downto 0) xor triangle_xor_ext;
|
||
osc_xored:= osc_sawtooth(10 downto 0) xor triangle_xor_ext;
|
||
|
||
if (waveselect_in(1)='1') then
|
||
sawtooth := osc_in(11) & osc_xored(10 downto 0);
|
||
sawtooth := osc_sawtooth(11) & osc_xored(10 downto 0);
|
||
end if;
|
||
|
||
if (waveselect_in(0)='1') then
|
||
... | ... | |
-- In fact transistors drive against each other with different resistances and
|
||
-- a corrupt waveform is generated.
|
||
-- TODO: Either compute or use flash storage (optionally)
|
||
if (multiple_wave_bits='0') then
|
||
wave_next <= noise or pulse or sawtooth or triangle;
|
||
if (no_wave_bits='1') then
|
||
if (enable='1') then
|
||
wave0count1_next <= unsigned("0"&wave0count1_reg(8 downto 0)) + 1;
|
||
if (wave0count1_reg(9)='1') then -- carry
|
||
wave0tmp := unsigned("0"&wave_reg) - 1; -- head to zero over 2 seconds!
|
||
if (wave0tmp(12) = '1') then
|
||
wave_next <= (others=>'0');
|
||
else
|
||
wave_next <= std_logic_vector(wave0tmp(11 downto 0));
|
||
end if;
|
||
end if;
|
||
end if;
|
||
else
|
||
if (wave_data_ready='1') then
|
||
wave_next <= wave_data and pulse;
|
||
if (multiple_wave_bits='0') then
|
||
wave_next <= noise or pulse or sawtooth or triangle;
|
||
else
|
||
if (wave_data_ready='1') then
|
||
if (waveselect_in(2)='1') then
|
||
wave_next <= wave_data and pulse;
|
||
else
|
||
wave_next <= wave_data;
|
||
end if;
|
||
end if;
|
||
end if;
|
||
end if;
|
||
|
||
end process;
|
||
|
||
multiple_wave_bits <=
|
||
multiple_wave_bits <= --NPST (?ST) or PS or PT
|
||
not(waveselect_in(3)) and
|
||
(
|
||
(waveselect_in(0) and waveselect_in(1))
|
||
... | ... | |
(waveselect_in(2) and (waveselect_in(0) or waveselect_in(1)))
|
||
)
|
||
;
|
||
no_wave_bits <= not(or_reduce(waveselect_in));
|
||
wave_data_needed_next <= (wave_data_needed_reg or (multiple_wave_bits and changing)) and not(wave_data_ready);
|
||
|
||
--output
|
Also available in: Unified diff
Test driven SID improvements