Merge pull request #22 from brNX/master

Sound fixes
This commit is contained in:
sorgelig
2018-12-16 23:13:58 +08:00
committed by GitHub

View File

@@ -53,7 +53,9 @@ architecture SYN of gbc_snd is
signal sq1_svol : std_logic_vector(3 downto 0); -- Sq1 initial volume
signal sq1_envsgn : std_logic; -- Sq1 envelope sign
signal sq1_envsgn_old: std_logic; -- Sq1 old envelope sign (used in zombie mode)
signal sq1_envper : std_logic_vector(2 downto 0); -- Sq1 envelope period
signal sq1_envper_old: std_logic_vector(2 downto 0); -- Sq1 old envelope period (used in zombie mode)
signal sq1_freq : std_logic_vector(10 downto 0); -- Sq1 frequency
signal sq1_trigger : std_logic; -- Sq1 trigger play note
signal sq1_lenchk : std_logic; -- Sq1 length check enable
@@ -61,7 +63,7 @@ architecture SYN of gbc_snd is
signal sq1_fr2 : std_logic_vector(10 downto 0); -- Sq1 frequency (shadow copy)
signal sq1_vol : std_logic_vector(3 downto 0); -- Sq1 initial volume
signal sq1_volchange : std_logic;
signal sq1_nr2change : std_logic;
signal sq1_lenchange : std_logic;
signal sq1_lenquirk : std_logic;
signal sq1_freqchange : std_logic;
@@ -72,11 +74,13 @@ architecture SYN of gbc_snd is
signal sq2_duty : std_logic_vector(1 downto 0); -- Sq2 duty cycle
signal sq2_slen : std_logic_vector(6 downto 0); -- Sq2 play length
signal sq2_svol : std_logic_vector(3 downto 0); -- Sq2 initial volume
signal sq2_volchange : std_logic;
signal sq2_nr2change : std_logic;
signal sq2_lenchange : std_logic;
signal sq2_lenquirk : std_logic;
signal sq2_envsgn : std_logic; -- Sq2 envelope sign
signal sq2_envper : std_logic_vector(2 downto 0); -- Sq2 envelope period
signal sq2_envsgn_old: std_logic; -- Sq2 old envelope sign (used in zombie mode)
signal sq2_envper_old: std_logic_vector(2 downto 0); -- Sq2 old envelope period (used in zombie mode)
signal sq2_freq : std_logic_vector(10 downto 0); -- Sq2 frequency
signal sq2_trigger : std_logic; -- Sq2 trigger play note
signal sq2_lenchk : std_logic; -- Sq2 length check enable
@@ -102,16 +106,18 @@ architecture SYN of gbc_snd is
signal noi_lenchange : std_logic;
signal noi_lenquirk : std_logic;
signal noi_svol : std_logic_vector(3 downto 0);
signal noi_volchange : std_logic;
signal noi_nr2change : std_logic;
signal noi_envsgn : std_logic;
signal noi_envper : std_logic_vector(2 downto 0);
signal noi_envsgn_old: std_logic; -- noi old envelope sign (used in zombie mode)
signal noi_envper_old: std_logic_vector(2 downto 0); -- noi old envelope period (used in zombie mode)
signal noi_freqsh : std_logic_vector(3 downto 0);
signal noi_freqchange: std_logic;
signal noi_short : std_logic;
signal noi_div : std_logic_vector(2 downto 0);
signal noi_trigger : std_logic;
signal noi_lenchk : std_logic;
signal noi_fr2 : std_logic_vector(10 downto 0); -- Noise frequency (shadow copy)
signal noi_vol : std_logic_vector(3 downto 0); -- Noise initial volume
signal noi_playing : std_logic; -- Noise channel active
signal noi_wav : std_logic_vector(5 downto 0); -- Noise output waveform
@@ -245,9 +251,10 @@ begin
noi_trigger <= '0';
end if;
sq2_volchange <= '0';
sq1_volchange <= '0';
noi_volchange <= '0';
sq2_nr2change <= '0';
sq1_nr2change <= '0';
noi_nr2change <= '0';
noi_freqchange<= '0';
sq2_lenchange <= '0';
sq1_lenchange <= '0';
@@ -275,12 +282,15 @@ begin
sq1_swshift <= s1_writedata(2 downto 0);
when "010001" => -- NR11 FF11 DDLL LLLL Duty, Length load (64-L)
sq1_duty <= s1_writedata(7 downto 6);
-- sq1_slen <= s1_writedata(5 downto 0);
sq1_slen <= std_logic_vector("1000000" - unsigned(s1_writedata(5 downto 0)));
sq1_lenchange <= '1';
when "010010" => -- NR12 FF12 VVVV APPP Starting volume, Envelope add mode, period
-- zombie mode copy old values
sq1_envsgn_old <= sq1_envsgn;
sq1_envper_old <= sq1_envper;
-- write to registers
sq1_nr2change <= '1';
sq1_svol <= s1_writedata(7 downto 4);
sq1_volchange <= '1';
sq1_envsgn <= s1_writedata(3);
sq1_envper <= s1_writedata(2 downto 0);
when "010011" => -- NR13 FF13 FFFF FFFF Frequency LSB
@@ -296,12 +306,15 @@ begin
-- Square 2
when "010110" => -- NR21 FF16 DDLL LLLL Duty, Length load (64-L)
sq2_duty <= s1_writedata(7 downto 6);
-- sq2_slen <= s1_writedata(5 downto 0);
sq2_slen <= std_logic_vector("1000000" - unsigned(s1_writedata(5 downto 0)));
sq2_lenchange <= '1';
when "010111" => -- NR22 FF17 VVVV APPP Starting volume, Envelope add mode, period
-- zombie mode copy old values
sq2_envsgn_old <= sq2_envsgn;
sq2_envper_old <= sq2_envper;
-- write to registers
sq2_svol <= s1_writedata(7 downto 4);
sq2_volchange <= '1';
sq2_nr2change <= '1';
sq2_envsgn <= s1_writedata(3);
sq2_envper <= s1_writedata(2 downto 0);
when "011000" => -- NR23 FF18 FFFF FFFF Frequency LSB
@@ -338,14 +351,19 @@ begin
noi_slen <= std_logic_vector("1000000" - unsigned(s1_writedata(5 downto 0)));
noi_lenchange <= '1';
when "100001" => -- NR42 FF21 VVVV APPP Starting volume, Envelope add mode, period
-- zombie mode copy old values
noi_envsgn_old <= noi_envsgn;
noi_envper_old <= noi_envper;
-- write to registers
noi_svol <= s1_writedata(7 downto 4);
noi_volchange <= '1';
noi_nr2change <= '1';
noi_envsgn <= s1_writedata(3);
noi_envper <= s1_writedata(2 downto 0);
when "100010" => -- NR43 FF22 SSSS WDDD Clock shift, Width mode of LFSR, Divisor code
noi_freqsh <= s1_writedata(7 downto 4);
noi_short <= s1_writedata(3);
noi_div <= s1_writedata(2 downto 0);
noi_freqchange <= '1';
when "100011" => -- NR44 FF23 TL-- ---- Trigger, Length enable
noi_trigger <= s1_writedata(7);
if noi_lenchk = '0' and s1_writedata(6) = '1' and en_len_r then
@@ -541,11 +559,13 @@ begin
variable sweep_calculate: boolean;
variable sweep_update: boolean;
variable sweep_negate: boolean;
variable sq1_envoff : boolean; -- check if envelope is on (zombiemode)
variable sq2_fcnt : unsigned(10 downto 0);
variable sq2_phase : integer range 0 to 7;
variable sq2_len : std_logic_vector(6 downto 0);
variable sq2_envcnt : std_logic_vector(3 downto 0); -- Sq2 envelope timer count
variable sq2_envoff : boolean; -- check if envelope is on (zombiemode)
variable sq2_out : std_logic;
variable wav_fcnt : unsigned(10 downto 0);
@@ -555,13 +575,16 @@ begin
variable wav_index : unsigned(4 downto 0);
variable noi_divisor : unsigned(10 downto 0); -- Noise frequency divisor
variable noi_freq : unsigned(10 downto 0); -- Noise frequency (calculated)
variable noi_period : unsigned(10 downto 0); -- Noise period (calculated)
variable noi_fcnt : unsigned(10 downto 0);
variable noi_lfsr : unsigned(14 downto 0); -- 15 bits
variable noi_len : std_logic_vector(6 downto 0);
variable noi_envcnt : std_logic_vector(3 downto 0); -- Noise envelope timer count
variable noi_envoff : boolean; -- check if envelope is on (zombiemode)
variable noi_out : std_logic;
variable noi_xor : std_logic;
variable tmp_volume : unsigned(7 downto 0); -- used in zombie mode
variable acc_fcnt : unsigned(11 downto 0);
begin
@@ -578,9 +601,9 @@ begin
sq1_swoffs := (others => '0');
sq1_swfr := (others => '0');
sq1_out := '0';
sq2_playing <= '0';
-- sq2_fr2 <= (others => '0');
sq2_fcnt := (others => '0');
sq2_phase := 0;
sq2_len := (others => '0');
@@ -595,7 +618,6 @@ begin
wav_index := (others => '0');
noi_playing <= '0';
noi_fr2 <= (others => '0');
noi_fcnt := (others => '0');
noi_lfsr := (others => '1');
noi_len := (others => '0');
@@ -606,10 +628,19 @@ begin
sweep_update := false;
sq1_sweep_en := false;
sweep_negate := false;
-- zombie mode check if env is still updating
sq2_envoff := false;
sq1_envoff := false;
noi_envoff := false;
elsif rising_edge(clk) then
----------------------- Square channel 1 -----------------------------
if en_snd4 then
-- Sq1 frequency timer
-- Sq1 frequency timer Frequency = 131072/(2048-x) Hz
if sq1_playing = '1' then
acc_fcnt := ('0'&sq1_fcnt) + to_unsigned(1, acc_fcnt'length);
if acc_fcnt(acc_fcnt'high) = '1' then
@@ -623,41 +654,7 @@ begin
sq1_fcnt := acc_fcnt(sq1_fcnt'range);
end if;
end if;
-- Sq2 frequency timer
if sq2_playing = '1' then
acc_fcnt := ('0'&sq2_fcnt) + to_unsigned(1, acc_fcnt'length);
if acc_fcnt(acc_fcnt'high) = '1' then
if sq2_phase < 7 then
sq2_phase := sq2_phase + 1;
else
sq2_phase := 0;
end if;
sq2_fcnt := unsigned(sq2_freq);
else
sq2_fcnt := acc_fcnt(sq2_fcnt'range);
end if;
end if;
-- Noi frequency timer
if noi_playing = '1' then
acc_fcnt := ('0'&noi_fcnt) + to_unsigned(1, acc_fcnt'length);
if acc_fcnt(acc_fcnt'high) = '1' then
-- Noise LFSR
noi_xor := noi_lfsr(0) xor noi_lfsr(1);
noi_lfsr := noi_xor & noi_lfsr(14 downto 1);
if noi_short = '1' then
noi_lfsr(6) := noi_xor;
end if;
noi_out := not noi_lfsr(0);
noi_fcnt := unsigned(noi_fr2);
else
noi_fcnt := acc_fcnt(noi_fcnt'range);
end if;
end if;
case sq1_duty is
when "00" => sq1_out := duty_0(sq1_phase);
when "01" => sq1_out := duty_1(sq1_phase);
@@ -670,31 +667,9 @@ begin
sq1_wav <= sq1_vol & "00";
else
sq1_wav <= "000000";
end if;
case sq2_duty is
when "00" => sq2_out := duty_0(sq2_phase);
when "01" => sq2_out := duty_1(sq2_phase);
when "10" => sq2_out := duty_2(sq2_phase);
when "11" => sq2_out := duty_3(sq2_phase);
when others => null;
end case;
if sq2_out = '1' then
sq2_wav <= sq2_vol & "00";
else
sq2_wav <= "000000";
end if;
if noi_out = '1' then
noi_wav <= noi_vol & "00";
else
noi_wav <= "000000";
end if;
end if;
-- Square channel 1
end if;
end if;
-- Length counter
if en_len or sq1_lenquirk = '1' then
if sq1_len > 0 and sq1_lenchk = '1' then
@@ -757,7 +732,6 @@ begin
if (sq1_swper /= "000" and sq1_swshift /= "000") then
sq1_fr2 <= std_logic_vector(sq1_swfr(10 downto 0));
sq1_freqchange <= '1';
-- sq1_freq <= std_logic_vector(sq1_swfr(10 downto 0)); TODO: update reg
sweep_calculate:= true; -- when updating calculate 2nd time
end if;
end if;
@@ -775,10 +749,14 @@ begin
if sq1_envsgn = '1' then
if sq1_vol /= "1111" then -- sq1_vol < 15
sq1_vol <= std_logic_vector(unsigned(sq1_vol) + 1);
else
sq1_envoff := true; -- envelope done
end if;
else
if sq1_vol /= "0000" then -- sq1_vol >
sq1_vol <= std_logic_vector(unsigned(sq1_vol) - 1);
else
sq1_envoff := true; -- envelope done
end if;
end if;
@@ -802,16 +780,33 @@ begin
sq1_swcnt := (others => '0');
sq1_swfr := (others => '0');
sq1_sweep_en := false;
--sq1_wav <= "000000";
end if;
end if;
if sq1_trigger = '1' or sq1_volchange = '1' then
sq1_vol <= sq1_svol;
if sq1_trigger = '1' or sq1_nr2change = '1' then
-- "zombie" mode
tmp_volume := "0000"&unsigned(sq1_vol);
if sq1_envper_old="000" and not sq1_envoff then
tmp_volume := "0000"&unsigned(sq1_vol) + 1;
else
if sq1_envsgn_old = '0' then
tmp_volume := "0000"&unsigned(sq1_vol) + 2;
end if;
end if;
if (sq1_envsgn xor sq1_envsgn_old) = '1' then
tmp_volume := X"10" - tmp_volume;
end if;
sq1_vol <= std_logic_vector(tmp_volume(3 downto 0));
-- check if dac is enabled
if sq1_svol = "00000" and sq1_envsgn = '0' then -- dac disabled
sq1_playing <= '0';
end if;
end if;
if sq1_lenchange = '1' then
sq1_len := sq1_slen;
@@ -820,7 +815,7 @@ begin
-- Check sample trigger and start playing
if sq1_trigger = '1' then
sq1_vol <= sq1_svol;
sq1_fr2 <= sq1_freq; -- shadow frequency register for sweep unit
sq1_sweep_en := sq1_swper /= "000" or sq1_swshift /= "000" ; -- sweep unit enabled ?
---- sweep quirks ---
@@ -846,6 +841,8 @@ begin
else
sq1_envcnt := '0' & sq1_envper; -- set to period
end if;
sq1_envoff := false;
sq1_phase := 0;
if sq1_len = 0 then -- trigger quirks
@@ -858,7 +855,39 @@ begin
end if;
-- Square channel 2
----------------------- Square channel 2 -----------------------------
if en_snd4 then
-- Sq2 frequency timer Frequency = 131072/(2048-x) Hz
if sq2_playing = '1' then
acc_fcnt := ('0'&sq2_fcnt) + to_unsigned(1, acc_fcnt'length);
if acc_fcnt(acc_fcnt'high) = '1' then
if sq2_phase < 7 then
sq2_phase := sq2_phase + 1;
else
sq2_phase := 0;
end if;
sq2_fcnt := unsigned(sq2_freq);
else
sq2_fcnt := acc_fcnt(sq2_fcnt'range);
end if;
end if;
case sq2_duty is
when "00" => sq2_out := duty_0(sq2_phase);
when "01" => sq2_out := duty_1(sq2_phase);
when "10" => sq2_out := duty_2(sq2_phase);
when "11" => sq2_out := duty_3(sq2_phase);
when others => null;
end case;
if sq2_out = '1' then
sq2_wav <= sq2_vol & "00";
else
sq2_wav <= "000000";
end if;
end if;
-- Length counter
if en_len or sq2_lenquirk = '1' then
if sq2_len > 0 and sq2_lenchk = '1' then
@@ -877,10 +906,14 @@ begin
if sq2_envsgn = '1' then
if sq2_vol /= "1111" then -- sq2_vol < 15
sq2_vol <= std_logic_vector(unsigned(sq2_vol) + 1);
else
sq2_envoff := true;
end if;
else
if sq2_vol /= "0000" then -- sq2_vol > 0
sq2_vol <= std_logic_vector(unsigned(sq2_vol) - 1);
else
sq2_envoff := true;
end if;
end if;
@@ -899,12 +932,28 @@ begin
then
sq2_playing <= '0';
sq2_envcnt := "0000";
--sq2_wav <= "000000";
end if;
end if;
if sq2_volchange ='1' or sq2_trigger= '1' then
sq2_vol <= sq2_svol;
if sq2_nr2change ='1' or sq2_trigger= '1' then
-- "zombie" mode
tmp_volume := "0000"&unsigned(sq2_vol);
if sq2_envper_old="000" and not sq2_envoff then
tmp_volume := "0000"&unsigned(sq2_vol) + 1;
else
if sq2_envsgn_old = '0' then
tmp_volume := "0000"&unsigned(sq2_vol) + 2;
end if;
end if;
if (sq2_envsgn xor sq2_envsgn_old) = '1' then
tmp_volume := X"10" - tmp_volume;
end if;
sq2_vol <= std_logic_vector(tmp_volume(3 downto 0));
-- check if dac is enabled
if sq2_svol = "00000" and sq2_envsgn = '0' then -- dac disabled
sq2_playing <= '0';
end if;
@@ -916,6 +965,7 @@ begin
-- Check sample trigger and start playing
if sq2_trigger = '1' then
sq2_vol <= sq2_svol;
-- sq2_fr2 <= sq2_freq;
sq2_fcnt := unsigned(sq2_freq);
@@ -930,6 +980,7 @@ begin
else
sq2_envcnt := '0' & sq2_envper; -- set to period
end if;
sq2_envoff := false;
sq2_phase := 0;
if sq2_len = 0 then -- trigger quirks
@@ -942,7 +993,35 @@ begin
end if;
-- Noise channel
----------------------- Noise channel -----------------------------
-- Noi frequency timer Frequency = 524288 Hz / r / 2^(s+1) ;For r=0 assume r=0.5 instead
if en_snd4 then
if noi_playing = '1' then
acc_fcnt := ('0'&noi_fcnt) - to_unsigned(1, acc_fcnt'length);
if acc_fcnt = 0 then
-- Noise LFSR
noi_xor := noi_lfsr(0) xor noi_lfsr(1);
noi_lfsr := noi_xor & noi_lfsr(14 downto 1);
if noi_short = '1' then
noi_lfsr(6) := noi_xor;
end if;
noi_out := not noi_lfsr(0);
noi_fcnt := noi_period;
else
noi_fcnt := acc_fcnt(noi_fcnt'range);
end if;
end if;
if noi_out = '1' then
noi_wav <= noi_vol & "00";
else
noi_wav <= "000000";
end if;
end if;
-- Length counter
if en_len or noi_lenquirk = '1' then
if noi_len > 0 and noi_lenchk = '1' then
@@ -961,10 +1040,14 @@ begin
if noi_envsgn = '1' then
if noi_vol /= "1111" then -- noi_vol < 15
noi_vol <= std_logic_vector(unsigned(noi_vol) + 1);
else
noi_envoff := true;
end if;
else
if noi_vol /= "0000" then -- noi_vol > 0
noi_vol <= std_logic_vector(unsigned(noi_vol) - 1);
else
noi_envoff := true;
end if;
end if;
@@ -986,8 +1069,25 @@ begin
end if;
end if;
if noi_volchange ='1' or noi_trigger= '1' then
noi_vol <= noi_svol;
if noi_nr2change ='1' or noi_trigger= '1' then
-- "zombie" mode
tmp_volume := "0000"&unsigned(noi_vol);
if noi_envper_old="000" and not noi_envoff then
tmp_volume := "0000"&unsigned(noi_vol) + 1;
else
if noi_envsgn_old = '0' then
tmp_volume := "0000"&unsigned(noi_vol) + 2;
end if;
end if;
if (noi_envsgn xor noi_envsgn_old) = '1' then
tmp_volume := X"10" - tmp_volume;
end if;
noi_vol <= std_logic_vector(tmp_volume(3 downto 0));
-- check if dac is enabled
if noi_svol = "00000" and noi_envsgn = '0' then -- dac disabled
noi_playing <= '0';
end if;
@@ -996,36 +1096,32 @@ begin
if noi_lenchange = '1' then
noi_len := noi_slen;
end if;
-- Check sample trigger and start playing
if noi_trigger = '1' then
if noi_trigger = '1' or noi_freqchange = '1' then
-- Calculate noise frequency
case noi_div is
when "000" => noi_divisor := to_unsigned(2048 - 8, noi_divisor'length);
when "001" => noi_divisor := to_unsigned(2048 - 16, noi_divisor'length);
when "010" => noi_divisor := to_unsigned(2048 - 32, noi_divisor'length);
when "011" => noi_divisor := to_unsigned(2048 - 48, noi_divisor'length);
when "100" => noi_divisor := to_unsigned(2048 - 64, noi_divisor'length);
when "101" => noi_divisor := to_unsigned(2048 - 80, noi_divisor'length);
when "110" => noi_divisor := to_unsigned(2048 - 96, noi_divisor'length);
when others => noi_divisor := to_unsigned(2048 - 112, noi_divisor'length);
when "000" => noi_period := to_unsigned(2, noi_period'length);
when "001" => noi_period := to_unsigned(4, noi_period'length);
when "010" => noi_period := to_unsigned(8, noi_period'length);
when "011" => noi_period := to_unsigned(12, noi_period'length);
when "100" => noi_period := to_unsigned(16, noi_period'length);
when "101" => noi_period := to_unsigned(20, noi_period'length);
when "110" => noi_period := to_unsigned(24, noi_period'length);
when others => noi_period := to_unsigned(28, noi_divisor'length);
end case;
noi_period := noi_period sll to_integer(unsigned(noi_freqsh));
noi_fcnt := noi_period;
end if;
-- Check sample trigger and start playing
if noi_trigger = '1' then
noi_vol <= noi_svol;
noi_lfsr := (others => '1');
-- case noi_freqsh is
-- when "000" => noi_freq := unsigned(noi_divisor);
-- when "001" => noi_freq := '0' & unsigned(noi_divisor(10 downto 1));
-- when "010" => noi_freq := "00" & unsigned(noi_divisor(10 downto 2));
-- when "011" => noi_freq := "000" & unsigned(noi_divisor(10 downto 3));
-- when "100" => noi_freq := "0000" & unsigned(noi_divisor(10 downto 4));
-- when "101" => noi_freq := "00000" & unsigned(noi_divisor(10 downto 5));
-- when "110" => noi_freq := "000000" & unsigned(noi_divisor(10 downto 6));
-- when "111" => noi_freq := "0000000" & unsigned(noi_divisor(10 downto 7));
-- when others => noi_freq := unsigned(noi_divisor);
-- end case;
noi_freq := noi_divisor sll to_integer(unsigned(noi_freqsh));
noi_fr2 <= std_logic_vector(noi_freq);
noi_fcnt := noi_freq;
-- reload envelope counter with period
if noi_envper = "000" then
@@ -1033,6 +1129,7 @@ begin
else
noi_envcnt := '0' & noi_envper; -- set to period
end if;
noi_envoff := false;
if not (noi_svol = "00000" and noi_envsgn = '0') then -- dac enabled
noi_playing <= '1';
@@ -1046,9 +1143,11 @@ begin
end if;
end if;
end if;
----------------------------- Wave channel -----------------------------------
if en_snd2 then
-- Wave frequency timer
-- Wave frequency timer Frequency = 4194304/(64*(2048-x)) Hz = 65536/(2048-x) Hz
wav_shift := false;
if wav_playing = '1' then
acc_fcnt := ('0'&wav_fcnt) + to_unsigned(1, acc_fcnt'length);
@@ -1079,7 +1178,6 @@ begin
end if;
end if;
-- Wave channel
if wav_playing = '1' then
-- Check for end of playing conditions
if (wav_lenchk = '1' and wav_len = 0) or wav_enable = '0' then