Revision 1510
Added by markw 1 day ago
| atari_chips/pokeyv2/PSG/volume_profile.vhdl | ||
|---|---|---|
|
CHANNEL_MASK_1 : IN STD_LOGIC_VECTOR(5 downto 0); --1ABC/2ABC
|
||
|
CHANNEL_MASK_2 : IN STD_LOGIC_VECTOR(5 downto 0);
|
||
|
|
||
|
AUDIO_OUT_1 : OUT STD_LOGIC_VECTOR(15 downto 0);
|
||
|
AUDIO_OUT_2 : OUT STD_LOGIC_VECTOR(15 downto 0);
|
||
|
AUDIO_OUT_1 : OUT UNSIGNED(15 downto 0);
|
||
|
AUDIO_OUT_2 : OUT UNSIGNED(15 downto 0);
|
||
|
|
||
|
PROFILE_ADDR : OUT std_logic_vector(4 downto 0);
|
||
|
PROFILE_REQUEST : OUT std_logic;
|
||
| ... | ... | |
|
ready <= profile_ready;
|
||
|
|
||
|
-- output
|
||
|
AUDIO_OUT_1 <= STD_LOGIC_VECTOR(vol_1_reg);
|
||
|
AUDIO_OUT_2 <= STD_LOGIC_VECTOR(vol_2_reg);
|
||
|
AUDIO_OUT_1 <= vol_1_reg;
|
||
|
AUDIO_OUT_2 <= vol_2_reg;
|
||
|
|
||
|
PROFILE_ADDR <= channel_mux;
|
||
|
PROFILE_REQUEST <= request;
|
||
| atari_chips/pokeyv2/SID/postFilterSum.vhdl | ||
|---|---|---|
|
|
||
|
VOLUME : IN STD_LOGIC_VECTOR(3 downto 0);
|
||
|
|
||
|
CHANNEL_OUT : OUT STD_LOGIC_VECTOR(15 downto 0)
|
||
|
CHANNEL_OUT : OUT SIGNED(15 downto 0)
|
||
|
);
|
||
|
END SID_postFilterSum;
|
||
|
|
||
|
ARCHITECTURE vhdl OF SID_postFilterSum IS
|
||
|
signal out_reg: std_logic_vector(15 downto 0);
|
||
|
signal out_next: std_logic_vector(15 downto 0);
|
||
|
signal out_reg: signed(15 downto 0);
|
||
|
signal out_next: signed(15 downto 0);
|
||
|
|
||
|
function saturate(input : signed(17 downto 0)) return signed is
|
||
|
variable ret : signed(15 downto 0);
|
||
| ... | ... | |
|
variable volume_adj : signed(7 downto 0);
|
||
|
|
||
|
variable mult_res : signed(26 downto 0);
|
||
|
variable mult_res_un : unsigned(21 downto 6);
|
||
|
variable mult_res_saturated : signed(21 downto 6);
|
||
|
begin
|
||
|
filter_sel0ext := (others=>filter_sel(0));
|
||
|
filter_sel1ext := (others=>filter_sel(1));
|
||
| ... | ... | |
|
|
||
|
-- Then apply volume
|
||
|
mult_res := sum * resize(volume_adj,9);
|
||
|
mult_res_un := unsigned(saturate(mult_res(23 downto 6)) + 32768);
|
||
|
out_next <= std_logic_vector(mult_res_un(21 downto 6));
|
||
|
mult_res_saturated := saturate(mult_res(23 downto 6));
|
||
|
out_next <= mult_res_saturated(21 downto 6);
|
||
|
end process;
|
||
|
|
||
|
-- output
|
||
| atari_chips/pokeyv2/SID/top.vhdl | ||
|---|---|---|
|
DO : out std_logic_vector(7 downto 0);
|
||
|
DRIVE_DO : out std_logic;
|
||
|
|
||
|
AUDIO : out std_logic_vector(15 downto 0);
|
||
|
AUDIO : out signed(15 downto 0);
|
||
|
|
||
|
DEBUG_WV1 : out unsigned(11 downto 0);
|
||
|
DEBUG_EV1 : out unsigned(7 downto 0);
|
||
| ... | ... | |
|
-- op regs
|
||
|
signal addr_decoded : std_logic_vector(31 downto 0);
|
||
|
|
||
|
signal audio_reg: std_logic_vector(15 downto 0);
|
||
|
signal audio_reg: signed(15 downto 0);
|
||
|
|
||
|
-- osc regs
|
||
|
signal osc_a_reg : std_logic_vector(11 downto 0);
|
||
| atari_chips/pokeyv2/mixer.vhdl | ||
|---|---|---|
|
LIBRARY ieee;
|
||
|
USE ieee.std_logic_1164.all;
|
||
|
use ieee.numeric_std.all;
|
||
|
USE IEEE.STD_LOGIC_UNSIGNED.ALL;
|
||
|
use IEEE.STD_LOGIC_MISC.all;
|
||
|
use work.AudioTypes.all;
|
||
|
|
||
| ... | ... | |
|
DETECT_RIGHT : IN STD_LOGIC;
|
||
|
POST_DIVIDE : IN STD_LOGIC_VECTOR(7 downto 0);
|
||
|
FANCY_ENABLE : IN STD_LOGIC;
|
||
|
GTIA_EN : IN STD_LOGIC_VECTOR(3 downto 0);
|
||
|
ADC_EN : IN STD_LOGIC_VECTOR(3 downto 0);
|
||
|
B_CH0_EN : IN STD_LOGIC_VECTOR(3 downto 0);
|
||
|
B_CH1_EN : IN STD_LOGIC_VECTOR(3 downto 0);
|
||
|
|
||
|
CH0 : IN UNSIGNED(15 downto 0); --pokey0
|
||
|
CH1 : IN UNSIGNED(15 downto 0); --pokey1
|
||
|
CH2 : IN UNSIGNED(15 downto 0); --pokey2
|
||
|
CH3 : IN UNSIGNED(15 downto 0); --pokey3
|
||
|
CH4 : IN UNSIGNED(15 downto 0); --sample0
|
||
|
CH5 : IN UNSIGNED(15 downto 0); --sample1
|
||
|
CH6 : IN UNSIGNED(15 downto 0); --sid0
|
||
|
CH7 : IN UNSIGNED(15 downto 0); --sid1
|
||
|
CH8 : IN UNSIGNED(15 downto 0); --psg0
|
||
|
CH9 : IN UNSIGNED(15 downto 0); --psg1
|
||
|
CHA : IN UNSIGNED(15 downto 0); --gtia0
|
||
|
CHB : IN UNSIGNED(15 downto 0); --adc
|
||
|
L_CH0 : IN SIGNED(15 downto 0);
|
||
|
L_CH1 : IN SIGNED(15 downto 0);
|
||
|
L_CH2 : IN SIGNED(15 downto 0);
|
||
|
L_CH3 : IN SIGNED(15 downto 0);
|
||
|
L_CH4 : IN SIGNED(15 downto 0);
|
||
|
R_CH0 : IN SIGNED(15 downto 0);
|
||
|
R_CH1 : IN SIGNED(15 downto 0);
|
||
|
R_CH2 : IN SIGNED(15 downto 0);
|
||
|
R_CH3 : IN SIGNED(15 downto 0);
|
||
|
R_CH4 : IN SIGNED(15 downto 0);
|
||
|
B_CH0 : IN SIGNED(15 downto 0);
|
||
|
B_CH1 : IN SIGNED(15 downto 0);
|
||
|
|
||
|
AUDIO_0_UNSIGNED : out unsigned(15 downto 0);
|
||
|
AUDIO_1_UNSIGNED : out unsigned(15 downto 0);
|
||
|
AUDIO_2_UNSIGNED : out unsigned(15 downto 0);
|
||
|
AUDIO_3_UNSIGNED : out unsigned(15 downto 0)
|
||
|
AUDIO_0_SIGNED : out signed(15 downto 0);
|
||
|
AUDIO_1_SIGNED : out signed(15 downto 0);
|
||
|
AUDIO_2_SIGNED : out signed(15 downto 0);
|
||
|
AUDIO_3_SIGNED : out signed(15 downto 0)
|
||
|
);
|
||
|
END mixer;
|
||
|
|
||
|
ARCHITECTURE vhdl OF mixer IS
|
||
|
|
||
|
-- DC blocker constants
|
||
|
constant DC_EXTRA_BITS : integer := 4;
|
||
|
constant DC_ACC_WIDTH : integer := 16 + DC_EXTRA_BITS; -- 20 bits
|
||
|
constant DC_K : integer := 10;
|
||
|
|
||
|
subtype dc_acc_t is signed(DC_ACC_WIDTH-1 downto 0);
|
||
|
type dc_arr_t is array (0 to 3) of dc_acc_t;
|
||
|
|
||
|
-- DETECT RIGHT PLAYING
|
||
|
signal RIGHT_PLAYING_RECENTLY : std_logic;
|
||
|
signal RIGHT_NEXT : std_logic;
|
||
| ... | ... | |
|
signal RIGHT_PLAYING_COUNT_REG : unsigned(23 downto 0);
|
||
|
|
||
|
-- sums
|
||
|
signal audio0_reg : unsigned(15 downto 0);
|
||
|
signal audio0_next : unsigned(15 downto 0);
|
||
|
signal audio1_reg : unsigned(15 downto 0);
|
||
|
signal audio1_next : unsigned(15 downto 0);
|
||
|
signal audio2_reg : unsigned(15 downto 0);
|
||
|
signal audio2_next : unsigned(15 downto 0);
|
||
|
signal audio3_reg : unsigned(15 downto 0);
|
||
|
signal audio3_next : unsigned(15 downto 0);
|
||
|
signal audio0_reg : signed(15 downto 0);
|
||
|
signal audio0_next : signed(15 downto 0);
|
||
|
signal audio1_reg : signed(15 downto 0);
|
||
|
signal audio1_next : signed(15 downto 0);
|
||
|
signal audio2_reg : signed(15 downto 0);
|
||
|
signal audio2_next : signed(15 downto 0);
|
||
|
signal audio3_reg : signed(15 downto 0);
|
||
|
signal audio3_next : signed(15 downto 0);
|
||
|
|
||
|
signal acc_reg : unsigned(19 downto 0);
|
||
|
signal acc_next : unsigned(19 downto 0);
|
||
|
signal acc_reg : signed(19 downto 0);
|
||
|
signal acc_next : signed(19 downto 0);
|
||
|
|
||
|
-- DC blocker per-channel state
|
||
|
signal dc_reg : dc_arr_t;
|
||
|
signal dc_next : dc_arr_t;
|
||
|
|
||
|
-- Pipeline register: holds dc-corrected divided value between state_dc and state_clear
|
||
|
signal dc_corrected_reg : signed(19 downto 0);
|
||
|
signal dc_corrected_next : signed(19 downto 0);
|
||
|
|
||
|
signal out_ch_reg : std_logic_vector(1 downto 0);
|
||
|
signal out_ch_next : std_logic_vector(1 downto 0);
|
||
|
|
||
|
signal secondBatch_reg : std_logic;
|
||
|
signal secondBatch_next : std_logic;
|
||
|
|
||
|
signal state_reg : unsigned(3 downto 0);
|
||
|
signal state_next : unsigned(3 downto 0);
|
||
|
constant state_pokeyA_L : unsigned(3 downto 0) := "0000";
|
||
|
constant state_pokeyB_L : unsigned(3 downto 0) := "0001";
|
||
|
constant state_sample_L : unsigned(3 downto 0) := "0010";
|
||
|
constant state_sid_L : unsigned(3 downto 0) := "0011";
|
||
|
constant state_psg_L : unsigned(3 downto 0) := "0100";
|
||
|
constant state_adc_L : unsigned(3 downto 0) := "0101";
|
||
|
constant state_gtia_L : unsigned(3 downto 0) := "0110";
|
||
|
constant state_clear_L : unsigned(3 downto 0) := "0111";
|
||
|
constant state_pokeyA_R : unsigned(3 downto 0) := "1000";
|
||
|
constant state_pokeyB_R : unsigned(3 downto 0) := "1001";
|
||
|
constant state_sample_R : unsigned(3 downto 0) := "1010";
|
||
|
constant state_sid_R : unsigned(3 downto 0) := "1011";
|
||
|
constant state_psg_R : unsigned(3 downto 0) := "1100";
|
||
|
constant state_adc_R : unsigned(3 downto 0) := "1101";
|
||
|
constant state_gtia_R : unsigned(3 downto 0) := "1110";
|
||
|
constant state_clear_R : unsigned(3 downto 0) := "1111";
|
||
|
|
||
|
constant state_CH0 : unsigned(3 downto 0) := "0000";
|
||
|
constant state_CH1 : unsigned(3 downto 0) := "0001";
|
||
|
constant state_CH2 : unsigned(3 downto 0) := "0010";
|
||
|
constant state_CH3 : unsigned(3 downto 0) := "0011";
|
||
|
constant state_CH4 : unsigned(3 downto 0) := "0100";
|
||
|
constant state_BCH0 : unsigned(3 downto 0) := "0101";
|
||
|
constant state_BCH1 : unsigned(3 downto 0) := "0110";
|
||
|
constant state_dc : unsigned(3 downto 0) := "0111"; -- divide + dc block
|
||
|
constant state_clear : unsigned(3 downto 0) := "1000"; -- saturate + write output
|
||
|
|
||
|
signal channelsel : std_logic_vector(3 downto 0);
|
||
|
signal include_in_output : std_logic_vector(3 downto 0);
|
||
|
signal left_on_right : std_logic;
|
||
|
|
||
|
signal volume : unsigned(15 downto 0);
|
||
|
signal saturated : unsigned(15 downto 0);
|
||
|
signal volume : signed(15 downto 0);
|
||
|
signal saturated : signed(15 downto 0);
|
||
|
|
||
|
signal ready : std_logic;
|
||
|
|
||
|
signal write_0 : std_logic;
|
||
|
signal write_1 : std_logic;
|
||
|
signal write_2 : std_logic;
|
||
|
signal write_3 : std_logic;
|
||
|
signal write : std_logic;
|
||
|
|
||
|
BEGIN
|
||
|
-- DETECT IF RIGHT CHANNEL PLAYING
|
||
|
-- TODO: into another entity
|
||
| ... | ... | |
|
audio2_reg <= (others=>'0');
|
||
|
audio3_reg <= (others=>'0');
|
||
|
acc_reg <= (others=>'0');
|
||
|
secondBatch_reg <= '0';
|
||
|
state_reg <= state_pokeyA_L;
|
||
|
out_ch_reg <= (others=>'0');
|
||
|
dc_corrected_reg <= (others=>'0');
|
||
|
state_reg <= state_CH0;
|
||
|
for i in 0 to 3 loop
|
||
|
dc_reg(i) <= (others=>'0');
|
||
|
end loop;
|
||
|
elsif (clk'event and clk='1') then
|
||
|
RIGHT_REG <= RIGHT_NEXT;
|
||
|
RIGHT_PLAYING_COUNT_REG <= RIGHT_PLAYING_COUNT_NEXT;
|
||
| ... | ... | |
|
audio2_reg <= audio2_next;
|
||
|
audio3_reg <= audio3_next;
|
||
|
acc_reg <= acc_next;
|
||
|
secondBatch_reg <= secondBatch_next;
|
||
|
out_ch_reg <= out_ch_next;
|
||
|
dc_reg <= dc_next;
|
||
|
dc_corrected_reg <= dc_corrected_next;
|
||
|
state_reg <= state_next;
|
||
|
end if;
|
||
|
end process;
|
||
| ... | ... | |
|
RIGHT_PLAYING_RECENTLY <= or_reduce(std_logic_vector(RIGHT_PLAYING_COUNT_REG));
|
||
|
|
||
|
|
||
|
process(state_reg,secondBatch_reg,acc_reg,volume,ready,
|
||
|
POST_DIVIDE,FANCY_ENABLE,RIGHT_PLAYING_RECENTLY,DETECT_RIGHT,RIGHT_REG,SATURATED,GTIA_EN,ADC_EN)
|
||
|
variable postdivide : std_logic_vector(1 downto 0);
|
||
|
variable presaturate : unsigned(19 downto 0);
|
||
|
variable leftOnRight : std_logic;
|
||
|
variable clearAcc : std_logic;
|
||
|
variable R : std_logic;
|
||
|
variable pdsel : std_logic_vector(1 downto 0);
|
||
|
process(state_reg,RIGHT_REG,out_ch_reg,acc_reg,volume,dc_reg,dc_corrected_reg,
|
||
|
POST_DIVIDE,SATURATED,include_in_output)
|
||
|
variable postdivide : std_logic_vector(1 downto 0);
|
||
|
variable presaturate : signed(19 downto 0);
|
||
|
variable addAcc : std_logic;
|
||
|
variable clearAcc : std_logic;
|
||
|
-- DC blocker datapath variables
|
||
|
variable ch_idx : integer range 0 to 3;
|
||
|
variable x_ext : dc_acc_t;
|
||
|
variable dc_cur : dc_acc_t;
|
||
|
variable err : dc_acc_t;
|
||
|
variable adj : dc_acc_t;
|
||
|
variable dc_new_v : dc_acc_t;
|
||
|
variable y_new : dc_acc_t;
|
||
|
begin
|
||
|
state_next <= state_reg;
|
||
|
secondBatch_next <= secondBatch_reg;
|
||
|
acc_next <= acc_reg;
|
||
|
RIGHT_NEXT <= RIGHT_REG;
|
||
|
|
||
|
leftOnRight := not(FANCY_ENABLE) or (not(RIGHT_PLAYING_RECENTLY) AND DETECT_RIGHT);
|
||
|
clearAcc := '0';
|
||
|
state_next <= state_reg;
|
||
|
out_ch_next <= out_ch_reg;
|
||
|
acc_next <= acc_reg;
|
||
|
RIGHT_NEXT <= RIGHT_REG;
|
||
|
dc_next <= dc_reg;
|
||
|
dc_corrected_next <= dc_corrected_reg;
|
||
|
|
||
|
write_0 <= '0';
|
||
|
write_1 <= '0';
|
||
|
write_2 <= '0';
|
||
|
write_3 <= '0';
|
||
|
R := '0';
|
||
|
write <= '0';
|
||
|
channelsel <= (others=>'0');
|
||
|
saturated <= (others=>'0');
|
||
|
|
||
|
if (ready='1') then
|
||
|
case state_reg is
|
||
|
when state_pokeyA_L =>
|
||
|
channelsel <= x"0";
|
||
|
state_next <= state_pokeyB_L;
|
||
|
when state_pokeyB_L =>
|
||
|
channelsel <= x"2";
|
||
|
state_next <= state_sample_L;
|
||
|
when state_sample_L =>
|
||
|
channelsel <= x"4";
|
||
|
state_next <= state_sid_L;
|
||
|
when state_sid_L =>
|
||
|
channelsel <= x"6";
|
||
|
state_next <= state_psg_L;
|
||
|
when state_psg_L =>
|
||
|
channelsel <= x"8";
|
||
|
state_next <= state_adc_L;
|
||
|
when state_adc_L =>
|
||
|
channelsel <= x"b";
|
||
|
write_0 <= not(adc_en(0));
|
||
|
write_1 <= not(adc_en(0)) and leftOnRight;
|
||
|
write_2 <= not(adc_en(2));
|
||
|
write_3 <= not(adc_en(2)) and leftOnRight;
|
||
|
state_next <= state_gtia_L;
|
||
|
when state_gtia_L =>
|
||
|
channelsel <= x"a";
|
||
|
write_0 <= not(gtia_en(0));
|
||
|
write_1 <= not(gtia_en(0)) and leftOnRight;
|
||
|
write_2 <= not(gtia_en(2));
|
||
|
write_3 <= not(gtia_en(2)) and leftOnRight;
|
||
|
state_next <= state_clear_L;
|
||
|
when state_clear_L =>
|
||
|
clearAcc := '1';
|
||
|
write_0 <= gtia_en(0);
|
||
|
write_1 <= gtia_en(0) and leftOnRight;
|
||
|
write_2 <= gtia_en(2);
|
||
|
write_3 <= gtia_en(2) and leftOnRight;
|
||
|
state_next <= state_pokeyA_R;
|
||
|
when state_pokeyA_R =>
|
||
|
channelsel <= x"1";
|
||
|
R := '1';
|
||
|
state_next <= state_pokeyB_R;
|
||
|
when state_pokeyB_R =>
|
||
|
channelsel <= x"3";
|
||
|
R := '1';
|
||
|
state_next <= state_sample_R;
|
||
|
when state_sample_R =>
|
||
|
channelsel <= x"5";
|
||
|
R := '1';
|
||
|
state_next <= state_sid_R;
|
||
|
when state_sid_R =>
|
||
|
channelsel <= x"7";
|
||
|
R := '1';
|
||
|
state_next <= state_psg_R;
|
||
|
when state_psg_R =>
|
||
|
channelsel <= x"9";
|
||
|
R := '1';
|
||
|
state_next <= state_adc_R;
|
||
|
when state_adc_R =>
|
||
|
channelsel <= x"b";
|
||
|
R := '1';
|
||
|
write_1 <= not(adc_en(1)) and not(leftOnRight);
|
||
|
write_3 <= not(adc_en(3)) and not(leftOnRight);
|
||
|
-- NEEDS DOING WITHOUT ADC GTIA mixed, since those plays on all channels!!
|
||
|
RIGHT_NEXT <= xor_reduce(std_logic_vector(saturated));
|
||
|
state_next <= state_gtia_R;
|
||
|
when state_gtia_R =>
|
||
|
channelsel <= x"a";
|
||
|
R := '1';
|
||
|
write_1 <= not(gtia_en(1)) and not(leftOnRight);
|
||
|
write_3 <= not(gtia_en(3)) and not(leftOnRight);
|
||
|
state_next <= state_clear_R;
|
||
|
when state_clear_R =>
|
||
|
clearAcc := '1';
|
||
|
R := '1';
|
||
|
write_1 <= gtia_en(1) and not(leftOnRight);
|
||
|
write_3 <= gtia_en(3) and not(leftOnRight);
|
||
|
state_next <= state_pokeyA_L;
|
||
|
secondBatch_next <= not(secondBatch_reg);
|
||
|
when others =>
|
||
|
state_next <= state_pokeyA_L;
|
||
|
end case;
|
||
|
saturated <= (others=>'0');
|
||
|
addAcc := '0';
|
||
|
clearAcc := '0';
|
||
|
postdivide := "00";
|
||
|
|
||
|
pdsel(1) := secondBatch_reg;
|
||
|
pdsel(0) := R;
|
||
|
case pdsel is
|
||
|
when "00" =>
|
||
|
postdivide:=POST_DIVIDE(1 downto 0);
|
||
|
when "01" =>
|
||
|
postdivide:=POST_DIVIDE(3 downto 2);
|
||
|
when "10" =>
|
||
|
postdivide:=POST_DIVIDE(5 downto 4);
|
||
|
when "11" =>
|
||
|
postdivide:=POST_DIVIDE(7 downto 6);
|
||
|
case out_ch_reg is
|
||
|
when "00" =>
|
||
|
postdivide := POST_DIVIDE(1 downto 0);
|
||
|
addAcc := include_in_output(0);
|
||
|
when "01" =>
|
||
|
postdivide := POST_DIVIDE(3 downto 2);
|
||
|
addAcc := include_in_output(1);
|
||
|
when "10" =>
|
||
|
postdivide := POST_DIVIDE(5 downto 4);
|
||
|
addAcc := include_in_output(2);
|
||
|
when "11" =>
|
||
|
postdivide := POST_DIVIDE(7 downto 6);
|
||
|
addAcc := include_in_output(3);
|
||
|
when others =>
|
||
|
end case;
|
||
|
|
||
|
case state_reg is
|
||
|
when state_CH0 =>
|
||
|
channelsel <= x"0";
|
||
|
state_next <= state_CH1;
|
||
|
when state_CH1 =>
|
||
|
channelsel <= x"1";
|
||
|
state_next <= state_CH2;
|
||
|
when state_CH2 =>
|
||
|
channelsel <= x"2";
|
||
|
state_next <= state_CH3;
|
||
|
when state_CH3 =>
|
||
|
channelsel <= x"3";
|
||
|
state_next <= state_CH4;
|
||
|
when state_CH4 =>
|
||
|
channelsel <= x"4";
|
||
|
state_next <= state_BCH0;
|
||
|
when state_BCH0 =>
|
||
|
channelsel <= x"6";
|
||
|
state_next <= state_BCH1;
|
||
|
-- NEEDS DOING WITHOUT BCH* mixed, since those plays on all channels!!
|
||
|
RIGHT_NEXT <= (xor_reduce(std_logic_vector(acc_reg)) and out_ch_reg(0)) or (RIGHT_REG and not(out_ch_reg(0)));
|
||
|
when state_BCH1 =>
|
||
|
channelsel <= x"7";
|
||
|
state_next <= state_dc;
|
||
|
|
||
|
when state_dc =>
|
||
|
-- Divide accumulator and run dc blocker.
|
||
|
-- Result registered into dc_corrected_reg, accumulator cleared.
|
||
|
-- Critical path: shift + subtract + shift_right(K) + add + subtract
|
||
|
case postdivide is
|
||
|
when "00" => presaturate := resize(acc_reg(19 downto 0), 20);
|
||
|
when "01" => presaturate := resize(acc_reg(19 downto 1), 20);
|
||
|
when "10" => presaturate := resize(acc_reg(19 downto 2), 20);
|
||
|
when "11" => presaturate := resize(acc_reg(19 downto 3), 20);
|
||
|
when others =>
|
||
|
end case;
|
||
|
|
||
|
ch_idx := to_integer(unsigned(out_ch_reg));
|
||
|
x_ext := resize(presaturate, DC_ACC_WIDTH);
|
||
|
dc_cur := dc_reg(ch_idx);
|
||
|
err := x_ext - dc_cur;
|
||
|
adj := shift_right(err, DC_K);
|
||
|
dc_new_v := dc_cur + adj;
|
||
|
y_new := x_ext - dc_new_v;
|
||
|
|
||
|
dc_next(ch_idx) <= dc_new_v;
|
||
|
dc_corrected_next <= resize(y_new, 20);
|
||
|
clearAcc := '1';
|
||
|
state_next <= state_clear;
|
||
|
|
||
|
when state_clear =>
|
||
|
-- Saturate the registered dc-corrected value and write to output.
|
||
|
-- Critical path: just the saturation check + mux
|
||
|
write <= '1';
|
||
|
out_ch_next <= std_logic_vector(unsigned(out_ch_reg)+1);
|
||
|
state_next <= state_CH0;
|
||
|
|
||
|
when others =>
|
||
|
end case;
|
||
|
|
||
|
case postdivide is
|
||
|
when "00" =>
|
||
|
presaturate := resize(acc_reg(19 downto 0),20);
|
||
|
when "01" =>
|
||
|
presaturate := resize(acc_reg(19 downto 1),20);
|
||
|
when "10" =>
|
||
|
presaturate := resize(acc_reg(19 downto 2),20);
|
||
|
when "11" =>
|
||
|
presaturate := resize(acc_reg(19 downto 3),20);
|
||
|
when others =>
|
||
|
end case;
|
||
|
if or_reduce(std_logic_vector(presaturate(19 downto 16)))='1' then
|
||
|
saturated <= (others=>'1');
|
||
|
else
|
||
|
saturated <= presaturate(15 downto 0);
|
||
|
end if;
|
||
|
state_next <= state_CH0;
|
||
|
end case;
|
||
|
|
||
|
if (clearAcc='1') then
|
||
|
acc_next <= (others=>'0');
|
||
|
else
|
||
|
acc_next <= acc_reg + resize(volume,19);
|
||
|
end if;
|
||
|
channelsel(3) <= out_ch_reg(0);
|
||
|
|
||
|
-- Saturation reads from the pipeline register, so only the
|
||
|
-- saturation check itself is on the state_clear critical path
|
||
|
if dc_corrected_reg(19 downto 15) /= "00000" and
|
||
|
dc_corrected_reg(19 downto 15) /= "11111" then
|
||
|
saturated(14 downto 0) <= (others => not dc_corrected_reg(19));
|
||
|
saturated(15) <= dc_corrected_reg(19);
|
||
|
else
|
||
|
saturated <= dc_corrected_reg(15 downto 0);
|
||
|
end if;
|
||
|
|
||
|
-- Accumulator update: clear takes priority over add
|
||
|
if clearAcc = '1' then
|
||
|
acc_next <= (others=>'0');
|
||
|
elsif addAcc = '1' then
|
||
|
acc_next <= acc_reg + resize(volume, 20);
|
||
|
end if;
|
||
|
|
||
|
end process;
|
||
|
|
||
|
|
||
|
process(state_reg,channelsel,
|
||
|
ch0,ch1,ch2,ch3,ch4,ch5,ch6,ch7,ch8,ch9,cha,chb
|
||
|
L_CH0,L_CH1,L_CH2,L_CH3,L_CH4,
|
||
|
R_CH0,R_CH1,R_CH2,R_CH3,R_CH4,
|
||
|
B_CH0,B_CH1,
|
||
|
B_CH0_EN,B_CH1_EN
|
||
|
)
|
||
|
begin
|
||
|
volume <= (others=>'0');
|
||
|
ready <= '1';
|
||
|
--left
|
||
|
include_in_output(0) <= not(channelsel(3));
|
||
|
include_in_output(2) <= not(channelsel(3));
|
||
|
--right
|
||
|
include_in_output(1) <= channelsel(3);
|
||
|
include_in_output(3) <= channelsel(3);
|
||
|
case channelsel is
|
||
|
when x"0" =>
|
||
|
volume <= ch0;
|
||
|
volume <= L_CH0;
|
||
|
when x"1" =>
|
||
|
volume <= ch1;
|
||
|
volume <= L_CH1;
|
||
|
when x"2" =>
|
||
|
volume <= ch2;
|
||
|
volume <= L_CH2;
|
||
|
when x"3" =>
|
||
|
volume <= ch3;
|
||
|
volume <= L_CH3;
|
||
|
when x"4" =>
|
||
|
volume <= ch4;
|
||
|
when x"5" =>
|
||
|
volume <= ch5;
|
||
|
when x"6" =>
|
||
|
volume <= ch6;
|
||
|
when x"7" =>
|
||
|
volume <= ch7;
|
||
|
volume <= L_CH4;
|
||
|
when x"8" =>
|
||
|
volume <= ch8;
|
||
|
volume <= R_CH0;
|
||
|
when x"9" =>
|
||
|
volume <= ch9;
|
||
|
volume <= R_CH1;
|
||
|
when x"a" =>
|
||
|
volume <= cha;
|
||
|
volume <= R_CH2;
|
||
|
when x"b" =>
|
||
|
volume <= chb;
|
||
|
volume <= R_CH3;
|
||
|
when x"c" =>
|
||
|
volume <= R_CH4;
|
||
|
when x"6"|x"e" =>
|
||
|
include_in_output <= B_CH0_EN;
|
||
|
volume <= B_CH0;
|
||
|
when x"7"|x"f" =>
|
||
|
include_in_output <= B_CH1_EN;
|
||
|
volume <= B_CH1;
|
||
|
when others =>
|
||
|
end case;
|
||
|
end process;
|
||
|
|
||
|
process(saturated,secondBatch_reg,write_0,write_1,write_2,write_3,audio0_reg,audio1_reg,audio2_reg,audio3_reg)
|
||
|
left_on_right <= not(FANCY_ENABLE) or (not(RIGHT_PLAYING_RECENTLY) AND DETECT_RIGHT);
|
||
|
|
||
|
process(write,saturated,out_ch_reg,left_on_right,audio0_reg,audio1_reg,audio2_reg,audio3_reg)
|
||
|
variable out_ch_adj : std_logic_vector(2 downto 0);
|
||
|
variable wr : std_logic_vector(3 downto 0);
|
||
|
begin
|
||
|
audio0_next <= audio0_reg;
|
||
|
audio1_next <= audio1_reg;
|
||
|
audio2_next <= audio2_reg;
|
||
|
audio3_next <= audio3_reg;
|
||
|
|
||
|
out_ch_adj(1 downto 0) := out_ch_reg;
|
||
|
out_ch_adj(2) := left_on_right;
|
||
|
|
||
|
if (write_0='1' and secondBatch_reg='0') then
|
||
|
wr := (others=>'0');
|
||
|
case out_ch_adj is
|
||
|
when "000" =>
|
||
|
wr(0) := write;
|
||
|
when "001" =>
|
||
|
wr(1) := write;
|
||
|
when "010" =>
|
||
|
wr(2) := write;
|
||
|
when "011" =>
|
||
|
wr(3) := write;
|
||
|
when "100" =>
|
||
|
wr(0) := write;
|
||
|
wr(1) := write;
|
||
|
when "110" =>
|
||
|
wr(2) := write;
|
||
|
wr(3) := write;
|
||
|
when others =>
|
||
|
-- 101 -> write to right, dropped since we are playing ONLY left on right
|
||
|
-- 111 -> write to right, dropped since we are playing ONLY left on right
|
||
|
-- Deliberate! We accumulate right still for the right detect logic but do not output it
|
||
|
end case;
|
||
|
|
||
|
if (wr(0)='1') then
|
||
|
audio0_next <= saturated;
|
||
|
end if;
|
||
|
if (write_1='1' and secondBatch_reg='0') then
|
||
|
if (wr(1)='1') then
|
||
|
audio1_next <= saturated;
|
||
|
end if;
|
||
|
if (write_2='1' and secondBatch_reg='1') then
|
||
|
if (wr(2)='1') then
|
||
|
audio2_next <= saturated;
|
||
|
end if;
|
||
|
if (write_3='1' and secondBatch_reg='1') then
|
||
|
if (wr(3)='1') then
|
||
|
audio3_next <= saturated;
|
||
|
end if;
|
||
|
end if;
|
||
|
end process;
|
||
|
|
||
|
-- output
|
||
|
AUDIO_0_UNSIGNED <= audio0_reg;
|
||
|
AUDIO_1_UNSIGNED <= audio1_reg;
|
||
|
AUDIO_2_UNSIGNED <= audio2_reg;
|
||
|
AUDIO_3_UNSIGNED <= audio3_reg;
|
||
|
AUDIO_0_SIGNED <= audio0_reg;
|
||
|
AUDIO_1_SIGNED <= audio1_reg;
|
||
|
AUDIO_2_SIGNED <= audio2_reg;
|
||
|
AUDIO_3_SIGNED <= audio3_reg;
|
||
|
end vhdl;
|
||
| atari_chips/pokeyv2/pokeymax.vhd | ||
|---|---|---|
|
signal WRITE_DATA : std_logic_vector(7 downto 0);
|
||
|
signal DEVICE_ADDR : std_logic_vector(3 downto 0);
|
||
|
|
||
|
signal POKEY_AUDIO_0 : unsigned(15 downto 0);
|
||
|
signal POKEY_AUDIO_1 : unsigned(15 downto 0);
|
||
|
signal POKEY_AUDIO_2 : unsigned(15 downto 0);
|
||
|
signal POKEY_AUDIO_3 : unsigned(15 downto 0);
|
||
|
signal POKEY_AUDIO_UNSIGNED : UNSIGNED_AUDIO_TYPE(3 downto 0);
|
||
|
|
||
|
signal AUDIO_0_UNSIGNED : unsigned(15 downto 0);
|
||
|
signal AUDIO_1_UNSIGNED : unsigned(15 downto 0);
|
||
|
signal AUDIO_2_UNSIGNED : unsigned(15 downto 0);
|
||
|
signal AUDIO_3_UNSIGNED : unsigned(15 downto 0);
|
||
|
signal AUDIO_MIXED_SIGNED : SIGNED_AUDIO_TYPE(3 downto 0);
|
||
|
|
||
|
signal AUDIO_0_SIGMADELTA : std_logic;
|
||
|
signal AUDIO_1_SIGMADELTA : std_logic;
|
||
| ... | ... | |
|
|
||
|
-- SID
|
||
|
signal SID_CLK_ENABLE : std_logic;
|
||
|
signal SID_AUDIO : SID_AUDIO_TYPE(1 downto 0);
|
||
|
signal SID_AUDIO_SIGNED : SIGNED_AUDIO_TYPE(1 downto 0);
|
||
|
signal SID_FLASH1_ADDR : std_logic_vector(16 downto 0);
|
||
|
signal SID_FLASH1_ROMREQUEST : std_logic;
|
||
|
signal SID_FLASH1_ROMREADY : std_logic;
|
||
| ... | ... | |
|
signal PSG_ENABLE_2Mhz : std_logic;
|
||
|
signal PSG_ENABLE_1Mhz : std_logic;
|
||
|
signal PSG_ENABLE : std_logic;
|
||
|
signal PSG_AUDIO : PSG_AUDIO_TYPE(1 downto 0);
|
||
|
signal PSG_AUDIO_UNSIGNED : UNSIGNED_AUDIO_TYPE(1 downto 0);
|
||
|
|
||
|
signal PSG_CHANNEL : PSG_CHANNEL_TYPE(5 downto 0);
|
||
|
signal PSG_CHANGED : std_logic_vector(1 downto 0);
|
||
| ... | ... | |
|
signal FANCY_ENABLE : std_logic;
|
||
|
signal FANCY_SWITCH : std_logic;
|
||
|
signal A4_DETECTED : std_logic;
|
||
|
signal GTIA_AUDIO : std_logic;
|
||
|
signal GTIA_AUDIO_OUT : std_logic;
|
||
|
signal GTIA_AUDIO_SIGNED : signed(15 downto 0);
|
||
|
|
||
|
signal EXT_INT : std_logic_vector(20 downto 0);
|
||
|
|
||
| ... | ... | |
|
signal CONFIG_ENABLE_NEXT: std_logic;
|
||
|
|
||
|
-- SAMPLE/COVOX
|
||
|
signal SAMPLE_AUDIO : SAMPLE_AUDIO_TYPE(1 downto 0);
|
||
|
signal SAMPLE_AUDIO_SIGNED : SIGNED_AUDIO_TYPE(1 downto 0);
|
||
|
signal SAMPLE_IRQ : std_logic;
|
||
|
signal SAMPLE_RAM_ADDRESS : std_logic_vector(15 downto 0);
|
||
|
signal SAMPLE_RAM_WRITE_ENABLE : std_logic;
|
||
| ... | ... | |
|
signal fir_data_address :std_logic_vector(9 downto 0);
|
||
|
signal fir_data_ready :std_logic;
|
||
|
|
||
|
signal SIO_AUDIO : unsigned(15 downto 0);
|
||
|
signal SIO_AUDIO_UNSIGNED : unsigned(15 downto 0);
|
||
|
|
||
|
-- paddles
|
||
|
signal PADDLE_ADJ : std_logic_vector(7 downto 0);
|
||
| ... | ... | |
|
else return RIGHT;
|
||
|
end if;
|
||
|
end function min;
|
||
|
|
||
|
function unsigned_to_signed(audio_in : unsigned(15 downto 0)) return signed is
|
||
|
variable ret : std_logic_vector(15 downto 0);
|
||
|
begin
|
||
|
ret(15) := not(audio_in(15));
|
||
|
ret(14 downto 0) := std_logic_vector(audio_in(14 downto 0));
|
||
|
return signed(ret);
|
||
|
end function unsigned_to_signed;
|
||
|
|
||
|
function signed_to_unsigned(audio_in : signed(15 downto 0)) return unsigned is
|
||
|
variable ret : std_logic_vector(15 downto 0);
|
||
|
begin
|
||
|
ret(15) := not(audio_in(15));
|
||
|
ret(14 downto 0) := std_logic_vector(audio_in(14 downto 0));
|
||
|
return unsigned(ret);
|
||
|
end function signed_to_unsigned;
|
||
|
|
||
|
BEGIN
|
||
|
EXT <= (others=>'Z');
|
||
| ... | ... | |
|
EXT_INT(ext_bits downto 1) <= EXT;
|
||
|
|
||
|
synchronizer_gtia_audio : entity work.synchronizer
|
||
|
port map (clk=>clk, raw=>EXT_INT(gtia_audio_bit), sync=>GTIA_AUDIO);
|
||
|
port map (clk=>clk, raw=>EXT_INT(gtia_audio_bit), sync=>GTIA_AUDIO_OUT);
|
||
|
synchronizer_fancy_enable : entity work.synchronizer
|
||
|
port map (clk=>clk, raw=>EXT_INT(fancy_switch_bit), sync=>FANCY_SWITCH);
|
||
|
|
||
| ... | ... | |
|
CHANNEL_1 => CHANNEL1SUM_REG,
|
||
|
CHANNEL_2 => CHANNEL2SUM_REG,
|
||
|
CHANNEL_3 => CHANNEL3SUM_REG,
|
||
|
VOLUME_OUT_0 => POKEY_AUDIO_0,
|
||
|
VOLUME_OUT_1 => POKEY_AUDIO_1,
|
||
|
VOLUME_OUT_2 => POKEY_AUDIO_2,
|
||
|
VOLUME_OUT_3 => POKEY_AUDIO_3,
|
||
|
VOLUME_OUT_0 => POKEY_AUDIO_UNSIGNED(0),
|
||
|
VOLUME_OUT_1 => POKEY_AUDIO_UNSIGNED(1),
|
||
|
VOLUME_OUT_2 => POKEY_AUDIO_UNSIGNED(2),
|
||
|
VOLUME_OUT_3 => POKEY_AUDIO_UNSIGNED(3),
|
||
|
PROFILE_ADDR => POKEY_PROFILE_ADDR,
|
||
|
PROFILE_REQUEST => POKEY_PROFILE_REQUEST,
|
||
|
PROFILE_READY => POKEY_PROFILE_READY,
|
||
| ... | ... | |
|
-- SID
|
||
|
--------------------------------------------------------
|
||
|
sid_off : if enable_sid=0 generate
|
||
|
SID_AUDIO(0) <= (others=>'0');
|
||
|
SID_AUDIO(1) <= (others=>'0');
|
||
|
SID_AUDIO_SIGNED(0) <= to_signed(0,16);
|
||
|
SID_AUDIO_SIGNED(1) <= to_signed(0,16);
|
||
|
SID_DO(0) <= (others=>'0');
|
||
|
SID_DO(1) <= (others=>'0');
|
||
|
SID_DRIVE_DO(0) <= '0';
|
||
| ... | ... | |
|
--POT_X => (others=>'0'),
|
||
|
--POT_Y => (others=>'0'),
|
||
|
--EXTFILTER_EN => '0',
|
||
|
AUDIO => SID_AUDIO(0),
|
||
|
AUDIO => SID_AUDIO_SIGNED(0),
|
||
|
|
||
|
SIDTYPE => SID_FILTER1_REG(0),
|
||
|
EXT => "0"&SID_FILTER1_REG(1),
|
||
| ... | ... | |
|
--POT_X => (others=>'0'),
|
||
|
--POT_Y => (others=>'0'),
|
||
|
--EXTFILTER_EN => '0',
|
||
|
AUDIO => SID_AUDIO(1),
|
||
|
AUDIO => SID_AUDIO_SIGNED(1),
|
||
|
|
||
|
SIDTYPE => SID_FILTER2_REG(0),
|
||
|
EXT => "0"&SID_FILTER2_REG(1),
|
||
| ... | ... | |
|
-- PSG
|
||
|
--------------------------------------------------------
|
||
|
psg_off : if enable_psg=0 generate
|
||
|
PSG_AUDIO(0) <= (others=>'0');
|
||
|
PSG_AUDIO(1) <= (others=>'0');
|
||
|
PSG_AUDIO_UNSIGNED(0) <= to_unsigned(0,16);
|
||
|
PSG_AUDIO_UNSIGNED(1) <= to_unsigned(0,16);
|
||
|
PSG_DO(0) <= (others=>'0');
|
||
|
PSG_DO(1) <= (others=>'0');
|
||
|
end generate psg_off;
|
||
| ... | ... | |
|
CHANNEL_MASK_1=>PSG_MIX1, --LABC:RABC
|
||
|
CHANNEL_MASK_2=>PSG_MIX2,
|
||
|
|
||
|
AUDIO_OUT_1 => PSG_AUDIO(0),
|
||
|
AUDIO_OUT_2 => PSG_AUDIO(1),
|
||
|
AUDIO_OUT_1 => PSG_AUDIO_UNSIGNED(0),
|
||
|
AUDIO_OUT_2 => PSG_AUDIO_UNSIGNED(1),
|
||
|
|
||
|
--PROFILE_SELECT=>PSG_PROFILESEL_REG,
|
||
|
PROFILE_ADDR => PSG_PROFILE_ADDR,
|
||
| ... | ... | |
|
covox_off : if enable_covox=0 generate
|
||
|
SAMPLE_IRQ <= '0';
|
||
|
SAMPLE_DO <= (others=>'0');
|
||
|
SAMPLE_AUDIO(0) <= (others=>'0');
|
||
|
SAMPLE_AUDIO(1) <= (others=>'0');
|
||
|
SAMPLE_AUDIO_SIGNED(0) <= to_signed(0,16);
|
||
|
SAMPLE_AUDIO_SIGNED(1) <= to_signed(0,16);
|
||
|
ADPCM_STEP_REQUEST <= '0';
|
||
|
end generate covox_off;
|
||
|
|
||
| ... | ... | |
|
ADDR => ADDR_IN(1 downto 0),
|
||
|
DI => WRITE_DATA(7 downto 0),
|
||
|
DO => SAMPLE_DO,
|
||
|
AUDIO0 => SAMPLE_AUDIO(0),
|
||
|
AUDIO1 => SAMPLE_AUDIO(1)
|
||
|
AUDIO0 => SAMPLE_AUDIO_SIGNED(0),
|
||
|
AUDIO1 => SAMPLE_AUDIO_SIGNED(1)
|
||
|
);
|
||
|
end generate covox_on;
|
||
|
|
||
| ... | ... | |
|
ADDR => ADDR_IN(4 downto 0),
|
||
|
DI => WRITE_DATA(7 downto 0),
|
||
|
DO => SAMPLE_DO,
|
||
|
AUDIO0 => SAMPLE_AUDIO(0),
|
||
|
AUDIO1 => SAMPLE_AUDIO(1),
|
||
|
AUDIO0 => SAMPLE_AUDIO_SIGNED(0),
|
||
|
AUDIO1 => SAMPLE_AUDIO_SIGNED(1),
|
||
|
IRQ => SAMPLE_IRQ,
|
||
|
|
||
|
RAM_ADDR => SAMPLE_RAM_ADDRESS,
|
||
| ... | ... | |
|
|
||
|
-------------------------------------------------------
|
||
|
-- AUDIO mixing
|
||
|
GTIA_AUDIO_SIGNED(15) <= not(GTIA_AUDIO_OUT);
|
||
|
GTIA_AUDIO_SIGNED(14 downto 0) <= to_signed(0,15);
|
||
|
mixer1 : entity work.mixer
|
||
|
PORT MAP
|
||
|
(
|
||
| ... | ... | |
|
POST_DIVIDE => POST_DIVIDE_REG,
|
||
|
DETECT_RIGHT => DETECT_RIGHT_REG,
|
||
|
FANCY_ENABLE => FANCY_ENABLE,
|
||
|
GTIA_EN => GTIA_ENABLE_REG,
|
||
|
ADC_EN => "1100",
|
||
|
B_CH0_EN => GTIA_ENABLE_REG,
|
||
|
B_CH1_EN => "1100",
|
||
|
|
||
|
CH0 => POKEY_AUDIO_0,
|
||
|
CH1 => POKEY_AUDIO_1,
|
||
|
CH2 => POKEY_AUDIO_2,
|
||
|
CH3 => POKEY_AUDIO_3,
|
||
|
CH4 => unsigned(SAMPLE_AUDIO(0)),
|
||
|
CH5 => unsigned(SAMPLE_AUDIO(1)),
|
||
|
CH6 => unsigned(SID_AUDIO(0)),
|
||
|
CH7 => unsigned(SID_AUDIO(1)),
|
||
|
CH8 => unsigned(PSG_AUDIO(0)),
|
||
|
CH9 => unsigned(PSG_AUDIO(1)),
|
||
|
CHA(14 downto 0) => (others=>'0'),
|
||
|
CHA(15) => GTIA_AUDIO,
|
||
|
CHB => SIO_AUDIO,
|
||
|
L_CH0 => unsigned_to_signed(POKEY_AUDIO_UNSIGNED(0)),
|
||
|
R_CH0 => unsigned_to_signed(POKEY_AUDIO_UNSIGNED(1)),
|
||
|
L_CH1 => unsigned_to_signed(POKEY_AUDIO_UNSIGNED(2)),
|
||
|
R_CH1 => unsigned_to_signed(POKEY_AUDIO_UNSIGNED(3)),
|
||
|
L_CH2 => SAMPLE_AUDIO_SIGNED(0),
|
||
|
R_CH2 => SAMPLE_AUDIO_SIGNED(1),
|
||
|
L_CH3 => SID_AUDIO_SIGNED(0),
|
||
|
R_CH3 => SID_AUDIO_SIGNED(1),
|
||
|
L_CH4 => unsigned_to_signed(PSG_AUDIO_UNSIGNED(0)),
|
||
|
R_CH4 => unsigned_to_signed(PSG_AUDIO_UNSIGNED(1)),
|
||
|
B_CH0 => GTIA_AUDIO_SIGNED,
|
||
|
B_CH1 => unsigned_to_signed(SIO_AUDIO_UNSIGNED),
|
||
|
|
||
|
AUDIO_0_UNSIGNED => AUDIO_0_UNSIGNED,
|
||
|
AUDIO_1_UNSIGNED => AUDIO_1_UNSIGNED,
|
||
|
AUDIO_2_UNSIGNED => AUDIO_2_UNSIGNED,
|
||
|
AUDIO_3_UNSIGNED => AUDIO_3_UNSIGNED
|
||
|
AUDIO_0_SIGNED => AUDIO_MIXED_SIGNED(0),
|
||
|
AUDIO_1_SIGNED => AUDIO_MIXED_SIGNED(1),
|
||
|
AUDIO_2_SIGNED => AUDIO_MIXED_SIGNED(2),
|
||
|
AUDIO_3_SIGNED => AUDIO_MIXED_SIGNED(3)
|
||
|
);
|
||
|
|
||
|
--approx line level by using 5V/4 -> ok 1.25V, should be ok approx
|
||
| ... | ... | |
|
clk => clk,
|
||
|
clk2 => CLK116,
|
||
|
ENABLE_179 => ENABLE_CYCLE,
|
||
|
audin => AUDIO_0_UNSIGNED,
|
||
|
audin => signed_to_unsigned(AUDIO_MIXED_SIGNED(0)),
|
||
|
AUDOUT => AUDIO_0_SIGMADELTA
|
||
|
);
|
||
|
|
||
| ... | ... | |
|
clk => clk,
|
||
|
clk2 => CLK106,
|
||
|
ENABLE_179 => ENABLE_CYCLE,
|
||
|
audin => AUDIO_1_UNSIGNED,
|
||
|
audin => signed_to_unsigned(AUDIO_MIXED_SIGNED(1)),
|
||
|
AUDOUT => AUDIO_1_SIGMADELTA
|
||
|
);
|
||
|
|
||
| ... | ... | |
|
clk => clk,
|
||
|
clk2 => CLK116,
|
||
|
ENABLE_179 => ENABLE_CYCLE,
|
||
|
audin => AUDIO_2_UNSIGNED,
|
||
|
audin => signed_to_unsigned(AUDIO_MIXED_SIGNED(2)),
|
||
|
AUDOUT => AUDIO_2_SIGMADELTA
|
||
|
);
|
||
|
|
||
| ... | ... | |
|
clk => clk,
|
||
|
clk2 => CLK106,
|
||
|
ENABLE_179 => ENABLE_CYCLE,
|
||
|
audin => AUDIO_3_UNSIGNED,
|
||
|
audin => signed_to_unsigned(AUDIO_MIXED_SIGNED(3)),
|
||
|
AUDOUT => AUDIO_3_SIGMADELTA
|
||
|
);
|
||
|
|
||
| ... | ... | |
|
PORT MAP
|
||
|
(
|
||
|
CLK => clk,
|
||
|
AUDIO_IN => audio_2_unsigned,
|
||
|
AUDIO_IN => signed_to_unsigned(AUDIO_MIXED_SIGNED(2)),
|
||
|
SAMPLE_IN => enable_cycle,
|
||
|
AUDIO_OUT => audio_2_filtered
|
||
|
);
|
||
| ... | ... | |
|
PORT MAP
|
||
|
(
|
||
|
CLK => clk,
|
||
|
AUDIO_IN => audio_3_unsigned,
|
||
|
AUDIO_IN => signed_to_unsigned(AUDIO_MIXED_SIGNED(3)),
|
||
|
SAMPLE_IN => enable_cycle,
|
||
|
AUDIO_OUT => audio_3_filtered
|
||
|
);
|
||
| ... | ... | |
|
adc_out_signed <= adc_in_signed;
|
||
|
end generate fir_off;
|
||
|
|
||
|
SIO_AUDIO <= unsigned(not(adc_use_reg(15))&adc_use_reg(14 downto 0));
|
||
|
SIO_AUDIO_UNSIGNED <= unsigned(not(adc_use_reg(15))&adc_use_reg(14 downto 0));
|
||
|
|
||
|
process(adc_reg,adc_output,adc_valid,ADC_VOLUME_REG)
|
||
|
variable adc_shrunk : signed(19 downto 0);
|
||
| ... | ... | |
|
adc_off : if enable_adc=0 generate
|
||
|
process(SIO_DATA_VOLUME_REG)
|
||
|
begin
|
||
|
SIO_AUDIO(15 downto 0) <= (others=>'0');
|
||
|
SIO_AUDIO_UNSIGNED(15 downto 0) <= (others=>'0');
|
||
|
|
||
|
case SIO_DATA_VOLUME_REG is
|
||
|
when "01" =>
|
||
|
SIO_AUDIO(10) <= SIO_RXD_ADC;
|
||
|
SIO_AUDIO_UNSIGNED(10) <= SIO_RXD_ADC;
|
||
|
when "10" =>
|
||
|
SIO_AUDIO(11) <= SIO_RXD_ADC;
|
||
|
SIO_AUDIO_UNSIGNED(11) <= SIO_RXD_ADC;
|
||
|
when "11" =>
|
||
|
SIO_AUDIO(12) <= SIO_RXD_ADC;
|
||
|
SIO_AUDIO_UNSIGNED(12) <= SIO_RXD_ADC;
|
||
|
when others =>
|
||
|
end case;
|
||
|
end process;
|
||
| atari_chips/pokeyv2/sample/adpcm.vhdl | ||
|---|---|---|
|
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
|
||
|
data_out : OUT std_logic_vector(15 downto 0); -- current output (signed)
|
||
|
|
||
|
dirty : IN STD_LOGIC_VECTOR(3 downto 0); -- channel needs updating
|
||
|
|
||
| ... | ... | |
|
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));
|
||
|
data_out <= std_logic_vector(acc_mux);
|
||
|
|
||
|
select_channel <= sel;
|
||
|
step_addr <= std_logic_vector(decstep_mux);
|
||
| atari_chips/pokeyv2/sample/top.vhdl | ||
|---|---|---|
|
DI : in std_logic_vector(7 downto 0);
|
||
|
|
||
|
DO : out std_logic_vector(7 downto 0);
|
||
|
AUDIO0 : out std_logic_vector(15 downto 0);
|
||
|
AUDIO1 : out std_logic_vector(15 downto 0);
|
||
|
AUDIO0 : out signed(15 downto 0);
|
||
|
AUDIO1 : out signed(15 downto 0);
|
||
|
IRQ : out std_logic;
|
||
|
|
||
|
RAM_ADDR : out std_logic_vector(15 downto 0);
|
||
| ... | ... | |
|
|
||
|
process(addr_decoded5,CH0_REG,CH1_REG,CH2_REG,CH3_REG,
|
||
|
ram_cpu_addr_reg, ram_data,
|
||
|
irq_en_reg,irq_active_reg
|
||
|
irq_en_reg,irq_active_reg,
|
||
|
adpcm_reg,bits8_reg
|
||
|
)
|
||
|
begin
|
||
|
DO <= (others=>'0');
|
||
| ... | ... | |
|
store_data <= (others=>'0');
|
||
|
case store_source is
|
||
|
when "0001"|"0011"|"0101"|"0111"|"1001"|"1011"|"1101"|"1111" =>
|
||
|
store_data(12 downto 5) <= di;
|
||
|
store_data(12) <= not(di(7));
|
||
|
store_data(11 downto 5) <= di(6 downto 0);
|
||
|
when "0110"|"1110" =>
|
||
|
store_data <= adpcm_decoded(15 downto 3);
|
||
|
when "1100" =>
|
||
|
store_data(12) <= not(ram_data(7));
|
||
|
store_data(11 downto 5) <= ram_data(6 downto 0);
|
||
|
store_data(12 downto 5) <= ram_data(7 downto 0);
|
||
|
when "0100" =>
|
||
|
if (data_nibble='0') then
|
||
|
store_data(12) <= not(ram_data(7));
|
||
|
store_data(11 downto 9) <= ram_data(6 downto 4);
|
||
|
store_data(12 downto 9) <= ram_data(7 downto 4);
|
||
|
else
|
||
|
store_data(12) <= not(ram_data(3));
|
||
|
store_data(11 downto 9) <= ram_data(2 downto 0);
|
||
|
store_data(12 downto 9) <= ram_data(3 downto 0);
|
||
|
end if;
|
||
|
|
||
|
when others=>
|
||
| ... | ... | |
|
|
||
|
process (ch0_reg,ch1_reg,ch2_reg,ch3_reg,
|
||
|
ch0_volume_reg,ch1_volume_reg,ch2_volume_reg,ch3_volume_reg)
|
||
|
variable l : unsigned(26 downto 0);
|
||
|
variable r : unsigned(26 downto 0);
|
||
|
variable l : signed(26 downto 0);
|
||
|
variable r : signed(26 downto 0);
|
||
|
begin
|
||
|
l := resize(unsigned(CH0_REG),18)*resize(unsigned(ch0_volume_reg),9);
|
||
|
l := l + resize(unsigned(CH3_REG),18)*resize(unsigned(ch3_volume_reg),9);
|
||
|
r := resize(unsigned(CH1_REG),18)*resize(unsigned(ch1_volume_reg),9);
|
||
|
r := r + resize(unsigned(CH2_REG),18)*resize(unsigned(ch2_volume_reg),9);
|
||
|
l := resize(signed(CH0_REG),18)*resize(signed('0'&ch0_volume_reg),9);
|
||
|
l := l + resize(signed(CH3_REG),18)*resize(signed('0'&ch3_volume_reg),9);
|
||
|
r := resize(signed(CH1_REG),18)*resize(signed('0'&ch1_volume_reg),9);
|
||
|
r := r + resize(signed(CH2_REG),18)*resize(signed('0'&ch2_volume_reg),9);
|
||
|
-- TODO: probably need to register here?
|
||
|
AUDIO0 <= std_logic_vector(l(19 downto 4));
|
||
|
AUDIO1 <= std_logic_vector(r(19 downto 4));
|
||
|
AUDIO0(15 downto 0) <= l(19 downto 4);
|
||
|
AUDIO1(15 downto 0) <= r(19 downto 4);
|
||
|
|
||
|
-- TODO: modulation?
|
||
|
-- TODO: samples from rom and put in voice samples after core?
|
||
| atari_chips/pokeyv2/sigmadelta_2ndorder_dither.vhd | ||
|---|---|---|
|
ENTITY sigmadelta_2ndorder_dither IS
|
||
|
GENERIC (
|
||
|
DITHER_ENABLE : integer := 1; -- 0/1
|
||
|
DITHER_BITS : integer := 2; -- 1..4; start small
|
||
|
DITHER_BITS : integer := 3; -- 1..4; start small
|
||
|
LFSR_SEED : unsigned(15 downto 0) := x"ACE1"
|
||
|
);
|
||
|
PORT
|
||
Use natural signed/unsigned source depending on which chip. Mix with signed, with a dc blocker. Add a bit more dither to make the mid level voltage acceptable through the sigma delta, since it now sits a 2.5v for silence (internally, external is ac coupled). This fixes the sample engine clicks when playing mod files due to the sample engine volume being applied on unsigned converted samples, which gave a dc bias betwen samples. Paula samples have to end/start at signed midpoint you see.