SOUND: sq1 sweep unit rewrite, trigger and length quirks implemented

This commit is contained in:
Bruno Gouveia
2018-11-24 01:01:14 +00:00
parent 478f4c65b4
commit 938d8f6dbe

View File

@@ -38,6 +38,7 @@ architecture SYN of gbc_snd is
signal en_snden4 : boolean; -- Enable at clk/4
signal en_len : boolean; -- Sample length
signal en_len_r : boolean;
signal en_env : boolean; -- Envelope
signal en_sweep : boolean; -- Sweep
@@ -55,11 +56,13 @@ architecture SYN of gbc_snd is
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
signal sq1_len_en_change : std_logic; -- Sq1 length off -> on
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_lenchange : std_logic;
signal sq1_lenquirk : std_logic;
signal sq1_playing : std_logic; -- Sq1 channel active
signal sq1_wav : std_logic_vector(5 downto 0); -- Sq1 output waveform
@@ -69,6 +72,7 @@ architecture SYN of gbc_snd is
signal sq2_svol : std_logic_vector(3 downto 0); -- Sq2 initial volume
signal sq2_volchange : 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_freq : std_logic_vector(10 downto 0); -- Sq2 frequency
@@ -83,6 +87,7 @@ architecture SYN of gbc_snd is
signal wav_enable : std_logic; -- Wave enable
signal wav_slen : std_logic_vector(8 downto 0); -- Wave play length
signal wav_lenchange : std_logic;
signal wav_lenquirk : std_logic;
signal wav_volsh : std_logic_vector(1 downto 0); -- Wave volume shift
signal wav_freq : std_logic_vector(10 downto 0); -- Wave frequency
signal wav_trigger : std_logic; -- Wave trigger play note
@@ -95,6 +100,7 @@ architecture SYN of gbc_snd is
signal noi_slen : std_logic_vector(6 downto 0);
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_envsgn : std_logic;
@@ -112,6 +118,7 @@ architecture SYN of gbc_snd is
signal ch_map : std_logic_vector(7 downto 0);
signal ch_vol : std_logic_vector(7 downto 0);
signal framecnt : integer range 0 to 7 := 0;
begin
@@ -121,16 +128,16 @@ begin
en_snd <= true;
-- Calculate divided and frame sequencer clock enables
process(clk, en_snd, reset)
process(clk, en_snd, snd_enable, reset)
variable clkcnt : unsigned(1 downto 0);
variable cnt_512 : unsigned(12 downto 0);
variable temp_512 : unsigned(13 downto 0);
variable framecnt : integer range 0 to 7 := 0;
begin
if reset = '1' then
if reset = '1' or snd_enable='0' then --only clock frame sequencer if sound is enabled, restart at 0
clkcnt := "00";
cnt_512 := (others => '0');
framecnt := 0;
framecnt <= 0;
en_len_r <= false;
elsif rising_edge(clk) then
-- Base clock divider
@@ -153,8 +160,10 @@ begin
en_env <= false;
en_sweep <= false;
if en_512 then
en_len_r <= not en_len_r;
if framecnt = 0 or framecnt = 2 or framecnt = 4 or framecnt = 6 then
en_len <= true;
en_len_r <= not en_len_r;
end if;
if framecnt = 2 or framecnt = 6 then
en_sweep <= true;
@@ -164,9 +173,9 @@ begin
end if;
if framecnt < 7 then
framecnt := framecnt + 1;
framecnt <= framecnt + 1;
else
framecnt := 0;
framecnt <= 0;
end if;
end if;
@@ -244,6 +253,12 @@ begin
sq1_lenchange <= '0';
wav_lenchange <= '0';
noi_lenchange <= '0';
sq1_lenquirk <= '0';
sq2_lenquirk <= '0';
wav_lenquirk <= '0';
noi_lenquirk <= '0';
if s1_write = '1' then
case s1_addr is
@@ -266,6 +281,9 @@ begin
sq1_freq(7 downto 0) <= s1_writedata;
when "010100" => -- NR14 FF14 TL-- -FFF Trigger, Length enable, Frequency MSB
sq1_trigger <= s1_writedata(7);
if sq1_lenchk = '0' and s1_writedata(6) = '1' and en_len_r then
sq1_lenquirk <= '1';
end if;
sq1_lenchk <= s1_writedata(6);
sq1_freq(10 downto 8) <= s1_writedata(2 downto 0);
@@ -284,6 +302,9 @@ begin
sq2_freq(7 downto 0) <= s1_writedata;
when "011001" => -- NR24 FF19 TL-- -FFF Trigger, Length enable, Frequency MSB
sq2_trigger <= s1_writedata(7);
if sq2_lenchk = '0' and s1_writedata(6) = '1' and en_len_r then
sq2_lenquirk <= '1';
end if;
sq2_lenchk <= s1_writedata(6);
sq2_freq(10 downto 8) <= s1_writedata(2 downto 0);
@@ -300,6 +321,9 @@ begin
wav_freq(7 downto 0) <= s1_writedata;
when "011110" => -- NR34 FF1E TL-- -FFF Trigger, Length enable, Frequency MSB
wav_trigger <= s1_writedata(7);
if wav_lenchk = '0' and s1_writedata(6) = '1' and en_len_r then
wav_lenquirk <= '1';
end if;
wav_lenchk <= s1_writedata(6);
wav_freq(10 downto 8) <= s1_writedata(2 downto 0);
@@ -318,6 +342,9 @@ begin
noi_div <= s1_writedata(2 downto 0);
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
noi_lenquirk <= '1';
end if;
noi_lenchk <= s1_writedata(6);
-- -- Control/Status
@@ -497,10 +524,13 @@ begin
variable sq1_phase : integer range 0 to 7;
variable sq1_len : std_logic_vector(6 downto 0);
variable sq1_envcnt : std_logic_vector(2 downto 0); -- Sq1 envelope timer count
variable sq1_swcnt : std_logic_vector(2 downto 0); -- Sq1 sweep timer count
variable sq1_swcnt : std_logic_vector(3 downto 0); -- Sq1 sweep timer count
variable sq1_swoffs : unsigned(11 downto 0);
variable sq1_swfr : unsigned(11 downto 0);
variable sq1_out : std_logic;
variable sq1_sweep_en: boolean;
variable sweep_calculate: boolean;
variable sweep_update: boolean;
variable sq2_fcnt : unsigned(10 downto 0);
variable sq2_phase : integer range 0 to 7;
@@ -521,6 +551,7 @@ begin
variable noi_len : std_logic_vector(6 downto 0);
variable noi_envcnt : std_logic_vector(2 downto 0); -- Noise envelope timer count
variable noi_out : std_logic;
variable noi_xor : std_logic;
variable acc_fcnt : unsigned(11 downto 0);
begin
@@ -533,7 +564,7 @@ begin
sq1_len := (others => '0');
sq1_vol <= "0000";
sq1_envcnt := "000";
sq1_swcnt := "000";
sq1_swcnt := "0000";
sq1_swoffs := (others => '0');
sq1_swfr := (others => '0');
sq1_out := '0';
@@ -561,6 +592,9 @@ begin
noi_vol <= "0000";
noi_envcnt := "000";
noi_out := '0';
sweep_calculate:= false;
sweep_update := false;
sq1_sweep_en := false;
elsif rising_edge(clk) then
if en_snd4 then
@@ -599,10 +633,11 @@ begin
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(15 downto 1);
if noi_short = '1' then
noi_lfsr := (noi_lfsr(0) xor noi_lfsr(1)) & noi_lfsr(15 downto 8) & (noi_lfsr(0) xor noi_lfsr(1)) & noi_lfsr(6 downto 1);
else
noi_lfsr := (noi_lfsr(0) xor noi_lfsr(1)) & noi_lfsr(15 downto 1);
noi_lfsr(6) := noi_xor;
end if;
noi_out := not noi_lfsr(0);
@@ -650,11 +685,68 @@ begin
-- Square channel 1
-- Length counter
if en_len then
if en_len or sq1_lenquirk = '1' then
if sq1_len > 0 and sq1_lenchk = '1' then
sq1_len := std_logic_vector(unsigned(sq1_len) - 1);
end if;
end if;
-- Sweep processing
-- sweep counter
if en_sweep then
sq1_swcnt := std_logic_vector(unsigned(sq1_swcnt) - 1);
if sq1_swcnt = 0 then
-- reload counter with period
if sq1_swper = "000" then
sq1_swcnt := "1000"; -- set to 8
else
sq1_swcnt := '0' & sq1_swper; -- set to period
end if;
-- check if update needed
if sq1_sweep_en and sq1_swper /= "000" then
sweep_calculate:= true;
sweep_update:=true;
end if;
end if;
end if;
if sq1_sweep_en then
-- Calculate next sweep frequency
if sweep_calculate then
case sq1_swshift is
when "000" => sq1_swoffs := unsigned('0' & sq1_fr2);
when "001" => sq1_swoffs := "00" & unsigned(sq1_fr2(10 downto 1));
when "010" => sq1_swoffs := "000" & unsigned(sq1_fr2(10 downto 2));
when "011" => sq1_swoffs := "0000" & unsigned(sq1_fr2(10 downto 3));
when "100" => sq1_swoffs := "00000" & unsigned(sq1_fr2(10 downto 4));
when "101" => sq1_swoffs := "000000" & unsigned(sq1_fr2(10 downto 5));
when "110" => sq1_swoffs := "0000000" & unsigned(sq1_fr2(10 downto 6));
when "111" => sq1_swoffs := "00000000" & unsigned(sq1_fr2(10 downto 7));
when others => sq1_swoffs := unsigned('0' & sq1_fr2);
end case;
if sq1_swdir = '1' then
sq1_swfr := ('0' & unsigned(sq1_fr2)) - sq1_swoffs;
else
sq1_swfr := ('0' & unsigned(sq1_fr2)) + sq1_swoffs;
end if;
sweep_calculate:= false;
end if;
-- update registers, and calculate next frequency
if sweep_update then
sweep_update := false;
if (sq1_swper /= "000" and sq1_swshift /= "000") then
sq1_fr2 <= std_logic_vector(sq1_swfr(10 downto 0));
-- 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;
end if;
if sq1_playing = '1' then
@@ -677,49 +769,16 @@ begin
end if;
end if;
-- Sweep processing
if en_sweep or sq1_trigger = '1' then
case sq1_swshift is
when "000" => sq1_swoffs := unsigned('0' & sq1_fr2);
when "001" => sq1_swoffs := "00" & unsigned(sq1_fr2(10 downto 1));
when "010" => sq1_swoffs := "000" & unsigned(sq1_fr2(10 downto 2));
when "011" => sq1_swoffs := "0000" & unsigned(sq1_fr2(10 downto 3));
when "100" => sq1_swoffs := "00000" & unsigned(sq1_fr2(10 downto 4));
when "101" => sq1_swoffs := "000000" & unsigned(sq1_fr2(10 downto 5));
when "110" => sq1_swoffs := "0000000" & unsigned(sq1_fr2(10 downto 6));
when "111" => sq1_swoffs := "00000000" & unsigned(sq1_fr2(10 downto 7));
when others => sq1_swoffs := unsigned('0' & sq1_fr2);
end case;
-- Calculate next sweep frequency
if sq1_swper /= "000" then
if sq1_swdir = '0' then
sq1_swfr := ('0' & unsigned(sq1_fr2)) - sq1_swoffs;
else
sq1_swfr := ('0' & unsigned(sq1_fr2)) + sq1_swoffs;
end if;
else -- Sweep disabled
sq1_swfr := unsigned('0' & sq1_fr2);
end if;
-- Sweep counter
if sq1_swper /= "000" then
sq1_swcnt := std_logic_vector(unsigned(sq1_swcnt) + to_unsigned(1, sq1_swcnt'length));
if sq1_swcnt = sq1_swper then
sq1_fr2 <= std_logic_vector(sq1_swfr(10 downto 0));
sq1_swcnt := "000";
end if;
end if;
end if;
-- Check for end of playing conditions
--if sq1_vol = X"0" -- Volume == 0
if (sq1_lenchk = '1' and sq1_len = 0) -- Play length timer overrun
or (sq1_swper /= "000" and sq1_swfr(11) = '1') -- Sweep frequency overrun
or (sq1_sweep_en and sq1_swfr(11) = '1') -- Sweep frequency overrun
then
sq1_playing <= '0';
sq1_envcnt := "000";
sq1_swcnt := "000";
sq1_envcnt := (others => '0');
sq1_swcnt := (others => '0');
sq1_swfr := (others => '0');
sq1_sweep_en := false;
--sq1_wav <= "000000";
end if;
end if;
@@ -738,24 +797,41 @@ begin
-- Check sample trigger and start playing
if sq1_trigger = '1' then
sq1_fr2 <= sq1_freq;
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 ---
if sq1_swshift /= "000" then
sweep_calculate := true;
end if;
if sq1_swper = "000" then
sq1_swcnt := "1000"; -- set to 8
else
sq1_swcnt := '0' & sq1_swper; -- set to period
end if;
---- sweep quirks ---
sq1_fcnt := unsigned(sq1_freq);
if not (sq1_svol = "00000" and sq1_envsgn = '0') then -- dac enabled
sq1_playing <= '1';
end if;
sq1_envcnt := "000";
sq1_swcnt := "000";
sq1_phase := 0;
if sq1_len = 0 then
sq1_len := "1000000";
if sq1_len = 0 then -- trigger quirks
if sq1_lenchk = '1' and en_len_r then
sq1_len := "0111111"; -- 63
else
sq1_len := "1000000"; -- 64
end if;
end if;
end if;
-- Square channel 2
-- Length counter
if en_len then
if en_len or sq2_lenquirk = '1' then
if sq2_len > 0 and sq2_lenchk = '1' then
-- sq2_len := std_logic_vector(unsigned(sq2_len) + to_unsigned(1, sq2_len'length));
sq2_len := std_logic_vector(unsigned(sq2_len) - 1);
end if;
end if;
@@ -811,15 +887,19 @@ begin
end if;
sq2_envcnt := "000";
sq2_phase := 0;
if sq2_len = 0 then
sq2_len := "1000000";
if sq2_len = 0 then -- trigger quirks
if sq2_lenchk = '1' and en_len_r then
sq2_len := "0111111"; -- 63
else
sq2_len := "1000000"; -- 64
end if;
end if;
end if;
-- Noise channel
-- Length counter
if en_len then
if en_len or noi_lenquirk = '1' then
if noi_len > 0 and noi_lenchk = '1' then
noi_len := std_logic_vector(unsigned(noi_len) - 1);
end if;
@@ -900,8 +980,12 @@ begin
noi_playing <= '1';
end if;
if noi_len = 0 then
noi_len := "1000000"; -- set to max
if noi_len = 0 then -- trigger quirks
if noi_lenchk = '1' and en_len_r then
noi_len := "0111111"; -- 63
else
noi_len := "1000000"; -- 64
end if;
end if;
end if;
@@ -931,7 +1015,7 @@ begin
end if;
-- Length counter
if en_len then
if en_len or wav_lenquirk = '1' then
if wav_len > 0 and wav_lenchk = '1' then
wav_len := std_logic_vector(unsigned(wav_len) - 1);
end if;
@@ -955,9 +1039,14 @@ begin
wav_fr2 <= wav_freq;
wav_fcnt := unsigned(wav_freq);
wav_playing <= '1';
if wav_len = 0 then
wav_len := "100000000"; -- set to max
if wav_len = 0 then -- trigger quirks
if wav_lenchk = '1' and en_len_r then
wav_len := "011111111"; -- 255
else
wav_len := "100000000"; -- 256
end if;
end if;
end if;
if wav_enable = '1' and wav_volsh /= "00" then