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 @@
-
+
@@ -95,6 +95,7 @@
+
@@ -150,9 +151,7 @@
-
- Vivado Synthesis Defaults
-
+
@@ -161,9 +160,7 @@
-
- Default settings for Implementation.
-
+