diff --git a/LAB2/sim/tb_rgb2gray.vhd b/LAB2/sim/tb_rgb2gray.vhd index f742af1..e1806f6 100644 --- a/LAB2/sim/tb_rgb2gray.vhd +++ b/LAB2/sim/tb_rgb2gray.vhd @@ -45,35 +45,89 @@ ARCHITECTURE Behavioral OF rgb2gray_tb IS BEGIN - m_axis_tready<='1'; - - clk <= not clk AFTER clk_period / 2; -- Clock generation + clk <= NOT clk AFTER clk_period / 2; -- Clock generation -- Instantiate the Device Under Test (DUT) - DUT: rgb2gray - PORT MAP ( - clk => clk, - resetn => resetn, - m_axis_tvalid => m_axis_tvalid, - m_axis_tdata => m_axis_tdata, - m_axis_tready => m_axis_tready, - m_axis_tlast => m_axis_tlast, - s_axis_tvalid => s_axis_tvalid, - s_axis_tdata => s_axis_tdata, - s_axis_tready => s_axis_tready, - s_axis_tlast => s_axis_tlast - ); + DUT : rgb2gray + PORT MAP( + clk => clk, + resetn => resetn, + m_axis_tvalid => m_axis_tvalid, + m_axis_tdata => m_axis_tdata, + m_axis_tready => m_axis_tready, + m_axis_tlast => m_axis_tlast, + s_axis_tvalid => s_axis_tvalid, + s_axis_tdata => s_axis_tdata, + s_axis_tready => s_axis_tready, + s_axis_tlast => s_axis_tlast + ); -- Stimulus process stimulus_process : PROCESS VARIABLE pixel_value : INTEGER := 1; -- Variable to increment pixel values BEGIN - wait for 10 ns; - resetn<='1'; + WAIT FOR 10 ns; + resetn <= '1'; s_axis_tvalid <= '1'; -- Send multiple RGB pixels with incrementing values - FOR i IN 0 TO 10 LOOP -- Send 10 pixels + FOR i IN 0 TO 5 LOOP -- Send 10 pixels + -- R component + s_axis_tdata <= STD_LOGIC_VECTOR(TO_UNSIGNED(pixel_value, 8)); + WAIT FOR clk_period; + + -- G component + pixel_value := pixel_value + 5; + s_axis_tdata <= STD_LOGIC_VECTOR(TO_UNSIGNED(pixel_value, 8)); + WAIT FOR clk_period; + + -- B component + pixel_value := pixel_value + 1; + s_axis_tdata <= STD_LOGIC_VECTOR(TO_UNSIGNED(pixel_value, 8)); + WAIT FOR clk_period; + + -- Reset last signal + pixel_value := pixel_value + 1; + END LOOP; + + m_axis_tready <= '0'; + + -- R component + s_axis_tdata <= STD_LOGIC_VECTOR(TO_UNSIGNED(pixel_value, 8)); + WAIT FOR clk_period; + + -- G component + pixel_value := pixel_value + 5; + s_axis_tdata <= STD_LOGIC_VECTOR(TO_UNSIGNED(pixel_value, 8)); + WAIT FOR clk_period; + + -- B component + pixel_value := pixel_value + 1; + s_axis_tdata <= STD_LOGIC_VECTOR(TO_UNSIGNED(pixel_value, 8)); + WAIT FOR clk_period; + + FOR i IN 0 TO 3 LOOP -- Send 10 pixels + -- R component + s_axis_tdata <= STD_LOGIC_VECTOR(TO_UNSIGNED(pixel_value, 8)); + WAIT FOR clk_period; + + -- G component + pixel_value := pixel_value + 5; + s_axis_tdata <= STD_LOGIC_VECTOR(TO_UNSIGNED(pixel_value, 8)); + WAIT FOR clk_period; + + -- B component + pixel_value := pixel_value + 1; + s_axis_tdata <= STD_LOGIC_VECTOR(TO_UNSIGNED(pixel_value, 8)); + WAIT FOR clk_period; + + -- Reset last signal + pixel_value := pixel_value + 1; + END LOOP; + + m_axis_tready <= '1'; + + FOR i IN 0 TO 3 LOOP -- Send 10 pixels -- R component s_axis_tdata <= STD_LOGIC_VECTOR(TO_UNSIGNED(pixel_value, 8)); WAIT FOR clk_period; diff --git a/LAB2/src/depacketizer.vhd b/LAB2/src/depacketizer.vhd index 2816982..d1437ef 100644 --- a/LAB2/src/depacketizer.vhd +++ b/LAB2/src/depacketizer.vhd @@ -1,99 +1,94 @@ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - - -entity depacketizer is - generic ( - HEADER: INTEGER :=16#FF#; - FOOTER: INTEGER :=16#F1# +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; +ENTITY depacketizer IS + GENERIC ( + HEADER : INTEGER := 16#FF#; + FOOTER : INTEGER := 16#F1# ); - port ( - clk : in std_logic; - aresetn : in std_logic; + PORT ( + clk : IN STD_LOGIC; + aresetn : IN STD_LOGIC; - s_axis_tdata : in std_logic_vector(7 downto 0); - s_axis_tvalid : in std_logic; - s_axis_tready : out std_logic; + s_axis_tdata : IN STD_LOGIC_VECTOR(7 DOWNTO 0); + s_axis_tvalid : IN STD_LOGIC; + s_axis_tready : OUT STD_LOGIC; - m_axis_tdata : out std_logic_vector(7 downto 0); - m_axis_tvalid : out std_logic; - m_axis_tready : in std_logic; - m_axis_tlast : out std_logic + m_axis_tdata : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); + m_axis_tvalid : OUT STD_LOGIC; + m_axis_tready : IN STD_LOGIC; + m_axis_tlast : OUT STD_LOGIC ); -end entity depacketizer; +END ENTITY depacketizer; -architecture rtl of depacketizer is +ARCHITECTURE rtl OF depacketizer IS -- Enumeration for the state machine -- IDLE: Waiting for the start of a new packet -- STREAMING: Actively processing and forwarding packet data - type state_type is (IDLE, STREAMING); - signal state : state_type := IDLE; + TYPE state_type IS (IDLE, STREAMING); + SIGNAL state : state_type := IDLE; -- Buffer to handle backpressure - signal buffer_in : std_logic_vector(7 downto 0) := (others => '0'); - signal buffer_valid : std_logic := '0'; -- Indicates if buffer_in contains valid data -begin + SIGNAL buffer_in : STD_LOGIC_VECTOR(7 DOWNTO 0) := (OTHERS => '0'); + SIGNAL buffer_valid : STD_LOGIC := '0'; -- Indicates if buffer_in contains valid data +BEGIN - depacketizer_fsm: process(clk) - begin - if rising_edge(clk) then - if aresetn = '0' then + depacketizer_fsm : PROCESS (clk) + BEGIN + IF rising_edge(clk) THEN + IF aresetn = '0' THEN -- Reset: back to idle and clear everything - state <= IDLE; + state <= IDLE; s_axis_tready <= '0'; m_axis_tvalid <= '0'; - m_axis_tlast <= '0'; - m_axis_tdata <= (others => '0'); - buffer_in <= (others => '0'); - buffer_valid <= '0'; + m_axis_tlast <= '0'; + m_axis_tdata <= (OTHERS => '0'); + buffer_in <= (OTHERS => '0'); + buffer_valid <= '0'; - else + ELSE -- Defaults for each clock cycle s_axis_tready <= '1'; m_axis_tvalid <= '0'; - m_axis_tlast <= '0'; + m_axis_tlast <= '0'; - case state is + CASE state IS - when IDLE => + WHEN IDLE => -- Wait for start of a new packet - if s_axis_tvalid = '1' then - if s_axis_tdata = std_logic_vector(to_unsigned(HEADER, 8)) then + IF s_axis_tvalid = '1' THEN + m_axis_tvalid <= '0'; + IF s_axis_tdata = STD_LOGIC_VECTOR(to_unsigned(HEADER, 8)) THEN state <= STREAMING; - end if; - end if; + END IF; + END IF; + + WHEN STREAMING => + IF s_axis_tvalid = '1' THEN - when STREAMING => - if s_axis_tvalid = '1' then -- End of packet detected - if s_axis_tdata = std_logic_vector(to_unsigned(FOOTER, 8)) then - state <= IDLE; - m_axis_tlast <= '1'; -- Let receiver know packet ends - else + IF s_axis_tdata = STD_LOGIC_VECTOR(to_unsigned(FOOTER, 8)) THEN + -- Send the last data and transition to IDLE + m_axis_tdata <= buffer_in; -- Send the last buffered data + state <= IDLE; + m_axis_tlast <= '1'; -- Let receiver know packet ends + ELSE -- Valid payload: send to output - if buffer_valid = '1' then - if m_axis_tready = '1' then - m_axis_tdata <= buffer_in; - m_axis_tvalid <= '1'; - buffer_valid <= '0'; -- Clear the buffer - end if; - else - if m_axis_tready = '1' then - m_axis_tdata <= s_axis_tdata; - m_axis_tvalid <= '1'; - else - buffer_in <= s_axis_tdata; - buffer_valid <= '1'; -- Mark buffer as valid - end if; - end if; - end if; - end if; + IF buffer_valid = '1' AND m_axis_tready = '1' THEN + m_axis_tdata <= buffer_in; + m_axis_tvalid <= '1'; + buffer_valid <= '0'; -- Clear the buffer + END IF; - end case; - end if; - end if; - end process; + buffer_in <= s_axis_tdata; + buffer_valid <= '1'; + END IF; + END IF; -end architecture; + END CASE; + END IF; + END IF; + END PROCESS; + +END ARCHITECTURE; \ No newline at end of file diff --git a/LAB2/src/divider_by_3.vhd b/LAB2/src/divider_by_3.vhd index 27a37eb..b96076e 100644 --- a/LAB2/src/divider_by_3.vhd +++ b/LAB2/src/divider_by_3.vhd @@ -7,11 +7,11 @@ USE IEEE.MATH_REAL.ALL; ENTITY divider_by_3 IS GENERIC ( - BIT_DEPTH : INTEGER := 8 + BIT_DEPTH : INTEGER := 7 ); PORT ( dividend : IN UNSIGNED(BIT_DEPTH + 1 DOWNTO 0); - gray : OUT UNSIGNED(BIT_DEPTH - 1 DOWNTO 0) + result : OUT UNSIGNED(BIT_DEPTH - 1 DOWNTO 0) ); END divider_by_3; @@ -20,12 +20,11 @@ ARCHITECTURE Behavioral OF divider_by_3 IS CONSTANT DIVISION_MULTIPLIER : INTEGER := INTEGER(floor(real(2 ** (BIT_DEPTH + 2)) / 3.0)); -- Constant to calculate the length of the result signal - CONSTANT RESULT_WIDTH : INTEGER := (2 * BIT_DEPTH) + 2; + CONSTANT RESULT_WIDTH : INTEGER := (2 * BIT_DEPTH) + 2; -- 16 bit -- Signals to hold the sum of the RGB channels and the intermediate results - SIGNAL rgb_sum_extended : UNSIGNED(BIT_DEPTH + 1 DOWNTO 0) := (OTHERS => '0'); - SIGNAL scaled_result : UNSIGNED(RESULT_WIDTH DOWNTO 0) := (OTHERS => '0'); - SIGNAL grayscale_value : UNSIGNED(BIT_DEPTH - 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL sum_extended : UNSIGNED(BIT_DEPTH + 1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL scaled_result : UNSIGNED(RESULT_WIDTH - 1 DOWNTO 0) := (OTHERS => '0'); BEGIN -- Explanation of how the division by 3 is performed: @@ -37,15 +36,12 @@ BEGIN -- 4. The final grayscale value is extracted from the result and converted back to a std_logic_vector. -- Calculate the sum of the RGB channels - rgb_sum_extended <= dividend + TO_UNSIGNED(2, BIT_DEPTH + 2); + sum_extended <= dividend + TO_UNSIGNED(2, BIT_DEPTH + 2); -- Multiply the sum by the precomputed multiplier - scaled_result <= rgb_sum_extended * TO_UNSIGNED(DIVISION_MULTIPLIER, BIT_DEPTH + 1); + scaled_result <= RESIZE(sum_extended * TO_UNSIGNED(DIVISION_MULTIPLIER, BIT_DEPTH + 1), RESULT_WIDTH); -- Extract the grayscale value from the scaled result by right-shifting - grayscale_value <= scaled_result(RESULT_WIDTH - 1 DOWNTO RESULT_WIDTH - BIT_DEPTH); - - -- Assign the grayscale value to the output - gray <= grayscale_value; + result <= scaled_result(RESULT_WIDTH - 1 DOWNTO RESULT_WIDTH - BIT_DEPTH); END Behavioral; \ No newline at end of file diff --git a/LAB2/src/img_conv.vhd b/LAB2/src/img_conv.vhd index 731c637..2a8ff72 100644 --- a/LAB2/src/img_conv.vhd +++ b/LAB2/src/img_conv.vhd @@ -1,41 +1,177 @@ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; -entity img_conv is - generic( - LOG2_N_COLS: POSITIVE :=8; - LOG2_N_ROWS: POSITIVE :=8 +ENTITY img_conv IS + GENERIC ( + LOG2_N_COLS : POSITIVE := 8; + LOG2_N_ROWS : POSITIVE := 8 ); - port ( + PORT ( - clk : in std_logic; - aresetn : in std_logic; + clk : IN STD_LOGIC; + aresetn : IN STD_LOGIC; - m_axis_tdata : out std_logic_vector(7 downto 0); - m_axis_tvalid : out std_logic; - m_axis_tready : in std_logic; - m_axis_tlast : out std_logic; - - conv_addr: out std_logic_vector(LOG2_N_COLS+LOG2_N_ROWS-1 downto 0); - conv_data: in std_logic_vector(6 downto 0); + m_axis_tdata : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); + m_axis_tvalid : OUT STD_LOGIC; + m_axis_tready : IN STD_LOGIC; + m_axis_tlast : OUT STD_LOGIC; + + conv_addr : OUT STD_LOGIC_VECTOR(LOG2_N_COLS + LOG2_N_ROWS - 1 DOWNTO 0); + conv_data : IN STD_LOGIC_VECTOR(6 DOWNTO 0); + + start_conv : IN STD_LOGIC; + done_conv : OUT STD_LOGIC - start_conv: in std_logic; - done_conv: out std_logic - ); -end entity img_conv; +END ENTITY img_conv; -architecture rtl of img_conv is +ARCHITECTURE rtl OF img_conv IS + TYPE conv_mat_type IS ARRAY(0 TO 2, 0 TO 2) OF INTEGER; + CONSTANT conv_mat : conv_mat_type := ((-1, -1, -1),(-1, 8, -1),(-1, -1, -1)); - type conv_mat_type is array(0 to 2, 0 to 2) of integer; - constant conv_mat : conv_mat_type := ((-1,-1,-1),(-1,8,-1),(-1,-1,-1)); + -- Definizione della finestra 3x3; ogni pixel è rappresentato da 8 bit + TYPE window_array IS ARRAY(0 TO 2, 0 TO 2) OF STD_LOGIC_VECTOR(7 DOWNTO 0); + SIGNAL window : window_array := (OTHERS => (OTHERS => (OTHERS => '0'))); - + -- Parametri immagine + CONSTANT IMG_WIDTH : INTEGER := 2 ** LOG2_N_COLS; -- Larghezza dell'immagine + CONSTANT IMG_HEIGHT : INTEGER := 2 ** LOG2_N_ROWS; -- Altezza dell'immagine -begin + -- Indirizzo corrente per la lettura dei pixel + SIGNAL current_addr : STD_LOGIC_VECTOR(LOG2_N_COLS + LOG2_N_ROWS - 1 DOWNTO 0); + -- Variabili per il calcolo della convoluzione + SIGNAL conv_sum : INTEGER := 0; -- Somma dei prodotti + SIGNAL conv_out : STD_LOGIC_VECTOR(7 DOWNTO 0); -- Risultato della convoluzione + -- Stato della macchina a stati + TYPE state_type IS (IDLE, LOAD_PIXEL, COMPUTE, OUTPUT); + SIGNAL state : state_type := IDLE; -end architecture; + -- Contatori per riga e colonna + SIGNAL row, col : INTEGER RANGE 0 TO IMG_HEIGHT - 1 := 0; + +BEGIN + + -- Aggiornamento dell'indirizzo di lettura (mapping riga-colonna) + conv_addr <= STD_LOGIC_VECTOR(to_unsigned(row * IMG_WIDTH + col, conv_addr'length)); + + -- Processo principale: macchina a stati per la gestione della convoluzione + PROCESS (clk, aresetn) + BEGIN + IF aresetn = '0' THEN + -- Reset asincrono: inizializza tutti i segnali + state <= IDLE; + row <= 0; + col <= 0; + window <= (OTHERS => (OTHERS => (OTHERS => '0'))); + conv_sum <= 0; + conv_out <= (OTHERS => '0'); + m_axis_tdata <= (OTHERS => '0'); + m_axis_tvalid <= '0'; + m_axis_tlast <= '0'; + done_conv <= '0'; + current_addr <= (OTHERS => '0'); + ELSIF rising_edge(clk) THEN + CASE state IS + + -- Stato IDLE: attende il segnale di start per iniziare la convoluzione + WHEN IDLE => + m_axis_tvalid <= '0'; + m_axis_tlast <= '0'; + IF start_conv = '1' THEN + row <= 0; + col <= 0; + done_conv <= '0'; + -- Inizializza la finestra a zero per gestire il padding superiore + window <= (OTHERS => (OTHERS => (OTHERS => '0'))); + state <= LOAD_PIXEL; + END IF; + + -- Stato LOAD_PIXEL: carica un nuovo pixel e aggiorna la finestra + WHEN LOAD_PIXEL => + -- Aggiorna la finestra con il nuovo pixel (conv_data) + -- Lo shifting viene realizzato per spostare i dati verso sinistra + IF col = 0 THEN + -- Per ogni riga della finestra si forza la colonna sinistra a zero + FOR i IN 0 TO 2 LOOP + window(i)(0) <= (OTHERS => '0'); + END LOOP; + ELSE + FOR i IN 0 TO 2 LOOP + window(i)(0) <= window(i)(1); + window(i)(1) <= window(i)(2); + END LOOP; + END IF; + + -- Aggiorna la colonna destra della finestra con il nuovo pixel + FOR i IN 0 TO 2 LOOP + window(i)(2) <= conv_data; + END LOOP; + + -- Aggiorna i contatori per scorrere l'immagine + IF col = IMG_WIDTH - 1 THEN + col <= 0; + IF row = IMG_HEIGHT - 1 THEN + state <= COMPUTE; + ELSE + row <= row + 1; + END IF; + ELSE + col <= col + 1; + END IF; + + state <= COMPUTE; + + -- Stato COMPUTE: esegue il calcolo della convoluzione + WHEN COMPUTE => + -- Gestione dei bordi: imposta il risultato a zero se la finestra non è completa + IF (row = 0) OR (row = IMG_HEIGHT - 1) OR (col = 0) OR (col = IMG_WIDTH - 1) THEN + conv_sum <= 0; + ELSE + conv_sum <= 0; + -- Moltiplica cella per cella e somma i prodotti + FOR i IN 0 TO 2 LOOP + FOR j IN 0 TO 2 LOOP + conv_sum <= conv_sum + conv_mat(i, j) * to_integer(unsigned(window(i)(j))); + END LOOP; + END LOOP; + END IF; + + -- Saturazione del risultato + IF conv_sum < 0 THEN + conv_out <= STD_LOGIC_VECTOR(to_unsigned(0, 8)); + ELSIF conv_sum >= 256 THEN + conv_out <= STD_LOGIC_VECTOR(to_unsigned(255, 8)); + ELSE + conv_out <= STD_LOGIC_VECTOR(to_unsigned(conv_sum, 8)); + END IF; + + state <= OUTPUT; + + -- Stato OUTPUT: invia il risultato tramite l'interfaccia AXIS + WHEN OUTPUT => + IF m_axis_tready = '1' THEN + m_axis_tdata <= conv_out; + m_axis_tvalid <= '1'; + -- Se siamo sull'ultimo pixel dell'immagine, segnaliamo TLAST e il completamento + IF (row = IMG_HEIGHT - 1) AND (col = IMG_WIDTH - 1) THEN + m_axis_tlast <= '1'; + done_conv <= '1'; + state <= IDLE; + ELSE + m_axis_tlast <= '0'; + state <= LOAD_PIXEL; + END IF; + END IF; + + -- Stato di default: ritorna a IDLE + WHEN OTHERS => + state <= IDLE; + END CASE; + END IF; + END PROCESS; + +END ARCHITECTURE; \ No newline at end of file diff --git a/LAB2/src/rgb2gray.vhd b/LAB2/src/rgb2gray.vhd index 19718ec..c148ac6 100644 --- a/LAB2/src/rgb2gray.vhd +++ b/LAB2/src/rgb2gray.vhd @@ -30,29 +30,30 @@ ARCHITECTURE Behavioral OF rgb2gray IS COMPONENT divider_by_3 GENERIC ( - BIT_DEPTH : INTEGER := 8 + BIT_DEPTH : INTEGER := 7 ); PORT ( dividend : IN UNSIGNED(BIT_DEPTH + 1 DOWNTO 0); - gray : OUT UNSIGNED(BIT_DEPTH - 1 DOWNTO 0)); + result : OUT UNSIGNED(BIT_DEPTH - 1 DOWNTO 0)); END COMPONENT divider_by_3; TYPE state_type IS (WAIT_R, WAIT_G, WAIT_B); SIGNAL state : state_type := WAIT_R; SIGNAL r_val, g_val : unsigned(7 DOWNTO 0); - SIGNAL sum : unsigned(9 DOWNTO 0); - SIGNAL gray : UNSIGNED(7 DOWNTO 0); + SIGNAL sum : unsigned(8 DOWNTO 0); + SIGNAL gray : UNSIGNED(6 DOWNTO 0); + SIGNAL send_data : STD_LOGIC := '0'; BEGIN DIVIDER : divider_by_3 GENERIC MAP( - BIT_DEPTH => 8 + BIT_DEPTH => 7 ) PORT MAP( dividend => sum, - gray => gray + result => gray ); PROCESS (clk) @@ -70,32 +71,43 @@ BEGIN sum <= (OTHERS => '0'); ELSE -- Default control signals - s_axis_tready <= '1'; - m_axis_tlast <= '0'; + m_axis_tlast <= s_axis_tlast; + m_axis_tvalid <= '0'; -- If downstream is ready, send the grayscale pixel - IF m_axis_tready = '1' THEN - m_axis_tdata <= STD_LOGIC_VECTOR(gray); - m_axis_tlast <= s_axis_tlast; + IF m_axis_tready = '1' AND send_data = '1' THEN + m_axis_tdata <= STD_LOGIC_VECTOR('0' & gray); + m_axis_tvalid <= '1'; + send_data <= '0'; END IF; CASE state IS WHEN WAIT_R => IF s_axis_tvalid = '1' THEN r_val <= unsigned(s_axis_tdata); + + IF m_axis_tready = '0' THEN + s_axis_tready <= '0'; + END IF; + state <= WAIT_G; END IF; WHEN WAIT_G => IF s_axis_tvalid = '1' THEN g_val <= unsigned(s_axis_tdata); - state <= WAIT_B; + + IF m_axis_tready = '1' THEN + s_axis_tready <= '1'; + state <= WAIT_B; + END IF; END IF; WHEN WAIT_B => IF s_axis_tvalid = '1' THEN - sum <= ('0' & '0' & r_val) + ('0' & '0' & g_val) + ('0' & '0' & unsigned(s_axis_tdata)); - m_axis_tvalid <= '1'; + sum <= RESIZE(r_val + g_val + unsigned(s_axis_tdata), 9); + send_data <= '1'; + state <= WAIT_R; END IF; diff --git a/LAB2/vivado/rgb2grey_test/rgb2grey_test.xpr b/LAB2/vivado/rgb2grey_test/rgb2grey_test.xpr index 5326766..a338ead 100644 --- a/LAB2/vivado/rgb2grey_test/rgb2grey_test.xpr +++ b/LAB2/vivado/rgb2grey_test/rgb2grey_test.xpr @@ -47,7 +47,7 @@