Refactor volume_multiplier

This commit is contained in:
2025-05-21 20:37:47 +02:00
parent 4e3d7c45a2
commit 13cf70b984
5 changed files with 181 additions and 81 deletions

View File

@@ -27,62 +27,128 @@ ENTITY balance_controller IS
END balance_controller;
ARCHITECTURE Behavioral OF balance_controller IS
CONSTANT CENTER_VALUE : INTEGER := 2 ** (BALANCE_WIDTH - 1) - 1; -- 511 per BALANCE_WIDTH=10
CONSTANT DEADZONE : INTEGER := 32; -- Deadzone da -32 a +32
CONSTANT MAX_SHIFT : INTEGER := TDATA_WIDTH - 1; -- Massimo shift possibile
CONSTANT BAL_MID : INTEGER := 2 ** (BALANCE_WIDTH - 1); -- 512 per 10 bit
CONSTANT DEAD_ZONE : INTEGER := 32;
CONSTANT BLOCK_SIZE : INTEGER := 64;
SIGNAL balance_signed : signed(BALANCE_WIDTH - 1 DOWNTO 0);
SIGNAL shift_amount_left, shift_amount_right : NATURAL RANGE 0 TO MAX_SHIFT;
SIGNAL tvalid_reg : STD_LOGIC := '0';
SIGNAL tdata_reg : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0) := (OTHERS => '0');
SIGNAL tlast_reg : STD_LOGIC := '0';
-- Registri di pipeline
SIGNAL audio_in_reg : signed(TDATA_WIDTH - 1 DOWNTO 0);
SIGNAL tlast_reg : STD_LOGIC;
SIGNAL valid_reg : STD_LOGIC;
SIGNAL left_shift : INTEGER RANGE 0 TO BALANCE_WIDTH := 0;
SIGNAL right_shift : INTEGER RANGE 0 TO BALANCE_WIDTH := 0;
SIGNAL bal_int : INTEGER;
-- Segnali di controllo
SIGNAL ready_int : STD_LOGIC;
SIGNAL processing_active : STD_LOGIC;
BEGIN
-- Convert balance input to signed (-512 to +511)
balance_signed <= signed(balance);
-- Handshake & cattura dati in ingresso
-- Calcolo dello shift amount con deadzone e scaling esponenziale
PROCESS (balance_signed)
VARIABLE centered_value : signed(BALANCE_WIDTH - 1 DOWNTO 0);
VARIABLE abs_value : unsigned(BALANCE_WIDTH - 2 DOWNTO 0);
VARIABLE exp_shift : INTEGER;
BEGIN
-- Centra il valore intorno a 0 (da -512 a +511 -> da -511 a +511)
centered_value := balance_signed - to_signed(CENTER_VALUE, BALANCE_WIDTH);
-- Inizializzazione
shift_amount_left <= 0;
shift_amount_right <= 0;
-- Calcola il valore assoluto
IF centered_value(BALANCE_WIDTH - 1) = '1' THEN -- negativo
abs_value := unsigned(-centered_value(BALANCE_WIDTH - 2 DOWNTO 0));
ELSE
abs_value := unsigned(centered_value(BALANCE_WIDTH - 2 DOWNTO 0));
END IF;
-- Applica deadzone e calcola shift
IF centered_value > DEADZONE THEN
-- Calcola lo shift per il canale sinistro (valori positivi)
exp_shift := (to_integer(abs_value) - DEADZONE) / 2 ** BALANCE_STEP_2 + 1;
IF exp_shift > MAX_SHIFT THEN
shift_amount_left <= MAX_SHIFT;
ELSE
shift_amount_left <= exp_shift;
END IF;
ELSIF centered_value <- DEADZONE THEN
-- Calcola lo shift per il canale destro (valori negativi)
exp_shift := (to_integer(abs_value) - DEADZONE) / 2 ** BALANCE_STEP_2 + 1;
IF exp_shift > MAX_SHIFT THEN
shift_amount_right <= MAX_SHIFT;
ELSE
shift_amount_right <= exp_shift;
END IF;
END IF;
END PROCESS;
-- Il resto del codice rimane IDENTICO alla versione originale
-- Logica di controllo AXI
PROCESS (aclk)
VARIABLE temp : signed(TDATA_WIDTH + MAX_SHIFT - 1 DOWNTO 0);
BEGIN
IF rising_edge(aclk) THEN
IF aresetn = '0' THEN
tvalid_reg <= '0';
tdata_reg <= (OTHERS => '0');
-- Reset asincrono
valid_reg <= '0';
audio_in_reg <= (OTHERS => '0');
tlast_reg <= '0';
ELSIF s_axis_tvalid = '1' AND m_axis_tready = '1' THEN
tvalid_reg <= '1';
tdata_reg <= s_axis_tdata;
tlast_reg <= s_axis_tlast;
ELSIF m_axis_tready = '1' THEN
tvalid_reg <= '0';
processing_active <= '0';
ELSE
-- Gestione del flusso dati
IF ready_int = '1' THEN
valid_reg <= '0';
IF s_axis_tvalid = '1' THEN
-- Registrazione degli ingressi
audio_in_reg <= signed(s_axis_tdata);
tlast_reg <= s_axis_tlast;
valid_reg <= '1';
processing_active <= '1';
ELSE
processing_active <= '0';
END IF;
END IF;
-- Elaborazione del dato (sempre attiva)
IF processing_active = '1' OR valid_reg = '1' THEN
temp := resize(audio_in_reg, temp'length);
IF tlast_reg = '0' THEN
temp := shift_right(temp, shift_amount_left);
ELSE
temp := shift_right(temp, shift_amount_right);
END IF;
-- Saturazione
IF temp > 2 ** (TDATA_WIDTH - 1) - 1 THEN
m_axis_tdata <= STD_LOGIC_VECTOR(to_signed(2 ** (TDATA_WIDTH - 1) - 1, TDATA_WIDTH));
ELSIF temp <- 2 ** (TDATA_WIDTH - 1) THEN
m_axis_tdata <= STD_LOGIC_VECTOR(to_signed(-2 ** (TDATA_WIDTH - 1), TDATA_WIDTH));
ELSE
m_axis_tdata <= STD_LOGIC_VECTOR(temp(TDATA_WIDTH - 1 DOWNTO 0));
END IF;
m_axis_tlast <= tlast_reg;
END IF;
END IF;
END IF;
END PROCESS;
s_axis_tready <= m_axis_tready;
-- Logica combinazionale per tready
ready_int <= m_axis_tready OR NOT valid_reg;
s_axis_tready <= ready_int;
bal_int <= to_integer(unsigned(balance));
-- Calcolo shift esponenziale per balance con zona morta centrale e blocchi da 64
left_shift <= ((bal_int - (BAL_MID + DEAD_ZONE)) / BLOCK_SIZE) WHEN bal_int > (BAL_MID + DEAD_ZONE) ELSE 0;
right_shift <= (((BAL_MID - DEAD_ZONE) - bal_int) / BLOCK_SIZE) WHEN bal_int < (BAL_MID - DEAD_ZONE) ELSE 0;
-- Applicazione gain esponenziale tramite shift (process combinatorio)
PROCESS (tvalid_reg, tlast_reg, tdata_reg, left_shift, right_shift)
BEGIN
IF tvalid_reg = '1' THEN
IF tlast_reg = '0' THEN -- left
m_axis_tdata <= STD_LOGIC_VECTOR(shift_right(signed(tdata_reg), left_shift));
ELSE -- right
m_axis_tdata <= STD_LOGIC_VECTOR(shift_right(signed(tdata_reg), right_shift));
END IF;
ELSE
m_axis_tdata <= (OTHERS => '0');
END IF;
END PROCESS;
m_axis_tvalid <= tvalid_reg;
m_axis_tlast <= tlast_reg;
-- Assegnazione del valid in uscita
m_axis_tvalid <= valid_reg;
END Behavioral;

View File

@@ -27,76 +27,90 @@ end led_level_controller;
architecture Behavioral of led_level_controller is
constant REFRESH_CYCLES : natural := (refresh_time_ms * 1_000_000) / clock_period_ns;
signal volume_value : signed(CHANNEL_LENGHT-1 downto 0) := (others => '0');
signal abs_audio : unsigned(CHANNEL_LENGHT-2 downto 0) := (others => '0');
signal leds_int : std_logic_vector(NUM_LEDS-1 downto 0) := (others => '0');
signal led_update : std_logic := '0';
signal refresh_counter : natural range 0 to REFRESH_CYCLES-1 := 0;
signal volume_value : signed(CHANNEL_LENGHT-1 downto 0) := (others => '0');
signal abs_audio_left : unsigned(CHANNEL_LENGHT-2 downto 0) := (others => '0');
signal abs_audio_right : unsigned(CHANNEL_LENGHT-2 downto 0) := (others => '0');
signal leds_int : std_logic_vector(NUM_LEDS-1 downto 0) := (others => '0');
signal led_update : std_logic := '0';
signal refresh_counter : natural range 0 to REFRESH_CYCLES-1 := 0;
begin
led <= leds_int;
s_axis_tready <= '1';
-- Register the audio absolute value
-- Registrazione del valore audio assoluto
process(aclk)
variable sdata_signed : signed(CHANNEL_LENGHT-1 downto 0);
variable abs_value : unsigned(CHANNEL_LENGHT-1 downto 0);
begin
if rising_edge(aclk) then
if aresetn = '0' then
volume_value <= (others => '0');
volume_value <= (others => '0');
abs_audio_left <= (others => '0');
abs_audio_right<= (others => '0');
elsif s_axis_tvalid = '1' then
volume_value <= signed(s_axis_tdata);
if volume_value(volume_value'high) = '1' then
abs_audio <= unsigned(-volume_value(CHANNEL_LENGHT-2 downto 0));
sdata_signed := signed(s_axis_tdata);
volume_value <= sdata_signed;
-- Calcolo valore assoluto
if sdata_signed(CHANNEL_LENGHT-1) = '1' then
abs_value := unsigned(-sdata_signed);
else
abs_audio <= unsigned(volume_value(CHANNEL_LENGHT-2 downto 0));
abs_value := unsigned(sdata_signed);
end if;
-- Assegna al canale corretto
if s_axis_tlast = '1' then -- Canale sinistro
abs_audio_left <= abs_value(CHANNEL_LENGHT-2 downto 0);
else -- Canale destro
abs_audio_right <= abs_value(CHANNEL_LENGHT-2 downto 0);
end if;
end if;
end if;
end process;
-- Refresh counter
-- Contatore di refresh
process(aclk)
begin
if rising_edge(aclk) then
if aresetn = '0' then
refresh_counter <= 0;
led_update <= '0';
elsif refresh_counter = REFRESH_CYCLES-1 then
refresh_counter <= 0;
led_update <= '1';
else
if refresh_counter = REFRESH_CYCLES-1 then
refresh_counter <= 0;
led_update <= '1';
else
refresh_counter <= refresh_counter + 1;
led_update <= '0';
end if;
refresh_counter <= refresh_counter + 1;
led_update <= '0';
end if;
end if;
end process;
-- Linear scaling of the audio signal to LED levels
-- Scaling lineare e aggiornamento LED
process(aclk)
variable leds_on : natural range 0 to NUM_LEDS;
variable leds_on : natural range 0 to NUM_LEDS;
variable temp_led_level : integer range 0 to NUM_LEDS;
variable abs_audio_sum : unsigned(CHANNEL_LENGHT-1 downto 0);
begin
if rising_edge(aclk) then
if aresetn = '0' then
leds_int <= (others => '0');
elsif led_update = '1' then
-- Automatic linear scaling calculation:
if to_integer(abs_audio) = 0 then
abs_audio_sum := resize(abs_audio_left, CHANNEL_LENGHT) + resize(abs_audio_right, CHANNEL_LENGHT);
if (abs_audio_left = 0 and abs_audio_right = 0) then
temp_led_level := 0;
else -- -1 bit for sign, -4 to get 15+1 levels
temp_led_level := to_integer(shift_right(abs_audio,CHANNEL_LENGHT-4-1))+1;
else
-- Scaling automatico: puoi regolare la costante di shift per la sensibilit<69>
temp_led_level := 1 + to_integer(shift_right(abs_audio_sum, CHANNEL_LENGHT-4));
end if;
-- Limit to maximum number of LEDs
-- Limita al massimo numero di LED
if temp_led_level > NUM_LEDS then
leds_on := NUM_LEDS;
else
leds_on := temp_led_level;
end if;
-- Aggiorna i LED
leds_int <= (others => '0');
if leds_on > 0 then
leds_int(leds_on-1 downto 0) <= (others => '1');

View File

@@ -28,12 +28,10 @@ END volume_multiplier;
ARCHITECTURE Behavioral OF volume_multiplier IS
CONSTANT VOLUME_STEPS : INTEGER := (2 ** VOLUME_WIDTH) / (2 ** VOLUME_STEP_2);
CONSTANT CENTER_VOLUME_STEP : INTEGER := (2 ** (VOLUME_WIDTH - 1) - 1) / (2 ** VOLUME_STEP_2) + 1;
CONSTANT VOLUME_STEPS : INTEGER := (2 ** (VOLUME_WIDTH - 1)) / (2 ** VOLUME_STEP_2) + 1;
SIGNAL volume_exp_mult : INTEGER RANGE -VOLUME_STEPS TO VOLUME_STEPS := 0;
SIGNAL m_axis_tvalid_int : STD_LOGIC;
BEGIN
@@ -53,7 +51,7 @@ BEGIN
ELSE
-- Volume to signed and centered and convert to power of 2 exponent
volume_exp_mult <= to_integer(
shift_right(signed('0' & volume), VOLUME_STEP_2) - CENTER_VOLUME_STEP
shift_right(signed('0' & volume) - to_signed(480, volume'length + 1), VOLUME_STEP_2)
);
END IF;
@@ -74,6 +72,9 @@ BEGIN
m_axis_tdata <= (OTHERS => '0');
ELSE
-- Default output signals
m_axis_tlast <= '0';
-- Clear valid flag when master interface is ready
IF m_axis_tready = '1' THEN
m_axis_tvalid_int <= '0';