+-------------------------------------------------------------------------------
+--
+-- 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;
+