From 1d779b7d3a2e5fe28f4ecd67aad25c81d6b414ab Mon Sep 17 00:00:00 2001 From: Cd16d Date: Thu, 22 May 2025 11:22:57 +0200 Subject: [PATCH] Add testbench for balance_controller and update Vivado project files --- LAB3/sim/tb_balance_controller.vhd | 170 ++++++++++++++ LAB3/src/balance_controller.vhd | 174 ++++++-------- LAB3/src/volume_multiplier.vhd | 2 + .../balance_controller/balance_controller.xpr | 214 ++++++++++++++++++ .../tb_balance_controller_behav.wcfg | 97 ++++++++ 5 files changed, 552 insertions(+), 105 deletions(-) create mode 100644 LAB3/sim/tb_balance_controller.vhd create mode 100644 LAB3/vivado/balance_controller/balance_controller.xpr create mode 100644 LAB3/vivado/balance_controller/tb_balance_controller_behav.wcfg diff --git a/LAB3/sim/tb_balance_controller.vhd b/LAB3/sim/tb_balance_controller.vhd new file mode 100644 index 0000000..ff9e6f9 --- /dev/null +++ b/LAB3/sim/tb_balance_controller.vhd @@ -0,0 +1,170 @@ +---------------------------------------------------------------------------------- +-- Testbench for balance_controller +---------------------------------------------------------------------------------- +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + +ENTITY tb_balance_controller IS +END tb_balance_controller; + +ARCHITECTURE Behavioral OF tb_balance_controller IS + + CONSTANT TDATA_WIDTH : POSITIVE := 24; + CONSTANT BALANCE_WIDTH : POSITIVE := 10; + CONSTANT BALANCE_STEP_2 : POSITIVE := 6; + CONSTANT N_SAMPLES : INTEGER := 8; + CONSTANT N_BALANCES : INTEGER := 5; + + COMPONENT balance_controller IS + GENERIC ( + TDATA_WIDTH : POSITIVE := 24; + BALANCE_WIDTH : POSITIVE := 10; + BALANCE_STEP_2 : POSITIVE := 6 + ); + PORT ( + aclk : IN STD_LOGIC; + aresetn : IN STD_LOGIC; + s_axis_tvalid : IN STD_LOGIC; + s_axis_tdata : IN STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); + s_axis_tready : OUT STD_LOGIC; + s_axis_tlast : IN STD_LOGIC; + m_axis_tvalid : OUT STD_LOGIC; + m_axis_tdata : OUT STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); + m_axis_tready : IN STD_LOGIC; + m_axis_tlast : OUT STD_LOGIC; + balance : IN STD_LOGIC_VECTOR(BALANCE_WIDTH - 1 DOWNTO 0) + ); + END COMPONENT; + + SIGNAL aclk : STD_LOGIC := '0'; + SIGNAL aresetn : STD_LOGIC := '0'; + SIGNAL s_axis_tvalid : STD_LOGIC := '0'; + SIGNAL s_axis_tdata : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL s_axis_tlast : STD_LOGIC := '0'; + SIGNAL s_axis_tready : STD_LOGIC; + SIGNAL m_axis_tvalid : STD_LOGIC; + SIGNAL m_axis_tdata : STD_LOGIC_VECTOR(TDATA_WIDTH - 1 DOWNTO 0); + SIGNAL m_axis_tlast : STD_LOGIC; + SIGNAL m_axis_tready : STD_LOGIC := '1'; + SIGNAL balance : STD_LOGIC_VECTOR(BALANCE_WIDTH - 1 DOWNTO 0) := (OTHERS => '0'); + + -- Test input samples + TYPE sample_mem_type IS ARRAY(0 TO N_SAMPLES-1) OF STD_LOGIC_VECTOR(TDATA_WIDTH-1 DOWNTO 0); + SIGNAL sample_mem : sample_mem_type := ( + x"000100", -- +256 + x"FFFE00", -- -512 + x"000001", -- +1 + x"FFFFFF", -- -1 (2's comp) + x"7FFFFF", -- max positive + x"800000", -- max negative + x"000A00", -- +2560 + x"FFF600" -- -2560 + ); + + -- Balance values: left, center, right, slightly left, slightly right + TYPE balance_mem_type IS ARRAY(0 TO N_BALANCES-1) OF STD_LOGIC_VECTOR(BALANCE_WIDTH-1 DOWNTO 0); + SIGNAL balance_mem : balance_mem_type := ( + std_logic_vector(to_unsigned(0, BALANCE_WIDTH)), -- full left + std_logic_vector(to_unsigned(480, BALANCE_WIDTH)), -- center + std_logic_vector(to_unsigned(1023, BALANCE_WIDTH)), -- full right + std_logic_vector(to_unsigned(240, BALANCE_WIDTH)), -- slightly left + std_logic_vector(to_unsigned(800, BALANCE_WIDTH)) -- slightly right + ); + +BEGIN + + -- Clock generation + aclk <= NOT aclk AFTER 5 ns; + + -- DUT instantiation + uut: balance_controller + GENERIC MAP ( + TDATA_WIDTH => TDATA_WIDTH, + BALANCE_WIDTH => BALANCE_WIDTH, + BALANCE_STEP_2 => BALANCE_STEP_2 + ) + PORT MAP ( + aclk => aclk, + aresetn => aresetn, + s_axis_tvalid => s_axis_tvalid, + s_axis_tdata => s_axis_tdata, + s_axis_tready => s_axis_tready, + s_axis_tlast => s_axis_tlast, + m_axis_tvalid => m_axis_tvalid, + m_axis_tdata => m_axis_tdata, + m_axis_tready => m_axis_tready, + m_axis_tlast => m_axis_tlast, + balance => balance + ); + + -- Stimulus process + stimulus : PROCESS + BEGIN + -- Reset + WAIT FOR 10 ns; + aresetn <= '1'; + WAIT UNTIL rising_edge(aclk); + + -- Set balance to center + balance <= balance_mem(1); + WAIT UNTIL rising_edge(aclk); + + -- Send all samples (center) + FOR i IN 0 TO N_SAMPLES-1 LOOP + s_axis_tdata <= sample_mem(i); + s_axis_tvalid <= '1'; + IF i = N_SAMPLES-1 THEN + s_axis_tlast <= '1'; + ELSE + s_axis_tlast <= '0'; + END IF; + WAIT UNTIL rising_edge(aclk); + WHILE s_axis_tready = '0' LOOP + WAIT UNTIL rising_edge(aclk); + END LOOP; + END LOOP; + s_axis_tvalid <= '0'; + s_axis_tlast <= '0'; + + -- Change balance to full left + WAIT FOR 20 ns; + balance <= balance_mem(0); + + -- Send one more sample (left) + WAIT UNTIL rising_edge(aclk); + s_axis_tdata <= x"000100"; + s_axis_tvalid <= '1'; + s_axis_tlast <= '1'; + WAIT UNTIL rising_edge(aclk); + WHILE s_axis_tready = '0' LOOP + WAIT UNTIL rising_edge(aclk); + END LOOP; + s_axis_tvalid <= '0'; + s_axis_tlast <= '0'; + + -- Sweep through other balance values + FOR i IN 2 TO N_BALANCES-1 LOOP + WAIT FOR 20 ns; + balance <= balance_mem(i); + WAIT UNTIL rising_edge(aclk); + END LOOP; + + -- Wait and finish + WAIT FOR 100 ns; + WAIT; + END PROCESS; + + -- Optionally, block m_axis_tready to test backpressure + PROCESS + BEGIN + WAIT FOR 60 ns; + WAIT UNTIL rising_edge(aclk); + m_axis_tready <= '0'; + WAIT FOR 20 ns; + WAIT UNTIL rising_edge(aclk); + m_axis_tready <= '1'; + WAIT; + END PROCESS; + +END Behavioral; \ No newline at end of file diff --git a/LAB3/src/balance_controller.vhd b/LAB3/src/balance_controller.vhd index 45cb94a..4ec0d23 100644 --- a/LAB3/src/balance_controller.vhd +++ b/LAB3/src/balance_controller.vhd @@ -6,7 +6,7 @@ ENTITY balance_controller IS GENERIC ( TDATA_WIDTH : POSITIVE := 24; BALANCE_WIDTH : POSITIVE := 10; - BALANCE_STEP_2 : POSITIVE := 6 -- i.e., balance_values_per_step = 2**VOLUME_STEP_2 + BALANCE_STEP_2 : POSITIVE := 6 -- i.e., balance_values_per_step = 2**BALANCE_STEP_2 ); PORT ( aclk : IN STD_LOGIC; @@ -27,128 +27,92 @@ 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 - SIGNAL balance_signed : signed(BALANCE_WIDTH - 1 DOWNTO 0); - SIGNAL shift_amount_left, shift_amount_right : NATURAL RANGE 0 TO MAX_SHIFT; + CONSTANT BALANCE_STEPS : INTEGER := (2 ** (BALANCE_WIDTH - 1)) / (2 ** BALANCE_STEP_2) + 1; + CONSTANT BAL_MID : INTEGER := 2 ** (BALANCE_WIDTH - 1); -- 512 for 10 bit + CONSTANT BLOCK_SIZE : INTEGER := 2 ** BALANCE_STEP_2; + CONSTANT DEAD_ZONE : INTEGER := BLOCK_SIZE / 2; - -- 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_channel : INTEGER RANGE 0 TO BALANCE_STEPS := 0; + SIGNAL right_channel : INTEGER RANGE 0 TO BALANCE_STEPS := 0; - -- Segnali di controllo - SIGNAL ready_int : STD_LOGIC; - SIGNAL processing_active : STD_LOGIC; + SIGNAL m_axis_tvalid_int : STD_LOGIC; BEGIN - -- Convert balance input to signed (-512 to +511) - balance_signed <= signed(balance); + -- Assigning the output signals + m_axis_tvalid <= m_axis_tvalid_int; + s_axis_tready <= m_axis_tready AND aresetn; - -- 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 + -- Balance to exp PROCESS (aclk) - VARIABLE temp : signed(TDATA_WIDTH + MAX_SHIFT - 1 DOWNTO 0); BEGIN + IF rising_edge(aclk) THEN + IF aresetn = '0' THEN - -- Reset asincrono - valid_reg <= '0'; - audio_in_reg <= (OTHERS => '0'); - tlast_reg <= '0'; - processing_active <= '0'; + left_channel <= 0; + right_channel <= 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; + -- Balance left and right channels + IF unsigned(balance) > (BAL_MID + DEAD_ZONE) THEN + left_channel <= to_integer((unsigned(balance) - (BAL_MID + DEAD_ZONE)) SRL BALANCE_STEP_2) + 1; + ELSE + left_channel <= 0; 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; + IF unsigned(balance) < (BAL_MID - DEAD_ZONE) THEN + right_channel <= to_integer(((BAL_MID - DEAD_ZONE) - unsigned(balance)) SRL BALANCE_STEP_2) + 1; + ELSE + right_channel <= 0; END IF; + END IF; + END IF; + END PROCESS; - -- Logica combinazionale per tready - ready_int <= m_axis_tready OR NOT valid_reg; - s_axis_tready <= ready_int; + -- Handle AXIS stream + PROCESS (aclk) + BEGIN - -- Assegnazione del valid in uscita - m_axis_tvalid <= valid_reg; + IF rising_edge(aclk) THEN + + IF aresetn = '0' THEN + m_axis_tvalid_int <= '0'; + m_axis_tlast <= '0'; + 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'; + END IF; + + -- Handle the data flow + IF s_axis_tvalid = '1' AND m_axis_tready = '1' THEN + -- Joystick datasheet: (x-axis) a 0 value corresponds to the axis + -- being tilted fully to the left and a value of 1023 + -- corresponds fully to the right + IF s_axis_tlast = '0' THEN -- left + m_axis_tdata <= STD_LOGIC_VECTOR(shift_right(signed(s_axis_tdata), left_channel)); + ELSE -- right + m_axis_tdata <= STD_LOGIC_VECTOR(shift_right(signed(s_axis_tdata), right_channel)); + END IF; + + m_axis_tvalid_int <= '1'; + m_axis_tlast <= s_axis_tlast; + + END IF; + + END IF; + + END IF; + + END PROCESS; END Behavioral; \ No newline at end of file diff --git a/LAB3/src/volume_multiplier.vhd b/LAB3/src/volume_multiplier.vhd index 86a9bc9..5217502 100644 --- a/LAB3/src/volume_multiplier.vhd +++ b/LAB3/src/volume_multiplier.vhd @@ -83,6 +83,8 @@ BEGIN -- Handle the data flow IF s_axis_tvalid = '1' AND m_axis_tready = '1' THEN -- Multiply the input data with the volume and assign to output + -- Joystick datasheet: (y-axis) a value of 0 when it is tilted all the way down + -- and a value of 1023 when it is tilted all the way up IF volume_exp_mult >= 0 THEN m_axis_tdata <= STD_LOGIC_VECTOR( shift_left( diff --git a/LAB3/vivado/balance_controller/balance_controller.xpr b/LAB3/vivado/balance_controller/balance_controller.xpr new file mode 100644 index 0000000..76aebba --- /dev/null +++ b/LAB3/vivado/balance_controller/balance_controller.xpr @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Vivado Synthesis Defaults + + + + + + + + + + + Default settings for Implementation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default_dashboard + + + diff --git a/LAB3/vivado/balance_controller/tb_balance_controller_behav.wcfg b/LAB3/vivado/balance_controller/tb_balance_controller_behav.wcfg new file mode 100644 index 0000000..b6a040f --- /dev/null +++ b/LAB3/vivado/balance_controller/tb_balance_controller_behav.wcfg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + aclk + aclk + + + aresetn + aresetn + + + Balance + label + + + balance[9:0] + balance[9:0] + UNSIGNEDDECRADIX + + + left_shift + left_shift + + + right_shift + right_shift + + + s_axis + label + + + s_axis_tdata[23:0] + s_axis_tdata[23:0] + SIGNEDDECRADIX + + + s_axis_tlast + s_axis_tlast + + + s_axis_tvalid + s_axis_tvalid + #00FFFF + true + + + s_axis_tready + s_axis_tready + #FFD700 + true + + + m_axis + label + + + m_axis_tdata[23:0] + m_axis_tdata[23:0] + SIGNEDDECRADIX + + + m_axis_tlast + m_axis_tlast + + + m_axis_tvalid + m_axis_tvalid + #00FFFF + true + + + m_axis_tready + m_axis_tready + #FFD700 + true + +