Project

General

Profile

« Previous | Next » 

Revision 1510

Added by markw 1 day ago

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.

View differences:

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

Also available in: Unified diff