------------------------------------------------------------------------------- -- -- File : boxfilter_3x3.vhd -- Related files : -- -- Author(s) : stephane Domas (sdomas@univ-fcomte.fr) -- -- Creation Date : 2017/10/16 -- -- Description : This IP does a box (i.e. average) filter with a 3x3 mask -- on a grayscale image. The width of the image must be <= 1024. -- Image size must be provided via generics -- -- Note : -- CP = 1{$img_width*$img_height} -- PP = 0{$img_width+7}1{$img_width*$img_height} -- PC = {$img_width+2:$img_width*$img_height-($img_width+2):1},{$img_width*$img_height:$img_width+2,0} -- delta = $img_width*$img_height -- ------------------------------------------------------------------------------- library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; entity boxfilter_3x3 is generic( img_width : natural := 128; img_height : natural := 128; dsp_in_width : natural := 18; dsp_out_width : natural := 36 ); port( clk : in std_logic; reset : in std_logic; pix_in : in std_logic_vector(7 downto 0); pix_in_enb : in std_logic; pix_out : out std_logic_vector(7 downto 0); pix_out_enb : out std_logic ); end boxfilter_3x3; architecture rtl of boxfilter_3x3 is component ram_dp_1024x8 port ( clka : in std_logic; wea : in std_logic_vector(0 downto 0); addra : in std_logic_vector(9 downto 0); dina : in std_logic_vector(7 downto 0); douta : out std_logic_vector(7 downto 0); clkb : in std_logic; web : in std_logic_vector(0 downto 0); addrb : in std_logic_vector(9 downto 0); dinb : in std_logic_vector(7 downto 0); doutb : out std_logic_vector(7 downto 0) ); end component; -- Signals -- constant signal set tup to img limits signal count_col_end : unsigned (9 downto 0); signal count_row_end : unsigned (9 downto 0); -- for storing image rows signal sel_mem : unsigned (1 downto 0); -- the current memorize row signal wea_0 : std_logic_vector(0 downto 0); -- we for memorized row 0 signal wea_1 : std_logic_vector(0 downto 0); -- we for memorized row 1 signal wea_2 : std_logic_vector(0 downto 0); -- we for memorized row 2 signal dina_0 : std_logic_vector(7 downto 0); signal dina_1 : std_logic_vector(7 downto 0); signal dina_2 : std_logic_vector(7 downto 0); signal dina : std_logic_vector(7 downto 0); signal addra_w : std_logic_vector(9 downto 0); signal addra_w_s : unsigned (9 downto 0); signal wea : std_logic; signal addrb_r : std_logic_vector(9 downto 0); -- addr where to store signal addrb_r_s : unsigned (9 downto 0); -- addr where to store signal doutb_0 : std_logic_vector(7 downto 0); signal doutb_1 : std_logic_vector(7 downto 0); signal doutb_2 : std_logic_vector(7 downto 0); signal count_row_w : unsigned (10 downto 0); -- row counter while storing signal store_last_pix : std_logic; -- to be sure that last pixel is stored signal first_row_w : std_logic; -- '1' when the first row is read so that -- mem_0 is filled with zeroes signal all_pix_stored : std_logic; -- '1' when all pixels have been stored -- for reading image rows signal start_read : std_logic; signal do_read : std_logic; signal count_row_r : unsigned (10 downto 0); signal count_row_r_dly : unsigned (10 downto 0); signal wea_dly : std_logic; signal end_read : std_logic; -- for doing sums signal do_sum : std_logic; signal sum1 : unsigned (9 downto 0); signal sum2 : unsigned (9 downto 0); signal sum3 : unsigned (9 downto 0); -- for doing total signal do_total : std_logic; signal sum : unsigned (dsp_in_width-1 downto 0); signal count_col_total : unsigned (10 downto 0); signal count_row_total : unsigned (10 downto 0); signal jump_first_sum : std_logic; -- for doing final division signal do_div : std_logic; signal do_out : std_logic; signal end_filter : std_logic; signal cst_mult : unsigned(dsp_in_width-1 downto 0); -- eq. 14564 (=2^17/9) signal mult_result : unsigned (dsp_out_width-1 downto 0); begin img_row_0 : ram_dp_1024x8 port map ( clka => clk, wea => wea_0, addra => addra_w, dina => dina_0, clkb => clk, web => (others => '0'), addrb => addrb_r, dinb => (others => '0'), doutb => doutb_0 ); img_row_1 : ram_dp_1024x8 port map ( clka => clk, wea => wea_1, addra => addra_w, dina => dina_1, clkb => clk, web => (others => '0'), addrb => addrb_r, dinb => (others => '0'), doutb => doutb_1 ); img_row_2 : ram_dp_1024x8 port map ( clka => clk, wea => wea_2, addra => addra_w, dina => dina_2, clkb => clk, web => (others => '0'), addrb => addrb_r, dinb => (others => '0'), doutb => doutb_2 ); cst_mult <= to_unsigned(14564, dsp_in_width); count_col_end <= to_unsigned(img_width-1, 10); count_row_end <= to_unsigned(img_height-1, 10); addra_w <= std_logic_vector(addra_w_s); addrb_r <= std_logic_vector(addrb_r_s); wea_0 <= "1" when ((sel_mem = 0 or first_row_w = '1') and wea = '1') else "0"; wea_1 <= "1" when (sel_mem = 1 and wea = '1') else "0"; wea_2 <= "1" when (sel_mem = 2 and wea = '1') else "0"; dina_0 <= (others => '0') when (first_row_w = '1') else dina; dina_1 <= dina; dina_2 <= dina; store_row_process : process (clk, reset) begin if reset = '1' then sel_mem <= to_unsigned(0, 2); addra_w_s <= to_unsigned(img_width-1, 10); dina <= (others => '0'); wea <= '0'; count_row_w <= to_unsigned(0, 11); start_read <= '0'; first_row_w <= '1'; store_last_pix <= '0'; all_pix_stored <= '0'; elsif rising_edge(clk) then wea <= '0'; start_read <= '0'; dina <= (others => '0'); store_last_pix <= '0'; -- reset all when filter has ended if end_filter = '1' then count_row_w <= to_unsigned(0, 11); sel_mem <= to_unsigned(0, 2); addra_w_s <= to_unsigned(img_width-1, 10); first_row_w <= '1'; all_pix_stored <= '0'; elsif store_last_pix = '1' then addra_w_s <= to_unsigned(0, 10); -- select next ram if sel_mem = 2 then sel_mem <= to_unsigned(0, 2); else sel_mem <= sel_mem + 1; end if; all_pix_stored <= '1'; -- all pixels are stored elsif pix_in_enb = '1' then -- prepare to write wea <= '1'; -- take input dina <= pix_in; -- check if this is the last pixel if addra_w_s = img_width-2 and count_row_w = img_height then store_last_pix <= '1'; end if; -- if at line end if addra_w_s = img_width-1 then -- back to 0 addra_w_s <= to_unsigned(0, 10); -- select next ram if sel_mem = 2 then sel_mem <= to_unsigned(0, 2); else sel_mem <= sel_mem + 1; end if; -- end of first line to store if count_row_w = 1 then first_row_w <= '0'; start_read <= '1'; end if; count_row_w <= count_row_w + 1; else addra_w_s <= addra_w_s + 1; end if; end if; end if; end process store_row_process; read_rows_process : process (clk, reset) begin if reset = '1' then addrb_r_s <= to_unsigned(0, 10); do_read <= '0'; wea_dly <= '0'; count_row_r <= to_unsigned(0, 11); end_read <= '0'; do_sum <= '0'; elsif rising_edge(clk) then wea_dly <= wea; do_sum <= '0'; end_read <= '0'; if end_read = '1' then do_sum <= '1'; end if; if start_read = '1' then do_read <= '1'; elsif do_read = '1' and (all_pix_stored = '1' or wea_dly = '1') then do_sum <= '1'; -- whatever the case inc addr if not at end if addrb_r_s = img_width-1 then addrb_r_s <= to_unsigned(0, 10); if count_row_r = img_height-1 then count_row_r <= to_unsigned(0, 11); do_read <= '0'; end_read <= '1'; else count_row_r <= count_row_r+1; end if; else addrb_r_s <= addrb_r_s + 1; end if; end if; end if; end process read_rows_process; sum_process : process (clk, reset) begin if reset = '1' then sum1 <= to_unsigned(0, 10); sum2 <= to_unsigned(0, 10); sum3 <= to_unsigned(0, 10); count_row_r_dly <= to_unsigned(0, 11); do_total <= '0'; elsif rising_edge(clk) then do_total <= '0'; count_row_r_dly <= count_row_r; if end_filter = '1' then sum1 <= to_unsigned(0, 10); sum2 <= to_unsigned(0, 10); sum3 <= to_unsigned(0, 10); end if; if do_sum = '1' then sum3 <= sum2; sum2 <= sum1; if count_row_r_dly = img_height-1 then if sel_mem = 0 then sum1 <= unsigned("00" & doutb_1) + unsigned("00" & doutb_2); elsif sel_mem = 1 then sum1 <= unsigned("00" & doutb_0) + unsigned("00" & doutb_2); elsif sel_mem = 2 then sum1 <= unsigned("00" & doutb_0) + unsigned("00" & doutb_1); end if; else sum1 <= unsigned("00" & doutb_0) + unsigned("00" & doutb_1) + unsigned("00" & doutb_2); end if; do_total <= '1'; end if; end if; end process sum_process; total_process : process (clk, reset) begin if reset = '1' then sum <= to_unsigned(0, dsp_in_width); jump_first_sum <= '0'; count_row_total <= to_unsigned(0, 11); count_col_total <= to_unsigned(0, 11); do_div <= '0'; end_filter <= '0'; elsif rising_edge(clk) then do_div <= '0'; end_filter <= '0'; if do_total = '1' then if jump_first_sum = '1' then -- sum for the end of the line if count_col_total = img_width-1 then sum <= resize(sum2, dsp_in_width) + resize(sum3, dsp_in_width); count_col_total <= to_unsigned(0, 11); if count_row_total = img_height-1 then end_filter <= '1'; count_row_total <= to_unsigned(0, 11); jump_first_sum <= '0'; else count_row_total <= count_row_total + 1; end if; -- sum for the begining of the line elsif count_col_total = 0 then sum <= resize(sum1, dsp_in_width) + resize(sum2, dsp_in_width); count_col_total <= to_unsigned(1, 11); else sum <= resize(sum1, dsp_in_width) + resize(sum2, dsp_in_width) + resize(sum3, dsp_in_width); count_col_total <= count_col_total + 1; end if; do_div <= '1'; else jump_first_sum <= '1'; end if; end if; end if; end process total_process; final_div_process : process (clk, reset) begin if reset = '1' then mult_result <= to_unsigned(0, dsp_out_width); do_out <= '0'; elsif rising_edge(clk) then do_out <= '0'; if do_div = '1' then mult_result <= sum * cst_mult; do_out <= '1'; end if; end if; end process final_div_process; pix_out <= std_logic_vector(mult_result(24 downto 17)); pix_out_enb <= do_out; end rtl;