diff --git a/LAB3/sim/tb_volume_multiplier.vhd b/LAB3/sim/tb_volume_multiplier.vhd index 914b30d..ccb4e85 100644 --- a/LAB3/sim/tb_volume_multiplier.vhd +++ b/LAB3/sim/tb_volume_multiplier.vhd @@ -14,6 +14,7 @@ ARCHITECTURE Behavioral OF tb_volume_multiplier IS CONSTANT VOLUME_WIDTH : POSITIVE := 10; CONSTANT VOLUME_STEP_2 : POSITIVE := 6; CONSTANT N_SAMPLES : INTEGER := 8; + CONSTANT N_VOLUMES : INTEGER := 10; -- Output width calculation (as in DUT) CONSTANT TDATA_OUT_WIDTH : INTEGER := TDATA_WIDTH - 1 + 2 ** (VOLUME_WIDTH - VOLUME_STEP_2 - 1) + 1; @@ -63,6 +64,21 @@ ARCHITECTURE Behavioral OF tb_volume_multiplier IS x"000A00", -- +2560 x"FFF600" -- -2560 ); + + -- Vettore di memoria per i valori di volume + TYPE volume_mem_type IS ARRAY(0 TO N_VOLUMES-1) OF STD_LOGIC_VECTOR(VOLUME_WIDTH-1 DOWNTO 0); + SIGNAL volume_mem : volume_mem_type := ( + std_logic_vector(to_unsigned(0, VOLUME_WIDTH)), -- 0.25x (forte attenuazione) + std_logic_vector(to_unsigned(64, VOLUME_WIDTH)), -- 0.375x (attenuazione media) + std_logic_vector(to_unsigned(479, VOLUME_WIDTH)), -- 0.4375x (leggera attenuazione) + std_logic_vector(to_unsigned(480, VOLUME_WIDTH)), -- 0.5x (volume neutro) + std_logic_vector(to_unsigned(513, VOLUME_WIDTH)), -- Circa 0.5x (volume neutro) + std_logic_vector(to_unsigned(576, VOLUME_WIDTH)), -- 0.5625x (leggero aumento) + std_logic_vector(to_unsigned(640, VOLUME_WIDTH)), -- 0.625x (aumento medio) + std_logic_vector(to_unsigned(768, VOLUME_WIDTH)), -- 0.75x (aumento forte) + std_logic_vector(to_unsigned(896, VOLUME_WIDTH)), -- 0.875x (aumento molto forte) + std_logic_vector(to_unsigned(1023, VOLUME_WIDTH)) -- 1x (massimo volume) + ); BEGIN @@ -99,7 +115,7 @@ BEGIN WAIT UNTIL rising_edge(aclk); -- Set volume to mid (no gain/loss) - volume <= std_logic_vector(to_unsigned(511, VOLUME_WIDTH)); + volume <= volume_mem(0); WAIT UNTIL rising_edge(aclk); -- Send all samples @@ -122,7 +138,7 @@ BEGIN -- Change volume (attenuate) WAIT FOR 20 ns; - volume <= std_logic_vector(to_unsigned(256, VOLUME_WIDTH)); -- attenuate + volume <= volume_mem(1); -- Send one more sample WAIT UNTIL rising_edge(aclk); @@ -136,6 +152,12 @@ BEGIN s_axis_tvalid <= '0'; s_axis_tlast <= '0'; + FOR i IN 2 TO N_VOLUMES-1 LOOP + WAIT FOR 20 ns; + volume <= volume_mem(i); + WAIT UNTIL rising_edge(aclk); + END LOOP; + -- Wait and finish WAIT FOR 100 ns; WAIT; diff --git a/LAB3/src/balance_controller.vhd b/LAB3/src/balance_controller.vhd index 01b41cd..45cb94a 100644 --- a/LAB3/src/balance_controller.vhd +++ b/LAB3/src/balance_controller.vhd @@ -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; \ No newline at end of file diff --git a/LAB3/src/led_level_controller.vhd b/LAB3/src/led_level_controller.vhd index 69ea691..b48f151 100644 --- a/LAB3/src/led_level_controller.vhd +++ b/LAB3/src/led_level_controller.vhd @@ -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à + 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'); diff --git a/LAB3/src/volume_multiplier.vhd b/LAB3/src/volume_multiplier.vhd index 997c281..86a9bc9 100644 --- a/LAB3/src/volume_multiplier.vhd +++ b/LAB3/src/volume_multiplier.vhd @@ -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'; diff --git a/LAB3/vivado/volume_multiplier/volume_multiplier.xpr b/LAB3/vivado/volume_multiplier/volume_multiplier.xpr index 1ba8039..b7efd10 100644 --- a/LAB3/vivado/volume_multiplier/volume_multiplier.xpr +++ b/LAB3/vivado/volume_multiplier/volume_multiplier.xpr @@ -47,7 +47,7 @@